Docs v2 · testnet

Protocol · Disputes & committees

A bonded committee ladder — never a token vote

Any proposed outcome can be challenged. A challenge doesn't go to whoever holds the most governance tokens: it goes to a randomly drawn committee of resolvers who must re-check the source and put money on their answer. If two committees in a row can't agree, the event is Voided and every market built on it refunds.

Dispute bond

1 unit

0.01 ETH default · 0.0005 on testnet

Tier 1

≤7 · 1 h

3 units per vote

Tier 2

≤15 · 2 h

8 units per vote

To decide

66%

of committee SIZE, not of votes cast

Try it live

The Dispute Center lists every event that's open to challenge or in committee on Robinhood Chain testnet. File a dispute from your wallet, watch the committee vote in real time, and withdraw returned bonds. Every market page shows the same panel for the events it settles on.

The ladder

1

Proposed outcome

quorum agreed

2

Dispute

1 bond unit, in window

3

Tier 1

≤7 resolvers · 1 h

4

Tier 2

≤15 resolvers · 2 h

5

Finalized or Voided

no Tier 3

Two ways into a dispute

Challenge — dispute(eventId)

The event is ProposedOutcome and its dispute window (set per event, e.g. 10 minutes) is still open. The disputer sends exactly DISPUTE_BOND (one bond unit). The event moves to Disputed and Tier 1 opens.

Split quorum — escalateNonConvergence(eventId)

Resolvers disagreed and no answer reached the quorum by the observation deadline. Anyone (in practice the keeper) escalates it — no bond — and Tier 1 opens with no original proposal to defend.

Step by step

  1. 1

    Committee drawn

    DisputeManager
    Up to 7 authorized resolvers are drawn for Tier 1 (the whole pool if it is smaller). The draw is seeded from block data and the event ID.
  2. 2

    Members vote with a bond

    1 hour
    Each member calls submitTier1Vote(eventId, outcome) with the Tier-1 bond (3 units). Resolver nodes do this automatically: they re-run the same adapter and vote what they observe.
  3. 3

    66% decides

    instant
    The moment one side reaches 66% of the committee size, the tier resolves: the Registry finalizes that outcome (finalizeFromDispute) and bonds are settled.
  4. 4

    No decision → Tier 2

    keeper
    If the hour ends without 66%, escalateTier2 refunds every Tier-1 vote bond in full and draws up to 15 resolvers with the Tier-2 bond (8 units) and a 2-hour window.
  5. 5

    Still no decision → VOID

    floor
    voidAfterTier2Timeout marks the event permanently Voided. All Tier-2 bonds and the disputer's bond are refunded. Nothing escalates further.

How many votes decide?

The rule in code is votes × 100 ≥ committeeSize × 66. It counts the committee's size, not how many voted, so members who stay silent can't let a small group decide.

Authorized pool

2

Tier-1 committee

2

Votes to decide

2

Tier-2 committee

2

Votes to decide

2

Authorized pool

3 (today)

Tier-1 committee

3

Votes to decide

2

Tier-2 committee

3

Votes to decide

2

Authorized pool

5

Tier-1 committee

5

Votes to decide

4

Tier-2 committee

5

Votes to decide

4

Authorized pool

7

Tier-1 committee

7

Votes to decide

5

Tier-2 committee

7

Votes to decide

5

Authorized pool

10

Tier-1 committee

7

Votes to decide

5

Tier-2 committee

10

Votes to decide

7

Authorized pool

15+

Tier-1 committee

7

Votes to decide

5

Tier-2 committee

15

Votes to decide

10

Where the bonds go

When a tier decides, everyone who voted with the decision gets their bond back. The losing side's bonds are split in thirds:

Third

⅓

Goes to

Burned (sent to 0x…dEaD)

Third

⅓

Goes to

The protocol treasury — the TreasuryVault, which sweeps it in with sweepDisputeProceeds()

Third

⅓

Goes to

Shared equally by the members who voted with the decision (rounding dust goes to the treasury)

The disputer's bond

Committee decides…

against the original proposal (the disputer was right)

Disputer gets

their bond back in full

Committee decides…

the same as the original proposal (the disputer was wrong)

Disputer gets

nothing: ⅓ burned, ⅔ to the treasury

Committee decides…

nothing — event Voided

Disputer gets

their bond back in full

Worked example

Tier 1, 7 members: 5 vote TRUE, 2 vote FALSE

5 ≥ 4.62, so TRUE is decided. Losing pool = 2 × 0.03 = 0.06 ETH → 0.02 burned, 0.02 to the treasury, 0.02 shared by the 5 winners = 0.004 each. Each winner withdraws 0.03 + 0.004 = 0.034 ETH (default unit; on testnet every figure is 20× smaller). If the original proposal was FALSE, the disputer also gets their 0.01 back.

On top of the bonds, the committee is paid from market fees: the TreasuryVault's committee third for that event goes to the deciding tier's members who voted the final outcome. See Treasury & fee thirds.

Pull payments

DisputeManager never pushes ETH to members inside a vote. Everything owed is credited to pendingWithdrawals[address] and collected with withdraw(), so a contract that reverts on receiving ETH can't freeze a dispute. Resolver nodes withdraw automatically.

Constants

Bonds come from one deploy-time unit

DISPUTE_BOND is the unit; Tier-1 and Tier-2 vote bonds are always 3× and 8× it, so the escalation economics are identical at any scale. The default unit is 0.01 ETH. The Robinhood Chain testnet deployment uses 0.0005 ETH so three faucet-funded resolvers can actually post committee bonds — a full Tier-1 dispute costs each of them under 0.002 ETH.

Read directly from contracts/DisputeManager.sol.

Constant

DISPUTE_BOND

Value

1 unit · 0.01 ETH default · 0.0005 testnet

Meaning

Bond to challenge a proposed outcome.

Constant

TIER1_BOND

Value

3 units · 0.03 / 0.0015 ETH

Meaning

Bond per Tier-1 vote.

Constant

TIER1_COMMITTEE_SIZE

Value

7

Meaning

Maximum Tier-1 members (the whole pool if smaller).

Constant

TIER1_WINDOW

Value

1 hour

Meaning

Time Tier 1 has to decide.

Constant

TIER2_BOND

Value

8 units · 0.08 / 0.004 ETH

Meaning

Bond per Tier-2 vote.

Constant

TIER2_COMMITTEE_SIZE

Value

15

Meaning

Maximum Tier-2 members.

Constant

TIER2_WINDOW

Value

2 hours

Meaning

Time Tier 2 has to decide.

Constant

AGREEMENT_BPS

Value

66

Meaning

Percent of committee size needed to decide.

Functions

Function

dispute(eventId)

Who

anyone, DISPUTE_BOND

When

ProposedOutcome, inside the dispute window

Function

escalateNonConvergence(eventId)

Who

anyone

When

observation deadline passed without quorum

Function

submitTier1Vote / submitTier2Vote(eventId, outcome)

Who

drawn committee members, with the tier bond

When

inside the tier window

Function

escalateTier2(eventId)

Who

anyone

When

Tier-1 window over, no 66%

Function

voidAfterTier2Timeout(eventId)

Who

anyone

When

Tier-2 window over, no 66%

Function

withdraw()

Who

anyone owed ETH

When

any time

Function

getCommittee · getVote · getTierTally · getCaseSummary

Who

views

When

any time

Drawing a committee: commit-reveal

While the resolver pool fits in a tier (≤ 7 for Tier 1, ≤ 15 for Tier 2), the committee is the whole pool and voting starts at once. Once the pool is larger, the tier first runs a two-step draw that no single party — the sequencer included — can predict or steer:

  1. 1

    Commit

    10 min
    Each authorized resolver calls commitSeed(eventId, keccak256(eventId, tier, resolver, salt)). Nodes derive the salt from their own signature, so they can always reveal it later.
  2. 2

    Reveal

    10 min
    Each committer calls revealSeed(eventId, salt). The salts are XOR-combined, so the order of reveals doesn't matter.
  3. 3

    Draw

    anyone
    drawCommittee(eventId) seeds the draw with the combined salts. Committers that never revealed are excluded — withholding can only remove yourself. The voting window starts here.

Known limitations

Bonds are flat (no staking or reputation yet), and the contracts are unaudited. Committee selection is commit-reveal (above) rather than VRF, which isn't available on Robinhood Chain; its one residual is a last revealer withholding, which only removes themselves from the draw. If nobody reveals at all, the draw falls back to block data so a dispute can never stall. See the threat model.