PathrockNetwork Gno Explorer
HomeBlocksTransactionsRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/r/moul/x/daily/pullpaymentdemo/v0

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
v0
Namespace
moul / x / daily / pullpaymentdemo
Files
3 (README)(gnomod.toml)
Exported functions
1
Module
gno.land/r/moul/x/daily/pullpaymentdemo/v0
gno
0.9

Files (3)

  • README.mdmarkdown
  • gnomod.tomltoml
  • pullpaymentdemo.gnogno
pullpaymentdemo.gnogno
1// Package pullpaymentdemo is a small gnoweb demo of the escrow ledger provided2// by the [p/moul/x/daily/pullpayment](/p/moul/x/daily/pullpayment/v0) library:3// crediting a split, claiming it, and why a reentrant claim gets nothing.4//5// It contains no ledger logic of its own and holds no coins. Stateless, so6// Render is deterministic — which is precisely what the library is for.7package pullpaymentdemo89import (10	"strconv"11	"strings"1213	"gno.land/p/moul/x/daily/pullpayment/v0"14)1516// Render renders the demo for gnoweb.17func Render(path string) string {18	var b strings.Builder19	b.WriteString("# Pull Payment\n\n")20	b.WriteString("Credit and let recipients withdraw, demoing the ")21	b.WriteString("[`p/moul/x/daily/pullpayment`](/p/moul/x/daily/pullpayment/v0) library.\n\n")2223	b.WriteString("## Why not just send?\n\n")24	b.WriteString("Pushing value hands control to the recipient in the middle of your ")25	b.WriteString("state transition, and a hostile recipient re-enters before you have ")26	b.WriteString("finished updating. Pulling inverts it: you record a debt, and the ")27	b.WriteString("recipient's own withdrawal is the only state being touched.\n\n")2829	l := pullpayment.New()30	l.CreditMany([]string{"alice", "bob", "carol"}, []int64{500, 300, 200})3132	b.WriteString("## A split, credited\n\n")33	b.WriteString(table(l))34	b.WriteString("\nThe holding realm must keep `")35	b.WriteString(strconv.FormatInt(l.TotalOwed(), 10))36	b.WriteString("` in reserve — that is what `TotalOwed` is for.\n\n")3738	b.WriteString("## Bob claims\n\n")39	amt, _ := l.Withdraw("bob")40	b.WriteString("`Withdraw(\"bob\")` → `" + strconv.FormatInt(amt, 10) + "`, and the ledger ")41	b.WriteString("is updated **before** the caller transfers anything:\n\n")42	b.WriteString(table(l))43	b.WriteString("\nReserve is now `" + strconv.FormatInt(l.TotalOwed(), 10) + "`.\n\n")4445	b.WriteString("## The reentrancy attempt\n\n")46	b.WriteString("Bob's handler calls straight back in, before the transfer completes:\n\n")47	again, err := l.Withdraw("bob")48	b.WriteString("- second `Withdraw(\"bob\")` → `" + strconv.FormatInt(again, 10) + "`, error: `")49	if err != nil {50		b.WriteString(err.Error())51	} else {52		b.WriteString("<nil>")53	}54	b.WriteString("`\n\n")55	b.WriteString("Nothing left to take. The balance was deleted before control left the ")56	b.WriteString("function — checks, effects, *then* interactions. Lifetime withdrawn is ")57	b.WriteString("still `" + strconv.FormatInt(l.TotalWithdrawn(), 10) + "`, not double.\n\n")5859	b.WriteString("## Credits accumulate\n\n")60	l.Credit("alice", 100)61	b.WriteString("`Credit(\"alice\", 100)` on top of her existing balance:\n\n")62	b.WriteString(table(l))63	b.WriteString("\nOne withdrawal collects the lot — no dust left behind.\n\n")6465	b.WriteString("## Batch credits are all-or-nothing\n\n")66	b.WriteString("A split that is partly invalid applies **none** of itself; a ledger ")67	b.WriteString("half-agreeing with the funds it guards is worse than a rejected call:\n\n")68	before := l.TotalOwed()69	batchErr := l.CreditMany([]string{"dave", "eve"}, []int64{10, -1})70	b.WriteString("- `CreditMany([dave, eve], [10, -1])` → `")71	if batchErr != nil {72		b.WriteString(batchErr.Error())73	}74	b.WriteString("`\n- total owed before: `" + strconv.FormatInt(before, 10) + "`, after: `")75	b.WriteString(strconv.FormatInt(l.TotalOwed(), 10) + "` — unchanged, and `dave` was not credited\n")76	return b.String()77}7879func table(l *pullpayment.Ledger) string {80	var b strings.Builder81	b.WriteString("| payee | owed |\n|---|---|\n")82	l.Iterate(func(p string, amt int64) bool {83		b.WriteString("| `" + p + "` | " + strconv.FormatInt(amt, 10) + " |\n")84		return false85	})86	return b.String()87}88

Functions

  • Render(path string) string

Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

Rendered

RenderedRawgnoweb ↗

vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.