Skip to content

Events 2.1.0: grant milestone splits - #167

Merged
0xdevcollins merged 1 commit into
testnetfrom
feat/grant-milestone-split
Oct 8, 2026
Merged

0xdevcollins merged 1 commit into
testnetfrom
feat/grant-milestone-split

Conversation

@0xdevcollins

Copy link
Copy Markdown
Collaborator

Events 2.1.0: a grant can pay its milestones fixed, unequal shares of each award. This is the contract half of boundlessfi/boundless-nestjs#890 and boundlessfi/boundless-platform#809 (backend boundlessfi/boundless-nestjs#921, platform boundlessfi/boundless-platform#836).

Testnet already runs this build (details below). Mainnet does not change: it still goes from 1.7.0 to 2.0.0 through runbook Section 8, and takes 2.1.0 later as its own upgrade.

Why a contract change

2.0.0 pays every grant claim award / n, with whichever milestone settles last taking the remainder, and claim_milestone takes no amount. A 30 / 40 / 30 split could not be paid however the backend recorded it.

What changes

  • ReleaseKind::Split(Vec<u32>): each milestone's share of an award in basis points, in milestone order. The variant is appended, so stored records still decode and a caller that only sends Single or Multi is unaffected.
  • create_event accepts a split only on a grant, and refuses one that is empty, longer than 20 milestones, has a zero share or does not add up to 10,000, with the new InvalidMilestoneSplit (98).
  • claim_milestone and forfeit_milestone pay a milestone its share, rounded down; whichever settles last still takes what is left, which is its own share plus every rounding, so an award pays exactly its amount in any order.
  • select_winners refuses an award too small for the smallest share to pay a stroop, as it already did for an award smaller than its milestone count. That check stays a comparison for Multi, which has no length cap.
  • Version 2.1.0 (Cargo.toml, INITIAL_VERSION, contractmeta). WASM 63,294 bytes against the 64 KB ceiling (2.0.0 was 61,641).

Testing

  • cargo test --release: 337 events and 60 profile tests. A new split group covers storage, every refusal, payouts per share, awards of different sizes, rounding in any settlement order, forfeits and selecting once. The randomized run now gives half its multi-milestone grants a random split; 400 seeds reconcile to the last token.
  • scripts/test-storage-compat.sh: the mainnet replay upgrades into this build and then pays a split grant in full.
  • fmt, clippy with -D warnings, check-versions.sh, the admin-script and upgrade-guard tests: all pass.
  • Testnet: CBEODVJG… went 2.0.0 to 2.1.0 on 2026-10-08 (proposed fc713ba2…, applied d3f1e8c0…, 10 migrate_events pages, stamped d91f1ddc…). A grant created on 2.0.0 reads the same afterwards. The grant run, with a new split scenario, passed 337 of 337 checks across 163 transactions (docs/audit/testnet-grant-run-2.1.0.md); the 2.0.0 report is unchanged.

Docs

  • Threat model 1.3: Tamp.20 (a split that does not add up), Tamp.18 extended to splits, counts and test numbers updated. It still names 2.0.0 as the build under review, plus this split, and says the Scout scan covers 2.0.0 only.
  • Runbook Section 9 records the testnet upgrade and that mainnet takes 2.1.0 only after 2.0.0, behind the timelock. Section 8 is unchanged.
  • README: testnet versions (events 2.1.0, profile 1.2.1, which was already live but listed as 1.2.0).
  • BACKLOG: a P1 entry for 2.1.0 on mainnet, with the Scout rerun still to do.

Merge with a squash; the branch is one commit.

A grant can be published with ReleaseKind::Split: each milestone's share of
every award in basis points, in milestone order, adding up to 10,000. Each
claim or forfeit pays that milestone's share, rounded down, and whichever
milestone settles last takes what is left, so an award pays exactly its
amount in any order. create_event refuses a split that is empty, longer
than 20, has a zero share or does not add up (InvalidMilestoneSplit, 98),
or is not on a grant; selection refuses an award too small for its smallest
share. The variant is appended, so stored records decode and existing
callers are unaffected.

Testnet runs 2.1.0 since 2026-10-08 (runbook Section 9; grant run 337/337
with a split grant). Mainnet still goes to 2.0.0 first and takes 2.1.0 as a
separate upgrade.
@almanax-ai

almanax-ai Bot commented Oct 8, 2026

Copy link
Copy Markdown

Plan expired

Your subscription has expired. Please renew your subscription to continue using CI/CD integration and other features.

@0xdevcollins
0xdevcollins merged commit 7fb3b76 into testnet Oct 8, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant