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
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;
}
}