Skip to content

Appeals

Permissionless escalation to a larger panel. Anyone may appeal a resolved round within the appeal window.

The appeal window is per-Subaccord (dispute.terms.appeal_window, frozen at filing; default 3 days, floor 1 hour — ADR-0022). Set max_appeals == 0 to disable appeals entirely.

appeal()

appeal(ctx, new_evidence_hash) — the new_evidence_hash: [u8; 32] argument is the evidence-on-appeal channel (ADR-0023). It is stored at dispute.evidence_hashes[current_round + 1] (the round this appeal opens). Pass [0u8; 32] to appeal on the existing evidence only — the sentinel means "no new evidence this round," and round-N jurors reuse the accumulated evidence_hashes[0..=N].

Gate Error
!pause_state.paused ProgramPaused
state == RoundResolved InvalidState
current_round < max_appeals MaxAppealsReached
now < reveal_end + terms.appeal_window AppealWindowClosed
subaccord.staker_count ≥ new_panel InsufficientJurors

Panel ladder

Closed form panel_k = (J+1)·2^k − 1, capped at MAX_JURORS (31).

current_round (after++) panel (J=3)
1 7
2 15
3 31

Cost

fee_new = panel_new × fee_per_juror
bond    = fee_new                         // bond == new-round fee
total   = fee_new + bond                  // appellant ATA → vault

Bond settlement

  • Recorded in AppealBond PDA ["bond", dispute, round_idx] where round_idx = the new (larger) round.
  • prior_result: u64 = winning value of the round being appealed — option index (Plurality) or median (Median); u64 since ADR-0025.
  • finalize_dispute checks each bond: prior_result == final_ruling ⇒ no flip ⇒ bond folded into the final-round coherent pool and zeroed. prior_result != final_ruling ⇒ flip ⇒ bond left for claim_appeal_refund.
  • claim_appeal_refund returns flipped bonds to their appellant (idempotent).

Round reset

appeal increments current_round, stores new_evidence_hash into evidence_hashes[current_round] (the new round's slot), and resets state → Created, so the VRF → draw → vote cycle reruns for the larger panel. The same committed_vrf and frozen_root are reused — appeals draw a larger panel from the same fixed pool (no new VRF, no re-grind; ADR-0012).

accord::appeal(ctx.contexts, new_evidence_hash)?;   // [u8; 32]; [0u8; 32] = no new evidence
// later, after Final:
accord::claim_appeal_refund(ctx.contexts, round_idx)?;  // round_idx = appealed round
import { appeal, claimAppealRefund } from "@useaccord/sdk";

// newEvidenceHash: Uint8Array(32); all-zeros = appeal on existing evidence (ADR-0023)
await appeal(accord.adapter, accord.PROGRAM_ID, { dispute, newEvidenceHash });
// after finalize_dispute:
await claimAppealRefund(accord.adapter, accord.PROGRAM_ID, {
  dispute,
  roundIdx,
});

Why permissionless + bond economics: ADR-0004. Cross-round settlement against the final ruling: Kleros §4.6.