Skip to content

Status Management and Control

RunTimeAdmin edited this page Oct 28, 2026 · 13 revisions

Status Management & Control

**Referenced Files in This Document** - [SigvaraIdentity.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/src/SigvaraIdentity.sol) - [SigvaraStaking.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/src/SigvaraStaking.sol) - [SigvaraIdentity.t.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/test/SigvaraIdentity.t.sol) - [README.md](https://github.com/RunTimeAdmin/Sigvara/blob/main/README.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

Introduction

This document explains how agent status is managed and controlled in SigvaraIdentity, focusing on suspension, reactivation, the meaning and permissions of each status, and the contract interactions that enforce them. It also documents event emissions for off-chain monitoring and provides practical workflow examples based on the actual Solidity implementation.

The system separates identity management from stake management:

  • SigvaraIdentity stores agent identities, their operator, public key, and status.
  • SigvaraStaking manages collateral, slashing, and dispute timelines, and coordinates with SigvaraIdentity to update status during slash flows.

There are no standalone functions named suspendAgent or reactivateAgent. Suspension and reactivation are performed through the shared updateStatus function, with different callers (operator vs staking core) and different preconditions depending on the target state.

This page describes the contracts on main. The Arc testnet proxies have run this code since 26 October 2026 (apart from the bound on upholding a dispute, which they take at their next upgrade), but their role administrators were written by the September initialisation, so there the admin (not the timelock) grants the staking-core role and repoints the stake view.

Project Structure

The relevant code lives in two contracts:

  • SigvaraIdentity: Agent registry, status transitions, operator control, and slash-suspension locking.
  • SigvaraStaking: Stake bonding, withdrawal, slashing initiation/dispute/execution, and coordination with identity status.
graph TB
Operator["Operator"]
StakingCommittee["Slashing Committee<br/>STAKING_CORE_ROLE caller"]
Identity["SigvaraIdentity"]
Staking["SigvaraStaking"]
Reputation["Reputation Registry"]
Token["SVR Token"]
Operator --> Identity
StakingCommittee --> Staking
Staking --> Identity
Staking --> Reputation
Staking --> Token
Loading

Diagram sources

Section sources

Core Components

  • Agent status is represented by an enum with four values: Active, Suspended, Slashed, and PendingBond.
  • The primary write interface for status changes is updateStatus(bytes32 didHash, AgentStatus newStatus).
  • The staking contract calls updateStatus when initiating a slash, resolving disputes, executing slashes, or dropping proposals.
  • A special internal lock slashSuspended[didHash] prevents an operator from reactivating an agent while a slash initiated by the staking core is pending.

Key responsibilities:

  • Operator: Can toggle between Active and Suspended, subject to collateral checks when returning to Active.
  • Staking core: Can set Suspended (slash initiation), clear the slash-suspension lock, reinstate to Active after a dropped proposal if bonded, and set Slashed (terminal).
  • Anyone: Can observe events and view states; only authorized roles can change critical statuses.

Section sources

Architecture Overview

The status lifecycle is enforced across both contracts:

stateDiagram-v2
[*] --> PendingBond : registerAgent()
PendingBond --> Active : depositStake() reaches minimumStake
Active --> Suspended : operator.updateStatus()
Active --> Suspended : StakingCore.initiateSlash()
Suspended --> Active : operator.updateStatus() with sufficient collateral
Suspended --> Active : resolveDispute(false) and bond >= minimumStake
Suspended --> Active : cancelSlash()/vetoSlash()/expireDispute()/expireSlash() and bond >= minimumStake
Active --> Slashed : StakingCore.executeSlash()
Suspended --> Slashed : StakingCore.executeSlash()
Slashed --> [*] : terminal
Loading

Diagram sources

Detailed Component Analysis

Status Enumeration and Meanings

  • Active: Fully operational agent backed by at least minimumStake. Operators may suspend it; staking core may slash it.
  • Suspended: Temporarily halted. May be self-imposed by the operator or imposed by the staking core during a slash challenge window. Key rotation remains allowed for recovery.
  • Slashed: Terminal state. No further status updates or key rotation are permitted. Reputation is zeroed out by staking settlement.
  • PendingBond: Initial registration state before any stake is posted. Becomes Active automatically once the first deposit meets minimumStake.

Permissions summary:

  • Only the operator can toggle Active ↔ Suspended.
  • Only the staking core can set Slashed.
  • Returning to Active always requires sufficient collateral via the stake view oracle.
  • The stake view is repointed only by UPGRADER_ROLE (setStakeView), the timelock's role and not the admin's, because a contract that answers yes for everyone would switch the collateral gate off.
  • STAKING_CORE_ROLE is administered by UPGRADER_ROLE: the admin cannot grant it, but can revoke it at once.
  • An operator cannot lift a staking-core-applied suspension until the staking core clears the lock.
  • A guardian pause closes new registrations (registerAgent) and nothing else here: updateStatus and key rotation keep working while it runs.

Section sources

Suspension: Who Can Initiate and Immediate Effects

Suspension is implemented through updateStatus(didHash, Suspended):

  • Operator-initiated suspension:

    • Caller must be the operator.
    • Does not set the slash-suspension lock.
    • Immediately halts the agent’s capabilities.
    • Allows key rotation even while suspended.
  • Staking-core-initiated suspension:

    • Caller must have STAKING_CORE_ROLE.
    • Sets slashSuspended[didHash] = true, preventing the operator from reactivating mid-challenge.
    • Used by initiateSlash to halt activity during the dispute window.

Immediate effects:

  • The agent becomes non-active; downstream systems should treat it as unavailable.
  • If the staking core applied the suspension, the operator cannot call updateStatus(Active) until the staking core clears the lock.

Section sources

Reactivation: Conditions, Locks, and Restoration

Reactivation is implemented through updateStatus(didHash, Active):

  • Operator-driven reactivation:

    • Requires the caller to be the operator.
    • Requires the stake view oracle to report sufficient collateral (hasMinimumStake).
    • Allowed only if there is no active slash-suspension lock.
    • Restores normal agent capabilities.
  • Staking-core-driven reactivation:

    • Permitted only when clearing a slash-suspension lock or reinstating after a dropped proposal.
    • Also enforces sufficient collateral before setting Active.
    • Clears slashSuspended[didHash] when transitioning from Suspended to Active.

Cooldown periods:

  • There is no explicit cooldown timer in updateStatus.
  • Time-based constraints come from the staking flow:
    • Challenge period before slash execution.
    • Dispute resolution period before anyone can expire an unresolved dispute.
    • Execution period (14 days after the challenge deadline) before anyone can lapse a pending proposal that nobody executed.
    • Re-file cooldown: after a proposal is dropped, the committee cannot suspend the agent through a new one for one challenge period.
    • Unbonding period before withdrawing queued stakes.

Privilege restoration:

  • On successful reactivation, the agent regains its full operational privileges.
  • Reputation is not restored by reactivation; reputation is zeroed only when slashed.

Section sources

Function Call Examples and Parameter Validation

Example 1: Operator Suspends Agent

  • Caller: operator
  • Function: identity.updateStatus(didHash, Suspended)
  • Validation:
    • Agent must be registered.
    • Caller must be the operator.
    • Agent must not be Slashed.
  • Effect:
    • Status becomes Suspended.
    • Slash-suspension lock remains false.
    • Agent capabilities are halted.

Example 2: Operator Reactivates Agent After Re-bonding

  • Caller: operator
  • Function: identity.updateStatus(didHash, Active)
  • Validation:
    • Agent must be registered.
    • Caller must be the operator.
    • Agent must not be Slashed.
    • Stake view oracle must confirm sufficient collateral.
    • Slash-suspension lock must be false.
  • Effect:
    • Status becomes Active.
    • Agent regains full capabilities.

Example 3: Staking Core Suspends During Slash Initiation

  • Caller: staking core (STAKING_CORE_ROLE)
  • Function: staking.initiateSlash(...) which internally calls identity.updateStatus(didHash, Suspended)
  • Validation:
    • Caller has SLASHING_COMMITTEE_ROLE.
    • Victim is not the reporter.
    • Total slashable balance is nonzero.
    • No active slash proposal exists.
    • No proposal against the agent was dropped less than one challenge period ago.
  • Effect:
    • Agent becomes Suspended.
    • Slash-suspension lock becomes true.
    • Slash proposal enters pending state.

Example 4: Dropped Proposal Clears Lock Without Forcing Active

  • Caller: staking core
  • Function: identity.clearSlashSuspension(didHash)
  • Validation:
    • Caller has STAKING_CORE_ROLE.
    • Agent is registered.
  • Effect:
    • Slash-suspension lock becomes false.
    • Agent remains Suspended unless the operator explicitly reactivates it.

These examples reflect the actual validation paths and side effects defined in the contracts.

Section sources

Relationship Between Status States and Contract Interactions

sequenceDiagram
participant Operator as "Operator"
participant Identity as "SigvaraIdentity"
participant Staking as "SigvaraStaking"
participant StakeView as "IStakeView"
Operator->>Identity : "updateStatus(didHash, Suspended)"
Identity-->>Operator : "status = Suspended"
Operator->>Staking : "depositStake(didHash, amount)"
Staking->>StakeView : "hasMinimumStake(didHash)"
StakeView-->>Staking : "bool"
Staking->>Identity : "updateStatus(didHash, Active) if PendingBond and bonded"
Identity-->>Staking : "status updated"
Staking->>Identity : "updateStatus(didHash, Suspended) on initiateSlash"
Identity-->>Staking : "slashSuspended = true"
Staking->>Identity : "updateStatus(didHash, Active) on drop/cancel if bonded"
Identity-->>Staking : "slashSuspended = false"
Staking->>Identity : "updateStatus(didHash, Slashed) on executeSlash"
Identity-->>Staking : "terminal state"
Loading

Diagram sources

Operations available per state:

  • PendingBond:
    • Register: already done.
    • Deposit stake: allowed; auto-activates when reaching minimumStake.
    • Suspend/reactivate: not applicable until bonded.
  • Active:
    • Suspend: allowed by operator.
    • Slash: possible via staking committee.
    • Withdraw: allowed under staking rules.
  • Suspended:
    • Reactivate: allowed by operator if bonded; allowed by staking core when clearing slash lock.
    • Rotate key: allowed for recovery.
    • Slash: possible if slash was initiated while active.
  • Slashed:
    • No status changes.
    • No key rotation.
    • Reputation zeroed.

Section sources

Event Emissions for Off-Chain Monitoring

Off-chain systems should listen for these events:

  • AgentRegistered: New agent identity created; includes didHash, operator, agentAddress, and ed25519PubKey.
  • AgentStatusUpdated: Any status transition; includes didHash and newStatus.
  • PublicKeyRotated: Ed25519 key changed; includes didHash and new key.
  • OperatorTransferOffered, OperatorTransferCancelled, OperatorTransferred: Ownership handover lifecycle.
  • StakeViewSet: Stake view oracle address configured.

Monitoring recommendations:

  • Track AgentStatusUpdated to maintain a real-time status map.
  • Use AgentRegistered to bootstrap identity indexes.
  • Use PublicKeyRotated to refresh verification keys.
  • Combine with staking events (SlashInitiated, SlashDisputed, SlashExecuted, SlashCancelled, and SlashVetoed when the admin dropped the proposal) to correlate slash-related suspensions and terminations.

Section sources

Dependency Analysis

  • SigvaraIdentity depends on OpenZeppelin upgradeable access control and UUPS upgradeability.
  • SigvaraStaking imports SigvaraIdentity directly to share the AgentStatus enum and interact with identity storage.
  • SigvaraStaking also interacts with a reputation registry to zero reputation upon slashing.
  • SigvaraIdentity uses an IStakeView interface to check collateral without creating a circular dependency.
classDiagram
class SigvaraIdentity {
+enum AgentStatus
+function updateStatus(didHash, newStatus)
+function rotatePublicKey(didHash, newEd25519PubKey)
+function clearSlashSuspension(didHash)
+event AgentStatusUpdated
+event PublicKeyRotated
}
class SigvaraStaking {
+function initiateSlash(...)
+function disputeSlash(...)
+function executeSlash(...)
+function cancelSlash(...)
+function vetoSlash(...)
+function expireDispute(...)
+function expireSlash(...)
+event SlashInitiated
+event SlashExecuted
+event SlashCancelled
}
class IStakeView {
+function hasMinimumStake(didHash) bool
}
SigvaraStaking --> SigvaraIdentity : "updates status"
SigvaraIdentity --> IStakeView : "checks collateral"
Loading

Diagram sources

Section sources

Performance Considerations

  • Status transitions are constant-time operations except where operator index maintenance is involved.
  • Operator agent lists use swap-and-pop removal with recorded positions to avoid linear scans for most cases.
  • Off-chain consumers should page through getOperatorAgentsPaged rather than fetching unbounded lists. A limit of the maximum uint256 asks for the rest of the list; it used to overflow.
  • Collateral checks rely on the external IStakeView; performance depends on the underlying staking implementation.

Troubleshooting Guide

Common issues and resolutions:

  • Attempting to reactivate without sufficient collateral:

    • Error: InsufficientCollateral.
    • Resolution: Deposit enough stake so hasMinimumStake returns true, then call updateStatus(Active).
  • Trying to reactivate while slash-suspension lock is active:

    • Error: SlashSuspensionLocked.
    • Resolution: Wait for the staking core to clear the lock via clearSlashSuspension or a resolved/dropped slash flow.
  • Calling updateStatus(Slashed) on a slashed agent:

    • Error: SlashedAgentImmutable.
    • Resolution: No further status changes are allowed; the agent is terminated.
  • Trying to return to PendingBond:

    • Error: CannotReturnToPendingBond.
    • Resolution: Agents do not revert to PendingBond; they suspend and exit instead.
  • Not being the operator:

    • Error: NotOperator.
    • Resolution: Ensure the caller matches the stored operator for the agent.
  • Stake view not configured:

    • Error: StakeViewNotSet.
    • Resolution: The admin calls initializeV2, or the upgrader (the timelock's role) calls setStakeView, with a valid stake view contract.

Section sources

Conclusion

Agent status management in SigvaraIdentity is centered around updateStatus, with strict role-based controls and collateral enforcement. Suspension can be operator-driven or staking-core-driven, with the latter imposing a protective lock to prevent premature reactivation during slash challenges. Reactivation requires sufficient collateral and clearance of any slash-suspension lock. The four status values define a clear lifecycle: registration begins at PendingBond, moves to Active upon bonding, can be temporarily halted at Suspended, and ends permanently at Slashed. Off-chain systems should monitor the emitted events to keep status, ownership, and cryptographic keys synchronized with on-chain state.

Overview

Clone this wiki locally