TotalSupply
Ask AI
Command
gnokey query vm/qeval -remote "https://rpc.onyx.testnets.gno.land" -data "gno.land/r/g1nq99m3h9ed7vqve6ajpr3qwy2ls252m8jnundm/garden/v7.TotalSupply()"
Result
Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.
Package garden is Gnotchi's pet realm, v7: the free, allowlisted, drand-rolled, hold-many realm MINT.md designs end to end, now carrying Batch One's personality, the kinship web and a batch of sixty. 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), and so does garden/v5's one.
============================================================================================ WHAT v7 IS: v6 PLUS EXACTLY TEN CHANGES. READ THIS, THEN "WHAT v6 IS" BELOW IT. ============================================================================================
v7's specification is realms/garden/v7/DESIGN.md (1,974 lines, written 2026-10-17 and reviewed before any of this was typed). This block is the summary; that document is the argument, and where this file disagreed with it the disagreement is marked in the source at the place it happens.
THE RULE THIS FILE IS WRITTEN UNDER, which is v6's own rule quoted back at its successor: "Every line of v5 that is not one of the two fixes below is carried forward byte-for-byte... v5 survived a security audit; every unrelated change made here would be a change that has not been audited, so none was made." v7 is the version that was reserved for changing things, so the door is open -- but THE AUDIT ARGUMENT DOES NOT EVAPORATE BECAUSE THE DOOR IS OPEN. Everything v6 carries forward is carried forward here too, byte-for-byte, unless it appears in the list below. The list is complete. If a change is not in it, it is not authorised, and the three defects mutation testing found in v5, along with every comment recording why something is shaped as it is, are all still here on purpose.
CHANGE 1 -- batchCap 24 -> 60. DECISIONS.md 2026-10-17, "Batch One becomes 60", superseding "Batch One stays 24" from earlier the same day. ONE CONSTANT.
CHANGE 2 -- FIVE ROLLED TRAIT AXES plus born-under, stored on the gnome. TRAITS.md sections 1 and 7.
CHANGE 3 -- THE DOMINANCE ORDER, stored as five explicit slots rather than a 7-bit Lehmer index. The reason is in the gnome struct's own comment: a factorial-base index needs a codec on both sides of the wire, which is two things that must agree forever over a convention nobody has written down, in the one function MINT.md section 9 names as needing its own audit pass above all others.
CHANGE 4 -- THE FOUR STATS on a shared budget, drawn from a 546-row legal set ENUMERATED AT init() FROM THE RULE rather than transcribed, because a transcription error in a 546-row table is undetectable by eye and the rule it transcribes is four comparisons. TRAITS.md section 4.2.
CHANGE 5 -- A SECRET ID, with the first-seventeen-distinct constraint. TRAITS.md section 3.2.2: without it, 36.9% of batches could not spell the acrostic of section 3.2.1.
CHANGE 6 -- A ROLLED CARE THRESHOLD, stored, WITH NO GETTER. The one declared exception to GAMES.md:38, and the only write-only field in the realm.
CHANGE 7 -- THE 84 KINSHIP EDGES on chain, STRUCTURE ONLY, keyed by batch index. LINEAGE.md section 6's OVERRULED box: "store the structure, keep the wording off chain where it can still be improved."
CHANGE 8 -- seedFor MOVES FROM FNV-1a TO SHA-256. NOT A FEATURE -- a defect DESIGN.md found while working out change 3. FNV-1a's low bits are provably a parity of the input bytes' low bits; v5 and v6 take % 100, % 60 and % 4 and mostly get away with it, and v7 takes % 2, % 3, % 5 and % 16 for the one field TRAITS.md's whole duplicate-vector argument rests on. THIS IS THE ONE TO READ FIRST IN REVIEW: it rewrites a line an audited realm carries. Proof at seedFor.
CHANGE 9 -- THE NAMED-EDITION ODDS ARE DECOUPLED FROM THE BATCH SIZE AND RAISED TEN-FOLD. 2026-10-18, the owner: "make the last few have them. The rates have to come out during a mint." ONE CONSTANT AND ONE LINE: namedPick's modulus was uint64(batchCap), so each of Hob, Thistle and Wick was a 1-in-60 shot per claimant and there was a 74.37% chance at least one of the three never existed. It is now uint64(namedPickRange), its own constant at 10 -- a 1-in-10 shot each, leaving 0.54% of full batches missing one. NOTHING ELSE ABOUT THE NAMED-EDITION PATH MOVES: the `namedPick < numNamedEditions` branch, the characterOwner.Has check and the transaction-ordering-race comment inside it are v6's byte-for-byte. THIS IS NOT A GUARANTEE and is not a replacement for the removed one; it is a probability, it fires nowhere new, and it reads nothing new. The arithmetic for all three rates, why the modulus is NOT batchCap (that coupling was accidental -- it made the rarest-asset odds a side effect of a batch size changed for unrelated reasons), why raising a rate is safe where the removed guarantee was not, and the honest cost (collisions become common; first settle wins) are at namedPickRange's declaration.
CHANGE 10 -- THE NAMED ONE-OF-ONES GO FROM THREE TO EIGHT. 2026-10-18, the owner: "If we are doing 60 there should be more specials than 3." He is right, and the reason is arithmetic that change 1 produced silently: three of 24 was 12.5% of a batch, and moving the batch to 60 without touching the roster quietly cut it to 5%. EIGHT OF 60 IS 13.3%, which restores the proportion the collection was designed at. ONE CONSTANT (numNamedEditions 3 -> 8) AND THREE TABLES IN STEP (namedEditionOrder, namedEditionDisplayNames, reservedNameKeys) -- plus List's lock message, which says the count out loud and is therefore a FOURTH place the roster's size appears; see numNamedEditions for the full list of what must move together.
THE FIVE NEW NAMES ARE BATCH-ONE.md section 7's, EXTENDED IN THAT SECTION'S OWN REGISTER AND JUSTIFIED THERE, NOT HERE: Tally, Glim, Vigil, Spruce, Yonder. They are EXISTING, ALREADY VALIDATED ART, renamed exactly the way Hob (the gilded gnome) and Thistle (the Viking) were -- trowel-hand, emberwing, nightwatch, gentleman and pirate from pack/04-pixel-art/characters.json, every one of them "works"/"confirmed at true 2x" in ARCHETYPES.md section 3 and section 6. NO NEW ART WAS DRAWN OR MODIFIED FOR THIS CHANGE and this realm does not know what any of them look like: `character` is a string, the look lives in the art pack, and that separation is unchanged.
namedPickRange STAYS AT 10, DELIBERATELY, AT THE OWNER'S APPROVED ODDS -- a specific edition is still a 1-in-10 shot per claimant and nothing about the pick, the branch or the race moves. What DOES move is what the odds compose to, and the new figures replace the old ones everywhere they are written down: (9/10)^60 = 0.18% per edition is unchanged, but P(at least one of EIGHT missing) = 1 - (1-0.0017971)^8 = 1.43%, up from 0.54% at three. A half-filled batch of 30 is 29.3%. The cost side moves much further: 48 of 60 claimants now hold a named-pointing pick (60 * 8/10) for eight slots, so about 40 of them lose the race and fall through to an ordinary draw. Full arithmetic, all four rows, at namedPickRange. NOTE THE HEADROOM: 10 >= 8 still holds, but only just -- at eight editions the modulus is two residues from the point where an edition becomes unreachable, so numNamedEditions may not grow again without raising namedPickRange, and TestNamedEditionOddsAreOneInTen is the test that fails if it does.
NOT A GUARANTEE, AGAIN AND FOR THE SAME REASONS: this adds five entries to three tables and no mechanism. No forcing, no namedEditionToForce, nothing keyed on a shrinking observable (AUDIT-01 RED-1). "TALLY WAS NEVER BORN" is now a 0.18% permanent fact per edition exactly as "HOB WAS NEVER BORN" is, and the chance that SOME edition is missing went UP, not down, because there are more editions to miss. That is the accepted price of the proportion the owner asked for.
NOT A CHANGE -- THE NAMED-EDITION GUARANTEE, WRITTEN 2026-10-17 AND REMOVED 2026-10-18. It was briefly a change of its own: "when the number of unsettled slots remaining equals the number of named editions still unclaimed, the remaining settles take them." AUDIT-01 RED-1 found that rule positionable -- its trigger was computable from two public readers and a wallet that never claimed until 57 were settled took an edition with certainty -- and the owner chose REMOVAL over any replacement, so the named-edition path here is v6's byte-for-byte apart from change 9's one modulus, and NO END-OF-BATCH FORCING AND NO namedEditionToForce EXISTS OR MAY BE RE-ADDED. The residual chance that at least one edition is never minted is KNOWN AND ACCEPTED: 74.4% when it was accepted, 0.54% after change 9, 1.43% after change 10 raised the roster from three to eight (more editions, more chances for one of them to be missed), never zero. The full record of the decision is in settleCore, next to the pick it would have overridden; do not re-add a guarantee without reading it, and note that changes 9 and 10 are deliberately NOT one -- between them they move two numbers and five table entries, not a mechanism.
WHAT v7 MUST NEVER DO, and these are named so that leaving them out is a decision on the record rather than an omission. From TRAITS.md section 7: no rarityScore(), no TraitCensus(), no traitCount(axis, id), no sort-by-stat, no trait-gated entrypoint anywhere in any realm, nothing that returns a distribution. From LINEAGE.md section 6.5: no KinOf(tokenID), no IsKin(a, b), no LineOf(tokenID), no LineCount(line), no KinCount and nothing that returns a degree, no sort/filter/gate of any kind on a line, a relation or a relative, and NO ENTRYPOINT ANYWHERE IN ANY REALM THAT BEHAVES DIFFERENTLY FOR TWO RELATED GNOMES THAN FOR TWO STRANGERS. Added by v7, because it is the first realm where they become reachable: no CareThreshold / CareScore / Band / PointsToThreshold or any fraction of them; no SecretCount / SecretCensus / HoldersOfSecret / IsFirstSeventeen and nothing exposing secretsDrawnMask; no Label / Archetype; no TraitsMatching or any filter or predicate; no unique-in-batch marker; AND NO READER, ANYWHERE, THAT TAKES TWO TOKEN IDS -- that last one is the structural form of all of it, because a function of two gnomes is the shape every kin-bonus, related-pair and shared-quest feature needs. See the shape rule stated once above the trait readers.
THE INVARIANT THOSE PROTECT, STATED ONCE: NO FUNCTION IN v7 BRANCHES ON A TRAIT, A STAT, A LINEAGE EDGE OR A SECRET. Not in a guard, not in a loop condition, not in a fee calculation, not in an eligibility check. Trait data is read by this realm's own code in exactly two places, and both are inside the draw writing itself down: drawRoll/assertRoll, and secretWeightsFor's one comparison of boast/fear against the secret target table, which produces a secret id and nothing else. TestTwoGnomesWithOppositeTraitsAreTreatedIdentically is that invariant as a test a CI run can check rather than a promise a reviewer has to take.
THE MIGRATION QUESTION, ANSWERED ONCE SO NOBODY RE-OPENS IT: v5's one gnome STAYS ON v5 and v4's two stay on v4. No migration, ever -- the identical answer BATCH-ONE.md section 0 gave one version earlier, for the identical reason: v5 is immutable, has no transfer-in path, and nothing in v7 can reach it. BATCH ONE IS THE SIXTY GNOMES ON THIS REALM AND NOTHING ELSE; the 60 is sixty, not fifty-nine plus the one already minted. v5's gnome holds no axis, no dominance order, no stat line, no secret, no sign, no threshold, no batch index and no kinship edge -- not because anything was withheld but because V5 HAS NO SUCH FIELDS, so it cannot be a member of a batch whose defining properties did not exist when it was minted. Nothing in this file knows v5 exists: not a field, not an import. No cross-realm per-wallet cap (MINT.md section 6 already settles it -- "a single wallet may hold a v4 gnome and any number of v5 gnomes at once" -- and importing v5 would make v7 undeployable anywhere v5 is not live), no batch-index offset, no legacy-holder benefit (if the owner wants the v5 holder on the v7 allowlist, that is one AdminAllow call and a curation decision), no cross-realm name uniqueness (impossible, and already true between v4 and v5), no cumulative TotalSupply, and no deprecation pointer in v5 (it is immutable). THE ONLY THING v7 INHERITS THAT IS NOT SOURCE CODE IS THE NAMESPACE.
AND ONE FACT THAT CHANGES THE SHAPE OF THIS VERSION: v7 SUPERSEDES A REALM THAT NEVER CAME UP. garden/v6 is written, audited, passing its tests and NOT ON CHAIN -- vm/qpkgmeta_json answers "status":"inert", three paid addpkg attempts produced nothing retrievable, and a five-line probe realm with no imports failed identically, which is what proves it is the chain and not the code (TESTNET.md:530-582). So v6's two fixes have never been live for anybody: SetName and SettledRound arrive for the first time here, and section 1.1's "byte-for-byte" is a claim about SOURCE, not about continuity of service. Before attempting to deploy this larger realm, re-run the five-line probe first -- and remember the lesson that file draws: "OK! from gnokey, success:true in the block, and a debited balance are together still not evidence that a deploy happened. Only reading the package back is."
============================================================================================ WHAT v6 IS: v5 PLUS EXACTLY TWO FIXES, AND NOTHING ELSE. READ THIS SECOND, AND READ IT WHOLE. IT IS THE RECORD OF THE AUDITED BASE THIS FILE IS A COPY OF, AND EVERY WORD OF IT STILL APPLIES EXCEPT WHERE THE TEN CHANGES ABOVE SAY OTHERWISE. ============================================================================================
garden/v5 is DEPLOYED AND LIVE on the onyx testnet. v6 exists because a review on 2026-10-16 found a hole that the original design, the test suite and the adversarial security review (ATTACK-REVIEW.md, eight attack goals) all missed -- not a vulnerability, a MISSING FEATURE that contradicts something the owner asked for in his own words. This file is a DELIBERATELY NARROW, SURGICAL COPY of v5. Every line of v5 that is not one of the two fixes below is carried forward byte-for-byte, including every comment recording why something is shaped as it is and the three real defects mutation testing found and fixed. v5 survived a security audit; every unrelated change made here would be a change that has not been audited, so none was made. If you are about to "also improve" something while reading this file: don't. Write a v7.
FIX 1 -- A v5 GNOME CANNOT HAVE A NAME, AND THE GAME NEEDS ONE.
1v5's gnome struct has no name field, no setter, and `character` -- the only identity string
2it carries -- is "" for every gnome outside the three capped one-of-ones. Confirmed on the
3LIVE CHAIN, not inferred: `GnomeByToken("0000002")` on the deployed v5 returns
4character "". So 21 of Batch One's 24 gnomes would have been permanently anonymous, with no
5way ever to fix it, because the realm is immutable.
6
7That directly contradicts the owner's own instruction that in-game characters "should
8refer to you as your gnome name" -- the adventure's whole NPC dialogue surface is built on
9a name existing. v5's own package doc argued the opposite ("NO PLAYER-CHOSEN NAME... the
10app is free to let an owner caption their own gnome off chain"), and that argument was
11WRONG in one specific, load-bearing way worth recording rather than quietly deleting: an
12off-chain caption is not an identity. It cannot travel with the token through a sale, it
13cannot be read by another realm, it cannot be reserved against impersonation, and the
14adventure realm cannot greet you by it. The reasoning that was right -- that nothing
15should be CHOSEN at mint time -- is preserved exactly: see SetName below.
16
17THE SHAPE, AND WHY. Naming is a SEPARATE ACT, AFTER the roll, never part of it. `Claim`
18still takes no arguments and `Settle` still takes no name: the entire point of the mint is
19that you do not choose what you get (MINT.md section 1a/section 2), and nothing here
20weakens that. Naming what you already got is a different act entirely, performed by a
21different function, at a different time, by the token's current owner only.
FIX 2 -- v5 NEVER STORED THE DRAND ROUND THAT PRODUCED EACH GNOME.
1v5 emits the settling round in its `Settle` event and then forgets it. "Which round made
2this gnome" was therefore a transaction-log archaeology problem rather than a state read:
3`Provenance` returns adoptedAt/acquiredAt/saleCount and there was no getter for the round
4at all. Since "provably unrigged" is this project's headline claim (ECONOMY.md section 1),
5a holder being unable to verify their own gnome with one query was a gap between what the
6project says and what the chain can answer. v6 stores the round on the gnome itself
7(gnome.settledRound) and exposes it (SettledRound). See settleCore.
============================================================================================
WHAT CHANGES FROM v4, IN ONE TABLE, EACH CITED TO THE DOCUMENT THAT DECIDED IT:
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:
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 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 % namedPickRange` (`seed % batchCap` until v7 change 9 moved the modulus off the batch size on 2026-10-18 -- a different constant, the same and only load-bearing property), 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 -- WRITTEN BEFORE CHANGES 1, 9 AND 10, and "low probability" and "a handful" are the two words that stopped being true; see the paragraph below), 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. v7 CHANGES 9 AND 10 (both 2026-10-18) MAKE THAT RACE MORE FREQUENT AND SAY SO: at namedPickRange = 10 roughly 18 of 60 claimants held a named-pointing pick for three slots, and at change 10's eight slots it is 48 of 60 (60 * 8/10) chasing eight, so collisions are now the NORMAL CASE rather than an unlucky one -- about 40 claimants draw a named pick and fall through to an ordinary draw. The race is unchanged in SHAPE -- first settle takes it, nobody can move his own pick -- and it rewards promptness, not lateness. The honest statement of that cost, and the reason the rate was raised anyway, are at namedPickRange.
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:
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:
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.
gnokey query vm/qeval -remote "https://rpc.onyx.testnets.gno.land" -data "gno.land/r/g1nq99m3h9ed7vqve6ajpr3qwy2ls252m8jnundm/garden/v7.TotalSupply()"