azeth_list_agreements
List and filter payment agreements for smart accounts to track subscriptions, identify agreements due for execution, and review payment commitments with status summaries.
Instructions
List all payment agreements for a smart account with summary status.
Use this when: You need to find an agreement ID, see all active subscriptions, check which agreements are due for execution, or get an overview of payment commitments.
Returns: Array of agreement summaries sorted by ID (newest first), with status and timing.
Note: This is a read-only on-chain query. Iterates through all agreements for the account. For accounts with many agreements, this may take a few seconds.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| chain | No | Target chain. Defaults to AZETH_CHAIN env var or "baseSepolia". Accepts "base", "baseSepolia", "ethereumSepolia", "ethereum" (and aliases like "base-sepolia", "eth-sepolia", "sepolia", "eth", "mainnet"). | |
| account | No | Smart account to query: address, name, "me", or "#N". Defaults to "me". | |
| status | No | Filter by status. "due" shows only agreements ready for execution right now. | all |
Implementation Reference
- src/tools/agreements.ts:671-780 (handler)The handler logic for the azeth_list_agreements tool. It iterates through agreements for a given smart account and returns a list of formatted agreement summaries.
async (args) => { let client; try { client = await createClient(args.chain); const chain = resolveChain(args.chain); // Resolve account (default to "me") let account: `0x${string}`; try { const accountInput = args.account ?? 'me'; const resolved = await resolveAddress(accountInput, client); account = resolved.address; } catch (resolveErr) { return handleError(resolveErr); } // Get count from first getAgreementData call (avoids separate getAgreementCount RPC) let count: bigint; try { const firstData = await client.getAgreementData(0n, account); count = firstData.count; } catch { return success({ account, totalAgreements: 0, showing: 0, filter: args.status ?? 'all', agreements: [], }); } if (count === 0n) { return success({ account, totalAgreements: 0, showing: 0, filter: args.status ?? 'all', agreements: [], }); } const now = BigInt(Math.floor(Date.now() / 1000)); const statusFilter = args.status ?? 'all'; const agreements: Array<Record<string, unknown>> = []; // Iterate from newest to oldest — 1 RPC per agreement via getAgreementData for (let i = Number(count) - 1; i >= 0; i--) { let data; try { data = await client.getAgreementData(BigInt(i), account); } catch { continue; } const { agreement, executable, isDue: contractIsDue, nextExecutionTime: nextExecTime } = data; const decimals = tokenDecimals(agreement.token, chain); const tokenSymbol = resolveTokenSymbol(agreement.token, chain); const status = deriveStatus(agreement, now); // Status filter if (statusFilter === 'due') { if (status !== 'active' || !contractIsDue) continue; } else if (statusFilter !== 'all' && status !== statusFilter) { continue; } // Compute timing for active agreements let isDue = contractIsDue; let nextExecutionIn: string | undefined; if (status === 'active') { const nowSecs = Math.floor(Date.now() / 1000); const diff = Number(nextExecTime) - nowSecs; if (diff <= 0) { isDue = true; nextExecutionIn = `now (overdue by ${formatOverdue(-diff)})`; } else { nextExecutionIn = formatCountdown(diff); } } // Payee name (best-effort) const payeeName = await lookupPayeeName(client, agreement.payee); agreements.push({ agreementId: i.toString(), payee: agreement.payee, ...(payeeName ? { payeeName } : {}), tokenSymbol, amountPerInterval: formatUnits(agreement.amount, decimals), intervalHuman: formatInterval(Number(agreement.interval)), status, executionCount: agreement.executionCount.toString(), maxExecutions: agreement.maxExecutions === 0n ? 'unlimited' : agreement.maxExecutions.toString(), totalPaid: formatUnits(agreement.totalPaid, decimals), ...(isDue !== undefined ? { isDue } : {}), ...(nextExecutionIn ? { nextExecutionIn } : {}), }); } return success({ account, totalAgreements: Number(count), showing: agreements.length, filter: statusFilter, agreements, }); } catch (err) { return handleError(err); } finally { - src/tools/agreements.ts:650-670 (registration)Registration of the azeth_list_agreements tool, including its description and input schema.
server.registerTool( 'azeth_list_agreements', { description: [ 'List all payment agreements for a smart account with summary status.', '', 'Use this when: You need to find an agreement ID, see all active subscriptions,', 'check which agreements are due for execution, or get an overview of payment commitments.', '', 'Returns: Array of agreement summaries sorted by ID (newest first), with status and timing.', '', 'Note: This is a read-only on-chain query. Iterates through all agreements for the account.', 'For accounts with many agreements, this may take a few seconds.', ].join('\n'), inputSchema: z.object({ chain: z.string().optional().describe('Target chain. Defaults to AZETH_CHAIN env var or "baseSepolia". Accepts "base", "baseSepolia", "ethereumSepolia", "ethereum" (and aliases like "base-sepolia", "eth-sepolia", "sepolia", "eth", "mainnet").'), account: z.string().optional().describe('Smart account to query: address, name, "me", or "#N". Defaults to "me".'), status: z.enum(['all', 'active', 'completed', 'cancelled', 'due']).optional().default('all') .describe('Filter by status. "due" shows only agreements ready for execution right now.'), }), },