Skip to content

SigvaraOracleBond Contract

RunTimeAdmin edited this page Oct 27, 2026 · 7 revisions

SigvaraOracleBond Contract

**Referenced Files in This Document** - [SigvaraOracleBond.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/src/SigvaraOracleBond.sol) - [SigvaraReputation.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/src/SigvaraReputation.sol) - [DeployOracleBond.s.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/script/DeployOracleBond.s.sol) - [SigvaraOracleBond.t.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/test/SigvaraOracleBond.t.sol) - [reputation-model.md](https://github.com/RunTimeAdmin/Sigvara/blob/main/docs/reputation-model.md) - [arc.md](https://github.com/RunTimeAdmin/Sigvara/blob/main/docs/arc.md) - [tokenomics.md](https://github.com/RunTimeAdmin/Sigvara/blob/main/archive/token-launch/docs/tokenomics.md) - [RUNBOOK-second-operator.md](https://github.com/RunTimeAdmin/Sigvara/blob/main/oracle/RUNBOOK-second-operator.md) - [InflowGuard.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/src/InflowGuard.sol) - [TimelockedGrants.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/src/TimelockedGrants.sol) - [OracleBondInvariant.t.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/test/OracleBondInvariant.t.sol) - [0004-operator-custody.md](https://github.com/RunTimeAdmin/Sigvara/blob/main/docs/adr/0004-operator-custody.md) - [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 SigvaraOracleBond contract, which manages oracle operator admission and performance bonding for the Sigvara oracle network. It is a separate accounting and slashing path from agent staking: it bonds oracle operators who propose reputation scores, not the agents whose scores are computed.

The contract defines a four-state lifecycle for operators: None, Bonded, Active, Exiting. Operators deposit SVR to become Bonded, governance admits them into the Active set, and they may initiate unbonding or be removed by governance. A designated slasher can slash active or exiting operators; slashing below the minimum bond demotes an operator out of the active set. The contract emits events for every state change and economic action, and its isActiveOperator view enforces both status and current bond level. An operator can also name a signer, the key an oracle service signs with, so the key on a server need not be the key that holds the bond.

The broader system uses this registry as an optional gate on score proposals: when configured, only an admitted, bonded operator, or the signer it has named, that holds ORACLE_ROLE may propose reputation updates. Oracle scoring itself is off-chain; the on-chain layer stores proposed and finalized scores, evidence roots, maturity, and committee challenges.

This page describes the contract on main. The Arc testnet proxy has run it since 26 October 2026, so its signer registry is live, though neither operator has named a signer. Its role administrators were written by the September initialisation, so the slasher grant and the slash-beneficiary change are not timelocked there.

Section sources

Project Structure

The relevant codebase parts are:

  • Core contracts under src/:
    • SigvaraOracleBond.sol: operator bonding, admission, slashing, and unbonding.
    • SigvaraReputation.sol: optimistic score proposal, challenge window, evidence roots, and optional operator-bond gating.
  • Deployment script under script/:
    • DeployOracleBond.s.sol: deploys the proxy, initializes parameters, validates role separation, and records the proxy address. On chain 5042 it also refuses the default bond amount or one under 2,500,000 SVR, an unbonding period outside 1 to 90 days, and a missing or unseparated guardian.
  • Tests under test/:
    • SigvaraOracleBond.t.sol: covers initialization, deposit/admit, slashing, unbonding, admin setters, signers, incumbent behavior, and storage layout pinning.
    • OracleBondInvariant.t.sol: five stateful invariants over arbitrary sequences of deposits, signers, slashes and exits.
  • Documentation:
    • docs/reputation-model.md: describes the six-factor score, maturity, oracle epochs, and multi-operator design.
    • docs/arc.md: deployment runbook notes and operational guidance around bonding, admission order, and live behavior.
    • archive/token-launch/docs/tokenomics.md: high-level tokenomics context for oracle operator bonds.
    • oracle/RUNBOOK-second-operator.md: practical testnet operator onboarding, bond floor changes, and failure modes.
graph TB
subgraph "On-chain Contracts"
OB["SigvaraOracleBond"]
REP["SigvaraReputation"]
ID["SigvaraIdentity"]
STK["SigvaraStaking"]
SVR["SVR Token"]
end
subgraph "Off-chain"
ORA["Oracle Network<br/>Scoring + Evidence"]
GOV["Governance / Committee"]
end
SVR --> OB
GOV --> OB
ORA --> REP
REP --> OB
REP --> ID
STK --> REP
Loading

Diagram sources

Section sources

Core Components

SigvaraOracleBond implements:

  • Operator lifecycle management:
    • Deposit bond: moves SVR into the contract and sets operator to Bonded. It is refused while a guardian pause is running.
    • Admit: governance promotes a Bonded operator with sufficient bond to Active.
    • Initiate unbonding: operator signals exit and starts cooldown.
    • Withdraw bond: after cooldown, operator clears their record and receives remaining SVR. Any signer the operator named is released.
    • Remove operator: governance forces an operator into Exiting.
    • Signer registry: an Active operator names one signer with setSigner, and clearSigner removes it in any status.
  • Slashing:
    • Slasher reduces an operator’s bond and transfers slashed tokens to the slash beneficiary.
    • If an Active operator falls below the required bond, they are demoted to Bonded and removed from the active count.
    • If the bond reaches zero, the operator record is reset to None and any signer is released.
  • Governance parameters:
    • Minimum bond amount (zero is refused).
    • Unbonding period (between 1 and 90 days, in initialize and in the setter).
    • Slash beneficiary (changed through the timelock, and never an address that holds the slasher role).
  • Read-only checks:
    • isActiveOperator(operator) returns true only if the operator is Active and their bond meets the current requirement. A registered signer is answered for as the operator that named it.
    • bondOf(operator) returns the recorded bond.
    • signerOf(operator) and operatorOfSigner(signer) read the signer registry in each direction.

Key roles:

  • DEFAULT_ADMIN_ROLE: admits/removes operators, sets the bond amount and the unbonding period, and revokes any role except UPGRADER_ROLE at once.
  • SLASHER_ROLE: slashes operator bonds. It is administered by UPGRADER_ROLE, so a grant takes the timelock's delay.
  • UPGRADER_ROLE: authorizes UUPS upgrades, grants SLASHER_ROLE and its own role, and sets the slash beneficiary.
  • GUARDIAN_ROLE: pauses new bond deposits for three days at a time, and nothing else.

Events emitted:

  • BondDeposited
  • OperatorAdmitted
  • OperatorSlashed
  • UnbondInitiated
  • BondWithdrawn
  • OperatorRemoved
  • BondAmountUpdated
  • UnbondingPeriodUpdated
  • SlashBeneficiaryUpdated
  • SignerSet
  • SignerCleared

Errors cover invalid addresses, zero amounts, wrong operator status, insufficient bond, slash exceeding bond, unbonding still active, no bond, an unbonding period outside its bounds, signer conflicts, and a slasher that is also the slash beneficiary.

Section sources

Architecture Overview

The bonding contract is designed to work alongside SigvaraReputation and the identity/staking layers:

  • SigvaraOracleBond owns the operator bond ledger and slashing logic.
  • SigvaraReputation optionally requires proposers to be active operators through IOperatorSet.isActiveOperator.
  • Governance controls admission and parameter changes.
  • The oracle network computes scores off-chain and proposes them on-chain within a challenge window.
  • The slash mechanism ensures operators have skin in the game for false or unreliable reporting.
sequenceDiagram
participant OP as "Oracle Operator"
participant OB as "SigvaraOracleBond"
participant GOV as "Governance"
participant REP as "SigvaraReputation"
participant SLP as "Slasher"
participant BEN as "Slash Beneficiary"
OP->>OB : "depositBond(amount)"
OB-->>OP : "BondDeposited"
GOV->>OB : "admit(operator)"
OB-->>GOV : "OperatorAdmitted"
OP->>REP : "proposeReputation(...)"
REP->>OB : "isActiveOperator(operator)"
OB-->>REP : "true/false"
REP-->>OP : "ScoreProposed"
SLP->>OB : "slash(operator, amount)"
OB->>BEN : "transfer slashed SVR"
OB-->>SLP : "OperatorSlashed(demoted?)"
Loading

Diagram sources

Detailed Component Analysis

Operator Registration and Admission

An operator begins by approving SVR and calling depositBond. The contract credits the actual received amount, handles fee-on-transfer differences safely, and transitions the operator from None to Bonded. Governance then calls admit, which verifies that the operator is Bonded and has at least bondAmount. On success, the operator becomes Active and increments the active count.

Important operational detail: raising bondAmount does not retroactively remove incumbents’ status, but isActiveOperator re-reads the bond requirement live. Therefore, an incumbent below the new threshold immediately fails the active-operator check even though their stored status remains Active until explicitly removed or slashed.

flowchart TD
Start(["Operator Registration"]) --> Approve["Approve SVR to contract"]
Approve --> Deposit["Call depositBond(amount)"]
Deposit --> StatusCheck{"Status == Exiting?"}
StatusCheck --> |Yes| RevertDeposit["Revert WrongStatus"]
StatusCheck --> |No| Transfer["Transfer SVR into contract"]
Transfer --> Credit["Credit received amount"]
Credit --> SetBonded["Set status = Bonded if None"]
SetBonded --> EmitDeposit["Emit BondDeposited"]
EmitDeposit --> Admit["Governance calls admit(operator)"]
Admit --> CheckBonded{"Status == Bonded and bond >= bondAmount?"}
CheckBonded --> |No| RevertAdmit["Revert InsufficientBond or WrongStatus"]
CheckBonded --> |Yes| SetActive["Set status = Active<br/>activeCount++"]
SetActive --> EmitAdmit["Emit OperatorAdmitted"]
EmitAdmit --> End(["Operator can propose scores"])
Loading

Diagram sources

Section sources

Operator Signers

The operator is whoever holds the bond: a cold key or a Safe. The signer is the key an oracle service uses to propose, finalize and charge, and it lives on a host. Before the two were separated they were one address, so whoever took the service's key could also start an unbond and withdraw once the cooldown ran.

  • setSigner(signer) is callable only by an Active operator, one governance has admitted and which still holds its bond. It names one signer and replaces any earlier one. The signer must be an address nobody else uses in the registry: it cannot hold a bond record, name a signer, or be another operator's signer (SignerNotFree).
  • isActiveOperator(signer) then answers for the operator that named it. Every function that moves the bond stays with the operator, and a signer cannot post a bond of its own (depositBond reverts AlreadySigner).
  • clearSigner() works in any status, Exiting included, and takes effect in the same block. The former signer's next propose or charge is refused, and the proposals it still has waiting out their challenge window will no longer finalize.
  • The signer is released when the operator withdraws its bond or is slashed to nothing. removeOperator does not release it.
  • Naming a signer grants no role anywhere. ORACLE_ROLE stays a separate governance decision on each contract, and the signer needs it as well.

An operator that never names a signer behaves exactly as before.

Section sources

Performance Monitoring and Scoring Context

SigvaraOracleBond does not compute oracle performance metrics directly. Instead, it provides the economic enforcement layer for operators who participate in the performance monitoring pipeline implemented off-chain by the oracle network and consumed by SigvaraReputation.

The reputation model defines six factors: fee activity, success rate, tenure, external trust, community standing, and trust propagation. Scores are proposed off-chain, committed on-chain with evidence roots, subject to a challenge window, and mature over time. When the operator-bond registry is configured, only admitted, bonded operators (or the signer one has named) may propose scores. Finalization stays permissionless, but it refuses a proposal whose proposer no longer holds ORACLE_ROLE or is no longer an active operator or signer, so removing an operator or clearing its signer also ends what that key has pending. A proposal from an authorized proposer replaces it.

flowchart TD
Scan["Oracle scans chain logs and attestations"] --> Compute["Compute six-factor score"]
Compute --> Evidence["Build Merkle evidence root"]
Evidence --> Propose["Call proposeReputation(...)"]
Propose --> Gate["SigvaraReputation checks ORACLE_ROLE"]
Gate --> BondGate["If configured, check isActiveOperator()"]
BondGate --> Pending["Store pending score + evidence root"]
Pending --> Challenge["Challenge window opens"]
Challenge --> Finalize["Anyone finalizes after window"]
Finalize --> Mature["Matured score grows toward earned score"]
Loading

Diagram sources

Section sources

Penalty Mechanisms and Slashing

Slashing is the primary penalty mechanism enforced by SigvaraOracleBond. A slasher can reduce an operator’s bond for provably incorrect reputation data or extended downtime. Slashed SVR is transferred to the slash beneficiary.

Key behaviors:

  • Slashing is permissioned to SLASHER_ROLE. The role is administered by UPGRADER_ROLE, so the admin cannot install a slasher in the next transaction, but can revoke one at once. The registry never lets one address be both the slasher and the slash beneficiary.
  • Slashing cannot exceed the operator’s bond.
  • If an Active operator’s bond drops below bondAmount, they are demoted to Bonded and removed from the active set.
  • If slashing reduces the bond to zero, the operator record is cleared to None and any signer is released.
  • Slashing works during unbonding, preventing operators from escaping accountability simply by initiating withdrawal.
flowchart TD
SlashStart["Slasher calls slash(operator, amount)"] --> Validate["Validate bond > 0, amount > 0, amount <= bond"]
Validate --> Reduce["Reduce operator.bond by amount"]
Reduce --> DemoteCheck{"Status == Active and bond < bondAmount?"}
DemoteCheck --> |Yes| Demote["Set status = Bonded<br/>activeCount--"]
DemoteCheck --> |No| KeepStatus["Keep current status"]
KeepStatus --> ZeroCheck{"bond == 0?"}
Demote --> ZeroCheck
ZeroCheck --> |Yes| ClearRecord["Set status = None<br/>unbondingAt = 0<br/>Release the signer"]
ZeroCheck --> |No| Transfer["Transfer amount to slashBeneficiary"]
ClearRecord --> Transfer
Transfer --> Emit["Emit OperatorSlashed"]
Emit --> SlashEnd(["Penalty applied"])
Loading

Diagram sources

Section sources

Governance Controls for Trusted Oracle Networks

Governance controls operator admission and key parameters:

  • Admitting operators: DEFAULT_ADMIN_ROLE calls admit(operator).
  • Removing operators: DEFAULT_ADMIN_ROLE calls removeOperator(operator). The operator's signer, if it has one, stays reserved until the operator withdraws or is slashed to nothing.
  • Setting minimum bond: DEFAULT_ADMIN_ROLE calls setBondAmount(newBondAmount). Zero is refused.
  • Adjusting unbonding period: DEFAULT_ADMIN_ROLE calls setUnbondingPeriod(newPeriod). The period must be between 1 day and 90 days (PeriodTooShort, PeriodTooLong), as it must be in initialize.
  • Changing slash beneficiary: UPGRADER_ROLE, which the timelock holds, calls setSlashBeneficiary(newBeneficiary), because the call decides where value flows. It refuses the zero address and any address that holds SLASHER_ROLE (SlasherIsBeneficiary).

The contract also supports UUPS upgrades via UPGRADER_ROLE. That role administers itself and SLASHER_ROLE, so installing a slasher takes the timelock's delay, while the admin can still revoke one at once (TimelockedGrants).

In the broader system, SigvaraReputation can be pointed at the operator-bond registry via setOperatorBond, which also needs UPGRADER_ROLE and not the admin role. Once enabled, proposing a score requires the caller to hold ORACLE_ROLE and pass isActiveOperator, either as an admitted operator or as the signer one has named. This is the integration point where trusted oracle networks are enforced economically.

Section sources

Examples

Operator Onboarding

A typical onboarding flow is:

  1. Operator acquires SVR and approves the bond contract.
  2. Operator calls depositBond(amount).
  3. Governance calls admit(operator).
  4. Governance grants ORACLE_ROLE on SigvaraReputation and/or SigvaraEpochFees.
  5. Operator begins proposing reputation scores.

If the bond is held by a cold key or a Safe, the operator calls setSigner(signingKey) once admitted and governance grants ORACLE_ROLE to the signing key instead.

Operational guidance emphasizes ordering: raise the bond floor only after ensuring existing operators remain above the new threshold, because isActiveOperator evaluates live.

Section sources

Performance Evaluation

Performance evaluation is primarily off-chain. The oracle network computes six-factor scores, proposes them on-chain, and commits evidence roots. Consumers read matured scores via getTotalScore. Disagreements between operators are intended to surface during the challenge window, enabling committee intervention.

Section sources

Penalty Enforcement

When misbehavior is established:

  1. Slasher calls slash(operator, amount).
  2. Contract reduces the bond and transfers slashed tokens to the slash beneficiary.
  3. If the operator was Active and now falls below the bond requirement, they are demoted.
  4. If the bond reaches zero, the operator record is cleared and any signer is released.
  5. Events allow off-chain monitoring of penalties and demotions.

Section sources

Economic Model and Skin in the Game

The economic model ties oracle credibility to a bond of SVR:

  • Operators must post a defined bond before being admitted.
  • Misreporting or prolonged downtime can trigger slashing.
  • Slashed bonds reduce the operator’s ability to propose scores if they fall below the minimum.
  • The unbonding period prevents operators from withdrawing collateral before accountability is resolved.
  • The bond is separate from agent stakes, ensuring oracle misconduct is penalized independently of agent misconduct.

The tokenomics documentation states that each oracle operator must stake a defined amount of SVR as a performance bond, managed via this dedicated contract. Slashing applies for provably incorrect reputation data or extended downtime.

Section sources

Event Emissions for Status and Metrics

SigvaraOracleBond emits clear events for all state and economic transitions:

  • BondDeposited(operator, amount, newBond)
  • OperatorAdmitted(operator)
  • OperatorSlashed(operator, amount, remaining, demoted)
  • UnbondInitiated(operator, claimableAt)
  • BondWithdrawn(operator, amount)
  • OperatorRemoved(operator)
  • BondAmountUpdated(newBondAmount)
  • UnbondingPeriodUpdated(newPeriod)
  • SlashBeneficiaryUpdated(newBeneficiary)
  • SignerSet(operator, signer)
  • SignerCleared(operator, signer)

These events enable off-chain monitoring dashboards, alerting systems, and audit trails for operator status changes and penalty enforcement.

Section sources

Decentralization Considerations

The design balances quality assurance with openness:

  • Quality assurance:
    • Only admitted, bonded operators may propose scores when the registry is configured.
    • Slashing removes economic incentives for false reporting.
    • Challenge windows and evidence roots allow verification and committee intervention.
  • Openness:
    • Any party meeting technical requirements and posting the required bond can apply for admission.
    • Governance admits operators rather than a single deployer controlling the entire set.
    • The operator-bond requirement is optional: leaving the registry unset allows a single-operator mode, while enabling it introduces multi-operator accountability.

The architecture encourages multiple bonded operators, with one proposer per epoch and others recomputing from committed evidence to detect divergence.

Section sources

Security Analysis of the Bonding Mechanism

Collusion Scenarios

Potential collusion risks include:

  • Multiple operators coordinating to submit inflated scores.
  • Wash trading to inflate fee activity or success metrics.
  • Colluding counterparties to boost propagation or external trust.

Mitigations:

  • Bonds create direct economic loss for malicious operators.
  • Slashing removes colluders from the active set.
  • Reputation scoring includes decay, caps, priors, and external trust dependencies that resist simple wash cycles.
  • Challenge windows and evidence roots allow independent verification.
  • Propagation deliberately inherits only external trust, reducing reflexivity.

However, collusion is not fully eliminated. The documentation acknowledges that weights bound cheap attacks, while only an executing slashing path bounds expensive ones. Multi-operator disagreement and committee oversight are part of the defense-in-depth strategy.

Section sources

Attack Vectors and Safeguards

  • Fee-on-transfer tokens: depositBond reads balance delta instead of trusting the requested amount, preventing over-crediting.
  • Zero bond edge case: slashing to zero resets the operator record to avoid permanently bricking the address.
  • Unbonding safety: slashing remains possible during unbonding, preventing escape from accountability.
  • Live bond checks: isActiveOperator enforces current bond level, so raising the requirement binds immediately on the gating call.
  • Admin safeguards: zero bond amount is rejected; zero slash beneficiary address is rejected; the unbonding period is held between 1 and 90 days; the slash beneficiary can only be changed through the timelock.
  • Role separation: the registry refuses one address as both slasher and slash beneficiary, in initialize, in every grant of SLASHER_ROLE and in setSlashBeneficiary. The deployment script stops on that pairing on every chain before anything is sent (both addresses default to the deployer, so state at least one), and on mainnet also refuses a deployer that holds either role. On testnet it only warns about the deployer.
  • Stolen signing key: a signer cannot start an unbond or withdraw the bond, and the operator ends its access in one transaction with clearSigner or setSigner.
  • Seized bonds: the admin cannot install a slasher or repoint the beneficiary without the timelock's delay, so a compromised admin cannot slash every operator and pay itself in one batch.

Section sources

Dependency Analysis

SigvaraOracleBond depends on:

  • OpenZeppelin upgradeable access control (through TimelockedGrants) and UUPS upgradeability.
  • InflowGuard, for the guardian's pause on bond deposits.
  • ERC20 interfaces for SVR.
  • SafeERC20 for secure token transfers.
  • ReentrancyGuard for protection against reentrant calls.

It integrates with:

  • SigvaraReputation and SigvaraEpochFees via the IOperatorSet interface, which this contract implements.
  • Governance through DEFAULT_ADMIN_ROLE and SLASHER_ROLE.
  • Deployment scripts for proxy setup and parameter initialization.
classDiagram
class SigvaraOracleBond {
+address svr
+uint256 bondAmount
+uint256 unbondingPeriod
+address slashBeneficiary
+uint256 activeCount
+depositBond(amount)
+initiateUnbond()
+withdrawBond()
+setSigner(signer)
+clearSigner()
+admit(operator)
+removeOperator(operator)
+slash(operator, amount)
+setBondAmount(newBondAmount)
+setUnbondingPeriod(newPeriod)
+setSlashBeneficiary(newBeneficiary)
+isActiveOperator(operator) bool
+bondOf(operator) uint256
}
class SigvaraReputation {
+proposeReputation(...)
+finalizeReputation(...)
+rejectReputation(...)
+setOperatorBond(address)
+getTotalScore(bytes32) uint8
}
class SVRToken {
+balanceOf(address) uint256
+safeTransferFrom(...)
+safeTransfer(...)
}
SigvaraOracleBond --> SVRToken : "uses IERC20"
SigvaraReputation --> SigvaraOracleBond : "checks IOperatorSet.isActiveOperator"
Loading

Diagram sources

Section sources

Performance Considerations

  • Constant-time operator index lookup: operator mapping access is O(1).
  • Live bond checks: isActiveOperator avoids unbounded loops by reading current bond and status.
  • Gas efficiency: slashing and withdrawals use SafeERC20 and emit events for off-chain tracking.
  • Storage layout pinning: tests verify slot positions to prevent accidental upgrade-related storage corruption.
  • Off-chain scoring: heavy computation is intentionally kept off-chain; on-chain logic focuses on verification, governance, and economic enforcement.

Recommendations:

  • Monitor event emissions for operator status changes and slashing.
  • Track active operator count and bond levels.
  • Ensure RPC providers support the required log ranges and receipt horizons for oracle operations.
  • Avoid lowering LOG_CHUNK_SIZE unnecessarily; provider throttling is better addressed by pacing.

Section sources

Troubleshooting Guide

Common issues and resolutions:

  • Operator cannot propose scores after bond floor increase:
    • Check isActiveOperator; if false, top up the bond before raising the floor.
    • Verify the operator’s bond meets the new requirement.
  • Operator stuck in Exiting state:
    • Wait until block.timestamp >= unbondingAt + unbondingPeriod.
    • Call withdrawBond to clear the record.
  • Slashing reverts:
    • Ensure slasher has SLASHER_ROLE.
    • Ensure slash amount does not exceed operator bond.
  • Zero bond after slashing:
    • Operator record is reset to None; operator must redeposit and be readmitted.
  • Deployment warnings:
    • If the slasher and the slash beneficiary are the same address, the script stops on every chain; both default to the deployer, so state at least one of them.
    • On mainnet the script also stops if the deployer holds either role; separate roles are required.
  • setSigner reverts:
    • WrongStatus: the caller is not an Active operator.
    • SignerNotFree: the address already has a bond record, names a signer, is another operator's signer, or is the caller.
    • Use clearSigner (any status) to drop a signer; it reverts NoSigner when there is none.
  • depositBond reverts InflowsPausedUntil: the guardian has paused new bonds; the pause ends by itself after three days. depositBond also reverts AlreadySigner for an address that is some operator's signer.

Section sources

Conclusion

SigvaraOracleBond provides the economic backbone for oracle operator accountability. It separates operator bonding from agent staking, enforces admission through governance, and enables slashing for misbehavior. Combined with SigvaraReputation’s optimistic scoring, evidence roots, challenge windows, and maturity mechanics, the system balances decentralization with quality assurance.

Operators must post meaningful collateral, maintain active status, and face economic penalties for false or unreliable reporting. Governance retains control over admission and parameters, while the live bond check ensures that policy changes bind immediately. Event emissions and tests provide transparency and reliability for operators, consumers, and auditors.

Appendices

API Summary

Function Access Purpose Key Behavior
depositBond(amount) Operator Post or top up bond Transfers SVR, sets Bonded, emits BondDeposited; closed while an inflow pause runs
initiateUnbond() Operator Signal exit Sets Exiting, starts cooldown, emits UnbondInitiated
withdrawBond() Operator Claim bond after cooldown Clears record and signer, transfers remaining SVR
setSigner(signer) Active operator Name the key that signs Replaces any earlier signer, requires an address nobody else uses, emits SignerSet
clearSigner() Operator, any status Stop anyone signing for the operator Takes effect in the same block, emits SignerCleared
admit(operator) DEFAULT_ADMIN_ROLE Admit bonded applicant Requires Bonded and sufficient bond, sets Active
removeOperator(operator) DEFAULT_ADMIN_ROLE Force exit Sets Exiting, emits OperatorRemoved
slash(operator, amount) SLASHER_ROLE Partially slash bond Transfers to beneficiary, demotes if needed
setBondAmount(newBondAmount) DEFAULT_ADMIN_ROLE Update minimum bond Rejects zero, emits BondAmountUpdated
setUnbondingPeriod(newPeriod) DEFAULT_ADMIN_ROLE Update cooldown Rejects under 1 day or over 90 days, emits UnbondingPeriodUpdated
setSlashBeneficiary(newBeneficiary) UPGRADER_ROLE Update payee Rejects zero address and any holder of SLASHER_ROLE, emits SlashBeneficiaryUpdated
pauseInflows() GUARDIAN_ROLE Pause new bonds Closes depositBond for 3 days; resumeInflows() (guardian or admin) lifts it early
isActiveOperator(operator) View Check active and bonded Returns true only if Active and bond >= bondAmount; a registered signer answers for its operator
bondOf(operator) View Read bond Returns operator bond
signerOf(operator), operatorOfSigner(signer) View Read the signer registry Zero means no signer

Section sources

Test Coverage Highlights

  • Initialization and role assignment.
  • Deposit and admit flows.
  • Slashing reductions, demotions, and beneficiary transfers.
  • Unbonding cooldown and withdrawal.
  • Admin-only setters and zero-value guards.
  • Incumbent behavior under bond changes.
  • Signer registry: naming, replacing, clearing, and the conflicts it refuses.
  • Five stateful invariants in OracleBondInvariant.t.sol: signer mappings stay symmetric, a signer is never also an operator, standing comes only from a bonded Active operator, no signer outlives its operator's record, and activeCount and custody still add up.
  • Storage layout pinning for upgrade safety.

Section sources

Overview

Clone this wiki locally