Skip to content

Implement durable on-chain dispute voting in treasury contract - #526

Merged
levoski1 merged 3 commits into
WHEELBACK:mainfrom
Prasiejames:main
Aug 27, 2026
Merged

Implement durable on-chain dispute voting in treasury contract#526
levoski1 merged 3 commits into
WHEELBACK:mainfrom
Prasiejames:main

Conversation

@Prasiejames

Copy link
Copy Markdown
Contributor

Closes #410
Closes #411
Closes #412
Closes #413

Summary

Closes the "dispute vote state is volatile" gap described for comebackhere-backend by 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-backend is a sibling repository (built from ../comebackhere-backend per docker-compose.override.yml); disputes.ts is not part of this tree. In this repo, dispute votes had no durable storage at all — vote_dispute_resolution was listed in the ABI and glossary but absent from the contract, and resolve_dispute was 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.rs

  • New on-chain Dispute record: settlement_id, status (Raised / ResolvedClaimant / ResolvedCounterparty), resolution_weight, voters (dedupes signers), raised_by, reason — stored under DataKey::Dispute(settlement_id) in instance storage.
  • raise_dispute: now persists the dispute record, keeps the settlement OnHold, and emits dispute_raised.
  • vote_dispute_resolution (new): auth-gated, signer-weight-gated, rejects double votes; accumulates resolution_weight and auto-resolves once cumulative weight ≥ threshold; emits dispute_resolution_voted.
  • resolve_dispute: finalizes explicitly once the threshold is met (ThresholdNotMet otherwise).
  • New TreasuryError variants: DisputeNotFound, DisputeAlreadyRaised, DisputeNotRaised, AlreadyVoted, UnauthorizedSigner, ThresholdNotMet.
  • 8 contract tests covering the full vote lifecycle and failure paths.

COMEBACKHERE-contracts/contracts/treasury/src/events.rs (new) — dispute_raised, dispute_resolution_voted, dispute_resolved events, matching the invoice contract's event conventions.

COMEBACKHERE-contracts/contracts/treasury/Cargo.toml — adds the soroban-sdk testutils dev-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_favor mapping: true = in favour of the claimant (dispute raiser) → settlement Cancelled; false = in favour of the counterparty (merchant) → settlement returns to Pending.
  • Single-counter resolution: resolution_weight accumulates all votes (per the glossary); the vote that crosses the threshold sets the resolution direction.
  • Votes are persisted per-signer in the voters list so a signer can never vote twice and resolution_weight can't be inflated.

Verification

  • abis/*.json validated as JSON; the ABI generator's function extraction matches the new source (includes vote_dispute_resolution).
  • Docs lint: no new issues introduced by this change (7 pre-existing issues in untouched files remain).
  • ⚠️ cargo test was not run: no Rust toolchain is available in the authoring environment. The 8 new tests in the treasury crate should be run (cargo test in COMEBACKHERE-contracts/contracts/treasury/) before merge.

Notes

  • Pre-existing (not addressed here): the committed abis/treasury.json remains richer than the generator output (spec fields + aspirational functions like propose_partial_settlement), so make check-abi-snapshots was already failing on main.
  • CI's contract job checks out WHEELBACK/COMEBACKHERE-contracts; if this change should also land there, it needs to be mirrored in that repo.

Prasiejames and others added 2 commits August 27, 2026 15:21
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
@drips-wave

drips-wave Bot commented Aug 27, 2026

Copy link
Copy Markdown

@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! 🚀

Learn more about application limits

@levoski1
levoski1 merged commit e8411b6 into WHEELBACK:main Aug 27, 2026
0 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment