Quickstart

Use a deployed ERC-8004 Identity Adapter from TypeScript with viem.

Prerequisites#

  • Node.js 18+
  • viem: npm install viem
  • An RPC URL for the target chain (this guide uses Sepolia)
  • A wallet with a small amount of ETH on the target chain for gas
  • An external token you control (ERC-721, ERC-1155, or ERC-6909)

Adapter addresses#

ChainChain IDAdapter Proxy
Ethereum10xde152AfB7db5373F34876E1499fbD893A82dD336
Base84530x270d25D2c59A8bcA1B0f40ad95fF7806c0025c27
Sepolia111551110x7621630cB63a73a194f45A3E6801B8C6A7eC2f92

Set up viem#

import { createPublicClient, createWalletClient, http, parseEventLogs, toHex } from 'viem';
import { sepolia } from 'viem/chains';
import { privateKeyToAccount } from 'viem/accounts';

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const publicClient = createPublicClient({ chain: sepolia, transport: http(process.env.RPC_URL) });
const walletClient = createWalletClient({ chain: sepolia, transport: http(process.env.RPC_URL), account });

const ADAPTER = '0x7621630cB63a73a194f45A3E6801B8C6A7eC2f92' as const;

Adapter ABI#

Minimal fragment for this quickstart:

const ADAPTER_ABI = [
  {
    type: 'function', name: 'register', stateMutability: 'nonpayable',
    inputs: [
      { name: 'standard', type: 'uint8' },
      { name: 'tokenContract', type: 'address' },
      { name: 'tokenId', type: 'uint256' },
      { name: 'agentURI', type: 'string' },
    ],
    outputs: [{ name: 'agentId', type: 'uint256' }],
  },
  {
    type: 'function', name: 'setAgentURI', stateMutability: 'nonpayable',
    inputs: [
      { name: 'agentId', type: 'uint256' },
      { name: 'newURI', type: 'string' },
    ],
    outputs: [],
  },
  {
    type: 'function', name: 'setMetadata', stateMutability: 'nonpayable',
    inputs: [
      { name: 'agentId', type: 'uint256' },
      { name: 'metadataKey', type: 'string' },
      { name: 'metadataValue', type: 'bytes' },
    ],
    outputs: [],
  },
  {
    type: 'function', name: 'getAgentWallet', stateMutability: 'view',
    inputs: [{ name: 'agentId', type: 'uint256' }],
    outputs: [{ type: 'address' }],
  },
  {
    type: 'event', name: 'AgentBound',
    inputs: [
      { name: 'agentId', type: 'uint256', indexed: true },
      { name: 'standard', type: 'uint8', indexed: true },
      { name: 'tokenContract', type: 'address', indexed: true },
      { name: 'tokenId', type: 'uint256', indexed: false },
      { name: 'registeredBy', type: 'address', indexed: false },
    ],
  },
] as const;

Register an agent#

Bind an external ERC-721 token to a new ERC-8004 identity using the no-metadata convenience overload. The caller must currently own tokenId on tokenContract.

const ERC721 = 0;          // 0 = ERC721, 1 = ERC1155, 2 = ERC6909
const NFT = '0xYourNftContractAddress' as const;
const TOKEN_ID = 1n;

const registerHash = await walletClient.writeContract({
  address: ADAPTER,
  abi: ADAPTER_ABI,
  functionName: 'register',
  args: [ERC721, NFT, TOKEN_ID, 'ipfs://your-agent-metadata.json'],
});

const receipt = await publicClient.waitForTransactionReceipt({ hash: registerHash });

const [event] = parseEventLogs({
  abi: ADAPTER_ABI,
  eventName: 'AgentBound',
  logs: receipt.logs,
});
const agentId = event.args.agentId;

Add metadata#

After registering, write additional metadata keys. The bound token's holder is the only address that can do this.

await walletClient.writeContract({
  address: ADAPTER,
  abi: ADAPTER_ABI,
  functionName: 'setMetadata',
  args: [agentId, 'description', toHex('My agent')],
});

Update the agent URI#

await walletClient.writeContract({
  address: ADAPTER,
  abi: ADAPTER_ABI,
  functionName: 'setAgentURI',
  args: [agentId, 'ipfs://new-metadata.json'],
});

The adapter checks the bound token contract on every write. If you no longer control the token, the call reverts.

Read the bound wallet#

const wallet = await publicClient.readContract({
  address: ADAPTER,
  abi: ADAPTER_ABI,
  functionName: 'getAgentWallet',
  args: [agentId],
});

Next steps#

  • Concepts, the binding model, shared control, and wallet proofs.
  • Contract Reference, the full function list including the metadata-array register overload.