Implement durable on-chain dispute voting in treasury contract - #526
Merged
Conversation
Dispute resolution votes previously had no durable storage anywhere: vote_dispute_resolution was documented in the ABI and glossary but not implemented, and resolve_dispute was an empty stub. Any vote state kept by the backend lived only in memory, so it was silently lost on process restarts and not shared across replicas. Add an on-chain Dispute record (status, resolution_weight, voters) persisted under DataKey::Dispute(settlement_id). raise_dispute now stores the record and emits dispute_raised; vote_dispute_resolution records each signer's vote with double-vote and authorization guards and auto-resolves once cumulative weight reaches the threshold; resolve_dispute finalizes explicitly. Emit dispute_resolution_voted and dispute_resolved events, add TreasuryError variants for the new failure modes, and cover the lifecycle with contract tests. Also sync abis/treasury.json errors to the implemented enum and document that votes are stored on-chain plus the post-resolution settlement outcome in docs/glossary.md. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
Implement durable on-chain dispute voting in treasury contract
|
@Prasiejames Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
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.
Closes #410
Closes #411
Closes #412
Closes #413
Summary
Closes the "dispute vote state is volatile" gap described for
comebackhere-backendby implementing the durable, on-chain dispute voting that this repo's treasury contract spec (abis/treasury.json,docs/glossary.md) already documents but never implemented.Context:
comebackhere-backendis a sibling repository (built from../comebackhere-backendperdocker-compose.override.yml);disputes.tsis not part of this tree. In this repo, dispute votes had no durable storage at all —vote_dispute_resolutionwas listed in the ABI and glossary but absent from the contract, andresolve_disputewas an empty stub — so any vote state kept by a backend would live only in memory and be silently lost on process restart or across replicas.Changes
COMEBACKHERE-contracts/contracts/treasury/src/lib.rsDisputerecord:settlement_id,status(Raised/ResolvedClaimant/ResolvedCounterparty),resolution_weight,voters(dedupes signers),raised_by,reason— stored underDataKey::Dispute(settlement_id)in instance storage.raise_dispute: now persists the dispute record, keeps the settlementOnHold, and emitsdispute_raised.vote_dispute_resolution(new): auth-gated, signer-weight-gated, rejects double votes; accumulatesresolution_weightand auto-resolves once cumulative weight ≥ threshold; emitsdispute_resolution_voted.resolve_dispute: finalizes explicitly once the threshold is met (ThresholdNotMetotherwise).TreasuryErrorvariants:DisputeNotFound,DisputeAlreadyRaised,DisputeNotRaised,AlreadyVoted,UnauthorizedSigner,ThresholdNotMet.COMEBACKHERE-contracts/contracts/treasury/src/events.rs(new) —dispute_raised,dispute_resolution_voted,dispute_resolvedevents, matching the invoice contract's event conventions.COMEBACKHERE-contracts/contracts/treasury/Cargo.toml— adds thesoroban-sdktestutilsdev-dependency for the new tests.abis/treasury.json— errors block synced to the implemented enum (it previously listed a stale, aspirational set).docs/glossary.md— documents that dispute votes are stored on-chain and the post-resolution settlement outcome.Design decisions
resolve_in_favormapping:true= in favour of the claimant (dispute raiser) → settlementCancelled;false= in favour of the counterparty (merchant) → settlement returns toPending.resolution_weightaccumulates all votes (per the glossary); the vote that crosses the threshold sets the resolution direction.voterslist so a signer can never vote twice andresolution_weightcan't be inflated.Verification
abis/*.jsonvalidated as JSON; the ABI generator's function extraction matches the new source (includesvote_dispute_resolution).cargo testwas not run: no Rust toolchain is available in the authoring environment. The 8 new tests in the treasury crate should be run (cargo testinCOMEBACKHERE-contracts/contracts/treasury/) before merge.Notes
abis/treasury.jsonremains richer than the generator output (spec fields + aspirational functions likepropose_partial_settlement), somake check-abi-snapshotswas already failing onmain.WHEELBACK/COMEBACKHERE-contracts; if this change should also land there, it needs to be mirrored in that repo.