IAgent.getAgentIds

getAgentIds(
  address wallet,
  PageRequest pageRequest
) external view returns (uint256[] agentIds, PageResponse pageResponse)

Paginated lookup by agent wallet: returns the IDs of the agents whose ERC-8004 agent wallet is wallet. The agent wallet is set to the registrant by register and changed with setAgentWallet / unsetAgentWallet; when the agent NFT is transferred, its entry is removed. So this is not a list of the agents an address OWNS — for that, use the IdentityRegistry's ERC-721 surface (balanceOf, Transfer events). The Agent precompile exposes this method because walking IdentityRegistry storage from inside a contract is too expensive; it reads a chain-side index. Registration, the agent URI, metadata, the agent wallet and ERC-721 ownership live on the ERC-8004 IdentityRegistry preinstall at 0x8004000000000000000000000000000000000001 — call it directly. The registry has no attest or revoke function.

Parameters

Name Type Required Description
wallet address ✓ The wallet address to look up.
pageRequest tuple ✓ Standard pagination tuple (bytes key, uint64 offset, uint64 limit, bool countTotal, bool reverse). Set key or offset, not both: a request with both reverts with QueryFailed. A tuple that does not ABI-decode reverts with ABISetupFailed.

Returns

Type: tuple

Returns (uint256[] agentIds, PageResponse pageResponse). pageResponse.nextKey is empty when the last page is reached.

Errors

Code Name Description
InvalidNumberOfArgs InvalidNumberOfArgs Declared in the shared IPrecompile error set as InvalidNumberOfArgs(uint256 expected, uint256 got), but getAgentIds does not revert with it for a wrong argument count: calldata too short for the two arguments reverts with ABISetupFailed, and bytes after the two arguments are ignored.
InvalidAddress InvalidAddress Declared in the shared IPrecompile error set as InvalidAddress(string bad), but not raised for the wallet argument: a 32-byte wallet value with non-zero upper bytes still decodes, and the lookup uses its low 20 bytes.
InvalidPageRequest InvalidPageRequest Declared in the shared IPrecompile error set as InvalidPageRequest(string method, uint256 index, string value), but not what a bad pageRequest returns here: a tuple that does not ABI-decode reverts with ABISetupFailed, and one with both key and offset set reverts with QueryFailed.
QueryFailed QueryFailed Reverts when the underlying chain-side index lookup fails or rejects the request, for example a pageRequest with both key and offset set (reason invalid request, either offset or key is expected, got both). Encoded as QueryFailed(string queryMethod, string reason).
ABISetupFailed ABISetupFailed Reverts when the calldata cannot be decoded against the precompile's ABI. An unknown 4-byte selector gives the reason no method with id: 0x…; arguments that are too short or do not ABI-decode give the decoder's message, for example abi: cannot marshal in to go type: length insufficient 32 require 64. Encoded as ABISetupFailed(string reason). An unknown selector does not revert with UnknownMethod, although the precompile declares it.

Examples

Paginate all agent IDs for a wallet

Iterate until nextKey is empty to collect the full list.

import { createPublicClient, http } from "viem";

const AGENT_PRECOMPILE = "0x100000000000000000000000000000000000000A" as const;
const agentAbi = [{
  type: "function", name: "getAgentIds", stateMutability: "view",
  inputs: [
    { name: "wallet", type: "address" },
    { name: "pageRequest", type: "tuple", components: [
      { name: "key",        type: "bytes"  },
      { name: "offset",     type: "uint64" },
      { name: "limit",      type: "uint64" },
      { name: "countTotal", type: "bool"   },
      { name: "reverse",    type: "bool"   },
    ]},
  ],
  outputs: [
    { name: "agentIds", type: "uint256[]" },
    { name: "pageResponse", type: "tuple", components: [
      { name: "nextKey", type: "bytes"  },
      { name: "total",   type: "uint64" },
    ]},
  ],
}] as const;

const publicClient = createPublicClient({ transport: http("https://rpc-testnet.maroo.io") });
// TODO: replace with the AGENT WALLET (IdentityRegistry.getAgentWallet(agentId)) before production —
// not the owner: the index is keyed by agent wallet. For the agents an address owns,
// use the registry's ERC-721 balanceOf / Transfer events.
const wallet = "0x8F3ac2B1d9E74c05A6B18FE27Dc4913e5A0F7b62";

let key: `0x${string}` = "0x";
const allIds: bigint[] = [];
do {
  const [ids, page] = await publicClient.readContract({
    address: AGENT_PRECOMPILE,
    abi: agentAbi,
    functionName: "getAgentIds",
    args: [wallet, { key, offset: 0n, limit: 100n, countTotal: false, reverse: false }],
  });
  allIds.push(...ids);
  key = page.nextKey as `0x${string}`;
} while (key !== "0x");

Decoding shared IPrecompile errors

Malformed calldata reverts with ABISetupFailed and a lookup the index rejects with QueryFailed, so the decoder lists both. The other entries are the shared IPrecompile signatures; the old bespoke InvalidArgsLength(method, got, want) is gone.

import { BaseError, ContractFunctionRevertedError, decodeErrorResult } from "viem";

const iPrecompileErrorsAbi = [
  { type: "error", name: "InvalidNumberOfArgs",
    inputs: [{ name: "expected", type: "uint256" }, { name: "got", type: "uint256" }] },
  { type: "error", name: "InvalidAddress", inputs: [{ name: "bad", type: "string" }] },
  { type: "error", name: "InvalidPageRequest",
    inputs: [
      { name: "method", type: "string"  },
      { name: "index",  type: "uint256" },
      { name: "value",  type: "string"  },
    ] },
  { type: "error", name: "QueryFailed",
    inputs: [{ name: "queryMethod", type: "string" }, { name: "reason", type: "string" }] },
  { type: "error", name: "ABISetupFailed", inputs: [{ name: "reason", type: "string" }] },
] as const;

try {
  await publicClient.readContract({
    address: AGENT_PRECOMPILE,
    abi: agentAbi,
    functionName: "getAgentIds",
    args: [wallet, { key: "0x", offset: 0n, limit: 100n, countTotal: false, reverse: false }],
  });
} catch (err) {
  // viem keeps the revert data on the ContractFunctionRevertedError in the cause chain, not on err.
  const revert = err instanceof BaseError ? err.walk((e) => e instanceof ContractFunctionRevertedError) : null;
  if (revert instanceof ContractFunctionRevertedError && revert.raw) {
    const decoded = decodeErrorResult({ abi: iPrecompileErrorsAbi, data: revert.raw });
    console.error("getAgentIds reverted:", decoded.errorName, decoded.args);
  } else {
    throw err;
  }
}
ESC
Type to search