azeth_get_agreement
View payment agreement details including status, payment history, and next execution time to inspect terms before executing or cancelling.
Instructions
View full details of a payment agreement including status, payment history, and next execution time.
Use this when: You want to inspect an agreement before executing or cancelling it, verify terms after creation, or check how much has been paid so far.
Returns: Complete agreement details with human-readable amounts, status, and timing.
Note: This is a read-only on-chain query. No gas or private key required for the query itself, but account resolution may need your key if using "me" or "#N".
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 | Yes | The payer smart account: Ethereum address, participant name, "me", or "#N". | |
| agreementId | Yes | The agreement ID to query. |
Implementation Reference
- src/tools/agreements.ts:543-645 (handler)The handler for `azeth_get_agreement` which retrieves agreement details from on-chain data.
async (args) => { let client; try { client = await createClient(args.chain); const chain = resolveChain(args.chain); let accountResolved; try { accountResolved = await resolveAddress(args.account, client); } catch (resolveErr) { return handleError(resolveErr); } const account = accountResolved.address; const agreementId = BigInt(args.agreementId); // Single RPC call: agreement + executability + isDue + nextExecutionTime + count let data; try { data = await client.getAgreementData(agreementId, account); } catch { return error('INVALID_INPUT', `Agreement #${args.agreementId} not found for account ${account}.`, 'Check the agreement ID with azeth_list_agreements.'); } const { agreement, executable, reason, isDue: contractIsDue, nextExecutionTime: nextExecTime } = data; const decimals = tokenDecimals(agreement.token, chain); const tokenSymbol = resolveTokenSymbol(agreement.token, chain); const now = BigInt(Math.floor(Date.now() / 1000)); const status = deriveStatus(agreement, now); const intervalSecs = Number(agreement.interval); // Timing const lastExecutedAt = agreement.lastExecuted === 0n ? null : new Date(Number(agreement.lastExecuted) * 1000).toISOString(); let nextExecutionTime: string; let nextExecutionIn: string; let isDue = contractIsDue; let canExecute = executable; let canExecuteReason: string | undefined; if (status !== 'active') { nextExecutionTime = 'N/A'; nextExecutionIn = `N/A (${status})`; canExecute = false; isDue = false; } else { nextExecutionTime = new Date(Number(nextExecTime) * 1000).toISOString(); const nowSecs = Math.floor(Date.now() / 1000); const diff = Number(nextExecTime) - nowSecs; if (diff <= 0) { nextExecutionIn = `now (overdue by ${formatOverdue(-diff)})`; isDue = true; } else { nextExecutionIn = formatCountdown(diff); } if (!executable && reason) { canExecuteReason = reason; } } // Payee name resolution const payeeName = await lookupPayeeName(client, agreement.payee); return success({ agreementId: args.agreementId.toString(), account, payee: agreement.payee, ...(payeeName ? { payeeName } : {}), token: agreement.token, tokenSymbol, status, // Payment terms amountPerInterval: formatUnits(agreement.amount, decimals), intervalSeconds: intervalSecs, intervalHuman: formatInterval(intervalSecs), // Execution state executionCount: agreement.executionCount.toString(), maxExecutions: agreement.maxExecutions === 0n ? 'unlimited' : agreement.maxExecutions.toString(), totalPaid: formatUnits(agreement.totalPaid, decimals), totalCap: agreement.totalCap === 0n ? 'unlimited' : formatUnits(agreement.totalCap, decimals), remainingBudget: agreement.totalCap === 0n ? 'unlimited' : formatUnits(agreement.totalCap - agreement.totalPaid, decimals), // Timing lastExecutedAt, nextExecutionTime, nextExecutionIn, expiresAt: agreement.endTime === 0n ? 'never' : new Date(Number(agreement.endTime) * 1000).toISOString(), // Checks isDue, canExecute, ...(canExecuteReason ? { canExecuteReason } : {}), }); } catch (err) { return handleError(err); } finally { try { await client?.destroy(); } catch (e) { process.stderr.write(`[azeth-mcp] destroy error: ${e instanceof Error ? e.message : String(e)}\n`); } } }, ); - src/tools/agreements.ts:523-542 (registration)Registration of the `azeth_get_agreement` tool.
server.registerTool( 'azeth_get_agreement', { description: [ 'View full details of a payment agreement including status, payment history, and next execution time.', '', 'Use this when: You want to inspect an agreement before executing or cancelling it,', 'verify terms after creation, or check how much has been paid so far.', '', 'Returns: Complete agreement details with human-readable amounts, status, and timing.', '', 'Note: This is a read-only on-chain query. No gas or private key required for the query itself,', 'but account resolution may need your key if using "me" or "#N".', ].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().describe('The payer smart account: Ethereum address, participant name, "me", or "#N".'), agreementId: z.coerce.number().int().min(0).describe('The agreement ID to query.'), }), },