Skip to main content
Glama

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

TableJSON Schema
NameRequiredDescriptionDefault
chainNoTarget chain. Defaults to AZETH_CHAIN env var or "baseSepolia". Accepts "base", "baseSepolia", "ethereumSepolia", "ethereum" (and aliases like "base-sepolia", "eth-sepolia", "sepolia", "eth", "mainnet").
accountNoSmart account to query: address, name, "me", or "#N". Defaults to "me".
statusNoFilter by status. "due" shows only agreements ready for execution right now.all

Implementation Reference

  • 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 {
  • 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.'),
        }),
      },

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/azeth-protocol/mcp-azeth'

If you have feedback or need assistance with the MCP directory API, please join our Discord server