The CredenceArbitration contract provides a weighted voting mechanism for dispute resolution, allowing authorized arbitrators to decide on outcomes.
Disputes are created with a specific duration. During this time, registered arbitrators can cast weighted votes for different outcomes. Once the voting period ends, the dispute can be resolved, and the outcome with the highest total weight is declared the winner.
Disputes follow a canonical status machine with enforced transitions:
Open ──────> Voting ──────> Resolving ──────> Resolved
│ │ │
└────────────┴──────────────┤──────────> Cancelled
↓
Tied
Open → Voting— Voting period begins (implicit at creation)Voting → Resolving— Voting period ends,resolve_disputecalledVoting → Cancelled— Dispute cancelled by creator or adminResolving → Resolved— Outcome tallied with a clear winnerResolving → Tied— Outcome tallied with a tie (two or more outcomes have equal highest weight)Open → Cancelled— Cancelled before voting starts
All other transitions are rejected with ArbitrationError::InvalidTransition.
| Status | Value | Description |
|---|---|---|
| Open | 0 | Initial state (immediately transitions to Voting) |
| Voting | 1 | Arbitrators can cast votes |
| Resolving | 2 | Tallying votes (transient state) |
| Resolved | 3 | Final outcome determined with a clear winner |
| Cancelled | 4 | Dispute cancelled by creator or admin |
| Tied | 5 | Votes resulted in a tie (equal highest weights) |
| Field | Type | Description |
|---|---|---|
| id | u64 | Unique identifier for the dispute |
| creator | Address | Address that created the dispute |
| description | String | Brief description of the dispute |
| voting_start | u64 | Timestamp when voting begins |
| voting_end | u64 | Timestamp when voting ends |
| status | DisputeStatus | Current status in the lifecycle |
| outcome | u32 | The winning outcome (0 only when Tied) |
| Error | Code | Description |
|---|---|---|
| InvalidTransition | 1 | Attempted an invalid status transition |
| AlreadyInitialized | 2 | Contract already initialized |
| NotInitialized | 3 | Contract not initialized |
| NotAdmin | 4 | Caller is not the admin |
| NotArbitrator | 5 | Voter is not a registered arbitrator |
| AlreadyVoted | 6 | Arbitrator already voted on this dispute |
| VotingInactive | 7 | Voting period is not active |
| VotingNotEnded | 8 | Voting period has not ended yet |
| DisputeNotFound | 9 | Dispute ID does not exist |
| InvalidOutcome | 10 | Outcome must be > 0 |
| WeightNotPositive | 11 | Arbitrator weight must be positive |
| NotAuthorized | 12 | Caller not authorized for this action |
Sets the contract administrator. Can only be called once.
Registers or updates an arbitrator with a specific voting weight. Requires admin authorization. Weight must be positive.
Removes an arbitrator's voting rights. Requires admin authorization.
create_dispute(creator: Address, description: String, duration: u64) -> Result<u64, ArbitrationError>
Creates a new dispute. Requires creator authorization. Returns the dispute ID. Status starts as Voting.
Cancels a dispute. Only the creator or admin may cancel. Valid from Open or Voting status.
Casts a weighted vote for an outcome. Requires voter authorization. Voter must be a registered arbitrator. Dispute must be in Voting status.
Resolves the dispute after the voting period has ended. Transitions Voting → Resolving → Resolved (or Tied if outcomes are tied). Calculates the winning outcome based on total weight. Returns the winning outcome if one is found, or 0 if a tie is detected. On tie, the dispute transitions to Tied status so consumers can distinguish it from a definite ruling.
Retrieves the details of a specific dispute.
Returns the current total weight for a specific outcome.
arbitrator_registered— Emitted when an arbitrator is registered or updatedarbitrator_unregistered— Emitted when an arbitrator is removeddispute_created— Emitted when a new dispute is openedstatus_transition— Emitted on every status change (from, to)vote_cast— Emitted when an arbitrator casts a votedispute_cancelled— Emitted when a dispute is cancelleddispute_resolved— Emitted when a dispute is resolved with a clear winnerdispute_tied— Emitted when a dispute resolution results in a tie
- Admin-only functions for arbitrator management
- Authorization required for creating disputes and casting votes
- Double-voting prevention
- Time-bound voting periods
- Overflow protection for weight tallies and counters
- Canonical status machine prevents invalid state transitions
- Result-based error handling for all state-changing operations
The contract includes comprehensive test coverage:
- Basic arbitration flow (creation, voting, resolution)
- Tie scenarios
- Double-voting prevention
- Unauthorized voter rejection
- All valid status transitions
- All invalid status transitions (regression tests)
- Edge cases (zero/negative weights, outcome validation, etc.)
Run tests:
cargo test -p credence_arbitration