AgentRegistry is the on-chain source of truth for whether an agent exists and whether it is active. Every off-chain claim about an agent can be checked against this program.
| Program ID (devnet) | 5jBmqyeo1vUAjHbEFuY59NMGTQR8cEe9Jvz2uCwCjp3L |
| Framework | Anchor 0.30 |
| Upgradeable? | No — non-upgradeable by design (ADR-010) |
| Source | packages/contracts-solana/programs/agent-registry |
Account layout
Each agent gets a Program Derived Address (PDA) keyed by its agent ID hash:
#[account]
pub struct Agent {
pub agent_id_hash: [u8; 32], // sha256(agent_id)
pub did_hash: [u8; 32], // sha256(canonical DID payload)
pub responsible_party_hash: [u8; 32], // sha256(responsible_party_id)
pub status: AgentStatus, // Active | Revoked
pub registered_at: i64, // unix seconds
pub revoked_at: Option<i64>,
pub bump: u8,
}The PDA seed is [b"agent", agent_id_hash], so anyone can re-derive the address and read the account.
Only hashes are stored — never the raw agent ID, DID payload, or responsible-party ID. This is for privacy: the on-chain record proves existence and status but doesn’t disclose the human behind the agent.
Instructions
register_agent
Writes a new Agent account in Active state.
| Account | Type | Notes |
|---|---|---|
agent | PDA | Initialized; payer-funded |
authority | Signer | Must be the protocol authority |
payer | Signer | Pays rent |
system_program | Program | — |
| Arg | Type | Notes |
|---|---|---|
agent_id_hash | [u8; 32] | SHA-256 of the agent ID string |
did_hash | [u8; 32] | SHA-256 of the canonical DID document |
responsible_party_hash | [u8; 32] | SHA-256 of the responsible party UUID |
Reverts if the PDA already exists.
revoke_agent
Flips status to Revoked and stamps revoked_at.
| Account | Type | Notes |
|---|---|---|
agent | Mutable PDA | Must exist; must be Active |
authority | Signer | Must be the protocol authority |
Reverts if the agent doesn’t exist or is already revoked. The protocol’s blockchain-worker calls this when a responsible party (or automated workflow) revokes an agent off-chain.
Trust model
Only the protocol authority can call register_agent or revoke_agent. This is intentional:
- Registration requires KYC verification, which the protocol enforces off-chain
- Revocation must follow the responsible-party authorization model
- A public, permissionless instruction would let anyone register or revoke arbitrary agents
The authority keypair lives in AWS KMS; only the blockchain-worker service can sign with it.
Verifying an agent off-chain
import { Connection, PublicKey } from "@solana/web3.js";
import { Program, AnchorProvider } from "@coral-xyz/anchor";
import { sha256 } from "js-sha256";
const connection = new Connection("https://api.devnet.solana.com");
const programId = new PublicKey("5jBmqyeo1vUAjHbEFuY59NMGTQR8cEe9Jvz2uCwCjp3L");
// Re-derive the agent's PDA
const agentIdHash = Buffer.from(sha256("agent_b1c59d23..."), "hex");
const [agentPda] = PublicKey.findProgramAddressSync(
[Buffer.from("agent"), agentIdHash],
programId,
);
// Read it
const account = await program.account.agent.fetch(agentPda);
console.log("Status:", account.status); // Active | Revoked
console.log("Registered:", account.registeredAt);
console.log("Revoked:", account.revokedAt);If the account is missing → the agent was never anchored. If status is Revoked → don’t trust any authorizations from this agent regardless of what the off-chain API says.