Computed reputation and staked slashing for autonomous AI agents, on top of ERC-8004.
As AI agents become independent economic actors, they need a trust score that means something and accountability that costs something. ERC-8004 gives agents a standard on-chain identity and a raw feedback ledger, but deliberately leaves out the hard parts: computing a trustworthy score from that feedback, and putting slashable stake behind it. Sigvara is that layer. It takes ERC-8004 as the identity and feedback substrate, computes a normalized reputation score with an oracle, and enforces bonds and slashing — the accountability the standard omits. (Ed25519 PKI challenge-response for agent-to-agent auth rides alongside.)
Token: not launched yet. The protocol's bond and fee asset will be SVR, a fixed-supply, ownerless ERC-20 launched through Tolly on Arc mainnet with no team allocation, no treasury allocation and no sale. Until its contract address appears in docs/token.md and on sigvara.xyz, there is no genuine SVR; anything trading under the Sigvara name before then, or at any other address after, did not come from this team. On-chain utility begins when the registries deploy to Arc mainnet after audit.
Where this stands. Sigvara is a computed-reputation and staked-slashing layer for autonomous agents on top of ERC-8004: the standard covers identity and raw feedback; Sigvara computes a normalized score and puts slashable bond behind it. Contracts, oracle and SDK are built and tested (Foundry unit, fuzz and invariant tests, Slither in CI). The same protocol ran for about a month on Robinhood Chain testnet with a live hourly oracle under its prior name (see docs/lineage.md). It is now deployed and running on Arc testnet (chain ID
5042002) with a live oracle, payment-verified attestations and a bonded oracle operator — addresses under Deployed contracts and details in docs/arc.md. A second bonded operator runs in checker mode alongside the primary as of 20 September 2026, though both are operated by the same party and only the primary writes scores. The divergence this produced on 20 September was left live and triaged in public rather than seeded away, because it was a delivery failure and not a disagreement; ADR 0003 decides the fix and the pull scanner that implements it is built and off by default, so a payment still enters a score by being reported rather than by having happened. There is no external audit. This is early protocol work with real engineering and a documented testnet lineage, not a mainnet product claim. The two-way CounterAudit integration is live: sealed audit packets carry the agent's Arc identity and score frozen at the moment of the action, and audited outcomes are attested back to the oracle.
Who builds this: docs/WHO.md — builder background, related projects, and contact.
This repository (sigvara) is the decentralized protocol: computed reputation and staked slashing on top of ERC-8004 identity, with no central authority. Trust here is enforced by cryptography and cryptoeconomics — nothing to sign up for, nothing to trust us on.
There is a separate product, the Countersig platform (countersig.com, public docs: Countersig-Public), which ships its own npm packages — @countersig/sdk, @countersig/verify, @countersig/mcp, @countersig/react. That platform is a centralized, hosted non-human-identity verification service. It is a different product with a different trust model, built by the same team, but it is not this protocol and does not read from or write to the contracts below. It kept the Countersig name; the protocol did not (see docs/lineage.md for why).
If you're looking for a hosted MCP server or React trust-badge components, those live in the platform repo, not here — though this repo does ship a small MCP tool gated on protocol reputation, built on SigvaraGate, which refuses a tool call to an agent that cannot prove itself or is below a threshold. If you're integrating with the on-chain protocol — DIDs, staked reputation, permissionless verification — you're in the right place, and @sigvara/protocol-sdk (source in packages/sdk, successor to the now-deprecated @countersig/protocol-sdk) is the only SDK for it.
| Guide | Audience |
|---|---|
| White paper | Everyone — the single document: design, trust model, known weaknesses, token, and commands to check every claim against the chain |
| Ecosystem Overview | Everyone — start here to understand the full picture |
| Quickstart | Developers — register your first agent in 10 minutes |
| Arc | Developers — deploy / test on Arc (5042002 / 5042), USDC gas |
| Deploy to Arc testnet | Developers — the first-deployment runbook, step by step |
| SVR token | Everyone — the bond and fee token: contract, distribution, treasury policy, when utility starts |
| Brand | Designers / frontend — colors, type, layout and component rules for every Sigvara surface |
| CounterAudit Integration | Enterprise — embed agent identity in your audit trail |
| AI Framework Integration | Developers — LangChain, AutoGen, CrewAI, Node.js |
| Reputation Model | Everyone — how the 6-factor score works and grows |
| Payment-backed attestations | Developers — how an attestation is tied to a settled payment, and the decay, diversity and evidence-root rules around it |
| Lineage | Everyone — the Robinhood Chain testnet run this protocol came from (addresses, oracle activity, what changed) |
| Security & Mainnet Readiness Review | Everyone — a point-in-time review dated 17 Sep 2026: conditional no-go for mainnet, with the blockers named |
Proxy addresses are stable; the code behind them is not. Every registry here is a UUPS proxy, so the address below never changes and the implementation does. The implementation each one is currently running is recorded under
implementationsindeployments/5042002.json, with the previous ones kept inhistorybecause that is what a rollback targets and what an incident review reads. Those records are read back off the chain, not written from intent:node scripts/record-implementations.mjs --checkfails if the file and the chain disagree.
Chain ID 5042002, RPC https://rpc.testnet.arc.io, USDC as native gas. Canonical
source is deployments/5042002.json; the table below is a
convenience copy.
| Contract | Address |
|---|---|
SigvaraIdentity |
0x7e3aFC532eE5d922ab3cc3FFb510c7C8151477Dd |
SigvaraReputation |
0x6603C96275e85F724Cdf74666b399365e4cA29ed |
SigvaraStaking |
0xA69d62B2a6774D21A2c15d5d83b27277eD31d35B |
SVRToken (testnet faucet token, not the SVR of docs/token.md) |
0x41De2D6D55318e197a00E8f5B496eA2790e23E6c |
SigvaraOracleBond |
0x3c9c12F27DDCa7048840eE3fbF0CAa1C547D8171 |
Testnet assets have no economic value. The bond token above is a faucet ERC-20 that exists so the staking path can be exercised; it is unrelated to the mainnet SVR.
Sigvara is the computed-reputation and staked-slashing layer on top of the ERC-8004 identity and feedback registries. See docs/architecture.md for the full signal flow.
graph TB
subgraph sources["Signal sources"]
CA["CounterAudit<br/>work-outcome attestations"]
WD["Watchdog scanners<br/>rug / abuse flags"]
end
subgraph erc8004["ERC-8004 · identity + feedback (canonical)"]
EID["Identity Registry<br/>agent identity"]
EREP["Reputation Registry<br/>raw feedback"]
end
subgraph sigvara["Sigvara · the trust layer"]
OR(["Reputation Oracle<br/>computes the score"])
REP["SigvaraReputation<br/>computed-score anchor"]
ST["SigvaraStaking<br/>bonds + slashing"]
end
CONS["SDK · consumers · on-chain readers"]
CA -->|"success / fail"| OR
WD -->|"flags"| OR
EID -->|"identity + age"| OR
EREP -->|"feedback to externalScore"| OR
OR -->|"propose / finalize"| REP
ST -->|"slash · zero score"| REP
CA -->|"giveFeedback"| EREP
REP -->|"getTotalScore · meetsThreshold"| CONS
Identity layer: ERC-8004. Sigvara has adopted the ERC-8004 Identity Registry as the canonical agent registry and no longer maintains a competing one. Sigvara is the computed-reputation and staked-slashing layer on top of the standard — the parts ERC-8004 deliberately leaves out. See ADR 0001.
Commerce layer: ERC-8183, watched not used. Arc pairs ERC-8004 identity with ERC-8183, where a job is escrow with a verdict written by a named evaluator. That verdict is the one input this protocol cannot check for itself today: the oracle proves a payment settled and takes "it went well" from whoever submitted the attestation. The oracle can now read an ERC-8183 registry (
GET /jobs/:address) and reportsscored: falseon every response, because the ERC is still a Draft and Arc has no canonical deployment. See docs/arc.md.
| Contract | Role |
|---|---|
SigvaraReputation |
Computed-score anchor. Stores the oracle's normalized, capped 6-factor score — the layer above ERC-8004's raw feedback. Exposes getTotalScore() and meetsThreshold() for on-chain consumers. |
SigvaraStaking |
Staked accountability. Agent bond management with committee-initiated slashing (7-day challenge window, permissionless execution after timelock). No ERC-8004 equivalent — this is the differentiator. Bond token is set by address at deploy: the faucet SVRToken on testnet, SVR on mainnet — the contracts treat it as a plain IERC20 either way. |
SigvaraIdentity |
The registry in use today. did:sigvara registration with proof of control by the agent address, on-chain Ed25519 PKI, bond-gated status (PendingBond → Active) and two-step operator transfer. ERC-8004 is the long-term identity layer (ADR 0001); until that migration lands this contract is what every deployed component reads and writes. Its non-redundant part (the Ed25519 auth key, bond-gated status, transfer history) becomes an extension keyed to an ERC-8004 agent id. |
SigvaraOracleBond |
Oracle accountability. Performance bonds for oracle operators. When wired into SigvaraReputation.operatorBond, only an admitted, bonded operator can propose a score. Deployed on Arc testnet and wired. |
The retained contracts use UUPS upgradeable proxies (OpenZeppelin v5), controlled by a governance timelock on mainnet.
Direction of travel. ERC-8004 agent ids are the intended long-term identifier (ADR 0001), and the
did:sigvaramethod below will become a view over one. That migration has not happened yet: every agent registered today, on testnet and through the SDK, gets adid:sigvaraand is keyed by itsdidHash.
Format: did:sigvara:<chainId>:<agentAddress>
Example: did:sigvara:1:0x1234...abcd
The didHash index key is derived trustlessly on-chain at registration:
bytes32 didHash = keccak256(
abi.encodePacked("did:sigvara:", block.chainid, ":", agentAddress)
);Any party can reproduce the hash without querying contract state. The on-chain derivation prevents off-chain forgery.
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/ed25519-2020/v1"
],
"id": "did:sigvara:1:0x1234abcd",
"controller": "did:pkh:eip155:1:0xOperatorAddress",
"verificationMethod": [{
"id": "did:sigvara:1:0x1234abcd#key-1",
"type": "Ed25519VerificationKey2020",
"controller": "did:sigvara:1:0x1234abcd",
"publicKeyMultibase": "z6MkhaXgBZDvotDkL5257faiztiCEsJ"
}],
"authentication": ["did:sigvara:1:0x1234abcd#key-1"],
"assertionMethod": ["did:sigvara:1:0x1234abcd#key-1"]
}stateDiagram-v2
direction LR
[*] --> PendingBond : registerAgent()\n(signed by the agent address)
PendingBond --> Active : depositStake() reaches minimumStake
Active --> Suspended : operator.updateStatus()\nor StakingCore.initiateSlash()
Suspended --> Active : operator.updateStatus()\nor resolveDispute(false)\nor cancelSlash() / expireDispute()
Active --> Slashed : StakingCore.executeSlash()
Suspended --> Slashed : StakingCore.executeSlash()
Slashed --> [*] : terminal — no further transitions
Key invariants:
- Registration mints
PendingBond, neverActive. An unbonded agent has nothing to slash, so it is not scoreable either. - Any transition into
Activerequires the agent to holdminimumStake— including the ones the staking core makes when a slash is dropped. There is no path back toActivewhile under-collateralized. - Nothing returns to
PendingBond. It describes an identity that has never been bonded; an agent does not become un-bonded, it suspends and exits. - Only
STAKING_CORE_ROLEcan setSlashed Slashedis terminal — no key rotation, no status change- Suspended agents may rotate their Ed25519 key (key-compromise recovery path)
Scores are computed off-chain by the oracle network and written to SigvaraReputation. The contract stores and serves; it does not compute.
| Factor | Max | Source | Formula | Status |
|---|---|---|---|---|
| Fee Activity | 20 | Settled payment volume to the agent, verified on chain | min(20, decayedVolume / PAYMENT_FEE_UNIT), capped per payer |
live |
| Success Rate | 15 | Outcome reported by whoever paid (e.g. CounterAudit) | floor(successful / (total + 5) × 15), on decayed weights |
live |
| Tenure | 30 | Span of verified paid activity, faded by how long since the last of it | min(30, floor(log₂(spanDays+1) × 3)) × recency |
live |
| External Trust | 25 | Normalized ERC-8004 feedback (linked agents) | mean of recognized tags × 25 | live |
| Community | 5 | Flags from watchdog feeds (e.g. HoodScan), age-weighted | max(0, 5 − flags × 2), flags decay on a 30-day half-life |
live |
| Propagation | 5 | Standing of the counterparties that paid the agent | 1 pt per fully-trusted counterparty, pro-rated by its score | live |
| Total | 100 |
All six factors are live. Four things shape what the number actually means:
- Only bonded agents are scored. A newly registered agent is
PendingBondand cannot be proposed a score at all. The bond is what makes it slashable, and scoring something unslashable is scoring nothing. - Evidence is payment-backed. With
PAYMENT_VERIFICATION=required, an attestation must carry the settlement transaction of a real payment to the agent's own address, and the payer is taken from the transfer log rather than asserted by the caller. Self-payments are refused and any one counterparty's evidence is capped. See payment-backed attestations. - Evidence decays. Each payment is weighted
0.5 ^ (age / half-life)from the time it settled, and the success rate divides bytotal + 5so a decaying record falls toward zero instead of holding a scale-invariant ratio forever. A farmed score is perishable and has to be renewed. - A score is earned before it is spendable.
getEarnedScore()returns the raw finalized figure;getTotalScore()returns the matured one, which climbs toward it at a fixed rate per day and is whatmeetsThreshold()checks. Falls apply immediately. Transferring an agent to a new operator restarts maturity.
externalScore is 0 unless the agent links an ERC-8004 identity it owns. See the Reputation Model for provenance detail and payment-backed attestations for how the inputs are verified and committed to.
Testnet: SLASHING_COMMITTEE_ROLE is held by a single EOA. Mainnet path: a 3-of-5 multisig, then UMA OptimisticOracleV3 or Kleros (isolated in the initiateSlash / disputeSlash interface, replaceable without storage migration).
No slash has been executed end to end on Arc testnet yet. The lifecycle below is covered by the E2E suite, not by a documented live run.
sequenceDiagram
participant V as Victim
participant CM as Slashing committee
participant ST as SigvaraStaking
participant ID as SigvaraIdentity
participant REP as SigvaraReputation
V->>CM: report agent + evidence package
CM->>ST: initiateSlash(didHash, victim, evidenceHash)
ST->>ID: updateStatus(didHash, Suspended)
Note over ST: 7-day challenge period begins
alt Operator disputes within window
Op->>ST: disputeSlash(didHash)
Note over ST: Proposal → Disputed. Bond stays frozen,<br/>agent stays Suspended
CM->>ST: resolveDispute(didHash, uphold)
Note over ST: Upheld slashes; rejected cancels and reinstates.<br/>Unresolved after 14 days, anyone may expireDispute()
else Challenge period elapses undisputed
Anyone->>ST: executeSlash(didHash)
ST->>ID: updateStatus(didHash, Slashed)
ST->>REP: zeroReputation(didHash)
ST-->>0xdead: 50% burned
ST-->>V: 25% to victim
ST-->>CM: 25% to reporter
end
| Recipient | Share | Mechanism |
|---|---|---|
address(0xdead) |
50% | Deflationary burn |
| Victim | 25% | Recourse for the harmed party |
| Committee reporter | 25% | Incentivizes accurate reporting |
sequenceDiagram
participant Op as Operator
participant ST as SigvaraStaking
participant ID as SigvaraIdentity
Note over Op: Generate Ed25519 keypair off-chain
Op->>ID: registrationDigest(agentAddress, operator, ed25519PubKey)
ID-->>Op: digest
Note over Op: The AGENT address signs the digest (personal_sign).<br/>EOA or ERC-1271 contract — both verify.
Op->>ID: registerAgent(agentAddress, ed25519PubKey, signature)
ID->>ID: didHash = keccak256("did:sigvara:" + chainId + ":" + agentAddress)
ID->>ID: verify signature over the digest
ID-->>Op: AgentRegistered(didHash, operator, agentAddress, pubKey)
Note over ID: Status = PendingBond. Resolvable, but not Active,<br/>not scoreable, not slashable.
Op->>ST: depositStake(didHash, minimumStake)
ST->>ID: updateStatus(didHash, Active)
ST-->>Op: bond recorded, agent Active
Registration requires a signature from the agent address itself, over a digest bound to the chain id, the registry, the operator and the Ed25519 key. Without it anyone could register an address they do not control and choose the public key that verifiers would check against it. The digest is returned unprefixed: a standard signer applies the EIP-191 prefix itself, and returning a pre-prefixed value would make every wallet double-prefix and produce signatures the contract rejects.
sequenceDiagram
participant A as Agent A
participant B as Agent B
participant ID as SigvaraIdentity
participant REP as SigvaraReputation
A->>B: request action
B->>A: challenge payload\n"SIGVARA-VERIFY:{DID}:{nonce}:{timestamp}"
A->>A: sign payload with Ed25519 private key
A->>B: { did, signature }
B->>ID: getIdentity(didHash)
ID-->>B: { ed25519PubKey, status: Active }
B->>B: verify Ed25519 signature against pubKey
B->>REP: meetsThreshold(didHash, 60)
REP-->>B: true / false
alt threshold met and signature valid
B-->>A: action permitted
else
B-->>A: rejected
end
Reputation updates go through a challenge window before taking effect, rather than writing atomically. This gives the slashing committee a chance to reject a bad proposal before it goes live, without needing a full multi-oracle consensus system.
sequenceDiagram
participant UC as User / Counterparty
participant OR as Oracle Network
participant REP as SigvaraReputation
participant CM as Slashing Committee
UC->>OR: attestation + settlement tx of the payment for the job
OR->>OR: verify the transfer on chain, take the payer from the log
Note over OR: epoch aggregation over decayed, per-payer-capped evidence
OR->>OR: compute 6-factor scores + Merkle root over the evidence used
OR->>REP: proposeReputation(didHash, ReputationData, evidenceRoot)
REP->>REP: validate per-factor caps, require a bonded agent
REP-->>OR: ScoreProposed(didHash, proposedAt)
Note over REP: Challenge window open (e.g. 1-6 hours)
alt Committee rejects during the window
CM->>REP: rejectReputation(didHash)
REP-->>CM: ScoreRejected(didHash)
Note over REP: Previous finalized score is untouched
else Window elapses unchallenged
UC->>REP: finalizeReputation(didHash) — permissionless
REP-->>UC: ReputationUpdated(didHash, totalScore)
Note over REP: Score now live for A2A threshold checks
end
Every proposal commits to the evidence behind it. evidenceRoots(didHash) holds a
Merkle root over the payments the oracle counted; the oracle serves the leaves from
GET /evidence/:didHash, unauthenticated at
oracle.sigvara.xyz,
and anyone can re-verify each payment against the chain,
rebuild the root and compare — locally or through verifyEvidence(didHash, leaf, proof).
This makes a quietly dropped or invented payment detectable. It does not prove the
oracle counted everything it should have; a payment nobody ever submitted leaves no
trace to be missing from.
If an Ed25519 private key is compromised:
- Operator calls
updateStatus(didHash, Suspended)immediately — invalidates the DID for authentication within one block. - Operator generates a new Ed25519 keypair off-chain.
- Operator calls
rotatePublicKey(didHash, newEd25519PubKey). - Operator reinstates:
updateStatus(didHash, Active).
Slashed agents cannot rotate. The identity is permanently terminated.
npm install @sigvara/protocol-sdkThe shortest path from a score to a decision. SigvaraGate issues a challenge, checks
the proof before touching the chain, spends the nonce so a captured response cannot be
replayed, and refuses with a reason you can act on.
import { SigvaraGate } from '@sigvara/protocol-sdk';
const gate = new SigvaraGate({
rpcUrl: 'https://rpc.testnet.arc.io',
addresses, // deployments/5042002.json
threshold: 40,
audience: 'https://your-service.example', // signed into every challenge
});
const challenge = gate.challenge(agentDid);
// ...the agent signs challenge.payload and returns the signature...
const result = await gate.admit(agentDid, challenge, signature);
if (!result.ok) {
// 'bad_proof' | 'replayed' | 'not_active' | 'below_threshold'
return refuse(result.reason);
}Only below_threshold is about reputation. not_active is a real, proven agent that
is unbonded, suspended or slashed, and sending that caller off to earn points would be
the wrong instruction. The default nonce store is per process; behind a load balancer
pass a NonceStore with an atomic consume(). Requires 1.0.0-alpha.9 or later. A
worked example lives in examples/mcp-gated-tool.
import { SigvaraAgent, SigvaraVerifier } from '@sigvara/protocol-sdk';
// Agent A — the prover
const agentA = new SigvaraAgent({
privateKey: process.env.AGENT_A_ED25519_SEED, // 32-byte hex seed
agentAddress: '0xAgentAAddress',
chainId: 5042002, // Arc testnet
});
// Agent B — the verifier (has its own identity + a verifier for on-chain lookups)
const agentB = new SigvaraAgent({
privateKey: process.env.AGENT_B_ED25519_SEED,
agentAddress: '0xAgentBAddress',
chainId: 5042002,
});
const verifier = new SigvaraVerifier({
rpcUrl: 'https://rpc.testnet.arc.io',
addresses: {
identity: '0x... /* from deployments/5042002.json */',
reputation: '0x... /* from deployments/5042002.json */',
staking: '0x... /* from deployments/5042002.json */',
},
chainId: 5042002,
});
// B issues a challenge to A
const challenge = agentB.issueChallenge(agentA.did);
// A signs and returns its DID + signature
const signature = agentA.signChallenge(challenge.payload);
// B verifies: resolves pubkey from chain, checks signature + reputation
const valid = await verifier.verifySignature(agentA.did, challenge.payload, signature);
const trusted = await verifier.meetsThreshold(agentA.did, 60);import { registerAgent, depositStake } from '@sigvara/protocol-sdk';
const { didHash } = await registerAgent(
signer, // ethers.Signer with operator wallet
agentA.agentAddress, // the agent's Ethereum address (the DID is derived from it)
agentA.publicKeyBytes32, // bytes32 Ed25519 public key
IDENTITY_CONTRACT_ADDRESS,
{ agentSigner }, // proves control of agentAddress; or { signature } if signed elsewhere
);
// The agent is PendingBond until this lands. The first deposit that carries it over
// minimumStake is what activates it.
// Sends the ERC-20 approval only if the allowance is short, then deposits.
await depositStake(signer, didHash, 1000n * 10n ** 18n, STAKING_CONTRACT_ADDRESS);const didDoc = await verifier.buildDidDocument(agentA.did);
// Returns W3C-compliant DID Document with Ed25519VerificationKey2020Requires Foundry.
git clone https://github.com/RunTimeAdmin/sigvara
cd sigvara
forge install
forge build
forge testDeploy and upgrade scripts live in script/. Deploy.s.sol brings up the
registries and wires roles; Upgrade.s.sol moves a single UUPS proxy to a new
implementation and is covered by test/Upgrade.t.sol. See
docs/arc.md for both.
Running the fuzz suite at higher intensity:
FOUNDRY_PROFILE=ci forge testEverything below runs offline, with no network access and no deployed contracts.
| Suite | Count | Command |
|---|---|---|
| Contracts — unit, fuzz, E2E, upgrade and 6 invariants | 246 | forge test |
| Oracle | 207 | cd oracle && node --test |
| SDK | 58 | cd packages/sdk && npx vitest run |
Test individual contract functions in isolation. These run on Foundry's in-memory EVM and require no external network.
forge test # all contract tests
FOUNDRY_PROFILE=ci forge test # denser fuzz runs (5000 iterations)Drive the staking and identity contracts through randomized call sequences and assert
properties that must hold in every reachable state — among them that no agent is ever
Active while below minimumStake. That one found a real escape: an operator could
queue a withdrawal while Suspended, draw a slash, dispute it, and be reinstated
under-collateralized.
forge test --match-contract StakingInvariantTestCover the full agent lifecycle: register → stake → propose/finalize reputation → slash → zero-reputation. These run in-memory with deployed fixture contracts.
forge test --match-contract E2EIntegrationTest -vvvKey scenarios tested:
- Full lifecycle from registration to slash
- Slash dispute and agent reinstatement
- Reputation challenge (committee rejects bad score)
- Unbonding period enforcement
- Slash sweeping unbonding queue (dodge prevention)
- Multiple epochs of score evolution
- Multiple independent agents
| Role | Holder (Testnet) | Mainnet target | Permissions |
|---|---|---|---|
DEFAULT_ADMIN_ROLE |
Deployer EOA 0x18CBcE50… |
Governance timelock | Grant/revoke all roles, set maturity rate, wire the stake view and oracle bond |
UPGRADER_ROLE |
Deployer EOA 0x18CBcE50… |
Governance timelock | Authorize UUPS upgrades |
STAKING_CORE_ROLE |
SigvaraStaking 0xA69d62B2… |
SigvaraStaking |
Suspend / slash agents, zero reputation, clear slash suspensions |
ORACLE_ROLE |
Primary 0x6352b8FF… + checker 0x989aabd6…, both bonded |
Multiple independently operated bonded operators | Propose reputation scores |
SLASHING_COMMITTEE_ROLE |
EOA 0x045d6c1D… |
3-of-5 multisig | Initiate slash proposals, reject bad scores |
| Operator | Agent registrant | Agent registrant | Register, suspend, reinstate, rotate key, transfer the agent |
Every privileged role on testnet is currently a single EOA, including the slashing committee — the 3-of-5 multisig is the mainnet target, not the present state. Moving admin and upgrade rights to a timelock or Safe is a named mainnet blocker; see the readiness review.
When SigvaraReputation.operatorBond is set, proposeReputation additionally requires
the caller to be an admitted, bonded operator in SigvaraOracleBond — so ORACLE_ROLE
alone is not enough to write a score. Finalizing stays permissionless.
Sigvara is designed as an open identity layer. Any system that needs to know which AI agent did what can integrate by querying the contracts or consuming CounterAudit enriched packets.
CounterAudit is the first integration. It shares an owner with Sigvara, as part of the CounterAegis suite, so it is not an arm's-length third party — see docs/ecosystem.md.
Enrichment is live as of 19 September 2026. It had been broken since the rename two days earlier: the code still parsed
did:countersig:and hashed that prefix, so every current DID was rejected and the derived hash would not have matched the registry anyway. It was also pointed at the predecessor deployment on Robinhood Chain. Both are fixed, and a verification packet onapi.counteraudit.iocarriesagent_chain_id: 5042002with the correct hash and live score.The reverse path went live the same day. It had posted outcomes without the
payment.txHashthe oracle requires, so every one was rejected. The fix was not to relax the oracle — the payment is the credential, which is what stops attestations being free to manufacture — but to carry the settlement hash through from the caller, who is a party to the payment and knows it. CounterAudit relays it and the oracle still verifies it against the chain independently, so CounterAudit is not a trusted party in that path.
How it works: an ingest call carrying agent_did makes CounterAudit query the Sigvara contracts at seal time and embed the agent's identity and reputation score inside the AES-GCM seal, covered by an RFC 3161 timestamp — proving what the agent's reputation was at the moment of each action rather than today. An ingest also carrying an outcome (success / failure) is reported to the oracle, feeding audited work outcomes back into Success Rate and Fee Activity. Reading and writing the same reputation is what closes the loop.
// Every action your agent takes gets sealed with identity + reputation
await fetch('https://api.counteraudit.io/v1/audit/ingest', {
method: 'POST',
headers: { 'Authorization': `Bearer ${CA_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
connector_id: 'my-agent',
agent_did: 'did:sigvara:5042002:0x...',
raw_event: { action: 'tool_call', tool: 'web_search', query: '...' },
}),
});
// The sealed packet contains:
// agent_reputation_score: 47
// agent_identity_status: "Active"
// agent_identity_verified: true
// agent_enriched_at: "2026-06-30T16:33:39Z"See the CounterAudit Integration Guide for full setup instructions.
HoodScan is a rug-risk scanner for Robinhood Chain tokens. When a scan returns a red (high-risk) verdict, it reports the token's deployer address to the reputation oracle as a community flag. If that deployer operates a registered Sigvara agent, the flag lowers its Community factor — so on-chain misbehavior detected off-chain shows up in the agent's reputation. This is the watchdog half of the signal loop: consumers attest to good work, scanners flag bad actors. The oracle's flag endpoint is chain-agnostic, so any scanner can play the same role on Arc.
Any smart contract can gate operations on an agent's reputation:
ISigvaraReputation rep = ISigvaraReputation(REPUTATION_ADDRESS);
require(rep.meetsThreshold(didHash, 60), "insufficient reputation");| Phase | Timeline | Deliverables |
|---|---|---|
| Core Protocol | Q3 2026 | contracts, reputation oracle and @sigvara/protocol-sdk v1.0 built and tested · CounterAudit attestation + HoodScan flag feeds |
| Arc Port | Q4 2026 | 5042002, USDC gas) |
| External Trust | Q4 2026 | externalScore from ERC-8004 feedback — built and tested, reading the ERC-8004 registries on Base Sepolia; it contributes 0 until an agent is linked to an 8004 id whose NFT is held by the same wallet and which carries feedback in a tag the oracle normalizes. No agent is linked today, so this factor is 0 for everyone · agent-vouching graph (propagationScore) — built and live, computed every epoch; it inherits only a counterparty's external standing, so like externalScore it reads 0 network-wide until ERC-8004 standing exists. Reachable ceiling today is 70/100 · deeper ERC-8004 interop (publish CounterAudit validations to the Validation Registry) |
| Sybil resistance | Q4 2026 | |
| Oracle decentralization | Q1 2027 | activeCount 2, separate host and RPC provider) · |
| Mainnet Registries | Q1 2027 | Tier-1 security audit · admin and upgrade roles onto a timelock or Safe · one documented end-to-end testnet slash · registry deployment on Arc mainnet (5042) with bonds and scoring fees in SVR |
| Cross-Chain | Q2 2027 | Solana + Base state mirroring via LayerZero |
The token-launch contract set (fixed-supply SVR, vesting, public sale) and the earlier tokenomics and oracle-first direction docs live under archive/token-launch/. They are out of the build; SVR will launch through Tolly rather than these contracts.
MIT