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

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

garden/v5 package

Overview

Package garden is Gnotchi's pet realm, v5: the free, allowlisted, drand-rolled, hold-many realm MINT.md designs end to end. It inherits garden/v4's machinery -- the SaveDay shape, meters, garden plots, levels, and the List/Buy/Cancel trading surface -- but NOT v4's invariants (MINT.md section 6). garden/v4 is live, immutable and untouched by this file; its two gnomes stay exactly where they are forever (MINT.md section 6, BATCH-ONE.md section 0).

WHAT CHANGES FROM v4, IN ONE TABLE, EACH CITED TO THE DOCUMENT THAT DECIDED IT:

  • Adopt(name, hat, coat, eyes, nose) is GONE. Nothing is chosen by a caller any more. DECISIONS.md 2026-10-15 deprecates the DIY picker as a product direction; MINT.md section 1a/section 2 replace it with a roll.
  • An ALLOWLIST gates who may ever claim (MINT.md section 11: "gate issuance, never the secondary market"). Admin-managed, additive and removable, never touching the mint itself once a claim has spent its roll.
  • ONE ROLL PER WALLET, FOREVER, enforced independently of whether the resulting gnome is still held (MINT.md section 1a/section 2.3). hasRolled is permanent; nothing in this file clears it, and selling the gnome does not refund the roll.
  • FREE. Claim refuses coins exactly as v4's Adopt refuses them (MINT.md section 1a/2.5, GAMES.md rule 6: "random when earned, exact when bought... free: random is allowed").
  • THE ROLL IS TWO-PHASE, SETTLED BY DRAND (MINT.md section 10, the load-bearing finding of this whole file). A single-transaction roll is peekable two ways, verified against gno.land's own source and binary rather than assumed from Ethereum's model: vm/qeval can call a crossing function for free with no signature, and `gnokey maketx call -simulate only` previews a real signed call against the last committed block with no gas and no broadcast. Neither tool is the cause; the cause is that gno.land exposes NO on-chain entropy at all -- chain/runtime has ChainHeight and nothing else, math/rand is PCG seeded (0,0) on every node forever, and there is no shipped VRF -- so any single-transaction formula, however it is dressed up, is something a caller can evaluate offline for every block it might land in before ever deciding to broadcast. The fix MINT.md section 10.5 settles on, and this file builds, is a commit/reveal split across this project's own deployed drand verifier: Claim spends the one-time roll and pins a ROUND THAT DOES NOT EXIST YET; Settle, permissionless, computes the result once that round is actually published. One player signature, not two -- the player signs Claim only.
  • PARTS FROM A WEIGHTED TABLE (ECONOMY.md section 3), not a player's choice, with three named one-of-ones (Hob, Thistle, Wick -- BATCH-ONE.md section 7) capped at one each.
  • COUNTED RARITY. Every part's population is tracked on chain and readable by anyone -- MINT.md section 13's "nine gnomes in the world have this nose" has to be a chain fact, and EyesCount/NoseCount/HatCount/CoatCount below are that fact, not an app claim layered on top.
  • MINT ONE, HOLD MANY, PLAY ONE (MINT.md section 2a). Buy's one-gnome-per-address refusal is GONE -- deliberately, and only from Buy, never from Claim (see Claim's hasRolled gate, which is the cap that still matters). An address may hold any number of gnomes; exactly one is ever AWAKE, tracked by activeToken, and only the awake one can ever gain a cared day, a streak, a level or XP. SaveDay and ChooseType resolve through activeToken, never through "the" gnome for an address, because there no longer is one.
  • SWITCHING (Wake) is free, at most once per UTC day (MINT.md section 2a), the same day-boundary discipline SaveDay's own dailyCareDay already uses.
  • THE SECONDARY MARKET IS OPEN: Buy/List/Cancel carry over v4's shape and fee (MINT.md section 11), with no allowlist on buying and no hold cap.
  • THE LOCK: the three named one-of-ones cannot be listed until they have lockCaredDays cared days; every ordinary gnome trades from day one (MINT.md section 12/13, "Option A" -- lock only the named one-of-ones, recommended there and NOT YET CONFIRMED BY THE OWNER, which is why lockCaredDays is one named constant and nothing else in this file assumes its value). A gnome's own caredDayCount never decreases and is not reset by Buy, so once a named gnome unlocks it stays unlocked through every future sale.
  • A GENESIS GNOME, minted to this realm's own address at deploy, non-transferable, never listable, separate from the 24-gnome batch (DECISIONS.md 2026-10-15: "the genesis gnome belongs to nobody, permanently, on purpose"). Its name is not yet settled anywhere in this project's documents; genesisGnomeName below is a placeholder, named as one.

WHAT IS DELIBERATELY OUT OF SCOPE FOR THIS FILE, EACH A SCOPING DECISION MADE BY THIS PASS, NOT A GAP IN THE BRIEF THAT ASKED FOR IT. Recorded here in the open the same way MINT.md records its own open questions, so a future reader finds the reasoning in one hop:

  • NO SetRule/FreezeRules TUNABLE ADMIN SURFACE. v4's ruleBand/SetRule/FreezeRules machinery is real and proven, but every care-mechanic number below is a fixed constant at v4's own deploy defaults instead. The brief this file was written against lists eleven concrete requirements and none of them is "tunable rules"; adding v4's whole admin-ratchet surface on top of everything already new here would have roughly doubled this file's size and its audit surface for a feature nobody asked for in this pass. A v6 (or a v5.1 companion design note) can add it back following v4's own pattern exactly if the owner wants it.
  • NO PLAYER-CHOSEN NAME. v4's name/validNameRune/validNameCharset/hasVisibleNameContent machinery (three audit rounds' worth, per v4's own comment) existed to validate a string nobody in this brief asked this realm to accept any more -- nothing is chosen by a caller at mint time, including a name. A gnome is identified by its tokenID and, for the three one-of-ones, by Character(tokenID); the app is free to let an owner caption their own gnome off chain. Dropping this also removes an entire validation subsystem's audit surface for no loss against the brief.
  • NO OpenBatch ADMIN SURFACE. MINT.md section 6 floats an owner-callable OpenBatch for adding future batches' rosters; the task this file was built against names a single 24-gnome batch (BATCH-ONE.md) and does not ask for a mechanism to open a second one. The batch here is sized once, at deploy, by the batchCap/numNamedEditions constants below. A garden/v6 is the natural place for OpenBatch if a second batch is ever wanted, the same way every other irreversible-shape decision in this project has gotten its own version rather than a retrofit.

A REAL FLAW FOUND AND FIXED WHILE DESIGNING Settle, RECORDED HERE RATHER THAN QUIETLY FIXED AND FORGOTTEN -- the same discipline MINT.md section 10 models for its own single-transaction finding. An earlier version of this design picked the three named one-of-ones by drawing "without replacement" from a shrinking pool: remainingTotal = batchCap - settledCount, remainingNamed = 3 - namedAssignedCount, and a claimant's pick = seed % remainingTotal. THAT IS PEEKABLE AND GAMEABLE, even though the seed itself is honestly drand-derived and unforgeable: because remainingTotal only ever shrinks as OTHER claimants settle, and Settle is permissionless and callable at any later time, a claimant whose seed is already fixed (the moment their pinned round publishes) can simply precompute, for every possible remainingTotal from 1 to batchCap, whether that value would win them a named edition -- and then wait, costing nothing, until the rest of the batch happens to settle into a state that does. The fix below removes every dependency on shrinking, observable, time-varying state from the decision: a claimant's own named-edition pick is `seed % batchCap`, against a modulus that is a COMPILE-TIME CONSTANT, not a moving count, so there is nothing left to wait for -- the only residual order-dependence is which of possibly several colliding claimants (bad luck, not strategy: nobody can change their own pick by choosing when to settle) gets a named edition that more than one of them rolled, and that is resolved by whichever Settle call lands on chain first.

A SECOND AUDIT PASS NAMED THIS PRECISELY: "settling promptly", said above and in an earlier version of Settle's own comment, OVERSTATES what the residual actually rewards. It is not "whoever claimed first" or "whoever cared most" -- pendingClaim.claimedAt is never consulted by the tie-break, and Settle is permissionless, so a bystander (a searcher, a bribed relayer, a claimant's own bot) can win a collision for whichever side pays for transaction-ordering priority, regardless of who rolled or claimed first. Considered and rejected: tie-breaking on claimedAt instead. It sounds like the honest fix, but it is not reachable without a worse trade-off -- Settle finalizes irrevocably (it mints a real token to a real owner, who may already have acted on it), so honoring an earlier claimedAt would mean either refusing to finalize ANY collision candidate until every possible earlier claimant's round has published and settled (reintroducing exactly the wait-and-see window section 10 and this fix exist to close, now around a deadline instead of a pool size) or reaching back to UNDO an already- settled mint (which nothing in this realm, or any grc721-based realm in this project, has ever claimed to be able to do, and which would be a strictly worse property than the one being fixed). What actually holds, stated precisely rather than aspirationally: nobody can improve THEIR OWN odds by choosing when to settle (the property section 10 is about, and the property this fix actually guarantees); the residual is an ordinary transaction-ordering race over a LOW-PROBABILITY, LOW-STAKES event (three slots in a batch of 24, decided among whichever handful of claimants happen to collide), the same shape of race every permissionless action on every chain is already subject to, not a new hole this design opened. See Settle's own comment for the arithmetic.

SETTLE CAN NOW PAY FOR ITS OWN BEACON RELAY, OWNER-APPROVED 2026-10-15, THE DAY AFTER THIS FILE WAS FIRST WRITTEN. The two-phase roll above depends on beacon/v2 actually having the pinned round's drand signature by the time Settle runs, and until this change that was somebody else's problem: a relay has to happen, by a human or a bot, running outside this realm and outside this project's control, or a claimant who has already spent their one-and-only roll is stuck mid-mint through no fault of their own -- found live, not hypothetically, while building this file: the project's own beacon was observed ~2 days stale. The fix the owner asked for ("can we have the mint transaction pay the beacon though") is `SettleWithSignature` below: the player's own app fetches the pinned round's signature from drand's public API (the same `https://api.drand.sh/<chain>/public/<round>` this file's own test fixtures are fetched from) and passes it straight through; Settle relays it itself, in the same transaction, before computing the result. One transaction, and the player pays its gas -- TO THE NETWORK, same as any other transaction's gas, NOT to this project, so it never touches the free-mint promise (MINT.md section 14: "gas is still a payment, just not to us... the operator takes no stake"). Three things this buys, in the owner's own order of importance:

  • IT COSTS THE PROJECT NOTHING. The alternative to a player-paid relay is an operator-run one -- a cron job or a bot calling beacon.Publish on a schedule, which is real recurring GNOT spend with no revenue to offset it (MINT.md section 14 forecloses an unlock fee, batch one is free end to end). This change deletes that cost rather than budgeting for it.
  • A PLAYER CAN NEVER BE BLOCKED BY THIS PROJECT'S OWN HOUSEKEEPING. The stuck-mid-mint state above is now unreachable for anyone willing to fetch their own round's signature: their own Settle call makes the round available, with no dependency on this project, a third-party relay, or anyone else's goodwill.
  • THE BEACON GETS FRESHER AS A SIDE EFFECT, FOR EVERYONE ELSE USING IT. beacon/v2 is a shared, permissionless, on-demand record (see its own package doc) -- a round this realm's own claimants cause to be published is published for every other consumer of that beacon too, not just for this realm.

THREE THINGS WORKED OUT BY QUERYING THE LIVE CHAIN, NOT ASSUMED, because this is new cross-realm write surface and this project's own history (the SPLASH beacon migration, MEMORY.md) is built from exactly the kind of interrealm detail that gets guessed wrong:

  1. WHAT beacon.Publish DOES ON AN ALREADY-PUBLISHED ROUND. Fetched byte-for-byte from the live deployed realm itself (gno.land/r/g1r4aw43kagaaquhegxw6xr346h9f2qu2ezf0jar/beacon/v2) via the public onyx-1 RPC's `vm/qfile` query, 2026-10-15, and diffed identical against this project's own vendored copy at realms/_vendor/beacon/v2/beacon.gno -- it PANICS, it does not no-op: `func Publish(cur realm, round int64, sigHex string) { if Published(round) { panic ("beacon: round already published") } ... }`. SettleWithSignature therefore checks `beacon.Published` itself BEFORE ever calling Publish, exactly once, and never calls Publish at all if the round is already there -- calling it unconditionally would make this function fail every time a relay (another claimant's own SettleWithSignature, or anyone else) beat it to the punch, which given Settle's own permissionless, callable-by-anyone design is an ordinary and expected race, not an edge case.
  2. THAT Publish IS REACHABLE CROSS-REALM AS `beacon.Publish(cross(cur), round, sigHex)`, and that it carries no caller-identity check at all for this function to trip over. Confirmed two ways: the live source pulled in point 1 shows Publish's body never reads `cur` or calls `cur.Previous()` -- it is permissionless by whoever relays, not merely by whichever address -- and this exact call shape is already proven working, not merely plausible, by this file's OWN test harness: garden_test.gno's `publishAs` helper has called `beacon.Publish(cross(cur), round, sigHex)` from this package since the day this file was written, and every test that calls it passes. SettleWithSignature's own call is the identical shape with `cur` being Settle's own realm parameter instead of a test helper's. (`cur.Previous()` inside beacon.Publish would resolve to THIS realm, garden/v5, when called this way rather than to the human wallet that called Settle -- a real interrealm fact worth recording even though Publish does not currently branch on it: if beacon/v2 ever grows a caller-identity check, re-read this paragraph before assuming Settle's relay still works.)
  3. GAS. Measured on this toolchain with r/splash/beacon/zz_gas_test.gno's own method (`gno test -run TestZZGas -print-runtime-metrics=true -v`, net of this package's own fixed per-test-call overhead): a bare Settle today costs ~6.2M gas; beacon.Publish alone costs ~18.5M gas on THIS realm's measurement (the same order of magnitude as beacon/v2's own documented 16,970,375, re-measured rather than quoted because toolchain and realm storage both shift it). SettleWithSignature's worst case -- the round not yet published at all -- is therefore on the order of ~25M gas total, call it 1% of the 3e9 block gas limit and a few hundredths of a GNOT at this chain's gas price. Reasonable: it is roughly four times a bare Settle, not an order of magnitude more, it still leaves room for well over a hundred such settlements in a single block, and it replaces a cost this project would otherwise have paid itself, recurringly, forever, to keep the beacon fresh by some other means.

THE SHAPE: TWO ENTRY POINTS, ONE SHARED CORE, NOT ONE FUNCTION WITH AN OPTIONAL SIGNATURE. `Settle(cur realm, claimant address)` is UNCHANGED in behaviour and UNCHANGED in signature -- every existing test and every existing caller that already knows (or does not care) whether the round is published keeps working exactly as before, at exactly its old gas cost, with no signature to fetch or supply. `SettleWithSignature(cur realm, claimant address, sigHex string)` is new, and is for a caller that HAS a signature and wants its transaction to publish the round if nobody else already has. A Gno realm's exported functions take a fixed argument list -- there is no overloading, and an optional/variadic last argument would still force every caller, including every test and the app's own simpler "it's already published" path, to pass an empty string they have no use for, for a case (publishing) that is the EXCEPTION, not the rule, since most settlements land after some earlier claimant or relay has already published the shared round. Two named entry points make the exception visible in the function name instead of buried in an argument, and cost nothing extra: both share one unexported `settleCore`, so there is exactly one copy of the draw-and-mint logic, not two drifting in parallel. And it is SAFE for either one to be called in either actual on-chain state: Settle still refuses cleanly, with its original message, if the round genuinely is not published yet; SettleWithSignature still succeeds, with its supplied signature simply going unused, if the round turns out to already be published by the time it runs (point 1's race) -- neither caller has to know in advance which state they are in, they only have to know whether they personally HAVE a signature to offer.

Function

GenesisTokenID

func GenesisTokenID() string
Ask AI Claude ChatGPT

Command

gnokey query vm/qeval -remote "https://rpc.onyx.testnets.gno.land" -data "gno.land/r/g1nq99m3h9ed7vqve6ajpr3qwy2ls252m8jnundm/garden/v5.GenesisTokenID()"

Result