Skip to content

Slashing Lifecycle and Dispute Resolution

RunTimeAdmin edited this page Oct 29, 2026 · 19 revisions

Slashing Lifecycle and Dispute Resolution

**Referenced Files in This Document** - [SigvaraStaking.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/src/SigvaraStaking.sol) - [DisputeFreeze.t.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/test/DisputeFreeze.t.sol) - [SlashDrillFork.t.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/test/SlashDrillFork.t.sol) - [slash-drill.md](https://github.com/RunTimeAdmin/Sigvara/blob/main/docs/slash-drill.md) - [demo-page.js](https://github.com/RunTimeAdmin/Sigvara/blob/main/site/assets/demo-page.js) - [Deploy.s.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/script/Deploy.s.sol) - [0005-governance-and-emergency-powers.md](https://github.com/RunTimeAdmin/Sigvara/blob/main/docs/adr/0005-governance-and-emergency-powers.md)

Table of Contents

  1. Introduction
  2. Project Structure
  3. Core Components
  4. Architecture Overview
  5. Detailed Component Analysis
  6. Dependency Analysis
  7. Performance Considerations
  8. Troubleshooting Guide
  9. Conclusion
  10. Appendices

Introduction

This document explains the slashing lifecycle and dispute resolution system implemented by the staking contract. It covers how a committee member initiates a slash, how the challenge period protects operators, how an operator disputes and freezes stake, how the admin rules on disputes and can veto a slash, how timeouts and lapses are handled, and how undisputed slashes are executed with token distribution. It also documents the SlashState state machine, security considerations around stake freezing, and complete workflow examples from initiation through execution or cancellation.

This page describes the contract on main. The Arc testnet proxies have run it since 26 October 2026, so the admin rules on disputes there too, with the veto, the lapse and the re-file cooldown. One change since is on main only: an uphold ruling is refused once the dispute can be expired (DisputeResolutionExpired, ADR 0005, decision 2), which the testnet proxies take at their next upgrade. test/SlashDrillFork.t.sol rehearses the deployed behaviour.

Project Structure

The slashing logic is centralized in the staking contract and interacts with identity and reputation contracts. Tests and documentation provide end-to-end workflows and regression coverage for dispute-related edge cases.

graph TB
Committee["Committee Member"] --> Staking["SigvaraStaking<br/>initiateSlash / executeSlash / disputeSlash / resolveDispute / expireDispute"]
Operator["Agent Operator"] --> Staking
Admin["Admin<br/>resolveDispute / vetoSlash"] --> Staking
Identity["SigvaraIdentity"] <--> Staking
Reputation["SigvaraReputation"] <--> Staking
Token["SVR Token (ERC20)"] <--> Staking
Loading

Diagram sources

Section sources

Core Components

  • Slash proposal state machine: SlashState enum with None, Pending, Executed, Cancelled, Disputed.
  • Slash proposal storage: reporter, victim, timestamps, evidence hash, challenge deadline snapshot, and dispute timestamp.
  • Stake accounting: active stake plus queued withdrawal amount are both slashable.
  • Who does what: the committee files and cancels; the admin rules on disputes and can veto; anyone can execute (while the reporter is still on the committee), expire a dispute, or lapse an unexecuted proposal.
  • Time windows:
    • Challenge period: minimum 3 days, maximum 30 days; default 7 days.
    • Unbonding period: minimum 1 day, maximum 90 days; default 21 days.
    • Dispute resolution period: 14 days, the admin's window to rule before anyone may expire the dispute.
    • Execution period: 14 days after the challenge deadline, after which anyone may lapse a Pending proposal that nobody executed.
    • Re-file cooldown: one challenge period after any dropped proposal against the agent.
    • Rejected evidence: evidence the admin vetoed or ruled against is refused for that agent from then on (EvidenceAlreadyRejected).
  • Settlement: 50% burn to 0xdead, 25% credited to victim, 25% credited to reporter. Proceeds are claimable rather than pushed.

Section sources

Architecture Overview

The slashing flow is permissioned at initiation but designed to avoid liveness dependence on the committee after filing.

sequenceDiagram
participant C as "Committee"
participant A as "Admin"
participant O as "Operator"
participant S as "SigvaraStaking"
participant I as "SigvaraIdentity"
participant R as "SigvaraReputation"
participant T as "SVR Token"
C->>S : initiateSlash(didHash, victim, evidenceHash)
S->>I : updateStatus(Suspended)
Note over S : Store proposal with Pending state,<br/>snapshot challengeDeadline
O->>S : disputeSlash(didHash)
S->>S : set state=Disputed,<br/>record disputedAt
Note over S : Stake remains frozen
alt Admin upholds
Note over S : Upholding waits for the challenge deadline and ends when the dispute can be expired
A->>S : resolveDispute(didHash, true)
S->>S : _settleSlash()
S->>T : transfer(0xdead, 50%)
S->>S : credit victim 25%, reporter 25%
S->>I : updateStatus(Slashed)
S->>R : zeroReputation()
else Admin rejects
A->>S : resolveDispute(didHash, false)
S->>S : _dropProposal()
S->>I : clearSlashSuspension or restore Active
end
Note over S : Anyone may call executeSlash after challenge window closes<br/>while the reporter still holds the committee role
Loading

Diagram sources

Detailed Component Analysis

initiateSlash

Purpose:

  • Allow a committee member to file a slash against an agent.
  • Validate roles, victim address, and stake availability.
  • Store evidence hash and suspend the agent immediately.

Key validations and behaviors:

  • Only callable by an account holding SLASHING_COMMITTEE_ROLE.
  • Victim cannot be the zero address.
  • Victim cannot be the same address as the reporter to prevent self-payment.
  • Slashable balance includes both active stake and queued withdrawal; if total is zero, revert.
  • Prevents re-filing while a Pending or Disputed proposal exists.
  • Refuses to file again until one challenge period has passed since the last dropped proposal against the agent (SlashCooldownActive).
  • Refuses evidence the admin has already vetoed or ruled against for the agent (EvidenceAlreadyRejected), checked after the cooldown.
  • Writes proposal state before external calls (CEI pattern).
  • Stores evidence hash for auditability.
  • Snapshots challengeDeadline = block.timestamp + challengePeriod so later admin changes do not move an in-flight window.
  • Immediately suspends the agent via the identity registry.

Events:

  • Emits SlashInitiated with didHash, reporter, victim, and timestamp.

Security notes:

  • The victim/reporter split prevents one committee signature from becoming a 50% self-payment.
  • Checking total slashable stake blocks escape attempts using queued withdrawals.
  • The re-file cooldown stops a file, cancel and file-again loop that would keep the agent suspended and its stake frozen for good. It leaves the operator a window to act, and a withdrawal queued in that window stays slashable.
  • Rejected evidence is remembered per agent (evidenceRejected), so the committee cannot file the same package every period. It is a speed bump and not a wall, because the committee chooses the evidence bytes. With the launch figures (21 days of unbonding, a cooldown of one 7-day challenge period) a committee that files again as soon as the cooldown allows freezes a queued withdrawal each time, and only the admin's veto and a committee that does not act alone stop it. That is the trust placed in the committee and not a gap in the contract: a limit on refiling would only limit honest filings, since a hostile committee changes the evidence bytes (ADR 0005, decision 3). A proposal the committee cancelled, one that lapsed, and a dispute that expired unruled are not recorded, since none was ruled against.

Section sources

Challenge Period Mechanism

Purpose:

  • Protect operators from immediate slashing by providing a time window to dispute.

Mechanism:

  • A challenge period begins when a slash is initiated.
  • During this window, the agent is Suspended and its stake is frozen.
  • After the window expires without a dispute, anyone may call executeSlash, as long as the reporter still holds SLASHING_COMMITTEE_ROLE. Once 14 days have passed since the deadline, anyone may instead lapse the proposal with expireSlash.
  • Admin can change the global challenge period, but each proposal snapshots its own deadline at initiation.

Constraints:

  • Minimum challenge period is 3 days.
  • Maximum challenge period is 30 days.
  • Default deployment uses 7 days.
  • A value outside the range is refused in the setter and in initialize.

Section sources

disputeSlash

Purpose:

  • Allow the operator to dispute a pending slash and move it to an admin ruling.

Key validations and behaviors:

  • Only callable when the proposal is in Pending state.
  • Must be called before the challenge deadline; otherwise reverts.
  • Caller must be the registered operator for the agent.
  • Sets proposal state to Disputed and records disputedAt.
  • Does not cancel the slash and does not reinstate the agent.
  • Keeps stake frozen; withdrawals remain blocked during dispute.

Security rationale:

  • Previously, disputing released the bond, enabling an operator to queue the entire stake, cancel every proposal, and withdraw after unbonding. The current design prevents that exploit.

Section sources

resolveDispute

Purpose:

  • Allow the admin to rule on a disputed slash. The committee files a slash and does not rule on it, so nobody is accuser, judge and payee at once.

Behavior:

  • Only callable by an account holding DEFAULT_ADMIN_ROLE.
  • Requires the proposal to be in Disputed state.
  • If upheld, settles the slash exactly like an undisputed execution, but only once the challenge deadline fixed at filing has passed (ChallengePeriodActive before that). A dispute therefore never brings a slash forward: one disputed on the first day is upheld between the end of the challenge period and the dispute's expiry.
  • On main, an uphold ends where the dispute does: once DISPUTE_RESOLUTION_PERIOD has passed since disputedAt, which is the second expireDispute stops refusing, it reverts with DisputeResolutionExpired(didHash, expiredAt), so only dropping and expiry are left and the two never overlap. Without that bound the timeout was a race between an admin who ruled late and an operator who expired the dispute, and whoever landed first won it.
  • If rejected, drops the proposal and reinstates the agent where possible. Dropping is open at any time.

Settlement vs drop:

  • Uphold triggers _settleSlash, which burns 50%, credits 25% to victim, 25% to reporter, marks the agent Slashed, and zeroes reputation.
  • Reject triggers _dropProposal, which clears the proposal and restores the agent’s status depending on stake level.

Section sources

expireDispute

Purpose:

  • Provide a permissionless escape hatch if the admin never rules on a dispute.

Behavior:

  • Callable by anyone once DISPUTE_RESOLUTION_PERIOD has elapsed since disputedAt.
  • Drops the proposal and reinstates the agent similarly to rejection.
  • Ensures an unruled dispute cannot freeze an operator’s bond indefinitely.

Constraints:

  • Dispute resolution period is 14 days.
  • On main a ruling to uphold is refused from that moment, so before day 14 only the admin can end a dispute in the committee's favour and after it only the expiry remains. With a challenge period of 14 days or more, a dispute filed early expires before an uphold could open; the launch period is 7 days.

Section sources

vetoSlash and expireSlash

Two more ways a proposal ends without a slash.

  • vetoSlash(didHash) is admin-only. It drops a Pending proposal, including one past its challenge deadline that nobody has executed yet, or a Disputed one, and emits SlashVetoed alongside SlashCancelled. The committee is trusted to file slashes, and a quarter of the bond goes to whoever filed it and a quarter to the victim it names, so a compromised or mistaken committee has a reason to file. The veto is the independent check inside the challenge period, and it needs no role grant, so it is usable in the middle of an incident.
  • expireSlash(didHash) is permissionless. Once the challenge window has closed the operator can no longer dispute, so a Pending proposal that nobody executes or cancels would otherwise stay Pending for good, with the agent suspended and its withdrawals blocked. Anyone can drop it 14 days (EXECUTION_PERIOD) after its challenge deadline (ExecutionPeriodActive before then). Until it lapses it can still be executed by anyone.
  • Both drop the proposal like any other: the agent is reinstated where it is still bonded, and the committee waits one challenge period before it can file against the agent again.

A legitimate slash therefore has to be executed within 14 days of its deadline, or anyone can lapse it, and it has to be filed again after the cooldown.

Section sources

executeSlash

Purpose:

  • Execute a slash after the challenge period has elapsed without dispute.

Behavior:

  • Permissionless: anyone may call it once the challenge window is closed. It stays open until someone lapses the proposal with expireSlash, which is possible 14 days after the deadline.
  • Validates that the proposal is still Pending and that the challenge deadline has passed.
  • Refuses with ReporterNotAuthorized if the reporter no longer holds SLASHING_COMMITTEE_ROLE, checked after the window. Revoking a compromised member therefore defuses the proposals it filed that nobody had executed: any current member can cancelSlash them, anyone can lapse them with expireSlash, and the committee can file again after the cooldown. The admin's resolveDispute ruling does not depend on the reporter. SigvaraReputation applies the same rule to a pending score whose proposer has lost its role.
  • Calls _settleSlash to distribute proceeds and finalize the slash.

Distribution:

  • 50% burned to 0xdead.
  • 25% credited to victim.
  • 25% credited to reporter.
  • Agent marked Slashed; reputation zeroed.

Section sources

Settlement Process and Token Distribution

Settlement details:

  • Sweeps both active stake and queued withdrawal into the slashed amount.
  • Zeros stake fields and sets proposal state to Executed.
  • Computes shares: half burned, quarter to victim, remainder to reporter (absorbs rounding dust).
  • Credits victim and reporter balances instead of pushing tokens, preventing recipient blocklists from permanently freezing the bond.
  • Burns the 50% share by transferring to 0xdead, an unowned address that cannot refuse a standard transfer.
  • Updates agent status to Slashed and zeros reputation.

Claiming proceeds:

  • Victims and reporters call claimSlashProceeds to receive their credited amounts.

Section sources

SlashState Enum Transitions and State Machine Logic

States:

  • None: no active proposal.
  • Pending: slash initiated, awaiting challenge window close or dispute.
  • Disputed: operator disputed within challenge window; awaiting the admin's ruling or timeout.
  • Executed: slash settled; stake burned and distributed; agent Slashed.
  • Cancelled: proposal dropped; agent reinstated where appropriate.

Transitions:

  • None → Pending: initiateSlash.
  • Pending → Disputed: disputeSlash.
  • Pending → Executed: executeSlash.
  • Disputed → Executed: resolveDispute(uphold=true).
  • Disputed → Cancelled: resolveDispute(uphold=false), vetoSlash or expireDispute.
  • Pending → Cancelled: cancelSlash, vetoSlash or expireSlash.
stateDiagram-v2
[*] --> None
None --> Pending : "initiateSlash"
Pending --> Disputed : "disputeSlash"
Pending --> Executed : "executeSlash"
Disputed --> Executed : "resolveDispute(uphold=true)"
Disputed --> Cancelled : "resolveDispute(uphold=false)"
Disputed --> Cancelled : "expireDispute"
Disputed --> Cancelled : "vetoSlash"
Pending --> Cancelled : "cancelSlash"
Pending --> Cancelled : "vetoSlash"
Pending --> Cancelled : "expireSlash"
Executed --> [*]
Cancelled --> [*]
Loading

Diagram sources

Complete Slash Workflow Examples

Example 1: Undisputed Slash Through Execution

  • Committee files slash; agent becomes Suspended; proposal enters Pending.
  • Challenge period elapses without dispute.
  • Any user executes slash; stake is swept, 50% burned, 25% credited to victim, 25% to reporter; agent becomes Slashed; reputation zeroed.

Verification points:

  • Proposal state transitions from Pending to Executed.
  • Stake becomes zero.
  • Burn increases by half the stake.
  • Claimable balances reflect victim and reporter shares.

Section sources

Example 2: Dispute Upheld by the Admin

  • Committee files slash; operator disputes within challenge window; proposal becomes Disputed; stake remains frozen.
  • Admin resolves with uphold once the challenge deadline has passed (and, on main, before the dispute can be expired); settlement occurs identically to undisputed execution.

Verification points:

  • Stake becomes zero.
  • Victim credited quarter of stake.
  • Reporter credited quarter of stake.
  • Agent becomes Slashed.

Section sources

Example 3: Dispute Rejected by the Admin

  • Committee files slash; operator disputes; admin rejects.
  • Proposal cancelled; agent reinstated; stake remains intact; withdrawals work again.

Verification points:

  • Stake unchanged.
  • Agent status restored to Active if it is still bonded; otherwise it stays Suspended with the slash lock cleared.
  • Withdrawals permitted.

Section sources

Example 4: Expired Dispute Timeout

  • Committee files slash; operator disputes; the admin never rules.
  • After 14 days, anyone expires the dispute; proposal cancelled; agent reinstated; stake released.

Verification points:

  • Agent becomes Active.
  • Stake remains intact.
  • No further action required from committee.

Section sources

Example 5: Queued Withdrawal Escape Attempt

  • Operator queues withdrawal; committee files slash; challenge period elapses; slash executes.
  • Both active stake and queued withdrawal are swept; queued withdrawal does not escape.

Verification points:

  • Claimable victim share equals quarter of original total stake.
  • Queued withdrawal amount becomes zero.

Section sources

Dependency Analysis

The staking contract depends on:

  • Access control for role-based permissions.
  • Identity registry for agent status updates and operator validation.
  • Reputation registry for zeroing reputation upon slash.
  • ERC20 token for depositing, burning, and crediting proceeds.

Coupling and cohesion:

  • Slashing logic is cohesive within the staking contract.
  • External dependencies are narrow: identity status, reputation zeroing, and token transfers.
  • Events provide off-chain observability for all lifecycle transitions.

Potential circular dependencies:

  • None observed; identity and reputation are read-only or single-call targets from staking.

External integration points:

  • Role grants for committee and admin.
  • Token behavior assumptions: fee-on-transfer tokens are accounted for deposits; payouts are credited to avoid blocking settlement.
graph LR
Staking["SigvaraStaking"] --> Identity["SigvaraIdentity"]
Staking --> Reputation["SigvaraReputation"]
Staking --> Token["IERC20 SVR"]
Staking --> Access["AccessControlUpgradeable"]
Loading

Diagram sources

Section sources

Performance Considerations

  • Settlement avoids repeated external calls by crediting proceeds rather than pushing tokens to potentially blocklist recipients.
  • Burning the 50% share is the only inline transfer, targeting an unowned address that cannot reject transfers.
  • Snapshotting challenge deadlines prevents admin manipulation of in-flight windows.
  • Reading live stake plus queued withdrawal ensures accurate slash accounting even during unbonding.

Troubleshooting Guide

Common issues and diagnostics:

  • Early execution attempt: reverts with challenge period active; wait until after the deadline.
  • Dispute after challenge window: reverts with challenge period expired; cannot dispute late.
  • Dispute by non-operator: reverts with not operator; ensure caller matches registered operator.
  • Dispute while already disputed, or with no pending proposal: reverts with no active pending slash; only a Pending proposal can be disputed. Filing a new proposal while one is Pending or Disputed reverts with slash already pending.
  • Admin resolving non-disputed slash: reverts with slash not disputed; ensure proposal is Disputed.
  • Upholding a dispute before the challenge deadline: reverts with challenge period active; wait for the deadline. Dropping is open at any time.
  • Expiring dispute too early: reverts with dispute resolution active; wait until 14 days after disputedAt.
  • Lapsing a pending slash too early: reverts with execution period active; wait until 14 days after the challenge deadline.
  • Filing against an agent again too soon: reverts with slash cooldown active; wait one challenge period after the last dropped proposal.
  • Filing evidence the admin already rejected for the agent: reverts with evidence already rejected; file new evidence.
  • Executing a slash whose reporter has left the committee: reverts with reporter not authorized; a current member can cancel it, or anyone can lapse it 14 days after its deadline.
  • Claiming nothing: reverts with nothing claimable; ensure settlement credited proceeds.
  • Blocklisted victim receiving token: settlement succeeds because proceeds are credited; only the victim’s claim may fail.

Operational checks:

  • Verify committee role holds before filing.
  • Confirm target agent is not the demo agent in drills.
  • Record challenge deadline and dispute timestamps for audits.
  • Run a keeper that executes a slash as soon as its window closes: execution is permissionless, so nothing happens unless someone calls it, and a slash not executed within 14 days of its deadline can be lapsed by anyone and has to be filed again. The keeper skips a proposal whose reporter has left the committee, because executeSlash refuses it.
  • Before revoking a committee address, execute or cancel the proposals it filed that are ripe.
  • Use fork tests to rehearse the full path against live wiring.

Section sources

Conclusion

The slashing lifecycle enforces accountability through a structured process: committee-initiated proposals, a protected challenge window, operator dispute rights with stake freezing, an admin ruling with a veto, and permissionless execution after the window. Settlement distributes proceeds fairly and securely, marking agents terminal and zeroing reputation. The state machine and safeguards prevent abuse, including escape attempts via queued withdrawals and indefinite freezes. Tests and documentation demonstrate end-to-end correctness and provide operational guidance for safe execution.

Appendices

Security Considerations Around Stake Freezing and Dispute Abuse Prevention

  • Disputes freeze stake rather than releasing it, preventing operators from escaping accountability by queuing withdrawals and cancelling proposals.
  • The committee cannot pay itself both halves by naming itself as victim; this is enforced at initiation.
  • Challenge deadlines are snapshotted at initiation, protecting against admin shortening of in-flight windows.
  • Dispute resolution period bounds the freeze; anyone can expire unruled disputes after 14 days.
  • The committee files and the admin rules, so no single key is accuser, judge and payee at once. A dispute can never bring a slash forward, because an upheld ruling waits for the challenge deadline.
  • The admin can veto a pending or disputed proposal, and anyone can lapse a proposal that nobody executes once 14 days have passed since its deadline, so a bond is never frozen for good by silence.
  • After any drop the committee waits one challenge period before it can file against the same agent again, and evidence the admin ruled against is refused for that agent.
  • Revoking a committee member also stops what it had already filed from being executed, so a compromised key is defused with one transaction instead of one veto per agent.
  • Settlement credits proceeds to avoid permanent freezes caused by unreceivable recipients.

Section sources

Demo Interface Behavior

The site demo illustrates the slash lifecycle with a simulated chain that follows the bond and slash rules on main. It leaves out score maturity, the per-payer fee cap and the PendingBond step. It files a slash without evidence and never rotates the committee or changes a parameter, so it does not exercise the rule that refuses evidence the admin rejected, the reporter check at execution, or the fixed claim time of a queued withdrawal.

  • Initiating a slash shows Suspended status and the challenge deadline.
  • Disputing keeps the bond frozen and the agent Suspended.
  • The admin upholds or rejects. Upholding is refused until the challenge deadline, so the clock has to be advanced first; the upheld slash then burns and credits the shares. Rejecting reinstates the agent and releases the stake.
  • The admin can veto a pending or disputed proposal, and the committee can cancel a pending one. Either starts a one challenge period cooldown before the committee can file again.
  • Expiring an unresolved dispute, or expiring an unexecuted slash 14 days after its deadline, reinstates the agent and releases the stake.
  • Executing a slash after 7 days shows burn, victim and reporter shares, and the terminal status.

Section sources

Overview

Clone this wiki locally