read.wallet.allowances
Read-onlyIdempotent
Check ERC20 token allowances for a spender address to avoid redundant approvals before transactions.
Instructions
Check ERC20 token allowances for a spender address. Use before write.wallet.approve to avoid redundant approvals — skip approving if the current allowance is already sufficient.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| owner_address | Yes | Token owner address (the wallet granting approval) | |
| spender_address | Yes | Spender address to check allowance for (e.g. Arcadia account address) | |
| token_addresses | Yes | ERC20 token contract addresses to check | |
| chain_id | No | Chain ID: 8453 (Base) or 130 (Unichain) |
Output Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| tokens | Yes |
Implementation Reference
- src/tools/read/wallet.ts:133-190 (handler)The handler for "read.wallet.allowances" tool, which uses a multicall to query ERC20 allowance, decimals, and symbol for given token addresses and returns the allowance details.
async ({ owner_address, spender_address, token_addresses, chain_id }) => { try { const validChainId = validateChainId(chain_id); const owner = validateAddress(owner_address, "owner_address"); const spender = validateAddress(spender_address, "spender_address"); const client = getPublicClient(validChainId, chains); const calls = token_addresses.flatMap((addr) => [ { address: addr as `0x${string}`, abi: erc20Abi, functionName: "allowance" as const, args: [owner, spender], }, { address: addr as `0x${string}`, abi: erc20Abi, functionName: "decimals" as const }, { address: addr as `0x${string}`, abi: erc20Abi, functionName: "symbol" as const }, ]); const results = (await client.multicall({ contracts: calls, allowFailure: true })) as { status: string; result?: unknown; }[]; const tokens = token_addresses.map((addr, i) => { const allowRes = results[i * 3]; const decRes = results[i * 3 + 1]; const symRes = results[i * 3 + 2]; const allowance = allowRes?.status === "success" ? BigInt(allowRes.result as bigint) : 0n; const decimals = decRes?.status === "success" ? Number(decRes.result) : 18; const symbol = symRes?.status === "success" ? String(symRes.result) : "???"; return { address: addr, symbol, decimals, allowance: String(allowance), formatted: formatUnits(allowance, decimals), is_max_approval: allowance === MAX_UINT256, }; }); return { content: [{ type: "text" as const, text: JSON.stringify({ tokens }, null, 2) }], structuredContent: { tokens }, }; } catch (err) { return { content: [ { type: "text" as const, text: `Error: ${err instanceof Error ? err.message : String(err)}`, }, ], isError: true, }; } }, - src/tools/read/wallet.ts:111-132 (registration)Tool registration for "read.wallet.allowances" within the registerWalletTools function.
server.registerTool( "read.wallet.allowances", { annotations: { title: "Get Token Allowances", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, }, description: "Check ERC20 token allowances for a spender address. Use before write.wallet.approve to avoid redundant approvals — skip approving if the current allowance is already sufficient.", inputSchema: { owner_address: z.string().describe("Token owner address (the wallet granting approval)"), spender_address: z .string() .describe("Spender address to check allowance for (e.g. Arcadia account address)"), token_addresses: z.array(z.string()).describe("ERC20 token contract addresses to check"), chain_id: z.number().default(8453).describe("Chain ID: 8453 (Base) or 130 (Unichain)"), }, outputSchema: WalletAllowanceOutput, },