This page assumes you don’t trust Regent’s database. Everything below uses standard Solana tooling and public on-chain data only.
Verify an agent
You need:
- An
agent_id(from Regent’s API or the dashboard) - The
AgentRegistryprogram ID:5jBmqyeo1vUAjHbEFuY59NMGTQR8cEe9Jvz2uCwCjp3L
import { Connection, PublicKey } from "@solana/web3.js";
import { sha256 } from "js-sha256";
const conn = new Connection("https://api.devnet.solana.com");
const programId = new PublicKey("5jBmqyeo1vUAjHbEFuY59NMGTQR8cEe9Jvz2uCwCjp3L");
const agentId = "agent_b1c59d23...";
const agentIdHash = Buffer.from(sha256(agentId), "hex");
const [pda] = PublicKey.findProgramAddressSync(
[Buffer.from("agent"), agentIdHash],
programId,
);
const info = await conn.getAccountInfo(pda);
if (!info) {
console.log("Agent not anchored on-chain — do not trust");
process.exit(1);
}
// Parse with anchor IDL or borsh-deserialize manually
// Expected: status field offset, registered_at, revoked_at, etc.If the account exists and status == Active, the agent is verifiably present and not revoked. If the account is missing, the agent claim is forged.
Verify a mandate’s limits
When a disputed transaction is challenged, you want to confirm the mandate’s limits at the time of authorization.
const programId = new PublicKey("8HAzw3UFGmabsHJkAsuGLfBZG8djYQ3J1FRNUVjkseMr");
const mandateIdBytes = uuidToBytes("cab07ae3-e0e3-48d7-9e41-dc10512c4329");
const [pda] = PublicKey.findProgramAddressSync(
[Buffer.from("mandate"), mandateIdBytes],
programId,
);
const account = await program.account.mandate.fetch(pda);
console.log("Per-tx:", account.perTxLimit?.toString()); // e.g. "5000" cents = $50
console.log("Daily:", account.dailyLimit?.toString()); // e.g. "30000" cents = $300
console.log("Status:", account.status); // Active | Suspended | RevokedThese limits are what the protocol used to authorize or reject the transaction. If the API’s reported limits differ from these, trust the on-chain values.
Verify an audit event
This is the most involved recipe — and the most valuable. It proves that a specific event was in a specific batch, and that the batch is anchored on Solana.
You need:
- The event’s
payload(orpayload_hash) - The event’s
batch_id,merkle_index,merkle_proof(returned byGET /audit/events/{event_id}) - The
AuditAnchorprogram ID:8N1PpbJZKmvJjG86XWpP82XrWzp8HY5FHZuzyQTgjJas
import { createHash } from "crypto";
// 1. Canonicalize the event payload and hash it
function canonicalJson(obj: unknown): string {
// Sort keys, no whitespace
return JSON.stringify(obj, Object.keys(obj as object).sort());
}
const payloadHash = createHash("sha256")
.update(canonicalJson(event.payload))
.digest();
// 2. Walk up the Merkle tree using the proof
function combine(left: Buffer, right: Buffer): Buffer {
return createHash("sha256").update(Buffer.concat([left, right])).digest();
}
let current = payloadHash;
let index = event.merkle_index;
for (const sibling of event.merkle_proof) {
const sibBuf = Buffer.from(sibling.replace(/^0x/, ""), "hex");
if (index % 2 === 0) {
current = combine(current, sibBuf);
} else {
current = combine(sibBuf, current);
}
index = Math.floor(index / 2);
}
const computedRoot = current.toString("hex");
// 3. Read the on-chain root for this batch
const programId = new PublicKey("8N1PpbJZKmvJjG86XWpP82XrWzp8HY5FHZuzyQTgjJas");
const [batchPda] = PublicKey.findProgramAddressSync(
[Buffer.from("batch"), uuidToBytes(event.batch_id)],
programId,
);
const batchAccount = await program.account.auditBatch.fetch(batchPda);
const onchainRoot = Buffer.from(batchAccount.merkleRoot).toString("hex");
// 4. Compare
if (computedRoot === onchainRoot) {
console.log("Event verified on-chain");
} else {
console.log("Mismatch — event is either tampered or the API lied");
}If steps 1–4 produce a match, the event was provably in the batch, and the batch is anchored on Solana. No trust in Regent is required.
Programmatic verification via the CLI
A future Regent CLI will wrap these recipes so a single command suffices:
regent verify agent agent_b1c59d23...
regent verify mandate cab07ae3-e0e3-48d7-9e41-dc10512c4329
regent verify event trade-2234146-d41d57ed…each returning a green check (or a structured failure reason). Until that lands, the snippets on this page are the source of truth.
What attacks this prevents
| Attack | Prevented? | How |
|---|---|---|
| Forging a non-existent agent | Yes | No on-chain account → verification fails |
| Re-activating a revoked agent in the DB | Yes | On-chain status is still Revoked |
| Widening a mandate’s limits retroactively | Yes | On-chain per_tx_limit is fixed |
| Inserting a fake past event into the audit log | Yes | Merkle root would change → mismatch with on-chain |
| Deleting an inconvenient event | Yes | Same — leaf removal changes the root |
| Modifying an event’s payload | Yes | Hash changes → mismatch |
What this does NOT prevent
- A forged audit event that was never ingested into the protocol won’t have an on-chain proof — but it also won’t carry the
payload_hashandmerkle_prooffields, so it’s trivially identifiable as not-from-Regent - Real-time censorship (the protocol could choose not to ingest an event in the first place — but the responsible party sees all events from their agent via the dashboard, so this is detectable)