Skip to content

feat: implement v2 settlement and forfeiture distribution - #87

Merged
collinsezedike merged 2 commits into
mainfrom
feat/v2-settlement
Aug 12, 2026
Merged

feat: implement v2 settlement and forfeiture distribution#87
collinsezedike merged 2 commits into
mainfrom
feat/v2-settlement

Conversation

@collinsezedike

Copy link
Copy Markdown
Collaborator

Summary

Implements #69: settlement, converting a Resolved assertion's decided outcome into per-position entitlements.

  • New permissionless settle(id, address): any caller may settle any known position. It doesn't move tokens itself; it accrues the computed payout to a new Credit(id, address) record (get_credit reads the balance). Withdrawal (actually transferring tokens against that balance) is a separate, not yet implemented, issue.
  • Winning-side rule depends on terminal_cause: the agreeing side for StrictMajorityFor, the disagreeing side for StrictMajorityAgainst, either side as long as it revealed for OptimisticTimeout. A winning position recovers its principal plus floor(amount * forfeited_pool / recipient_weight). A losing or never-revealed position recovers nothing.
  • recipient_weight and forfeited_pool are derived purely from Resolution fields that are already frozen once phase == Resolved (nothing in Resolution changes after that point), so every settle call recomputes the identical pair regardless of order — settling positions in any sequence, or interleaved with other assertions, never changes any individual result.
  • Floor division leaves at most recipient_weight - 1 units of dust. Once the last recipient position settles (tracked via new Resolution.settled_recipient_weight/settled_reward_total fields), the leftover is credited to a deterministic party: the winning asserter/disputer, or the asserter for a timeout default. Skipped entirely when forfeited_pool is 0.
  • Position gains agrees_with_outcome: Option<bool> (populated by reveal/open_reveal_phase once a position reveals, so settle has one uniform field to read regardless of PositionKind) and settled: bool (rejects a repeat settle with AlreadySettled).
  • Tightens initialize's max_total_weight bound from MAX_BOND_AMOUNT (~1.7 × 10^35) to a new, much stricter MAX_SETTLEMENT_TOTAL_WEIGHT (10^19). The old bound was sized only for finalize's single reward multiply; settlement's amount * forfeited_pool multiply needed max_total_weight² to stay inside i128, which the old bound didn't come close to guaranteeing. This was flagged as a TODO in the original MAX_BOND_AMOUNT comment when [Feature] V2: implement bonded assertion posting #65 landed it.

Test plan

  • cargo fmt --check, cargo clippy --workspace --all-targets -- -D warnings, and cargo test pass locally
  • cargo build -p tholos --target wasm32v1-none --release and cargo build --workspace --target wasm32v1-none --release pass locally
  • mdbook build docs passes locally
  • CONTRACT.md updated if the public interface changed — not applicable, tholos-v2 isn't documented there yet (tracked separately)
  • scripts/testnet-smoke.sh run against testnet — not run; this only touches tholos-v2, which isn't deployed yet
  • What you manually verified: added 10 new tests, including hand-computed strict-majority and optimistic-timeout scenarios with non-trivial floor-division remainders, verified against manually worked-out numbers in the test comments; an order-independence test settling the same scenario in reverse order and asserting identical payouts; a zero-forfeiture case confirming the dust step is skipped; and the failure modes (NotResolved pre-Resolved and on an uncontested-finalize assertion, AlreadySettled, unknown position). Every conserves-the-pool test also asserts the sum of all credits equals eligible_total exactly.

@collinsezedike
collinsezedike merged commit 893abe2 into main Aug 12, 2026
4 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