Repository navigation
Smart Contracts Reference
- Introduction
- Project Structure
- Core Components
- Architecture Overview
- Detailed Component Analysis
- Dependency Analysis
- Performance Considerations
- Troubleshooting Guide
- Conclusion
- Appendices
This document is a comprehensive reference for Sigvara’s Solidity contracts: the identity registry, staking and slashing engine, reputation store, and oracle operator bond registry. It explains the contract hierarchy, upgradeable proxy pattern, access control, public interfaces, state transitions, events, error codes, gas optimizations, usage flows, security considerations, and upgrade/migration procedures.
The system anchors AI agent identities on-chain, enforces slashable bonds, stores computed reputation scores, and optionally gates oracle operators behind a performance bond. All contracts are upgradeable via UUPS proxies and use OpenZeppelin AccessControl roles to separate governance, upgrades, and protocol operations.
This page describes the contracts on main. The Arc testnet proxies have run these contracts since 26 October 2026, so the guardian pause, the admin ruling and veto on slashes, the lapse of an unexecuted proposal, the re-file cooldown, the period ceilings, the operator signer registry, the stored proposer and fixed review window on scores, the reporter check at slash execution, the fixed claim time for a queued withdrawal and the refusal of rejected evidence are live there. The one later contract change, the bound on upholding a dispute, is on main only and reaches them at their next upgrade. The role administrators were written by the September initialisation, so the timelocked role grants of the shared bases below do not apply to them.
The core protocol lives under src/:
-
SigvaraIdentity.sol— DID registration, Ed25519 key storage, operator transfer, status management, and stake-view wiring. -
SigvaraStaking.sol— ERC-20 bond deposits, unbonding, slashing lifecycle, and reputation zeroing. -
SigvaraReputation.sol— Oracle-proposed 6-factor score store with challenge windows, maturity, and evidence roots. -
SigvaraOracleBond.sol— Operator admission, partial slashing, and unbonding for the oracle operator set. -
TimelockedGrants.solandInflowGuard.sol: two small abstract bases that the four registries inherit. Neither is deployed on its own. -
SigvaraReader.sol: a stateless, non-upgradeable read helper for contracts that check an agent's standing. It is not a registry, holds nothing, and is not read by the protocol; it has not been deployed anywhere.
graph TB
ID["SigvaraIdentity<br/>Agent registry"] --> ST["SigvaraStaking<br/>Bonds + slashing"]
ST --> REP["SigvaraReputation<br/>Score store"]
ORB["SigvaraOracleBond<br/>Operator bond"] --> REP
REP --> CONSUMERS["On-chain consumers"]
Diagram sources
- SigvaraIdentity.sol:32-140
- SigvaraStaking.sol:46-183
- SigvaraReputation.sol:76-233
- SigvaraOracleBond.sol:46-118
Section sources
- SigvaraIdentity: Base registry that computes deterministic DIDs, stores Ed25519 keys, manages operator ownership, and gates status transitions against collateral via a stake view.
- SigvaraStaking: Manages SVR token bonds per agent, enforces minimum stake, unbonding, and committee-filed slashing with admin-ruled dispute resolution.
- SigvaraReputation: Stores oracle-proposed 6-factor scores, exposes matured spendable scores, and supports evidence verification.
- SigvaraOracleBond: Tracks bonded oracle operators, admits/removes them, slashes their performance bonds, and lets an operator name a signer.
Key design principles across all contracts:
- Upgradeable via UUPS with an
UPGRADER_ROLE, which administers itself so the admin cannot grant it. - Role-based access control using OpenZeppelin
AccessControlUpgradeable, throughTimelockedGrantsin the four registries. - Append-only storage layout changes to preserve live proxy state.
- Fail-closed initialization where unset dependencies block unsafe behavior.
- Floors and ceilings on the periods, the window and the maturity rate, held in the initializers as well as the setters.
- A guardian pause on new inflows (
InflowGuard) that never covers exits, rulings or slash execution.
Section sources
- SigvaraIdentity.sol:32-161
- SigvaraStaking.sol:46-218
- SigvaraReputation.sol:76-260
- SigvaraOracleBond.sol:46-145
The architecture layers ERC-8004 identity with Sigvara’s trust layer:
- Identity is anchored by
SigvaraIdentity, which also binds operator control and agent status. - Staking backs agents with SVR and enables slashing; it coordinates with identity and reputation.
- Reputation stores computed scores from oracles and exposes threshold checks.
- Oracle bond ensures only admitted, bonded operators can propose scores when configured.
sequenceDiagram
participant Op as "Operator"
participant ID as "SigvaraIdentity"
participant ST as "SigvaraStaking"
participant REP as "SigvaraReputation"
participant ORB as "SigvaraOracleBond"
Op->>ID : registerAgent(agentAddress, ed25519PubKey, signature)
ID-->>Op : AgentRegistered(didHash, operator, agentAddress, pubKey)
Op->>ST : depositStake(didHash, amount)
ST->>ID : updateStatus(didHash, Active)
Note over ST,ID : Agent becomes Active once minimumStake is met
ORB->>REP : (optional) admit operator if operatorBond is set
REP-->>ORB : isActiveOperator check
REP->>REP : proposeReputation(didHash, data, evidenceRoot)
REP-->>REP : finalizeReputation(didHash) after challenge window
Diagram sources
- SigvaraIdentity.sol:295-321
- SigvaraStaking.sol:320-363
- SigvaraReputation.sol:378-448
- SigvaraOracleBond.sol:323-331
Identity, staking, reputation and the operator bond registry all inherit these two abstract contracts.
- Each registry makes
UPGRADER_ROLEits own role admin, and administers the roles that can move bonded funds or change an agent's standing with it:SLASHING_COMMITTEE_ROLE(staking, reputation),STAKING_CORE_ROLE(identity, reputation) andSLASHER_ROLE(bond registry). Granting one therefore takes the timelock's delay. - It overrides
revokeRoleso thatDEFAULT_ADMIN_ROLEcan revoke at once any role the upgrader administers, exceptUPGRADER_ROLE.ORACLE_ROLEandGUARDIAN_ROLEstay with the admin. - It adds no storage.
-
pauseInflows()is callable only byGUARDIAN_ROLE. It closes the entries markedwhenInflowsOpenforPAUSE_DURATION(3 days):registerAgent,depositStake,proposeReputation,proposeIfEmptyanddepositBond. Nothing else is covered. - The next pause cannot start until
PAUSE_COOLDOWN(1 day) after the last one would have ended, counted from its start even if it was lifted early. -
resumeInflows()lifts a pause early and is callable by the guardian or the admin. Views:inflowsPaused(),inflowsPausedUntil(),lastInflowPauseAt(). - Events:
InflowsPaused,InflowsResumed. Errors:InflowsPausedUntil,InflowsNotPaused,InflowsAlreadyPaused,PauseCooldownActive. - State lives in an ERC-7201 namespaced slot, so adding it to a live proxy shifts no existing variable.
Section sources
Base registry for agent identities and operator control.
- Deterministic DID derivation and registration with signed proof of agent control.
- Ed25519 public key storage and rotation.
- Status transitions: PendingBond → Active ↔ Suspended → Slashed.
- Two-step operator transfer with collateral checks.
- Stake view integration to gate activation and transfers.
-
registrationDigest(agentAddress, operator, ed25519PubKey)returns digest bytes32. -
verifyRegistration(agentAddress, operator, ed25519PubKey, signature)returns bool. -
registerAgent(agentAddress, ed25519PubKey, signature)returns didHash. Closed while a guardian pause is running. -
rotatePublicKey(didHash, newEd25519PubKey). -
updateStatus(didHash, newStatus). -
offerOperatorTransfer(didHash, newOperator). -
cancelOperatorTransfer(didHash). -
acceptOperatorTransfer(didHash). -
setStakeView(stakeView_), callable only byUPGRADER_ROLE(the timelock), because what it points at decides who counts as bonded. -
clearSlashSuspension(didHash). - View functions:
computeDidHash,getIdentity,isActive,getOperatorAgents,operatorAgentCount,getOperatorAgentsPaged.
stateDiagram-v2
[*] --> PendingBond : registerAgent()
PendingBond --> Active : depositStake() reaches minimumStake
Active --> Suspended : operator.updateStatus() or StakingCore.initiateSlash()
Suspended --> Active : operator.updateStatus() or resolveDispute(false) or cancelSlash()/vetoSlash()/expireDispute()/expireSlash()
Active --> Slashed : StakingCore.executeSlash()
Suspended --> Slashed : StakingCore.executeSlash()
Slashed --> [*] : terminal
Diagram sources
- SigvaraIdentity.sol:56-64
- SigvaraIdentity.sol:344-397
- SigvaraStaking.sol:473-528
- SigvaraStaking.sol:712-776
AgentRegistered(didHash, operator, agentAddress, ed25519PubKey)StakeViewSet(stakeView)OperatorTransferOffered(didHash, from, to)OperatorTransferCancelled(didHash, by)OperatorTransferred(didHash, from, to)AgentStatusUpdated(didHash, newStatus)PublicKeyRotated(didHash, newEd25519PubKey)
-
AlreadyRegistered,NotRegistered,NotOperator,ZeroPubKey,ZeroAgentAddress,SlashedAgentImmutable,SlashSuspensionLocked,StakeViewNotSet,InsufficientCollateral,NoTransferOffered,NotOfferedOperator,TransferWhileSlashPending,SameOperator,CannotReturnToPendingBond,BadRegistrationSignature.
- Appended storage fields preserve proxy layout.
- Constant-time removal from operator index via swap-and-pop with recorded positions.
- Paged operator listing avoids unbounded reads for callers.
Section sources
- SigvaraIdentity.sol:32-161
- SigvaraIdentity.sol:240-321
- SigvaraIdentity.sol:328-468
- SigvaraIdentity.sol:470-535
- SigvaraIdentity.sol:560-615
Manages agent bonds and slashing.
- Deposit and track SVR token stakes per agent.
- Enforce minimum stake and unbonding period.
- Initiate slash proposals, handle disputes, execute slashes, and distribute proceeds.
- Zero reputation upon slash.
-
depositStake(didHash, amount). Closed while a guardian pause is running. -
initiateWithdrawal(didHash, amount). Fixes the claim time when it queues. -
claimWithdrawal(didHash). Honours the claim time fixed when the withdrawal was queued. -
initiateSlash(didHash, victim, evidenceHash). Committee only; refused for one challenge period after the last dropped proposal against the agent, and refused for evidence the admin already rejected for the agent. -
disputeSlash(didHash). -
resolveDispute(didHash, uphold). Admin only; upholding waits for the challenge deadline and, onmain, is refused once the dispute can be expired (DisputeResolutionExpired). -
expireDispute(didHash). Permissionless once the dispute resolution period (14 days) has passed. -
expireSlash(didHash). Permissionless once the execution period (14 days) has passed since the challenge deadline of a pending proposal. -
cancelSlash(didHash). Committee only. -
vetoSlash(didHash). Admin only; drops a pending or disputed proposal and records its evidence as rejected for the agent. -
executeSlash(didHash). Permissionless once the challenge deadline has passed, as long as the reporter still holds the committee role. -
claimSlashProceeds()returns amount. - Admin:
setMinimumStake,setChallengePeriod,setUnbondingPeriod. - Views:
getStake,hasMinimumStake,getPendingWithdrawal,getSlashProposal,lastDroppedAt,unbondingClaimableAt,evidenceRejected.
flowchart TD
Start(["Initiate Slash"]) --> CheckRoles["Check SLASHING_COMMITTEE_ROLE"]
CheckRoles --> ValidateVictim{"Victim != Reporter?"}
ValidateVictim --> |No| RevertVictim["Revert VictimIsReporter"]
ValidateVictim --> |Yes| CheckStake{"Total stake > 0?"}
CheckStake --> |No| RevertNoStake["Revert NoStake"]
CheckStake --> WriteProposal["Write SlashProposal(Pending)"]
WriteProposal --> SuspendAgent["Update Identity to Suspended"]
SuspendAgent --> EmitInitiated["Emit SlashInitiated"]
EmitInitiated --> DisputePath{"Disputed within window?"}
DisputePath --> |Yes| Dispute["State=Disputed"]
Dispute --> Resolve["Admin rules: uphold or drop"]
Resolve --> Uphold["Settle Slash"]
Resolve --> Drop["Drop Proposal"]
DisputePath --> |No| Execute["Anyone executes after window"]
Execute --> Settle["Settle Slash"]
Settle --> Burn["Burn 50%"]
Settle --> PayVictim["Credit 25% to victim"]
Settle --> PayReporter["Credit 25% to reporter"]
Settle --> MarkSlashed["Mark Identity Slashed"]
Settle --> ZeroRep["Zero Reputation"]
Diagram sources
-
StakeDeposited,WithdrawalInitiated,WithdrawalClaimed -
SlashInitiated,SlashDisputed,SlashExecuted,SlashCancelled,SlashVetoed SlashProceedsClaimed-
MinimumStakeUpdated,ChallengePeriodUpdated,UnbondingPeriodUpdated
-
InsufficientStake,NoStake,AgentNotActive,SlashAlreadyPending,NoActivePendingSlash,ChallengePeriodActive,ChallengePeriodExpired,NotOperator,ZeroAddress,NoWithdrawalPending,WithdrawalAlreadyPending,UnbondingPeriodActive,VictimIsReporter,PeriodTooShort,PeriodTooLong,MinimumStakeZero,SlashNotDisputed,SlashCooldownActive,DisputeResolutionActive,DisputeResolutionExpired(onmain),ExecutionPeriodActive,NothingClaimable.
- Fee-on-transfer tokens are handled safely by measuring actual received amounts.
- Rebasing tokens are unsupported due to fixed accounting.
- Unbonding queue remains slashable until claimed.
- Minimum and maximum challenge/unbonding periods (3 to 30 days and 1 to 90 days) enforced by the admin setters and by
initialize; a zero minimum stake is refused. - The committee files and the admin rules, so no single key is accuser, judge and payee. A dispute cannot bring a slash forward, a proposal nobody executes can be lapsed by anyone, and a dropped proposal starts a re-file cooldown of one challenge period.
Section sources
- SigvaraStaking.sol:46-218
- SigvaraStaking.sol:320-363
- SigvaraStaking.sol:377-461
- SigvaraStaking.sol:473-776
- SigvaraStaking.sol:793-883
Stores oracle-proposed 6-factor reputation scores and exposes matured spendable values.
- Accept oracle proposals with factor caps and evidence roots.
- Challenge window with committee rejection.
- Finalize scores and compute matured spendable totals.
- Verify Merkle evidence leaves.
- Optional operator bond gating via
SigvaraOracleBond.
-
proposeReputation(didHash, data, evidenceRoot). Closed while a guardian pause is running. The pending score records its proposer andfinalizableAt, the time it can first be finalized, fixed when it is proposed. -
proposeIfEmpty(didHash, data, evidenceRoot). Reverts instead of replacing a pending proposal, unless that proposal's proposer is no longer authorized. -
finalizeReputation(didHash). Permissionless, but refuses a proposal whose proposer no longer holds ORACLE_ROLE or, with an operator registry configured, is no longer an active operator or signer. -
rejectReputation(didHash). Committee only, within the window fixed at proposal time. -
zeroReputation(didHash)(STAKING_CORE_ROLE). - Admin:
initializeV2,initializeV3,initializeV4,setOperatorBond(UPGRADER_ROLE, the timelock's role),setMaturityRate(above 0, at most 100 points a day),setChallengeWindow(1 hour to 7 days). - Views:
getReputation,getPendingScore,getTotalScore,verifyEvidence,getEarnedScore,meetsThreshold.
- Six capped factors summing to 100: fee, success, age, external, community, propagation.
- Matured score climbs toward earned score at a configurable rate per day.
- Handover restarts maturity to prevent immediate spending of purchased identities.
-
ScoreProposed,ReputationUpdated,ScoreRejected,ReputationZeroed -
ChallengeWindowUpdated,IdentityRegistrySet,MaturityRateUpdated,OperatorBondSet
-
ScoreOutOfRange,NoScorePending,ScoreAlreadyPending,ChallengeWindowActive,ChallengeWindowExpired,IdentityRegistryNotSet,StakeViewNotSet,AgentNotRegistered,AgentSlashed,AgentNotBonded,MaturityRateZero,MaturityRateTooHigh,ChallengeWindowTooShort,ChallengeWindowTooLong,OracleNotBonded,ProposerNotAuthorized.
-
verifyEvidence(didHash, leaf, proof)uses MerkleProof against stored root.
Section sources
- SigvaraReputation.sol:76-260
- SigvaraReputation.sol:378-504
- SigvaraReputation.sol:513-557
- SigvaraReputation.sol:566-672
- SigvaraReputation.sol:678-806
Performance-bond registry for oracle operators.
- Deposit/top-up operator bonds.
- Admit/remove operators.
- Partial slashing with demotion below bondAmount.
- Unbonding cooldown before withdrawal.
-
depositBond(amount). Closed while a guardian pause is running, and refused for an address that is some operator's signer. -
initiateUnbond(). -
withdrawBond(). Also releases the operator's signer. -
setSigner(signer). Active operators only; names the key that signs for the operator, which must be an address nobody else uses in the registry. -
clearSigner(). Any status; takes effect in the same block. -
admit(operator). -
removeOperator(operator). Does not release the operator's signer. -
slash(operator, amount).SLASHER_ROLE, which is granted through the timelock; slashing to zero also releases the signer. - Admin:
setBondAmount(above zero),setUnbondingPeriod(1 to 90 days),setSlashBeneficiary(UPGRADER_ROLE; refuses the zero address and any holder of the slasher role). - Views:
isActiveOperator(a registered signer answers for its operator),bondOf,signerOf,operatorOfSigner.
stateDiagram-v2
[*] --> Bonded : depositBond()
Bonded --> Active : admit() with bond >= bondAmount
Active --> Exiting : initiateUnbond() or removeOperator()
Bonded --> Exiting : initiateUnbond() or removeOperator()
Exiting --> None : withdrawBond() after cooldown
Active --> Bonded : slash() drops below bondAmount
Bonded --> None : slash() reduces bond to 0
Diagram sources
-
BondDeposited,OperatorAdmitted,OperatorSlashed,UnbondInitiated,BondWithdrawn,OperatorRemoved -
BondAmountUpdated,UnbondingPeriodUpdated,SlashBeneficiaryUpdated -
SignerSet,SignerCleared
-
ZeroAddress,ZeroAmount,PeriodTooShort,PeriodTooLong,WrongStatus,InsufficientBond,SlashExceedsBond,UnbondingActive,NoBond,SignerNotFree,AlreadySigner,NoSigner,SlasherIsBeneficiary.
Section sources
- SigvaraOracleBond.sol:46-145
- SigvaraOracleBond.sol:210-271
- SigvaraOracleBond.sol:323-419
- SigvaraOracleBond.sol:435-494
Contract-level dependencies:
-
SigvaraStakingimportsSigvaraIdentityand uses a narrow interface toSigvaraReputation(IReputationZero). -
SigvaraReputationimportsSigvaraIdentityand uses a narrow interface toSigvaraOracleBond(IOperatorSet, insrc/interfaces/IOperatorSet.sol, which the bond registry implements andSigvaraEpochFeesuses too). -
SigvaraIdentitydeclares a narrow interfaceIStakeViewto avoid circular imports while checking collateral. - All four registries inherit
TimelockedGrantsandInflowGuard.
graph LR
ST["SigvaraStaking"] --> ID["SigvaraIdentity"]
ST -.-> REP["SigvaraReputation (interface IReputationZero)"]
REP --> ID
REP -.-> ORB["SigvaraOracleBond (interface IOperatorSet)"]
Diagram sources
Section sources
- Fee-on-transfer safety: Both staking and oracle bond measure actual received amounts rather than trusting caller-supplied amounts.
- Storage layout stability: New variables are appended to preserve live proxy state without renumbering mappings.
- Constant-time operator index removal: Swap-and-pop with recorded positions avoids linear scans on hot paths.
- Paged queries: Operator agent lists support pagination to avoid unbounded reads.
- Fail-closed initialization: Missing stake view or identity registry blocks unsafe transitions.
- Period guards: Challenge and unbonding periods have lower bounds to prevent liveness attacks and upper bounds so one value cannot lock every queued exit.
Common issues and resolutions:
-
Registration fails with signature error: Ensure the agent address signs the unprefixed
registrationDigest; wallets apply EIP-191 prefix automatically. -
Activation fails with insufficient collateral: Confirm the agent holds at least
minimumStakeand thatstakeViewis set on identity. - Slash proposal reverts: Check that the victim is not the reporter, total stake is non-zero, no active slash exists, and no proposal against the agent was dropped less than one challenge period ago.
- Dispute cannot be filed: Ensure the challenge window has not expired and the caller is the operator.
- Finalization fails: Ensure the challenge window elapsed, a pending score exists, and its proposer is still authorized.
-
Operator cannot propose scores: If
operatorBondis set, the caller must be an admitted, bonded operator inSigvaraOracleBond, or the signer one has named. -
Registration, deposit, proposal or bond deposit reverts with
InflowsPausedUntil: A guardian pause is running; it ends by itself after three days.
Section sources
- SigvaraIdentity.sol:240-321
- SigvaraStaking.sol:473-528
- SigvaraReputation.sol:378-448
- SigvaraOracleBond.sol:323-331
Sigvara’s contracts form a cohesive trust layer over ERC-8004 identity: deterministic DID anchoring, slashable bonds, computed reputation with maturity, and optional operator bonding. The design emphasizes safe upgrades, role separation, fail-closed configuration, and robust economic incentives. Consumers should rely on getTotalScore and meetsThreshold for decisions, and integrate identity checks alongside reputation thresholds.
- Compute
registrationDigest(agentAddress, operator, ed25519PubKey). - Have the agent address sign the digest.
- Call
registerAgent(agentAddress, ed25519PubKey, signature)onSigvaraIdentity. - Approve and call
depositStake(didHash, amount)onSigvaraStaking. - On first deposit reaching
minimumStake, the agent becomes Active.
Section sources
- Deposit:
depositStake(didHash, amount). - Queue withdrawal:
initiateWithdrawal(didHash, amount). - Claim withdrawal:
claimWithdrawal(didHash)after unbonding period. - Query stake:
getStake(didHash)andhasMinimumStake(didHash).
Section sources
- Get earned score:
getEarnedScore(didHash). - Get matured score:
getTotalScore(didHash). - Threshold check:
meetsThreshold(didHash, threshold). - Evidence verification:
verifyEvidence(didHash, leaf, proof).
Section sources
- Token assumptions: Only exact-transfer ERC-20 tokens are fully supported; rebasing tokens are explicitly unsupported.
- Role separation: Governance timelock targets mainnet; testnet currently uses single EOAs. On mainnet the roles that move funds are granted through the timelock, the admin rules on disputed slashes and can veto, and a guardian can pause new inflows only.
-
Upgrade safety: UUPS upgrades gated by
UPGRADER_ROLE, which administers itself; initialize methods enforce fail-closed wiring. -
Launch floors: On chain 5042
script/Deploy.s.solrefuses a minimum stake under 10,000 SVR andscript/DeployOracleBond.s.sola bond under 2,500,000 SVR, refuses periods outside the contracts' floors and ceilings, and requires a guardian that is not the deployer, oracle, committee or slasher. - Slash integrity: Total stake (active + queued) is checked to prevent evasion via unbonding.
- Reputation gating: Scores require a bonded agent and valid identity; handover restarts maturity.
Section sources
- Use UUPS proxies; proxy addresses are stable while the implementation behind them changes.
- Deploy new implementation and call
upgradeToAndCallwith versioned initializers:-
initializeV2for setting stake view or unbonding periods. -
initializeV3for wiring identity registry in reputation. -
initializeV4for setting maturity rate.
-
- Reinitializers are
DEFAULT_ADMIN_ROLE-gated, and the timelock is not the admin, so behind a timelock the upgrade lands with empty data and the Safe calls the reinitializer in a second transaction. - Keep storage layout append-only to preserve live state.
- Record implementations off-chain and verify against chain state.
Section sources
- 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