Skip to content

Identity Layer

RunTimeAdmin edited this page Oct 29, 2026 · 12 revisions

Identity Layer

**Referenced Files in This Document** - [ADR 0001 — ERC-8004 as the identity layer](https://github.com/RunTimeAdmin/Sigvara/blob/main/docs/adr/0001-erc8004-as-identity-layer.md) - [SigvaraIdentity.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/src/SigvaraIdentity.sol) - [SigvaraReputation.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/src/SigvaraReputation.sol) - [SigvaraStaking.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/src/SigvaraStaking.sol) - [did.ts](https://github.com/RunTimeAdmin/Sigvara/blob/main/packages/sdk/src/did.ts) - [agent.ts](https://github.com/RunTimeAdmin/Sigvara/blob/main/packages/sdk/src/agent.ts) - [keys.ts](https://github.com/RunTimeAdmin/Sigvara/blob/main/packages/sdk/src/keys.ts) - [challenge.ts](https://github.com/RunTimeAdmin/Sigvara/blob/main/packages/sdk/src/challenge.ts) - [types.ts](https://github.com/RunTimeAdmin/Sigvara/blob/main/packages/sdk/src/types.ts) - [reputation-model.md](https://github.com/RunTimeAdmin/Sigvara/blob/main/docs/reputation-model.md) - [SigvaraIdentity.t.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/test/SigvaraIdentity.t.sol) - [InflowGuard.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/src/InflowGuard.sol) - [TimelockedGrants.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/src/TimelockedGrants.sol)

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 Sigvara’s identity layer and how it builds on ERC-8004. ERC-8004 provides canonical agent identity and a raw signed feedback ledger; Sigvara adds computed reputation and staked accountability on top. The system anchors an off-chain Ed25519 key to an on-chain agent registry, manages operator control, enforces a strict status lifecycle, and integrates with staking and slashing so that only bonded agents can earn spendable reputation.

The design intentionally separates:

  • Canonical identity and raw feedback (ERC-8004).
  • Computed reputation score (SigvaraReputation).
  • Bonding, unbonding, and slashing (SigvaraStaking).
  • On-chain identity extension for Ed25519 keys and slash state (SigvaraIdentity).

Direction of travel, not the present state: ADR 0001 makes ERC-8004 agent ids the intended long-term key, with SigvaraIdentity shrinking to an extension keyed to one. That cutover has not happened. Every agent registered today is keyed by its didHash in SigvaraIdentity, which script/Deploy.s.sol deploys for mainnet and which every deployed component reads and writes.

Section sources

Project Structure

The identity layer spans Solidity contracts and a TypeScript SDK:

  • Solidity core:
    • SigvaraIdentity.sol: deterministic DID derivation, Ed25519 public key anchoring, operator management, and status transitions.
    • SigvaraReputation.sol: oracle-proposed, challenge-windowed, finalized reputation scores with maturity.
    • SigvaraStaking.sol: stake bonds, unbonding, slash initiation/dispute/resolution, and execution.
  • TypeScript SDK:
    • did.ts, agent.ts, keys.ts, challenge.ts, types.ts: DID formatting, Ed25519 key handling, A2A challenge-response, and shared types.
  • Documentation and tests:
    • reputation-model.md describes scoring factors and lifecycle behavior.
    • SigvaraIdentity.t.sol exercises registration, status transitions, transfers, and storage layout.
graph TB
subgraph "On-chain"
ID["SigvaraIdentity<br/>DID + Ed25519 key + Status"]
REP["SigvaraReputation<br/>Computed Score"]
STK["SigvaraStaking<br/>Bond + Slash"]
E8004["ERC-8004<br/>Canonical Agent + Raw Feedback"]
end
subgraph "Off-chain"
SDK["TypeScript SDK<br/>DID / Keys / Challenge"]
ORACLE["Oracle Network<br/>Score Computation"]
end
SDK --> ID
ORACLE --> REP
STK --> ID
REP --> ID
REP -. reads .-> E8004
Loading

Diagram sources

Section sources

Core Components

  • SigvaraIdentity: Anchors each agent by a deterministic didHash, stores the Ed25519 public key, tracks the operator, and enforces status transitions. It also exposes a stake view gate so returning to Active requires sufficient collateral.
  • SigvaraReputation: Stores oracle-computed six-factor scores, enforces a challenge window, and applies maturity so earned points become spendable gradually. It binds scores to registered, non-slashed, bonded agents.
  • SigvaraStaking: Manages stake deposits, unbonding, slash proposals, disputes, and execution. Slashing marks the agent Slashed and zeros its reputation.
  • SDK: Provides deterministic DID computation, Ed25519 key generation and encoding, and A2A challenge-response with audience binding.

Key responsibilities:

  • Deterministic DID: did:sigvara:<chainId>:<agentAddress> → keccak256(...).
  • Operator-controlled identity lifecycle and transfer.
  • Off-chain cryptographic identity (Ed25519) anchored on-chain.
  • Reputation computed off-chain but enforced on-chain via bonding and slashing.

Section sources

Architecture Overview

The identity layer is layered:

  1. ERC-8004 defines canonical agent identity and raw feedback.
  2. SigvaraIdentity extends identity with Ed25519 keys and slash state, plus operator control.
  3. SigvaraStaking enforces “bond before trust” and provides economic finality through slashing.
  4. SigvaraReputation computes and stores normalized reputation, gated by bond and identity checks.
sequenceDiagram
participant Client as "Client / SDK"
participant Registry as "SigvaraIdentity"
participant Staking as "SigvaraStaking"
participant Reputation as "SigvaraReputation"
participant Oracle as "Oracle"
participant E8004 as "ERC-8004"
Client->>Registry : registerAgent(agentAddress, ed25519PubKey, signature)
Registry-->>Client : didHash (PendingBond)
Client->>Staking : depositStake(didHash, amount)
alt amount >= minimumStake
Staking->>Registry : updateStatus(didHash, Active)
end
Oracle->>Reputation : proposeReputation(didHash, data, evidenceRoot)
Reputation->>Registry : check identity + stakeView
Reputation-->>Client : finalizeReputation(didHash) after window
Reputation-. reads .-> E8004 : external feedback
Loading

Diagram sources

Detailed Component Analysis

DID Methodology and Key Anchoring

  • DID format: did:sigvara:<chainId>:<agentAddress>.
  • DID hash: keccak256(abi.encodePacked("did:sigvara:", chainId, ":", agentAddress)).
  • Off-chain Ed25519 public key (raw 32 bytes) is stored in SigvaraIdentity for A2A challenge-response verification.
  • SDK helpers:
    • formatDid, computeDidHash mirror on-chain derivation.
    • pubKeyToBytes32 converts Ed25519 public key to bytes32 hex for registration.
    • pubKeyToMultibase produces W3C DID-compatible multibase representation.
flowchart TD
Start(["Create Agent"]) --> GenKeys["Generate Ed25519 Keypair"]
GenKeys --> FormatDid["Format DID<br/>did:sigvara:<chainId>:<agentAddress>"]
FormatDid --> ComputeHash["Compute didHash<br/>keccak256(...)"]
ComputeHash --> Register["Register on SigvaraIdentity<br/>with signature"]
Register --> StoreKey["Store Ed25519 Public Key<br/>bytes32"]
Loading

Diagram sources

Section sources

Registration Process and Signature Binding

  • Registration digest binds:
    • Chain ID and registry address (prevents replay across deployments).
    • Agent address (claims ownership).
    • Operator address (binds who controls the identity).
    • Ed25519 public key (prevents key substitution).
  • Verification uses SignatureChecker, supporting EOAs and ERC-1271 contracts.
  • New identities start in PendingBond; they are not immediately Active.
sequenceDiagram
participant Client as "Operator"
participant Registry as "SigvaraIdentity"
participant Wallet as "Agent Address"
Client->>Registry : registrationDigest(agentAddress, operator, ed25519PubKey)
Wallet->>Wallet : sign(EIP-191 digest)
Client->>Registry : registerAgent(agentAddress, ed25519PubKey, signature)
Registry->>Registry : verifyRegistration()
Registry-->>Client : didHash (status = PendingBond)
Loading

Diagram sources

Section sources

Operator Management and Agent Transfer

  • Operator is the account controlling stake and status changes.
  • Two-step transfer prevents accidental loss:
    • offerOperatorTransfer(didHash, newOperator)
    • acceptOperatorTransfer(didHash)
  • Transfers are blocked while slash is pending and require the agent to be bonded at handover.
  • Transfer records:
    • operatorChangedAt restarts reputation maturity.
    • operatorTransferCount reports ownership history.
flowchart TD
Offer["offerOperatorTransfer(newOperator)"] --> CheckSlash{"Slash pending?"}
CheckSlash --> |Yes| Block["Revert"]
CheckSlash --> |No| Accept["acceptOperatorTransfer()"]
Accept --> CheckBond{"Has minimum stake?"}
CheckBond --> |No| Revert["Revert InsufficientCollateral"]
CheckBond --> |Yes| Update["Update operator,<br/>record changedAt,<br/>increment count"]
Loading

Diagram sources

Section sources

Status State Machine

States:

  • PendingBond: Registered but not yet bonded. It cannot be scored until it is bonded, but any stake it has already posted can be slashed.
  • Active: Bonded and operational. Can earn reputation.
  • Suspended: Temporarily halted; may be self-suspended or slashed-initiated.
  • Slashed: Terminal; cannot rotate keys or change status.

Transitions:

  • Registration → PendingBond.
  • Deposit ≥ minimumStake while PendingBond → Active.
  • Operator ↔ Suspended toggle allowed; returning to Active requires collateral.
  • Staking core sets Slashed; no further transitions.
  • Slash suspension lock prevents operator from clearing staking-applied suspension mid-slash.
  • When a slash proposal is dropped (committee cancel, admin veto or ruling, expireDispute, expireSlash), the staking core returns the agent to Active if its bond is still at least minimumStake. Otherwise the agent stays Suspended with the lock cleared, and its operator re-bonds and reactivates it.
stateDiagram-v2
[*] --> PendingBond : "registerAgent"
PendingBond --> Active : "depositStake >= minimumStake"
Active --> Suspended : "updateStatus(operator)"
Suspended --> Active : "updateStatus(operator) if bonded"
Active --> Slashed : "stake.executeSlash()"
Suspended --> Slashed : "stake.executeSlash()"
Slashed --> [*] : "terminal"
Loading

Diagram sources

Section sources

Integration Between Off-Chain Ed25519 Keys and On-Chain Registry

  • SDK generates Ed25519 keys and encodes them as bytes32 for on-chain storage.
  • SigvaraIdentity stores the raw 32-byte public key per agent.
  • A2A authentication uses challenge-response:
    • Verifier issues a challenge with prover DID and audience.
    • Prover signs the payload with its Ed25519 secret key.
    • Verifier verifies against the on-chain public key.
sequenceDiagram
participant Verifier as "Verifier"
participant Prover as "Prover Agent"
participant Registry as "SigvaraIdentity"
Verifier->>Prover : issueChallenge(proverDid, audience)
Prover->>Prover : signChallengeFor(payload, audience)
Prover-->>Verifier : base58(signature)
Verifier->>Registry : getIdentity(didHash)
Registry-->>Verifier : ed25519PubKey
Verifier->>Verifier : verifyChallenge(payload, signature, publicKey)
Loading

Diagram sources

Section sources

Reputation Layer on Top of ERC-8004

  • ERC-8004 provides canonical identity and raw feedback; Sigvara computes a normalized 6-factor score.
  • Factors include fee activity, success rate, tenure, external trust (from ERC-8004), community flags, and propagation.
  • Scores are proposed by oracles, challenged during a window, then finalized.
  • Maturity ensures earned scores become spendable gradually; transfers restart maturity.
flowchart TD
Link["Link ERC-8004 agent id"] --> External["Read ERC-8004 feedback"]
Payments["Scan payments & attestations"] --> Factors["Compute 6 factors"]
External --> Factors
Factors --> Propose["proposeReputation(didHash, data, root)"]
Propose --> Window["Challenge window"]
Window --> Finalize["finalizeReputation()"]
Finalize --> Mature["Matured score over time"]
Loading

Diagram sources

Section sources

Practical Lifecycle Examples

  • Agent creation:
    • Generate Ed25519 keypair.
    • Compute DID and didHash.
    • Sign registration digest.
    • Call registerAgent.
  • Activation:
    • Deposit stake ≥ minimumStake.
    • Identity transitions to Active.
  • Operation:
    • Perform tasks; receive payments.
    • Oracle proposes reputation; consumers check matured score.
  • Recovery:
    • Rotate Ed25519 key if compromised.
    • Suspend and re-bond if needed.
  • Exit or penalty:
    • Initiate withdrawal; claim after unbonding.
    • If slashed, identity becomes terminal; must register a new agent.

Section sources

Dependency Analysis

  • SigvaraIdentity depends on:
    • AccessControlUpgradeable and UUPSUpgradeable.
    • TimelockedGrants (lets the admin revoke upgrader-administered roles at once) and InflowGuard (the guardian’s pause on registrations), on main.
    • OpenZeppelin cryptography utilities for signature verification.
    • The IStakeView interface to check collateral for activation. It is wired after deployment: until initializeV2 or setStakeView sets it, any move to Active reverts with StakeViewNotSet, and on main setStakeView needs UPGRADER_ROLE.
  • SigvaraReputation depends on:
    • SigvaraIdentity to validate scorable agents.
    • Optional IOperatorSet to enforce bonded oracles.
  • SigvaraStaking depends on:
    • SigvaraIdentity for status and operator checks.
    • SigvaraReputation only via a narrow interface to zero scores on slash.
graph LR
ID["SigvaraIdentity"] --> StakeView["IStakeView"]
REP["SigvaraReputation"] --> ID
REP --> OpSet["IOperatorSet"]
STK["SigvaraStaking"] --> ID
STK --> RepZero["IReputationZero"]
Loading

Diagram sources

Section sources

Performance Considerations

  • Operator agent list removal was optimized from linear scan to constant-time swap-and-pop using a recorded index. Fallback scan remains for legacy entries.
  • Paging functions (getOperatorAgentsPaged) allow safe consumption without unbounded gas costs.
  • Reputation maturity is computed on read, avoiding frequent writes and allowing accrual even if oracles pause.
  • Evidence roots enable off-chain verification without trusting oracle JSON files.

Troubleshooting Guide

Common issues and resolutions:

  • Registration fails due to bad signature:
    • Ensure the agent address signs the exact registrationDigest.
    • Verify chain ID and registry address are correct.
  • Cannot return to Active after suspension:
    • Ensure minimum stake is posted; activation checks collateral.
  • Slash suspension lock prevents reactivation:
    • Only staking core can clear the lock, and it does so when the proposal is dropped: a committee cancel, an admin veto or ruling, expireDispute 14 days after a dispute, or expireSlash 14 days after the challenge deadline of an undisputed proposal. An executed slash leaves the agent Slashed, which is terminal.
  • Operator transfer blocked:
    • Slash pending transfers are disallowed; ensure no active slash proposal.
    • Agent must be bonded at handover.
  • Reputation not scoring:
    • Agent must be registered, not slashed, and bonded.
    • Identity registry and stake view must be configured.
    • Proposals are closed while a guardian pause is running.
  • Registration reverts with InflowsPausedUntil:
    • A guardian pause is running. It ends by itself within three days.

Section sources

Conclusion

Sigvara’s identity layer positions ERC-8004 as the canonical foundation for agent identity and raw feedback, while Sigvara adds computed reputation and staked accountability. Deterministic DIDs anchor off-chain Ed25519 keys, operator control is explicit and secure, and the status machine enforces “bond before trust.” Slashing provides economic finality, ensuring reputation is meaningful because it can be destroyed. Together, these components form a robust, extensible identity and reputation system suitable for decentralized AI agent ecosystems.

Overview

Clone this wiki locally