Repository navigation
feat: re-extract the public-sale bindings, 11 more participants paid at genesis - #75
Closed
alexiscolin wants to merge 1 commit into
Closed
alexiscolin wants to merge 1 commit into
alexiscolin wants to merge 1 commit into
Conversation
…at genesis The binding page has no deadline, so the list gnolang#65 froze keeps growing. inputs/README.md already says what to do about it: "replace the file at a new instant rather than adding rows to this one". This is the second extract. Eleven more of the 122 settled wallets named a gno.land address, so 78 are now paid directly at genesis and 44 stay with the [sale-unclaimed] multisig. One of the eleven is the largest unclaimed row in the sale, 2,739,572.093023 GNOT. SUPPLY-NEUTRAL, AS gnolang#65 WAS The eleven move 4,255,242.961239 GNOT out of the multisig row and into rows of their own. The sheet still totals 21,604,687.430103 GNOT, TOTAL_PUBLIC_SALE_UGNOT is untouched, and total supply stays at 1,332,999,998.328067 GNOT. balances.txt goes 3,262,454 -> 3,262,464 rows: eleven new addresses, one of which merges into an airdrop row it already held. That merge takes the pinned airdrop overlap 25 -> 26 addresses, and the merged row keeps its §132 schedule byte-for-byte over the airdrop portion alone, its sale portion liquid as §128 requires. THE NEW EXTRACT IS A NEW FILE inputs/publicsale-sonar-2026-09-11.csv, ending at address_bindings id 79. The 09-09 file is kept byte-for-byte: inputs/ is immutable, and that one has already been published and reviewed. The two differ only in which wallets had bound. No new lockup: all eleven are lockup_12m = no. The single declared vesting schedule is unchanged. TWO THINGS ON main THAT THIS CORRECTS IN PASSING Both live in files this change edits anyway. - The provenance dated its extract with a local (UTC+9) file timestamp written as if it were UTC, 9 hours out. The cutoff is now quoted as the address_bindings id, which is checkable, rather than a wall-clock instant. - The vesting caveat said dropping the one declared-schedule row makes a pre-331e17fc3 binary safe. It does not: 28 addresses are both in unrestricted.txt and carry a vesting line, so that removes 1 of 28 InitChain panic triggers. VERIFIED make verify passes. The eleven were re-derived from the Ethereum event log rather than copied: accepted USD as the sum of each wallet's CommitmentIncreased deltas, base at the 129/2000 clearing price, the tiered band by replaying the 173 increases in (block, logIndex) order, 24h eligibility from the first BidPlaced. Exact rational arithmetic. All eleven match to the ugnot. All 79 binding signatures recover to the paying wallet under EIP-191. gno's own GetBalancesFromSheet (at a revision containing 331e17fc3, gnolang/gno#6095) reads the sheet as 79 balances / 21,604,687,430,103 ugnot / 1 vesting schedule, and the gnogenesis binary reports "79 balances saved" with chain_id gnoland1 and verify passing.
alexiscolin
force-pushed
the
feat/publicsale-resnapshot-2026-09-11
branch
from
September 11, 2026 07:13
c92ff3f to
0911773
Compare
moul
added a commit
that referenced
this pull request
Sep 11, 2026
… time inputs/README.md says a snapshot is "replaced wholesale". #75 kept the 09-09 file alongside the 09-11 one instead, on the grounds that it had already been published and reviewed. Replaced means replaced: the id-68 extract is deleted, and this directory holds exactly one public-sale extract from now on. NOTHING IS LOST, AND THAT IS CHECKED RATHER THAN ASSUMED - the two hold the same 122 wallets with IDENTICAL amounts: the (ugnot_total, base, tiered_bonus, first24h_bonus, accepted_usd, lockup_12m, first_24h_eligible) tuples of the two files are the same multiset - every GENESIS row of the id-68 file -- address, bound_at and signer included -- is present VERBATIM in the id-79 one, so no binding was dropped or redirected between extracts - the file is still in git where it was captured, 9ecf4d3 (#65): git show 9ecf4d3:inputs/publicsale-sonar-2026-09-09.csv Nothing in the repository read it. No Go file, no test, no Makefile rule references either CSV by name -- they are reference material for humans, and the loaded rows live in mkgenesis/publicsale.txt. The table in inputs/README.md had already been corrected on main, where it claimed allocate/process_test.go consumed the 09-09 file. WHY DELETING IS THE SAFER OPTION, NOT THE BOLDER ONE Which extract is live is not recorded in either CSV. With two in the tree a reader has to work it out, and a stale file sitting next to a current one is the exact shape of the drift the rest of inputs/'s rules exist to prevent -- the same class of bug as a stale generated artifact. One file, named by the id it stops at, cannot be read wrong. inputs/README.md and README-publicsale-provenance.md say all of the above, so the next extract does not have to rediscover it. make verify green; no artifact changes -- the CSV is not an input to the build.
moul
pushed a commit
that referenced
this pull request
Sep 11, 2026
…at genesis The binding page has no deadline, so the list #65 froze keeps growing. inputs/README.md already says what to do about it: "replace the file at a new instant rather than adding rows to this one". This is the second extract. Eleven more of the 122 settled wallets named a gno.land address, so 78 are now paid directly at genesis and 44 stay with the [sale-unclaimed] multisig. One of the eleven is the largest unclaimed row in the sale, 2,739,572.093023 GNOT. SUPPLY-NEUTRAL, AS #65 WAS The eleven move 4,255,242.961239 GNOT out of the multisig row and into rows of their own. The sheet still totals 21,604,687.430103 GNOT, TOTAL_PUBLIC_SALE_UGNOT is untouched, and total supply stays at 1,332,999,998.328067 GNOT. balances.txt goes 3,262,463 -> 3,262,473 rows: eleven new addresses, one of which merges into an airdrop row it already held. That merge takes the pinned airdrop overlap 25 -> 26 addresses, and the merged row keeps its §132 schedule byte-for-byte over the airdrop portion alone, its sale portion liquid as §128 requires. THE NEW EXTRACT REPLACES THE OLD ONE inputs/publicsale-sonar-2026-09-11.csv, ending at address_bindings id 79. It does not sit beside the id-68 extract: inputs/README.md says a snapshot is "replaced wholesale", and the follow-up commit deletes that file. The two hold the same 122 wallets with identical amounts and differ only in which had bound, and git keeps the old one at 9ecf4d3 (#65) regardless. No new lockup: all eleven are lockup_12m = no. The single declared vesting schedule is unchanged. REBASED ONTO #73, WHICH CHANGES WHAT THIS HAS TO TOUCH Opened as #75 against main, where publicsale.txt was the only §136 carve-out. #73 makes it one of two, so five things are different here and none of them is a data change: - The §136 closure is now a three-line sum, and TestTheThreeSection136Lines- SumToTheTranche is left completely untouched. That is the strongest statement available that this change is supply-neutral: an extract that moved a single ugnot across the sale/tranche boundary could not leave that test alone. - verify/crosscheck is keyed by filename as of #73, so a fifth sheet no longer shifts genbalance's index. The version against main did not need that and would have silently reintroduced it the next time a sheet was added. - The four hand-maintained pins move through #73's shared readSheet() rather than the copy readSaleSheet() used to be. - mkgenesis/unrestricted.txt is GENERATED by #74 from both §136 sheets, so the eleven are not hand-added: `make -C mkgenesis` emits 80 -> 91 addresses. - ABOUT.md, docs/pipeline.md and README.md reconciled across THREE sheets, not two. #73 added investors.txt without them, so the row arithmetic in ABOUT.md and the tree in pipeline.md were 9 rows short before this; they now balance: 3,262,351 + (66 - 6) + (79 - 26) + 9 = 3,262,473 investors.txt intersects nothing -- not the airdrop, not the other two sheets -- so all nine are new rows. Checked by set arithmetic, not assumed. The rebase is checkable without trusting any of the above. Sorted, the sheet built here differs from the one on #75 by exactly eleven lines: the nine distribution rows, and INVESTORS_UNLOCKED_ADDRESS going 128,395,312.569897 -> 112,318,842.569897, which is -16,076,470 to the ugnot. Nothing else in 3.26M rows moves, so this carries #73's change and #75's change and invents neither. diff <(gzip -dc <#75's balances.txt.gz> | sort) \ <(gzip -dc mkgenesis/balances.txt.gz | sort) TWO THINGS ON main THAT THIS CORRECTS IN PASSING Both live in files this change edits anyway. - The provenance dated its extract with a local (UTC+9) file timestamp written as if it were UTC, 9 hours out. The cutoff is now quoted as the address_bindings id, which is checkable, rather than a wall-clock instant. - The vesting caveat said dropping the one declared-schedule row makes a pre-331e17fc3 binary safe. It does not: 28 addresses are both in unrestricted.txt and carry a vesting line, so that removes 1 of 28 InitChain panic triggers. Still 28 with the nine distribution rows on the list -- they are unlocked and none holds an airdrop entitlement -- and the paragraph now says to re-run the count rather than trust the number. ARTIFACTS mkgenesis/balances.txt.gz fa4a8124... -> be4ad951... 57,243,726 -> 57,243,893 B mkgenesis/unrestricted.txt 632de96e... -> 7b37a168... 80 -> 91 addresses Rebuilt with GNU gzip 1.12, which reproduces #73's own container bit-for-bit (verified by round-tripping it before rebuilding); Apple's gzip does not, so a macOS rebuild without GNU gzip on PATH shows that one file dirty. VERIFIED make verify is green end to end: allocate and mkgenesis tests, including the golden rebuild and #74's regenerated-list check, and crosscheck reports "Balance files match". Rebuilding twice produces the same bytes. The sale-side evidence is carried over from #75 rather than re-run, and it is about the same bytes: mkgenesis/publicsale.txt and the CSV here are byte- identical to that PR, checked by sha256. In alexis' words: The eleven were re-derived from the Ethereum event log rather than copied: accepted USD as the sum of each wallet's CommitmentIncreased deltas, base at the 129/2000 clearing price, the tiered band by replaying the 173 increases in (block, logIndex) order, 24h eligibility from the first BidPlaced. Exact rational arithmetic. All eleven match to the ugnot. All 79 binding signatures recover to the paying wallet under EIP-191. gno's own GetBalancesFromSheet (at a revision containing 331e17fc3, gnolang/gno#6095) reads the sheet as 79 balances / 21,604,687,430,103 ugnot / 1 vesting schedule, and the gnogenesis binary reports "79 balances saved" with chain_id gnoland1 and verify passing.
moul
added a commit
that referenced
this pull request
Sep 11, 2026
… time inputs/README.md says a snapshot is "replaced wholesale". #75 kept the 09-09 file alongside the 09-11 one instead, on the grounds that it had already been published and reviewed. Replaced means replaced: the id-68 extract is deleted, and this directory holds exactly one public-sale extract from now on. NOTHING IS LOST, AND THAT IS CHECKED RATHER THAN ASSUMED - the two hold the same 122 wallets with IDENTICAL amounts: the (ugnot_total, base, tiered_bonus, first24h_bonus, accepted_usd, lockup_12m, first_24h_eligible) tuples of the two files are the same multiset - every GENESIS row of the id-68 file -- address, bound_at and signer included -- is present VERBATIM in the id-79 one, so no binding was dropped or redirected between extracts - the file is still in git where it was captured, 9ecf4d3 (#65): git show 9ecf4d3:inputs/publicsale-sonar-2026-09-09.csv Nothing in the repository read it. No Go file, no test, no Makefile rule references either CSV by name -- they are reference material for humans, and the loaded rows live in mkgenesis/publicsale.txt. The table in inputs/README.md had already been corrected on main, where it claimed allocate/process_test.go consumed the 09-09 file. WHY DELETING IS THE SAFER OPTION, NOT THE BOLDER ONE Which extract is live is not recorded in either CSV. With two in the tree a reader has to work it out, and a stale file sitting next to a current one is the exact shape of the drift the rest of inputs/'s rules exist to prevent -- the same class of bug as a stale generated artifact. One file, named by the id it stops at, cannot be read wrong. inputs/README.md and README-publicsale-provenance.md say all of the above, so the next extract does not have to rediscover it. make verify green; no artifact changes -- the CSV is not an input to the build.
moul
added a commit
that referenced
this pull request
Sep 11, 2026
…at genesis (#75 rebased on #73) (#76) * feat: re-extract the public-sale bindings, 11 more participants paid at genesis The binding page has no deadline, so the list #65 froze keeps growing. inputs/README.md already says what to do about it: "replace the file at a new instant rather than adding rows to this one". This is the second extract. Eleven more of the 122 settled wallets named a gno.land address, so 78 are now paid directly at genesis and 44 stay with the [sale-unclaimed] multisig. One of the eleven is the largest unclaimed row in the sale, 2,739,572.093023 GNOT. SUPPLY-NEUTRAL, AS #65 WAS The eleven move 4,255,242.961239 GNOT out of the multisig row and into rows of their own. The sheet still totals 21,604,687.430103 GNOT, TOTAL_PUBLIC_SALE_UGNOT is untouched, and total supply stays at 1,332,999,998.328067 GNOT. balances.txt goes 3,262,463 -> 3,262,473 rows: eleven new addresses, one of which merges into an airdrop row it already held. That merge takes the pinned airdrop overlap 25 -> 26 addresses, and the merged row keeps its §132 schedule byte-for-byte over the airdrop portion alone, its sale portion liquid as §128 requires. THE NEW EXTRACT REPLACES THE OLD ONE inputs/publicsale-sonar-2026-09-11.csv, ending at address_bindings id 79. It does not sit beside the id-68 extract: inputs/README.md says a snapshot is "replaced wholesale", and the follow-up commit deletes that file. The two hold the same 122 wallets with identical amounts and differ only in which had bound, and git keeps the old one at 9ecf4d3 (#65) regardless. No new lockup: all eleven are lockup_12m = no. The single declared vesting schedule is unchanged. REBASED ONTO #73, WHICH CHANGES WHAT THIS HAS TO TOUCH Opened as #75 against main, where publicsale.txt was the only §136 carve-out. #73 makes it one of two, so five things are different here and none of them is a data change: - The §136 closure is now a three-line sum, and TestTheThreeSection136Lines- SumToTheTranche is left completely untouched. That is the strongest statement available that this change is supply-neutral: an extract that moved a single ugnot across the sale/tranche boundary could not leave that test alone. - verify/crosscheck is keyed by filename as of #73, so a fifth sheet no longer shifts genbalance's index. The version against main did not need that and would have silently reintroduced it the next time a sheet was added. - The four hand-maintained pins move through #73's shared readSheet() rather than the copy readSaleSheet() used to be. - mkgenesis/unrestricted.txt is GENERATED by #74 from both §136 sheets, so the eleven are not hand-added: `make -C mkgenesis` emits 80 -> 91 addresses. - ABOUT.md, docs/pipeline.md and README.md reconciled across THREE sheets, not two. #73 added investors.txt without them, so the row arithmetic in ABOUT.md and the tree in pipeline.md were 9 rows short before this; they now balance: 3,262,351 + (66 - 6) + (79 - 26) + 9 = 3,262,473 investors.txt intersects nothing -- not the airdrop, not the other two sheets -- so all nine are new rows. Checked by set arithmetic, not assumed. The rebase is checkable without trusting any of the above. Sorted, the sheet built here differs from the one on #75 by exactly eleven lines: the nine distribution rows, and INVESTORS_UNLOCKED_ADDRESS going 128,395,312.569897 -> 112,318,842.569897, which is -16,076,470 to the ugnot. Nothing else in 3.26M rows moves, so this carries #73's change and #75's change and invents neither. diff <(gzip -dc <#75's balances.txt.gz> | sort) \ <(gzip -dc mkgenesis/balances.txt.gz | sort) TWO THINGS ON main THAT THIS CORRECTS IN PASSING Both live in files this change edits anyway. - The provenance dated its extract with a local (UTC+9) file timestamp written as if it were UTC, 9 hours out. The cutoff is now quoted as the address_bindings id, which is checkable, rather than a wall-clock instant. - The vesting caveat said dropping the one declared-schedule row makes a pre-331e17fc3 binary safe. It does not: 28 addresses are both in unrestricted.txt and carry a vesting line, so that removes 1 of 28 InitChain panic triggers. Still 28 with the nine distribution rows on the list -- they are unlocked and none holds an airdrop entitlement -- and the paragraph now says to re-run the count rather than trust the number. ARTIFACTS mkgenesis/balances.txt.gz fa4a8124... -> be4ad951... 57,243,726 -> 57,243,893 B mkgenesis/unrestricted.txt 632de96e... -> 7b37a168... 80 -> 91 addresses Rebuilt with GNU gzip 1.12, which reproduces #73's own container bit-for-bit (verified by round-tripping it before rebuilding); Apple's gzip does not, so a macOS rebuild without GNU gzip on PATH shows that one file dirty. VERIFIED make verify is green end to end: allocate and mkgenesis tests, including the golden rebuild and #74's regenerated-list check, and crosscheck reports "Balance files match". Rebuilding twice produces the same bytes. The sale-side evidence is carried over from #75 rather than re-run, and it is about the same bytes: mkgenesis/publicsale.txt and the CSV here are byte- identical to that PR, checked by sha256. In alexis' words: The eleven were re-derived from the Ethereum event log rather than copied: accepted USD as the sum of each wallet's CommitmentIncreased deltas, base at the 129/2000 clearing price, the tiered band by replaying the 173 increases in (block, logIndex) order, 24h eligibility from the first BidPlaced. Exact rational arithmetic. All eleven match to the ugnot. All 79 binding signatures recover to the paying wallet under EIP-191. gno's own GetBalancesFromSheet (at a revision containing 331e17fc3, gnolang/gno#6095) reads the sheet as 79 balances / 21,604,687,430,103 ugnot / 1 vesting schedule, and the gnogenesis binary reports "79 balances saved" with chain_id gnoland1 and verify passing. * chore(inputs): delete the superseded id-68 extract — one extract at a time inputs/README.md says a snapshot is "replaced wholesale". #75 kept the 09-09 file alongside the 09-11 one instead, on the grounds that it had already been published and reviewed. Replaced means replaced: the id-68 extract is deleted, and this directory holds exactly one public-sale extract from now on. NOTHING IS LOST, AND THAT IS CHECKED RATHER THAN ASSUMED - the two hold the same 122 wallets with IDENTICAL amounts: the (ugnot_total, base, tiered_bonus, first24h_bonus, accepted_usd, lockup_12m, first_24h_eligible) tuples of the two files are the same multiset - every GENESIS row of the id-68 file -- address, bound_at and signer included -- is present VERBATIM in the id-79 one, so no binding was dropped or redirected between extracts - the file is still in git where it was captured, 9ecf4d3 (#65): git show 9ecf4d3:inputs/publicsale-sonar-2026-09-09.csv Nothing in the repository read it. No Go file, no test, no Makefile rule references either CSV by name -- they are reference material for humans, and the loaded rows live in mkgenesis/publicsale.txt. The table in inputs/README.md had already been corrected on main, where it claimed allocate/process_test.go consumed the 09-09 file. WHY DELETING IS THE SAFER OPTION, NOT THE BOLDER ONE Which extract is live is not recorded in either CSV. With two in the tree a reader has to work it out, and a stale file sitting next to a current one is the exact shape of the drift the rest of inputs/'s rules exist to prevent -- the same class of bug as a stale generated artifact. One file, named by the id it stops at, cannot be read wrong. inputs/README.md and README-publicsale-provenance.md say all of the above, so the next extract does not have to rediscover it. make verify green; no artifact changes -- the CSV is not an input to the build. --------- Co-authored-by: alexiscolin <alexis@jaunebleu.co>
Member
|
moving to #73 |
moul
added a commit
that referenced
this pull request
Sep 11, 2026
) * feat: pay the settled investor and partner distributions at genesis Nine obligations already owed to counterparties -- market making, exchange listing and integration, ecosystem liquidity -- paid at genesis out of the §136 tranche, by the same reasoning as the public sale: not an eighth bucket, just the part of that tranche already spoken for. 16,076,470 GNOT across 9 addresses Total supply is unchanged. INVESTORS_UNLOCKED_ADDRESS now holds the tranche NET of both carve-outs, 128,395,312.569897 -> 112,318,842.569897, and the three §136 lines still sum to exactly 150,000,000: 112,318,842.569897 INVESTORS_UNLOCKED_ADDRESS 21,604,687.430103 public sale (68 rows) 16,076,470.000000 distributions (9 rows) -------------------- 150,000,000.000000 TestTheThreeSection136LinesSumToTheTranche asserts that directly, so a future carve-out cannot quietly exceed the grant. COUNTERPARTIES ARE NOT NAMED -- ANYWHERE IN THIS DIFF Several are commercial counterparties whose identity and commercial terms are not ours to publish. Rows are labelled investor1..investor9 and ordered by ADDRESS, so neither the labels nor the ordering carries information. The real mapping is held privately and is not in this repository. That has to include the test that enforces it. The obvious way to write TestInvestorDistributionsMatchFile is a blocklist of forbidden names -- which publishes the whole counterparty list, in a public repository, inside the check meant to protect it. So the test asserts the SHAPE of a row instead: ^g1[0-9a-z]{38}=[0-9]+ugnot # investor[0-9]+$ Anything an edit could append -- a name, a desk, a ticker -- fails to parse, and it fails for every counterparty, including the ones nobody thought to enumerate. Strictly stronger than a blocklist, and it leaks nothing. Be honest about the limit: the AMOUNTS are in the genesis and are therefore public no matter what, and the GNOT price is knowable. What is withheld is WHICH counterparty each row belongs to. A stronger property needs the payment moved off the genesis sheet, not relabelled. The check also constrains the payable rows, not the prose header above them; that stays a human review. WHAT IS DELIBERATELY NOT HERE Obligations settled AFTER genesis: one counterparty wants the full amount post-genesis for regulatory reasons, and two more are still pending. The tranche multisig can pay them later; a genesis row cannot be undone. Their absence is why the constant is 16,076,470 rather than the 28,073,670 the working sheet totals. LIQUID, AND WHITELISTED These come out of the §136 UNLOCKED tranche, so build.go marks the whole file `unlocked` -- no §132 schedule, exactly like the sale. They must also be in mkgenesis/unrestricted.txt: at genesis $GNOT is non-transferable (§126), and an obligation paid into an address that cannot move it is not paid. ALSO: THE CROSSCHECK INDEXED BY POSITION verify/crosscheck compared balanceFiles[0] against balanceFiles[3]. Adding a fourth sheet shifted genbalance from [3] to [4], so it compared the wrong pair and reported every address as missing. Now keyed by filename, which is how I found it -- the failure was loud, but only by luck of ordering. Verified: crosscheck passes, total 1,332,999,998.328067 GNOT, rows 3,262,454 -> 3,262,463. REBASED ONTO #74 #74 landed first and generates mkgenesis/unrestricted.txt from publicsale.txt plus investors.txt when it exists. It exists now, so the committed list is regenerated here: 71 -> 80 addresses, the nine distribution rows. Without this the `generated` check is red on arrival -- #74 tolerates the file's absence, not a stale list. #74's TestUnrestrictedCoversEveryPublicSaleRow also had to learn about the second sheet. It asserted len(listed) == len(sale)+3, which is the right property on a tree with no investors.txt and a red build on one that has it -- the generator supports both paths, the test pinned one. It now reads investors.txt the same way the generator does, tolerating absence, and covers its rows too: a distribution paid into an address that cannot move it is the exact failure the test exists to prevent. * feat: re-extract the public-sale bindings, 11 more participants paid at genesis (#75 rebased on #73) (#76) * feat: re-extract the public-sale bindings, 11 more participants paid at genesis The binding page has no deadline, so the list #65 froze keeps growing. inputs/README.md already says what to do about it: "replace the file at a new instant rather than adding rows to this one". This is the second extract. Eleven more of the 122 settled wallets named a gno.land address, so 78 are now paid directly at genesis and 44 stay with the [sale-unclaimed] multisig. One of the eleven is the largest unclaimed row in the sale, 2,739,572.093023 GNOT. SUPPLY-NEUTRAL, AS #65 WAS The eleven move 4,255,242.961239 GNOT out of the multisig row and into rows of their own. The sheet still totals 21,604,687.430103 GNOT, TOTAL_PUBLIC_SALE_UGNOT is untouched, and total supply stays at 1,332,999,998.328067 GNOT. balances.txt goes 3,262,463 -> 3,262,473 rows: eleven new addresses, one of which merges into an airdrop row it already held. That merge takes the pinned airdrop overlap 25 -> 26 addresses, and the merged row keeps its §132 schedule byte-for-byte over the airdrop portion alone, its sale portion liquid as §128 requires. THE NEW EXTRACT REPLACES THE OLD ONE inputs/publicsale-sonar-2026-09-11.csv, ending at address_bindings id 79. It does not sit beside the id-68 extract: inputs/README.md says a snapshot is "replaced wholesale", and the follow-up commit deletes that file. The two hold the same 122 wallets with identical amounts and differ only in which had bound, and git keeps the old one at 9ecf4d3 (#65) regardless. No new lockup: all eleven are lockup_12m = no. The single declared vesting schedule is unchanged. REBASED ONTO #73, WHICH CHANGES WHAT THIS HAS TO TOUCH Opened as #75 against main, where publicsale.txt was the only §136 carve-out. #73 makes it one of two, so five things are different here and none of them is a data change: - The §136 closure is now a three-line sum, and TestTheThreeSection136Lines- SumToTheTranche is left completely untouched. That is the strongest statement available that this change is supply-neutral: an extract that moved a single ugnot across the sale/tranche boundary could not leave that test alone. - verify/crosscheck is keyed by filename as of #73, so a fifth sheet no longer shifts genbalance's index. The version against main did not need that and would have silently reintroduced it the next time a sheet was added. - The four hand-maintained pins move through #73's shared readSheet() rather than the copy readSaleSheet() used to be. - mkgenesis/unrestricted.txt is GENERATED by #74 from both §136 sheets, so the eleven are not hand-added: `make -C mkgenesis` emits 80 -> 91 addresses. - ABOUT.md, docs/pipeline.md and README.md reconciled across THREE sheets, not two. #73 added investors.txt without them, so the row arithmetic in ABOUT.md and the tree in pipeline.md were 9 rows short before this; they now balance: 3,262,351 + (66 - 6) + (79 - 26) + 9 = 3,262,473 investors.txt intersects nothing -- not the airdrop, not the other two sheets -- so all nine are new rows. Checked by set arithmetic, not assumed. The rebase is checkable without trusting any of the above. Sorted, the sheet built here differs from the one on #75 by exactly eleven lines: the nine distribution rows, and INVESTORS_UNLOCKED_ADDRESS going 128,395,312.569897 -> 112,318,842.569897, which is -16,076,470 to the ugnot. Nothing else in 3.26M rows moves, so this carries #73's change and #75's change and invents neither. diff <(gzip -dc <#75's balances.txt.gz> | sort) \ <(gzip -dc mkgenesis/balances.txt.gz | sort) TWO THINGS ON main THAT THIS CORRECTS IN PASSING Both live in files this change edits anyway. - The provenance dated its extract with a local (UTC+9) file timestamp written as if it were UTC, 9 hours out. The cutoff is now quoted as the address_bindings id, which is checkable, rather than a wall-clock instant. - The vesting caveat said dropping the one declared-schedule row makes a pre-331e17fc3 binary safe. It does not: 28 addresses are both in unrestricted.txt and carry a vesting line, so that removes 1 of 28 InitChain panic triggers. Still 28 with the nine distribution rows on the list -- they are unlocked and none holds an airdrop entitlement -- and the paragraph now says to re-run the count rather than trust the number. ARTIFACTS mkgenesis/balances.txt.gz fa4a8124... -> be4ad951... 57,243,726 -> 57,243,893 B mkgenesis/unrestricted.txt 632de96e... -> 7b37a168... 80 -> 91 addresses Rebuilt with GNU gzip 1.12, which reproduces #73's own container bit-for-bit (verified by round-tripping it before rebuilding); Apple's gzip does not, so a macOS rebuild without GNU gzip on PATH shows that one file dirty. VERIFIED make verify is green end to end: allocate and mkgenesis tests, including the golden rebuild and #74's regenerated-list check, and crosscheck reports "Balance files match". Rebuilding twice produces the same bytes. The sale-side evidence is carried over from #75 rather than re-run, and it is about the same bytes: mkgenesis/publicsale.txt and the CSV here are byte- identical to that PR, checked by sha256. In alexis' words: The eleven were re-derived from the Ethereum event log rather than copied: accepted USD as the sum of each wallet's CommitmentIncreased deltas, base at the 129/2000 clearing price, the tiered band by replaying the 173 increases in (block, logIndex) order, 24h eligibility from the first BidPlaced. Exact rational arithmetic. All eleven match to the ugnot. All 79 binding signatures recover to the paying wallet under EIP-191. gno's own GetBalancesFromSheet (at a revision containing 331e17fc3, gnolang/gno#6095) reads the sheet as 79 balances / 21,604,687,430,103 ugnot / 1 vesting schedule, and the gnogenesis binary reports "79 balances saved" with chain_id gnoland1 and verify passing. * chore(inputs): delete the superseded id-68 extract — one extract at a time inputs/README.md says a snapshot is "replaced wholesale". #75 kept the 09-09 file alongside the 09-11 one instead, on the grounds that it had already been published and reviewed. Replaced means replaced: the id-68 extract is deleted, and this directory holds exactly one public-sale extract from now on. NOTHING IS LOST, AND THAT IS CHECKED RATHER THAN ASSUMED - the two hold the same 122 wallets with IDENTICAL amounts: the (ugnot_total, base, tiered_bonus, first24h_bonus, accepted_usd, lockup_12m, first_24h_eligible) tuples of the two files are the same multiset - every GENESIS row of the id-68 file -- address, bound_at and signer included -- is present VERBATIM in the id-79 one, so no binding was dropped or redirected between extracts - the file is still in git where it was captured, 9ecf4d3 (#65): git show 9ecf4d3:inputs/publicsale-sonar-2026-09-09.csv Nothing in the repository read it. No Go file, no test, no Makefile rule references either CSV by name -- they are reference material for humans, and the loaded rows live in mkgenesis/publicsale.txt. The table in inputs/README.md had already been corrected on main, where it claimed allocate/process_test.go consumed the 09-09 file. WHY DELETING IS THE SAFER OPTION, NOT THE BOLDER ONE Which extract is live is not recorded in either CSV. With two in the tree a reader has to work it out, and a stale file sitting next to a current one is the exact shape of the drift the rest of inputs/'s rules exist to prevent -- the same class of bug as a stale generated artifact. One file, named by the id it stops at, cannot be read wrong. inputs/README.md and README-publicsale-provenance.md say all of the above, so the next extract does not have to rediscover it. make verify green; no artifact changes -- the CSV is not an input to the build. --------- Co-authored-by: alexiscolin <alexis@jaunebleu.co> --------- Co-authored-by: alexiscolin <alexis@jaunebleu.co>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Eleven more of the 122 settled public-sale wallets have named a gno.land address since #65, one of them the largest unclaimed row in the sale (2,739,572.093023 GNOT). This pays them at genesis instead of leaving them to the multisig. Supply-neutral.
Opening this per @dongwon8247's request, so @moul can decide whether to take it now or after genesis. Nothing breaks if it is not merged: the eleven stay covered by the multisig row and are paid by hand instead.
[sale-unclaimed]multisigThe new extract is a new file, per
inputs/README.md's own rule:inputs/publicsale-sonar-2026-09-11.csv, ending ataddress_bindingsid 79. The 09-09 file is kept byte-for-byte. The four hand-maintained pins inallocate/process_test.gomove with the data; no code behaviour changes (two one-line comments updated alongside).Reviewing the 57 MB binary in thirty seconds
14 lines: ten insertions, the one participant who also holds an airdrop (that row gains exactly its sale amount, §132 suffix byte-identical, the airdrop half still vests), and the multisig decrement. Nothing else in the 3.26M rows moves.
balances.txt.gzwas rebuilt with GNU gzip 1.12, which reproduces your container bit-for-bit; Apple's gzip does not, so a macOS rebuild shows that one file dirty.Also corrected, in files this change edits anyway
address_bindingsid, which is checkable. Nothing is wrong with either extract; only the label was.331e17fc3binary safe. It does not: 28 whitelisted addresses carry a vesting line (26 airdrop-overlapping sale rows + two §127 funds), so that removes 1 trigger of 28. The paragraph now says so, with a one-liner to list them.Before you merge
mkgenesis/unrestricted.txtgoes 71 -> 82 addresses: sha2569bc496a3…->683891151692a86b82c6f30fab9c81aa2c9191a7252241f649201837a18ad265.balances.txt.gz:aaf850fd…->38a604f2434ebb1c15fdf68c79dcbf26425c037888813023a69293e23cce9067(57,244,031 B). This repo's README records both as fetched by pinned URL fromgnolang/gnodeployment scripts; on current gno master I could only findgnoland1andtest13gen-genesis.sh, pinning commit9dec38a4(pre-sale). Whichever script cuts mainnet genesis needs the bump - say the word and I open it.docs/history.mdis deliberately untouched: a row here would sit across a long gap of unrecorded number changes (fix: enforce the IBC escrow skip — 36.62M GNOT to 106 keyless accounts #55-feat: generate the Constitution §126 unrestricted-address list (re-land) #74). Better one backfill later than a lone row implying nothing else moved.Verified beyond CI: all eleven re-derived from the raw Ethereum event log (accepted USD from
CommitmentIncreaseddeltas, base at 129/2000, tiered by replaying the 173 increases in order, 24h from the firstBidPlaced; exact rational arithmetic) - all match to the ugnot; all 79 binding signatures recover to the paying wallet under EIP-191;gnogenesisbuilt from a revision containing331e17fc3(gnolang/gno#6095) loads the sheet, reports "79 balances saved",verifypasses,;type=delayedsurvives verbatim.Left out on purpose: a test tying
mkgenesis/publicsale.txtto the settlement CSV (today, redirecting one destination and regenerating leaves the whole suite green - demonstrated). Written and mutation-tested; coming as its own PR so this one stays data-only.