Skip to content

feat: implement v2 PolicySnapshot and versioned assertion state - #79

Merged
collinsezedike merged 1 commit into
mainfrom
feat/v2-policy-snapshot
Aug 9, 2026
Merged

feat: implement v2 PolicySnapshot and versioned assertion state#79
collinsezedike merged 1 commit into
mainfrom
feat/v2-policy-snapshot

Conversation

@collinsezedike

Copy link
Copy Markdown
Collaborator

Summary

New crate contracts/tholos-v2, a wholly separate contract from v1 (never upgraded in place, blue/green migration per V2_RESOLUTION.md). This PR implements #64's scope only: the immutable PolicySnapshotV2 pinned at assertion creation, and the AssertionV2 record it lives on.

  • initialize: pins deployment-wide defaults (token, base_bond, registration/reveal durations, anti-sniping params, position/weight bounds) into a PolicySnapshotV2, validated and stored once.
  • Decided parameters implemented: min_resolution_bond always equals base_bond (a cheaper minimum would let a third party break an asserter/disputer tie for a fraction of what they risked); bounded anti-sniping extension capped by a hard maximum.
  • AssertionV2 stores the pinned policy, its hash, phase, and (once resolved) terminal_cause/final_outcome directly on the assertion, not only in events.
  • get_policy / get_assertion: read-only lookups.
  • create_pending_assertion: private helper building/storing a Pending AssertionV2 with a freshly pinned policy, not yet wired to a public entrypoint ([Feature] V2: implement bonded assertion posting #65 adds the real, bond-transferring assert_outcome on top of it) or moving any tokens. Marked #[allow(dead_code)] with a comment pointing at [Feature] V2: implement bonded assertion posting #65, which removes the allow.

One real SDK finding worth flagging for later v2 issues: soroban-sdk 26.1.0's contracttype derive doesn't generate an XDR ScVal conversion for Option<EnumType> (only Option of built-in types like Address/bool work), so AssertionV2 failed to compile with terminal_cause: Option<TerminalCause>. Worked around with a TerminalCause::NotYetDecided sentinel variant instead of None, documented inline. Worth remembering for #66-#71, which will define more enums.

Also fixed a real bug caught by testing, not by design: initialize's validation order made InvalidMaxTotalWeight's zero-case structurally unreachable (max_position <= max_total_weight always failed first when max_total_weight was 0). Reordered so total-weight bounds are checked before the position-relative check.

Closes #64

Test plan

  • cargo fmt --check, cargo clippy --workspace --all-targets --locked -- -D warnings, cargo test --workspace --locked all pass (67 v1 + 21 v2 + 2 integration-example tests)
  • cargo build -p tholos-v2 --target wasm32v1-none --release --locked succeeds
  • mdbook build succeeds
  • Every new Error variant has a dedicated test triggering it

@collinsezedike
collinsezedike merged commit 1e6dc0f into main Aug 9, 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.

[Feature] V2: implement PolicySnapshot and versioned assertion state

1 participant