feat: implement v2 settlement and forfeiture distribution - #87
Merged
Conversation
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.
Summary
Implements #69: settlement, converting a
Resolvedassertion's decided outcome into per-position entitlements.settle(id, address): any caller may settle any known position. It doesn't move tokens itself; it accrues the computed payout to a newCredit(id, address)record (get_creditreads the balance). Withdrawal (actually transferring tokens against that balance) is a separate, not yet implemented, issue.terminal_cause: the agreeing side forStrictMajorityFor, the disagreeing side forStrictMajorityAgainst, either side as long as it revealed forOptimisticTimeout. A winning position recovers its principal plusfloor(amount * forfeited_pool / recipient_weight). A losing or never-revealed position recovers nothing.recipient_weightandforfeited_poolare derived purely fromResolutionfields that are already frozen oncephase == Resolved(nothing inResolutionchanges after that point), so everysettlecall recomputes the identical pair regardless of order — settling positions in any sequence, or interleaved with other assertions, never changes any individual result.recipient_weight - 1units of dust. Once the last recipient position settles (tracked via newResolution.settled_recipient_weight/settled_reward_totalfields), the leftover is credited to a deterministic party: the winning asserter/disputer, or the asserter for a timeout default. Skipped entirely whenforfeited_poolis 0.Positiongainsagrees_with_outcome: Option<bool>(populated byreveal/open_reveal_phaseonce a position reveals, sosettlehas one uniform field to read regardless ofPositionKind) andsettled: bool(rejects a repeatsettlewithAlreadySettled).initialize'smax_total_weightbound fromMAX_BOND_AMOUNT(~1.7 × 10^35) to a new, much stricterMAX_SETTLEMENT_TOTAL_WEIGHT(10^19). The old bound was sized only forfinalize's single reward multiply; settlement'samount * forfeited_poolmultiply neededmax_total_weight²to stay insidei128, which the old bound didn't come close to guaranteeing. This was flagged as a TODO in the originalMAX_BOND_AMOUNTcomment when [Feature] V2: implement bonded assertion posting #65 landed it.Test plan
cargo fmt --check,cargo clippy --workspace --all-targets -- -D warnings, andcargo testpass locallycargo build -p tholos --target wasm32v1-none --releaseandcargo build --workspace --target wasm32v1-none --releasepass locallymdbook build docspasses locallyCONTRACT.mdupdated if the public interface changed — not applicable,tholos-v2isn't documented there yet (tracked separately)scripts/testnet-smoke.shrun against testnet — not run; this only touchestholos-v2, which isn't deployed yetNotResolvedpre-Resolvedand on an uncontested-finalize assertion,AlreadySettled, unknown position). Every conserves-the-pool test also asserts the sum of all credits equalseligible_totalexactly.