Repository navigation
Agent Registration and Lifecycle
- Introduction
- Project Structure
- Core Components
- Architecture Overview
- Detailed Component Analysis
- Dependency Analysis
- Performance Considerations
- Troubleshooting Guide
- Conclusion
This document explains the agent registration and lifecycle management in SigvaraIdentity. It covers how agents are registered, what data is stored, how status transitions work, how staking bonds gate activation, and which events are emitted for off-chain tracking. It also provides practical workflow examples using the SDK and Solidity tests as references.
The relevant code lives in:
- Solidity contracts:
src/SigvaraIdentity.sol(identity registry),src/SigvaraStaking.sol(bonding and slashing). - TypeScript SDK:
packages/sdk/src/agent.ts,packages/sdk/src/types.ts. - Test helpers and unit tests:
test/helpers/RegistrationHelper.sol,test/SigvaraIdentity.t.sol.
graph TB
subgraph "Solidity"
A["SigvaraIdentity.sol"]
B["SigvaraStaking.sol"]
end
subgraph "TypeScript SDK"
C["agent.ts"]
D["types.ts"]
end
subgraph "Tests"
E["RegistrationHelper.sol"]
F["SigvaraIdentity.t.sol"]
end
C --> A
D --> A
B --> A
E --> A
F --> A
Diagram sources
- SigvaraIdentity.sol
- SigvaraStaking.sol
- agent.ts
- types.ts
- RegistrationHelper.sol:1-42
- SigvaraIdentity.t.sol
Section sources
- SigvaraIdentity.sol
- SigvaraStaking.sol
- agent.ts
- types.ts
- RegistrationHelper.sol:1-42
- SigvaraIdentity.t.sol
- SigvaraIdentity: Anchors AI agent identities on-chain, validates registration signatures, manages operator control, public key rotation, status transitions, and DID derivation.
- SigvaraStaking: Manages stake tokens, minimum stake checks, deposit/withdrawal flows, slashing lifecycle, and coordinates with SigvaraIdentity to update statuses.
- TypeScript SDK: Provides Ed25519 key generation, DID computation, challenge issuance/signing, and helper types mirroring on-chain enums and structs.
Key responsibilities:
- Registration requires a signature from the agent address binding chain ID, registry address, agent address, operator, and Ed25519 public key.
- Agents start in PendingBond; they become Active only after their bond meets or exceeds minimumStake.
- Status transitions are gated by collateral checks and role permissions. Slashed is terminal.
Section sources
Agent registration and lifecycle involve two contracts working together:
- SigvaraIdentity stores identity metadata and enforces permissioned operations.
- SigvaraStaking holds bonds and triggers status changes through SigvaraIdentity when deposits reach minimumStake or during slashing.
sequenceDiagram
participant Client as "Client / Operator"
participant SDK as "SDK (agent.ts)"
participant Identity as "SigvaraIdentity"
participant Staking as "SigvaraStaking"
participant StakeView as "IStakeView"
Client->>SDK : Generate Ed25519 keys<br/>Compute didHash
SDK-->>Client : publicKeyBytes32, didHash
Client->>Identity : registerAgent(agentAddress, ed25519PubKey, signature)
Identity->>Identity : verifyRegistration()
Identity->>Identity : computeDidHash()
Identity-->>Client : didHash (status = PendingBond)
Client->>Staking : depositStake(didHash, amount)
Staking->>Identity : getIdentity(didHash)
alt amount >= minimumStake
Staking->>Identity : updateStatus(didHash, Active)
Identity->>StakeView : hasMinimumStake(didHash)
StakeView-->>Identity : true
Identity-->>Staking : success
else amount < minimumStake
Staking-->>Client : success (still PendingBond)
end
Diagram sources
- Fields:
- operator: Ethereum wallet controlling stake and operations.
- agentAddress: The agent’s Ethereum address used to derive the DID.
- ed25519PubKey: Raw 32-byte Ed25519 public key for off-chain authentication.
- status: One of Active, Suspended, Slashed, PendingBond.
- registeredAt: Timestamp when the agent was first registered.
- Enum values:
- Active: Fully operational and slashable.
- Suspended: Temporarily halted; may be self-suspended or slashed-initiated.
- Slashed: Terminal state; no further updates allowed.
- PendingBond: Registered but not yet bonded to at least minimumStake.
classDiagram
class AgentIdentity {
+address operator
+address agentAddress
+bytes32 ed25519PubKey
+AgentStatus status
+uint256 registeredAt
}
class AgentStatus {
<<enumeration>>
Active
Suspended
Slashed
PendingBond
}
AgentIdentity --> AgentStatus : "uses"
Diagram sources
Section sources
- Parameters:
- agentAddress: The agent’s Ethereum address. Must not be zero.
- ed25519PubKey: Raw 32-byte Ed25519 public key. Must not be zero.
- signature: Signature over registrationDigest() produced by agentAddress. Supports EOA and ERC-1271 contracts.
- Validation:
- Reverts with
InflowsPausedUntilwhile a guardian pause is running. - Zero-address and zero-key checks.
- Signature verification via SignatureChecker against MessageHashUtils-prefixed digest.
- Digest binds chainId, registry address, agentAddress, operator, and ed25519PubKey to prevent replay and interception.
- Reverts with
- State setup:
- Computes deterministic didHash from chainId and agentAddress.
- Creates AgentIdentity with operator set to caller, status PendingBond, and registeredAt set to current block timestamp.
- Updates operator index and emits AgentRegistered event.
flowchart TD
Start(["registerAgent entry"]) --> ValidateAgent["Validate agentAddress != 0"]
ValidateAgent --> ValidateKey["Validate ed25519PubKey != 0"]
ValidateKey --> VerifySig["verifyRegistration(agentAddress, operator, pubKey, sig)"]
VerifySig --> |Invalid| RevertSig["Revert BadRegistrationSignature"]
VerifySig --> ComputeDID["computeDidHash(agentAddress)"]
ComputeDID --> CheckDup{"Already registered?"}
CheckDup --> |Yes| RevertDup["Revert AlreadyRegistered"]
CheckDup --> Create["Create AgentIdentity<br/>status=PendingBond<br/>registeredAt=block.timestamp"]
Create --> Index["Update operatorAgents list"]
Index --> Emit["Emit AgentRegistered"]
Emit --> End(["Return didHash"])
Diagram sources
Section sources
- Using the SDK:
- Generate an Ed25519 keypair and obtain publicKeyBytes32 and didHash.
- Sign registrationDigest() with the agent’s private key.
- Call registerAgent(agentAddress, publicKeyBytes32, signature) from the operator.
- Deposit stake via SigvaraStaking.depositStake(didHash, amount); if amount >= minimumStake, the agent becomes Active automatically.
References:
- SDK key generation and DID helpers: agent.ts:43-68
- Test signing helper: RegistrationHelper.sol:27-41
- Successful registration test: SigvaraIdentity.t.sol:499-512
Note: Do not copy code here; use the referenced lines as implementation guidance.
Section sources
- Minimum stake requirement:
- An agent becomes Active only when its stake amount >= minimumStake.
- If depositStake brings the stake to at least minimumStake while the agent is PendingBond, SigvaraStaking calls updateStatus to Active.
- Collateral checks:
- Returning to Active always requires hasMinimumStake(didHash) to return true.
- If the stake view is unset, returning to Active reverts with StakeViewNotSet.
- Suspension and exit:
- Operators can suspend without collateral.
- Withdrawing stake below minimumStake while Active is disallowed unless fully exiting via suspension first.
- Guardian pause:
-
depositStakereverts withInflowsPausedUntilwhile a pause runs, asregisterAgentdoes. Withdrawals, claims, disputes and slash proceedings are never paused.
-
flowchart TD
Deposit["depositStake(didHash, amount)"] --> CheckStatus{"Agent status == PendingBond?"}
CheckStatus --> |Yes| CheckMin{"amount >= minimumStake?"}
CheckMin --> |Yes| Activate["updateStatus(didHash, Active)"]
CheckMin --> |No| KeepPending["Keep PendingBond"]
CheckStatus --> |No| Credit["Credit stake and emit event"]
Activate --> Done(["Success"])
KeepPending --> Done
Credit --> Done
Diagram sources
Section sources
Allowed transitions and constraints:
- PendingBond → Active:
- Requires depositStake to bring stake >= minimumStake, or operator calling updateStatus(Active) with sufficient collateral.
- Requires stakeView.hasMinimumStake(didHash) to return true.
- Active → Suspended:
- Allowed by operator or staking core. No collateral check required.
- Suspended → Active:
- Allowed by operator or staking core. Requires sufficient collateral.
- If staking core applied a slash suspension lock, operator cannot lift it; only staking core can clear the lock or reinstate.
- When a slash proposal is dropped (committee cancel, admin veto or ruling,
expireDispute,expireSlash), the staking core reinstates the agent only if its bond is still at leastminimumStake. Otherwise the agent stays Suspended with the lock cleared, and its operator re-bonds and reactivates it.
- Any → Slashed:
- Only STAKING_CORE_ROLE can set Slashed.
- Slashed is terminal: no further status updates, public key rotation, or transfers allowed.
stateDiagram-v2
[*] --> PendingBond
PendingBond --> Active : "stake >= minimumStake"
Active --> Suspended : "operator or staking core"
Suspended --> Active : "sufficient collateral"
Active --> Slashed : "STAKING_CORE_ROLE"
Suspended --> Slashed : "STAKING_CORE_ROLE"
PendingBond --> Slashed : "STAKING_CORE_ROLE"
Slashed --> [*]
Diagram sources
Section sources
- SigvaraIdentity.sol:344-397
- SigvaraStaking.sol:474-531
- SigvaraStaking.sol:715-778
- SigvaraStaking.sol:686-704
- SigvaraIdentity.sol:537-548
- AgentRegistered: Emitted upon successful registration with didHash, operator, agentAddress, and ed25519PubKey.
- StakeViewSet: Emitted when the stake view oracle is configured.
- OperatorTransferOffered / OperatorTransferred / OperatorTransferCancelled: Emitted during operator transfer workflows.
- PublicKeyRotated: Emitted when the Ed25519 public key is rotated.
- AgentStatusUpdated: Emitted whenever status changes.
These events enable off-chain systems to track registrations, ownership changes, key rotations, and status transitions.
Section sources
- SigvaraIdentity.sol:129-140
- SigvaraIdentity.sol:320-321
- SigvaraIdentity.sol:334-336
- SigvaraIdentity.sol:395-396
- SigvaraIdentity.sol:419-420
- SigvaraIdentity.sol:432-433
- SigvaraIdentity.sol:467-468
- SigvaraIdentity depends on:
- OpenZeppelin AccessControlUpgradeable and UUPSUpgradeable for roles and upgradeability.
- TimelockedGrants and InflowGuard on main: admin revocation of upgrader-administered roles, and the guardian’s pause on registrations.
- SignatureChecker and MessageHashUtils for signature verification.
- IStakeView interface to check collateral without importing SigvaraStaking directly. It is wired after deployment, and on main
setStakeViewneedsUPGRADER_ROLE.
- SigvaraStaking depends on:
- SigvaraIdentity for identity queries and status updates.
- IReputationZero interface to zero reputation upon slashing.
- SafeERC20 for token interactions.
graph LR
Identity["SigvaraIdentity.sol"] --> OZ1["AccessControlUpgradeable"]
Identity --> OZ2["UUPSUpgradeable"]
Identity --> OZ3["SignatureChecker"]
Identity --> OZ4["MessageHashUtils"]
Identity --> StakeView["IStakeView"]
Staking["SigvaraStaking.sol"] --> Identity
Staking --> Rep["IReputationZero"]
Staking --> Token["IERC20 / SafeERC20"]
Diagram sources
Section sources
- Operator indexing:
- New storage includes a position map to avoid linear scans during operator transfers.
- Removal uses swap-and-pop with recorded positions; fallback scan exists for legacy entries.
- Paged queries:
- getOperatorAgentsPaged allows safe pagination for large operator lists.
- Gas costs:
- Registration is gas-only and does not mint Active status, preventing free bulk registration.
- Activation requires collateral checks via stake view, adding minimal overhead.
Section sources
Common errors and resolutions:
- BadRegistrationSignature:
- Ensure the signature is produced by agentAddress over registrationDigest().
- Verify the operator bound in the digest matches the caller.
- AlreadyRegistered:
- Each didHash can only be registered once; do not attempt re-registration.
- InsufficientCollateral:
- Before updating to Active, ensure stake >= minimumStake via depositStake.
- SlashSuspensionLocked:
- If staking core initiated a slash, operators cannot lift suspension. The lock clears when the proposal is dropped: a committee cancel, an admin veto or ruling,
expireDispute14 days after a dispute, orexpireSlash14 days after the challenge deadline of an undisputed proposal. An executed slash leaves the agent Slashed, which is terminal.clearSlashSuspensionis called by the staking contract itself, when a dropped proposal leaves an under-bonded agent Suspended.
- If staking core initiated a slash, operators cannot lift suspension. The lock clears when the proposal is dropped: a committee cancel, an admin veto or ruling,
- NotOperator:
- Only the recorded operator can perform privileged actions like rotatePublicKey or offerOperatorTransfer.
Operational tips:
- Use SDK.generate to create Ed25519 keys and compute didHash deterministically.
- Always sign registrationDigest() with the agent’s private key before calling registerAgent.
- Monitor events AgentRegistered and AgentStatusUpdated for off-chain state synchronization.
Section sources
- SigvaraIdentity.sol:146-160
- SigvaraIdentity.sol:295-321
- SigvaraIdentity.sol:328-336
- SigvaraIdentity.sol:344-397
- SigvaraIdentity.t.sol:529-534
- SigvaraIdentity.t.sol:614-634
SigvaraIdentity provides a secure, deterministic agent registration system that ties identity to an Ethereum address and Ed25519 public key, enforced by cryptographic signatures. Agents begin in PendingBond and require a bond meeting minimumStake to become Active. The lifecycle is governed by strict state transitions and collateral checks, with slashing reserved for authorized roles. Events emitted throughout the process support robust off-chain tracking and integration. The TypeScript SDK simplifies key management and DID computation, while tests demonstrate correct parameter usage and edge-case handling.
- Agent Registration and Lifecycle
- Contract Overview and Architecture
- Economic Security Model and Incentives
- Evidence Verification and Merkle Proofs
- Key Management and Rotation
- Maturity Mechanism and Score Release
- Proposal Workflow and Challenge System
- Score Storage and Data Model
- SigvaraIdentity Contract
- SigvaraOracleBond Contract
- SigvaraReputation Contract
- SigvaraStaking Contract
- Slashing Lifecycle and Dispute Resolution
- Stake Management Functions
- Status Management and Control
- Token and Fee Contracts
- Unbonding Period and Withdrawal Security
- Anti-Manipulation and Security Measures
- Community Flag Processing
- Evidence Sources and Verification
- External Trust Integration
- Merkle Proof System
- Oracle Score Computation
- Payment-Backed Attestations
- Scoring Model and Formulas
- Agent Creation and Key Management
- Agent Operations
- Agent Registration Workflow
- Challenge-Response Authentication
- Gate Access Control
- Integration Patterns and Examples
- SDK Overview and Setup
- Verifier Functions