Add timelocked, quorum-approved WASM upgrade governance - #211
Merged
Obiajulu-gif merged 3 commits intoAug 20, 2026
Conversation
…nance Adds a governance module to the chainmove-pool Soroban contract: - init_governance bootstraps a static approver set, quorum, and timelock - propose_upgrade requires an approver and an explicit next schema version - approve_upgrade collects distinct approvals, rejecting duplicates - execute_upgrade requires quorum + elapsed timelock + matching schema version at execution time, then calls update_current_contract_wasm and advances the persisted schema version - cancel_upgrade lets the proposer or any approver kill a pending proposal - every transition emits an auditable event No single signer can upgrade immediately; execution is impossible before quorum and timelock conditions are met; an incompatible/stale schema version fails closed before any WASM is swapped.
BigDella
marked this pull request as draft
August 18, 2026 13:07
Obiajulu-gif
marked this pull request as ready for review
August 18, 2026 13:15
Collaborator
|
Hi! This PR currently has a merge conflict with the base branch and can't be merged as-is. Could you please rebase/merge |
Collaborator
|
Thanks for this PR! It currently has merge conflicts against |
…t CI fixes Resolves conflicts in contracts/chainmove-pool/src/lib.rs: keeps both the xdr::ToXdr import (idempotency key hashing, from main) and the Vec import (governance approver lists, from this branch), and renumbers the ContractError enum so the new RefundTooSmall variant from main (14) and the governance variants from this branch (previously also starting at 14) no longer collide. governance.rs references error variants by name only, so renumbering does not affect its logic.
Collaborator
|
Reopening to retrigger CI after pushing merge commit with main to pick up TypeScript fixes. |
…e#209) Resolves a second ContractError discriminant collision: main added InvestmentTooSmall = 15 (from Chainmove#209, merged after our previous sync), which collided with the governance module's error range that also started at 15. Shifts the governance variants to start at 16 (GovernanceAlreadyInitialized through StaleProposal = 26). governance.rs references variants by name only, so no other changes are needed.
5 tasks
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.
What changed
init_governancebootstraps a static approver set, quorum, and timelock (once only)propose_upgraderequires an approver and an explicit next schema version (current + 1), rejecting skipped/repeated versions before any WASM is touchedapprove_upgradecollects distinct approvals; an approver cannot approve the same proposal twiceexecute_upgraderequires quorum to be met, the timelock to have elapsed, and the persisted schema version to still match what the proposal was evaluated against (defense against a stale proposal executing after a different upgrade already moved the schema version on) - only then does it callupdate_current_contract_wasmand advance the persisted schema versioncancel_upgradelets the proposer or any approver kill a pending proposal; terminal states (Executed/Canceled) reject further approval, execution, or cancellation (no replay)chainmove_gov_v1eventWhy
The design docs call for upgradeable, governed Mainnet contracts, but the Soroban contracts exposed no controlled upgrade path - any deployer key could otherwise redeploy state-incompatible code with no quorum or delay.
Acceptance criteria
QuorumNotMet/TimelockNotElapsed).IncompatibleSchemaVersion/StaleProposal).Tests
Added
contracts/chainmove-pool/src/governance_test.rscovering: re-init rejection, invalid quorum/duplicate-approver config, authorization (only approvers propose/approve/execute), sequential schema-version enforcement, double-approval rejection, quorum gating, timelock gating, stale-proposal rejection via a simulated concurrent upgrade, cancellation authorization, and replay rejection on terminal proposals.Validation
rustfmt --edition 2021 --checkreports no parse errors for the changed files (only pre-existing formatting drift outside this diff, left untouched to keep the diff scoped).cargo testcould not link on this machine (link.exeis not a working MSVC linker in this environment - the same limitation noted on the other Soroban-contract PRs in this batch), so the test suite above was validated by careful manual review against the existingtest.rsfixture conventions rather than execution. The one gap this leaves: a fully-executed success path (realupdate_current_contract_wasmswap) needs a second compiled WASM artifact to upload viaenv.deployer().upload_contract_wasm, which isn't buildable here either - all guard conditions leading up to that call (auth, quorum, timelock, schema checks) are covered instead.Closes #164