Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

README.md

3.15 Kb · 64 lines

gno.land/p/moul/x/social/coin/v0

A GRC20 that refuses to exist until its mint rule, its sink and its buyer are written down: New, Earn, Spend, Supply, Earned, Spent, Render.

 1import "gno.land/p/moul/x/social/coin/v0"
 2
 3var points = coin.New("Thread Points", "THREAD", 0, 0, coin.Policy{
 4	Mint:  "1 per distinct address that replies to your thread",
 5	Sink:  "burned to pin a thread to the top of its page",
 6	Buyer: "anyone who wants placement and has not earned it",
 7}, 0, cur)
 8
 9points.Earn(author, 1)   // the mint rule, with exactly one call site
10points.Spend(buyer, 10)  // the sink, which is the only thing that removes supply

The three strings are the whole point. New panics on a blank one, so the declaration happens before the first unit exists rather than in a README written afterwards, and Render prints all three on the issuing realm's own page, where being wrong about them is visible to the people holding the token.

A mint rule with no sink is a scoreboard with a price. Supply only grows, the number is the product, and a holder has no reason to buy one from an earner. Nothing in a package can check that a declared sink is real, which is exactly why it is a declaration and not a validation: the cheap failure is forgetting to decide, not lying.

Earned and Spent are kept separately from the supply because a sink that never fires is invisible in the supply alone. A flat line reads the same as no sink at all; two counters say which it is.

Earn of a non-positive amount is a no-op rather than an abort. A mint rule that computes zero means nothing new happened, and that should not fail the transaction that discovered it. Spend is the opposite and aborts naming both numbers, because its caller is a user about to be told they cannot afford something.

Everything else is the embedded p/nt/grc20: transfers, approvals, balances and events are an ordinary GRC20, so wallets and indexers need to know nothing about this package. Token() hands it over for the realm to expose and to register with a token registry.

The trailing _ int, rlm realm on New is the shape a pure package has to use to reach the caller's frame: a p/ may not declare a crossing function, so the realm token is threaded as a later parameter, exactly as grc20's own tellers do.

Live user: r/moul/x/social/threads.


Part of moul/gno-contracts — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage.

Dependency graph:

gno.land/p/moul/x/social/coin/v0 dependency graph

🧪 Highly experimental — potentially vibe-coded. Not audited; may break, change, or be removed at any time. Do not use with anything of value. Full disclaimer: DISCLAIMER.