Quickstart

From zero to a registered, reputation-tracked AI agent on Arc testnet in about 10 minutes. You need Node.js 18+, Arc testnet USDC, and an RPC URL.

Testnet only. These instructions target Arc testnet (chain ID 5042002). Mainnet deployment is planned for Q1 2027.
1

Install the SDK

npm install @sigvara/protocol-sdk ethers
2

Get testnet stake tokens

Call the public faucet on the testnet SVRToken. This is a valueless test ERC-20 that exists so the staking path can be exercised — it is not the mainnet SVR, which has not launched. It mints up to 10,000 per call, one call per wallet per 24 hours.

import { ethers } from 'ethers';

const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const signer   = new ethers.Wallet(process.env.OPERATOR_PRIVATE_KEY, provider);
const svr     = new ethers.Contract(
  '0x41De2D6D55318e197a00E8f5B496eA2790e23E6c',
  ['function faucet(uint256 amount) external'],
  signer
);
await svr.faucet(ethers.parseEther('1000')); // Mints 1,000 SVR to your wallet
3

Generate an Ed25519 keypair

Your agent's cryptographic identity. The public key is stored on-chain. Store the private key securely — it cannot be recovered.

import { SigvaraAgent } from '@sigvara/protocol-sdk';

const { agent, privateKey } = SigvaraAgent.generate({
  agentAddress: signer.address,
  chainId:      5042002,
});

console.log(agent.did);
// → did:sigvara:5042002:0xYourAddress

// Store privateKey in your secrets manager — never commit it.
4

Register on-chain, then post the bond

Registration comes first, and the bond is what activates the agent — not the other way round. registerAgent leaves it PendingBond: resolvable, but not Active, not scoreable and not slashable. The first depositStake that carries it over minimumStake makes it Active. depositStake checks your allowance, sends the ERC-20 approval only if it is short, then deposits. The contract computes your didHash from the agent address and chain ID.

The agent address must also sign for its own registration, which is what stops anyone claiming an address they do not control and choosing the key verifiers would check against it. Pass a signer for that address, or { signature } if it was signed elsewhere — an HSM, a Safe, or any ERC-1271 contract agent.

import { registerAgent, depositStake } from '@sigvara/protocol-sdk';

const IDENTITY_ADDRESS = '0x7e3aFC532eE5d922ab3cc3FFb510c7C8151477Dd';
const STAKING_ADDRESS  = '0xA69d62B2a6774D21A2c15d5d83b27277eD31d35B';
const minStake = ethers.parseEther('1000'); // minimumStake on testnet

// agentSigner proves control of the agent address. Often the same wallet as the
// operator; when it is not, pass { signature } and sign with its key separately.
const agentSigner = signer;

const { didHash, txHash } = await registerAgent(
  signer, agent.agentAddress, agent.publicKeyBytes32, IDENTITY_ADDRESS, { agentSigner }
);
console.log('Registered:', `https://explorer.testnet.arc.io/tx/${txHash}`);

const bond = await depositStake(signer, didHash, minStake, STAKING_ADDRESS);
console.log('Bonded:', bond.txHash, bond.approveTxHash ? '(approval sent first)' : '');
5

Verify registration and check score

import { SigvaraVerifier } from '@sigvara/protocol-sdk';

const REPUTATION_ADDRESS = '0x6603C96275e85F724Cdf74666b399365e4cA29ed';

const verifier = new SigvaraVerifier({
  rpcUrl:    process.env.RPC_URL,
  addresses: { identity: IDENTITY_ADDRESS, reputation: REPUTATION_ADDRESS, staking: STAKING_ADDRESS },
  chainId:   5042002,
});

const identity = await verifier.getIdentity(agent.did);
console.log(identity.status);   // → Active

const { total } = await verifier.getReputation(agent.did);
console.log(total);             // → 0 until the first epoch finalizes

Two reasons that reads 0 at first. The oracle has to run an epoch and the proposed score has to clear its challenge window before anything is finalized. And total is the matured score, which climbs toward the earned one over days rather than landing at once — getEarnedScore on the contract shows the raw figure. A freshly bonded agent with no work earns 5, the community baseline, and spends it gradually.

This snippet previously called getTotalScore on the verifier, which the published SDK does not have: it went out as a plain TypeError for anyone following along. The method exists in the source now, but getReputation is used here because it works against the version actually on npm. The factor breakdown comes back in the same object.

6

Sign a challenge (A2A authentication)

When a peer agent asks your agent to prove who it is, sign the challenge with your Ed25519 key. The challenge names both your agent and who is asking, so a signature proves your agent was talking to that verifier specifically and cannot be relayed onward by whoever receives it.

const myAgent = new SigvaraAgent({
  privateKey:   process.env.AGENT_ED25519_SEED,
  agentAddress: signer.address,
  chainId:      5042002,
});

// Peer issues a challenge naming itself as the audience, then your agent signs it
const challenge = peerAgent.issueChallenge(myAgent.did);
const signature = myAgent.signChallenge(challenge.payload);

// Peer verifies: signature + on-chain pubkey + reputation threshold.
// The last argument is the expected audience. Leaving it off still compiles,
// and still accepts a proof that could have been relayed from elsewhere.
const valid   = await verifier.verifySignature(
  myAgent.did, challenge.payload, signature, 300, peerAgent.did,
);
const trusted = await verifier.meetsThreshold(myAgent.did, 60);

Requires @sigvara/protocol-sdk 1.0.0-alpha.8 or newer. Earlier versions bound no audience, so a verifier holding a valid response could present it to another verifier and be accepted as the agent.

7

Audit every action with your DID

Pass agent_did in each CounterAudit ingest call. Your on-chain identity and live reputation score are sealed into every packet.

await fetch('https://api.counteraudit.io/v1/audit/ingest', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${CA_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    connector_id: 'my-agent',
    agent_did:    myAgent.did,
    raw_event:    { action: 'tool_call', tool: 'web_search', query: '...' },
  }),
});

Next steps

Now that your agent is registered, explore the rest of the documentation: