@aifinpay/mcp 2.5.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +111 -20
  2. package/dist/config.d.ts +6 -2
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +39 -4
  5. package/dist/config.js.map +1 -1
  6. package/dist/native-price.d.ts +1 -1
  7. package/dist/native-price.d.ts.map +1 -1
  8. package/dist/native-price.js +3 -3
  9. package/dist/native-price.js.map +1 -1
  10. package/dist/pay-chains.d.ts +5 -4
  11. package/dist/pay-chains.d.ts.map +1 -1
  12. package/dist/pay-chains.js +29 -28
  13. package/dist/pay-chains.js.map +1 -1
  14. package/dist/payment-identity.d.ts +17 -0
  15. package/dist/payment-identity.d.ts.map +1 -0
  16. package/dist/payment-identity.js +75 -0
  17. package/dist/payment-identity.js.map +1 -0
  18. package/dist/payment-state.d.ts +2 -1
  19. package/dist/payment-state.d.ts.map +1 -1
  20. package/dist/payment-state.js +52 -17
  21. package/dist/payment-state.js.map +1 -1
  22. package/dist/server.d.ts +1 -1
  23. package/dist/server.d.ts.map +1 -1
  24. package/dist/server.js +3 -2
  25. package/dist/server.js.map +1 -1
  26. package/dist/tools/agent-claim-self.d.ts +3 -3
  27. package/dist/tools/agent-claim-self.d.ts.map +1 -1
  28. package/dist/tools/agent-claim-self.js +65 -88
  29. package/dist/tools/agent-claim-self.js.map +1 -1
  30. package/dist/tools/agent-history.d.ts +0 -1
  31. package/dist/tools/agent-history.d.ts.map +1 -1
  32. package/dist/tools/agent-history.js +51 -52
  33. package/dist/tools/agent-history.js.map +1 -1
  34. package/dist/tools/agent-quota.d.ts.map +1 -1
  35. package/dist/tools/agent-quota.js +42 -11
  36. package/dist/tools/agent-quota.js.map +1 -1
  37. package/dist/tools/payable-fetch.d.ts.map +1 -1
  38. package/dist/tools/payable-fetch.js +156 -57
  39. package/dist/tools/payable-fetch.js.map +1 -1
  40. package/package.json +6 -6
  41. package/skills/SKILL.md +165 -43
  42. package/dist/directory.d.ts +0 -55
  43. package/dist/directory.d.ts.map +0 -1
  44. package/dist/directory.js +0 -56
  45. package/dist/directory.js.map +0 -1
  46. package/dist/tools/agent-call.d.ts +0 -68
  47. package/dist/tools/agent-call.d.ts.map +0 -1
  48. package/dist/tools/agent-call.js +0 -129
  49. package/dist/tools/agent-call.js.map +0 -1
  50. package/dist/tools/agent-quote.d.ts +0 -41
  51. package/dist/tools/agent-quote.d.ts.map +0 -1
  52. package/dist/tools/agent-quote.js +0 -81
  53. package/dist/tools/agent-quote.js.map +0 -1
  54. package/dist/tools/pay-with-split.d.ts +0 -93
  55. package/dist/tools/pay-with-split.d.ts.map +0 -1
  56. package/dist/tools/pay-with-split.js +0 -138
  57. package/dist/tools/pay-with-split.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"agent-history.d.ts","sourceRoot":"","sources":["../../src/tools/agent-history.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,wBAAgB,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0B/B;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;GA2HpF"}
1
+ {"version":3,"file":"agent-history.d.ts","sourceRoot":"","sources":["../../src/tools/agent-history.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAShD,wBAAgB,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0B/B;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;GA+HpF"}
@@ -1,8 +1,10 @@
1
+ import { AGENT_RECEIPT_FIELDS, AGENT_TRANSACTION_FIELDS } from "@aifinpay/agent";
1
2
  import { apiUrl } from "../api.js";
3
+ import { isSolanaPublicKey, solanaHistorySelection, assertSolanaReadContext, solanaIndexingMetadata, } from "../payment-identity.js";
2
4
  export function agentHistoryTool() {
3
5
  return {
4
6
  name: "agent_history",
5
- description: "Read an agent's payment history by EVM address, public passport identifier, or both. Defaults to the current wallet. Transactions are indexed AiFinPay Polygon settlements, not arbitrary wallet transfers. Receipts include retained prepaid batches and test payments. Never pass a seed, private key or API secret as a passport.",
7
+ description: "Read an agent's indexed AiFinPay payment history by wallet address, public passport identifier, or both. Defaults to the configured payment chain and its local wallet. Solana history requires the owner-selected cluster; arbitrary wallet transfers are excluded. Receipts include retained prepaid batches and test payments. Never pass a seed, private key or API secret as a passport.",
6
8
  inputSchema: {
7
9
  type: "object",
8
10
  additionalProperties: false,
@@ -14,8 +16,7 @@ export function agentHistoryTool() {
14
16
  },
15
17
  network: {
16
18
  type: "string",
17
- default: "polygon",
18
- description: "Exact passport wallet network; indexed transactions currently support polygon only",
19
+ description: "Exact wallet chain; defaults to the configured payment chain (Polygon when unset). Solana cluster comes from owner configuration.",
19
20
  },
20
21
  source: { type: "string", enum: ["transactions", "receipts"], default: "transactions" },
21
22
  limit: { type: "integer", minimum: 1, maximum: 100, default: 25 },
@@ -27,7 +28,8 @@ export function agentHistoryTool() {
27
28
  }
28
29
  export async function runAgentHistory(ctx, args) {
29
30
  const base = ctx.config.baseUrl || "https://aifinpay.io";
30
- const source = args.source ?? "transactions", network = args.network ?? "polygon";
31
+ const source = args.source ?? "transactions", network = args.network ?? ctx.config.payChain ?? "polygon";
32
+ const solana = network === "solana";
31
33
  const limit = args.limit ?? 25, offset = args.offset ?? 0;
32
34
  const failure = (message) => ({
33
35
  isError: true,
@@ -51,6 +53,9 @@ export async function runAgentHistory(ctx, args) {
51
53
  return (await response.json());
52
54
  }
53
55
  try {
56
+ if (typeof network !== "string")
57
+ throw new Error("History network must be an exact chain name");
58
+ const solanaSelection = solana ? solanaHistorySelection(ctx.config) : undefined;
54
59
  let address = args.address == null ? undefined : String(args.address);
55
60
  if (args.passport) {
56
61
  const identifier = String(args.passport).trim();
@@ -60,67 +65,59 @@ export async function runAgentHistory(ctx, args) {
60
65
  const resolved = await get(`/api/agent/resolve/${encodeURIComponent(identifier)}`);
61
66
  if (resolved?.agent?.status !== "active" || !Array.isArray(resolved.agent.wallets))
62
67
  throw new Error("Passport is not active or has no verified wallets");
63
- const wallets = resolved.agent.wallets.filter((w) => w.network === network && w.chain_family === "evm" && Number(w.verified_at) > 0);
68
+ const wallets = resolved.agent.wallets.filter((w) => w.network === network && w.chain_family === (solana ? "solana" : "evm") && Number(w.verified_at) > 0);
64
69
  const wallet = wallets.find((w) => w.is_primary) || wallets[0];
65
70
  if (!wallet || typeof wallet.address !== "string")
66
- throw new Error("Passport has no verified EVM wallet on the requested network");
67
- if (address && address.toLowerCase() !== wallet.address.toLowerCase())
71
+ throw new Error("Passport has no verified wallet on the requested network");
72
+ if (address && (solana ? address !== wallet.address : address.toLowerCase() !== wallet.address.toLowerCase()))
68
73
  throw new Error("Address does not match passport wallet");
69
74
  address = wallet.address;
70
75
  }
71
- address ??= ctx.agent.evmAddress;
72
- if (!/^0x[0-9a-fA-F]{40}$/.test(address))
73
- return failure("Expected an EVM address");
76
+ address ??= solana ? ctx.agent.solanaAddress : ctx.agent.evmAddress;
77
+ if (solana ? !isSolanaPublicKey(address) : !/^0x[0-9a-fA-F]{40}$/.test(address))
78
+ return failure(solana ? "Expected a canonical 32-byte Solana address" : "Expected an EVM address");
79
+ const canonicalAddress = solana ? address : address.toLowerCase();
74
80
  const query = new URLSearchParams({ limit: String(limit), offset: String(offset) });
75
- if (source === "transactions")
81
+ if (source === "transactions" || solana)
76
82
  query.set("chain", String(network));
77
- const body = await get(`/v1/agents/${address.toLowerCase()}/${source}?${query}`);
83
+ if (solanaSelection) {
84
+ query.set("network", solanaSelection.network);
85
+ query.set("program", solanaSelection.program);
86
+ }
87
+ const body = await get(`/v1/agents/${canonicalAddress}/${source}?${query}`);
78
88
  if (!Array.isArray(body?.[source]))
79
89
  throw new Error("Invalid history response");
80
- const fields = source === "receipts"
81
- ? [
82
- "receipt_id",
83
- "merchant_id",
84
- "resource",
85
- "scope",
86
- "tier",
87
- "quota",
88
- "used",
89
- "remaining",
90
- "amount",
91
- "currency",
92
- "exp",
93
- "chain",
94
- "tx_ref",
95
- "payer",
96
- "network_mode",
97
- "settled_at",
98
- "expires_at",
99
- "unit_quota",
100
- "metering_version",
101
- ]
102
- : [
103
- "tx_hash",
104
- "log_index",
105
- "chain",
106
- "payment_id",
107
- "block_number",
108
- "block_ts",
109
- "agent_address",
110
- "merchant_address",
111
- "token_address",
112
- "total_amount",
113
- "merchant_amount",
114
- "treasury_fee",
115
- "ip_creator_fee",
116
- ];
117
- const items = body[source].map((row) => Object.fromEntries(fields.filter((f) => row?.[f] !== undefined).map((f) => [f, row[f]])));
90
+ if (solanaSelection)
91
+ assertSolanaReadContext(body, canonicalAddress, solanaSelection, "address");
92
+ const fields = [
93
+ ...(source === "receipts" ? AGENT_RECEIPT_FIELDS : AGENT_TRANSACTION_FIELDS),
94
+ "program_id",
95
+ "idl_sha256",
96
+ "token_decimals",
97
+ "asset",
98
+ "cost_allocation",
99
+ ];
100
+ const items = body[source].map((row) => {
101
+ if (solanaSelection)
102
+ assertSolanaReadContext(row, canonicalAddress, solanaSelection, source === "receipts" ? "payer" : "agent_address");
103
+ if (solanaSelection &&
104
+ fields.some((f) => row[f] !== undefined &&
105
+ row[f] !== null &&
106
+ (typeof row[f] === "object" ||
107
+ !["string", "number", "boolean"].includes(typeof row[f]) ||
108
+ (typeof row[f] === "number" && !Number.isFinite(row[f])))))
109
+ throw new Error("Invalid structured Solana public metadata");
110
+ return Object.fromEntries(fields.filter((f) => row?.[f] !== undefined).map((f) => [f, row[f]]));
111
+ });
112
+ const indexing = solanaSelection && source === "transactions" ? solanaIndexingMetadata(body.indexing) : undefined;
118
113
  return {
119
114
  content: [
120
115
  {
121
116
  type: "text",
122
117
  text: JSON.stringify({
123
- address: address.toLowerCase(),
118
+ address: canonicalAddress,
119
+ ...(solanaSelection ? { chain: "solana", ...solanaSelection } : {}),
120
+ ...(indexing ? { indexing } : {}),
124
121
  source,
125
122
  items,
126
123
  limit,
@@ -128,7 +125,9 @@ export async function runAgentHistory(ctx, args) {
128
125
  next_offset: typeof body.next_offset === "number" ? body.next_offset : null,
129
126
  coverage: source === "receipts"
130
127
  ? "Retained receipts only; externally metered quotas may lag"
131
- : "Indexed AiFinPay Polygon settlements only; excludes arbitrary wallet transfers and may lag the chain",
128
+ : solanaSelection
129
+ ? "Verified Solana settlements from retained RPC inventory only; partial history, no full archive or wallet coverage attestation; shared or unquoted transaction costs may be unavailable"
130
+ : "Indexed AiFinPay settlements for the requested chain and cluster; excludes arbitrary wallet transfers and may lag the chain",
132
131
  }, null, 2),
133
132
  },
134
133
  ],
@@ -1 +1 @@
1
- {"version":3,"file":"agent-history.js","sourceRoot":"","sources":["../../src/tools/agent-history.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-history.js","sourceRoot":"","sources":["../../src/tools/agent-history.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"agent-quota.d.ts","sourceRoot":"","sources":["../../src/tools/agent-quota.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAIhD,wBAAgB,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;EA0B7B;AAiBD,wBAAsB,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;GAqElF"}
1
+ {"version":3,"file":"agent-quota.d.ts","sourceRoot":"","sources":["../../src/tools/agent-quota.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAUhD,wBAAgB,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;EA0B7B;AAkBD,wBAAsB,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;GAgGlF"}
@@ -1,11 +1,12 @@
1
+ import { isSolanaPublicKey, solanaHistorySelection, assertSolanaReadContext, assertSolanaQuota, } from "../payment-identity.js";
1
2
  const DEFAULT_BASE = "https://api.aifinpay.io";
2
3
  export function agentQuotaTool() {
3
4
  return {
4
5
  name: "agent_quota",
5
- description: "How many prepaid requests this agent has left, per service. Lists the " +
6
+ description: "Read this agent's prepaid quota, per service. Lists the " +
6
7
  "agent's active quota batches (merchant, resource, used, remaining, " +
7
8
  "expiry). Read-only; never spends, pays, or signs anything. Ask it " +
8
- "things like: how many calls do I have left at mrch_x?",
9
+ "things like: how much prepaid quota do I have left at mrch_x?",
9
10
  inputSchema: {
10
11
  type: "object",
11
12
  properties: {
@@ -27,12 +28,21 @@ export function agentQuotaTool() {
27
28
  }
28
29
  export async function runAgentQuota(ctx, args) {
29
30
  const base = (ctx.config.baseUrl ?? DEFAULT_BASE).replace(/\/+$/, "");
30
- const address = ctx.agent.evmAddress;
31
+ const solana = ctx.config.payChain === "solana";
32
+ const address = solana ? ctx.agent.solanaAddress : ctx.agent.evmAddress;
31
33
  const merchantFilter = typeof args.merchant_id === "string" && args.merchant_id ? args.merchant_id : null;
32
34
  const includeExhausted = args.include_exhausted === true;
33
35
  let resp;
36
+ let solanaSelection;
34
37
  try {
35
- resp = await ctx.agent.inner.fetchImpl(`${base}/v1/agents/${address}/receipts`, {
38
+ let query = "";
39
+ if (solana) {
40
+ if (!isSolanaPublicKey(address))
41
+ throw new Error("Expected a canonical 32-byte Solana address");
42
+ solanaSelection = solanaHistorySelection(ctx.config);
43
+ query = `?${new URLSearchParams({ chain: "solana", network: solanaSelection.network, program: solanaSelection.program })}`;
44
+ }
45
+ resp = await ctx.agent.inner.fetchImpl(`${base}/v1/agents/${address}/receipts${query}`, {
36
46
  method: "GET",
37
47
  });
38
48
  }
@@ -43,7 +53,22 @@ export async function runAgentQuota(ctx, args) {
43
53
  if (!resp.ok) {
44
54
  return errorResult(`quota lookup failed: HTTP ${resp.status}`);
45
55
  }
46
- const body = (await resp.json());
56
+ let body;
57
+ try {
58
+ body = (await resp.json());
59
+ if (solanaSelection) {
60
+ assertSolanaReadContext(body, address, solanaSelection, "address");
61
+ if (!Array.isArray(body.receipts))
62
+ throw new Error("Invalid Solana quota response");
63
+ for (const row of body.receipts) {
64
+ assertSolanaReadContext(row, address, solanaSelection, "payer");
65
+ assertSolanaQuota(row);
66
+ }
67
+ }
68
+ }
69
+ catch {
70
+ return errorResult("Quota metadata is unavailable or does not match the selected wallet/network/program");
71
+ }
47
72
  const now = Math.floor(Date.now() / 1000);
48
73
  let batches = (body.receipts ?? [])
49
74
  .filter((r) => r.exp == null || r.exp > now)
@@ -56,7 +81,7 @@ export async function runAgentQuota(ctx, args) {
56
81
  tier: r.tier,
57
82
  used: r.used ?? 0,
58
83
  remaining: r.remaining ?? 0,
59
- quota: r.quota ?? 1,
84
+ quota: solanaSelection ? r.unit_quota : (r.quota ?? 1),
60
85
  paid: r.amount != null ? `${r.amount} ${r.currency ?? "USD"}` : undefined,
61
86
  expires: r.exp != null ? new Date(r.exp * 1000).toISOString() : undefined,
62
87
  receipt_id: r.receipt_id,
@@ -70,19 +95,25 @@ export async function runAgentQuota(ctx, args) {
70
95
  const key = b.merchant_id ?? "unknown";
71
96
  const cur = perMerchant.get(key) ?? { remaining: 0, batches: 0 };
72
97
  cur.remaining += b.remaining;
98
+ if (solanaSelection && !Number.isSafeInteger(cur.remaining))
99
+ return errorResult("Quota total exceeds safe integer range");
73
100
  cur.batches += 1;
74
101
  perMerchant.set(key, cur);
75
102
  }
76
103
  const payload = {
77
104
  agent: address,
105
+ ...(solanaSelection ? { chain: "solana", ...solanaSelection } : {}),
106
+ ...(solanaSelection ? { unit: "billing_units" } : {}),
78
107
  ...(merchantFilter ? { merchant_filter: merchantFilter } : {}),
79
108
  totals: Object.fromEntries(perMerchant),
80
109
  batches,
81
- note: batches.length === 0
82
- ? merchantFilter
83
- ? `no active quota at ${merchantFilter} — a new batch starts with that service's 402 (or agent_quote its URL first)`
84
- : "no active quota anywhere — pay a service's 402 to start a batch"
85
- : "`remaining` is authoritative where AiFinPay meters (hosted gateway); a merchant running its own @aifinpay/gate meters locally and our copy can lag behind by their traffic.",
110
+ note: solanaSelection
111
+ ? "Solana remaining/used/quota are billing units. The number of callable requests depends on each route's server-defined cost_units. Hosted gateway usage is durable; external merchant metering may lag. An empty result means no retained active quota in this selected wallet/network/program."
112
+ : batches.length === 0
113
+ ? merchantFilter
114
+ ? `no active quota at ${merchantFilter} — a new batch starts with that service's 402 (or agent_quote its URL first)`
115
+ : "no active quota anywhere — pay a service's 402 to start a batch"
116
+ : "`remaining` is authoritative where AiFinPay meters (hosted gateway); a merchant running its own @aifinpay/gate meters locally and our copy can lag behind by their traffic.",
86
117
  };
87
118
  return {
88
119
  content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
@@ -1 +1 @@
1
- {"version":3,"file":"agent-quota.js","sourceRoot":"","sources":["../../src/tools/agent-quota.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-quota.js","sourceRoot":"","sources":["../../src/tools/agent-quota.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"payable-fetch.d.ts","sourceRoot":"","sources":["../../src/tools/payable-fetch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAWhD,wBAAgB,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0B/B;AAED,2FAA2F;AAC3F,wBAAsB,eAAe,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;GAgPpF"}
1
+ {"version":3,"file":"payable-fetch.d.ts","sourceRoot":"","sources":["../../src/tools/payable-fetch.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAWhD,wBAAgB,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0B/B;AAED,2FAA2F;AAC3F,wBAAsB,eAAe,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;GAsWpF"}
@@ -1,4 +1,4 @@
1
- import { Aifp1SettlementUnsupportedError, parseGatewayUrl } from "@aifinpay/agent";
1
+ import { Aifp1SettlementUnsupportedError, Aifp1FinalizedFailureError, assertPreparedV14Recovery, parseGatewayUrl, } from "@aifinpay/agent";
2
2
  import { validatePaymentConfig } from "../config.js";
3
3
  import { PaymentStateError } from "../payment-state.js";
4
4
  import { independentNativeUsd } from "../native-price.js";
@@ -9,7 +9,7 @@ const SCOPES = ["exact", "merchant"];
9
9
  export function payableFetchTool() {
10
10
  return {
11
11
  name: "payable_fetch",
12
- description: 'Fetch a GET resource from an owner-approved AiFinPay merchant. Buys a prepaid batch through verified v1.4 on the chain the owner set in AIFINPAY_PAY_CHAIN (Polygon by default, or Base) — in its native currency (POL, ETH), or in the stablecoin the owner set in AIFINPAY_PAY_ASSET (e.g. USDC; gas is still native) — within owner limits, then reuses its receipt. With scope "merchant" one batch covers every path on the site. Pending payments are recovered without sending another transaction. Other payment protocols are unsupported.',
12
+ description: 'Fetch a GET resource from an owner-approved AiFinPay merchant. Buys a prepaid batch through verified v1.4 on the chain the owner set in AIFINPAY_PAY_CHAIN (Polygon by default; other supported networks require explicit owner selection) — in its native currency (POL, SOL, ETH, AVAX, BNB or XRP), or in the stablecoin the owner set in AIFINPAY_PAY_ASSET (e.g. USDC; gas is still native) — within owner limits, then reuses its receipt. With scope "merchant" one batch covers every path on the site. Pending payments are recovered without sending another transaction. Other payment protocols are unsupported.',
13
13
  inputSchema: {
14
14
  type: "object",
15
15
  properties: {
@@ -36,9 +36,9 @@ export async function runPayableFetch(ctx, args) {
36
36
  let state;
37
37
  let chain;
38
38
  try {
39
- let maxGasWei;
39
+ let feeCap;
40
40
  try {
41
- maxGasWei = validatePaymentConfig(ctx.config);
41
+ feeCap = validatePaymentConfig(ctx.config);
42
42
  chain = payChain(ctx.config.payChain);
43
43
  }
44
44
  catch (error) {
@@ -75,25 +75,89 @@ export async function runPayableFetch(ctx, args) {
75
75
  ctx.agent.aifp1Receipts.evict(entry);
76
76
  for (const entry of state.receipts)
77
77
  ctx.agent.aifp1Receipts.put(entry);
78
+ const reconcileFinalizedFailure = (error) => {
79
+ if (!(error instanceof Aifp1FinalizedFailureError))
80
+ return false;
81
+ const pending = state.pending;
82
+ const recovery = error.recovery;
83
+ if (!pending ||
84
+ pending.recovery.family !== "solana" ||
85
+ recovery?.family !== "solana" ||
86
+ JSON.stringify(recovery) !== JSON.stringify(pending.recovery) ||
87
+ pending.amountUsd !== recovery.reservedAmountUsd ||
88
+ !Number.isFinite(error.feeAmountUsd) ||
89
+ error.feeAmountUsd < 0 ||
90
+ error.feeAmountUsd > pending.amountUsd ||
91
+ typeof error.actualFeeLamports !== "bigint" ||
92
+ error.actualFeeLamports < 0n)
93
+ throw new Error("Finalized failure does not match the pending payment");
94
+ const entries = state.spend.filter((entry) => entry.tx === recovery.txRef);
95
+ if (entries.length !== 1 || entries[0].failure || entries[0].usd !== pending.amountUsd)
96
+ throw new Error("Finalized failure does not match the original debit");
97
+ // Only the SDK's exact canonical proof and durable ledger reconciliation
98
+ // can produce this terminal outcome. Persist our fee debit and removal
99
+ // of the pending guard together; never retry the purchase in this call.
100
+ entries[0].usd = error.feeAmountUsd;
101
+ entries[0].failure = true;
102
+ delete state.pending;
103
+ store.save(state);
104
+ return true;
105
+ };
106
+ const finalizedFailureResult = () => errorResult("The original Solana transaction finalized with failure. Its verified network fee remains in the spending ledger. No receipt was issued and no replacement payment was submitted.");
78
107
  if (state.pending) {
79
108
  const pending = state.pending;
80
109
  // Always recover the existing operation first, even if the caller asks
81
110
  // for another resource. This method cannot broadcast a transaction.
82
111
  const configuredApi = (ctx.config.baseUrl ?? "https://api.aifinpay.io").replace(/\/+$/, "");
83
112
  const call = pending.recovery.quote.settlement_call;
113
+ const solana = pay.name === "solana";
114
+ const payerMatches = solana
115
+ ? pending.recovery.quote.payer === ctx.agent.solanaAddress
116
+ : pending.recovery.quote.payer?.toLowerCase() === ctx.agent.evmAddress.toLowerCase();
84
117
  if (pending.recovery.apiBaseUrl.replace(/\/+$/, "") !== configuredApi ||
85
118
  (pending.recovery.paymentIssuer ?? configuredApi).replace(/\/+$/, "") !== configuredApi ||
86
- pending.recovery.quote.payer?.toLowerCase() !== ctx.agent.evmAddress.toLowerCase() ||
119
+ !payerMatches ||
120
+ (pending.recovery.chain !== undefined && pending.recovery.chain !== pay.name) ||
87
121
  call?.chain !== pay.name ||
88
122
  call.splitter_version !== "1.4" ||
89
- // Native calls from earlier versions may lack the field; they were POL.
90
123
  (call.asset ?? "POL") !== pending.recovery.asset ||
91
- ![pay.native, payAsset].includes(pending.recovery.asset)) {
92
- // A payment pending on another chain is recovered by switching back
93
- // to that chain; it is never re-sent here and never forgotten.
124
+ ![pay.native, payAsset].includes(pending.recovery.asset) ||
125
+ (solana ? pending.recovery.family !== "solana" : pending.recovery.family === "solana"))
94
126
  throw new Error(`Pending payment does not match the configured wallet/API/${pay.name} v1.4 route and asset`);
127
+ let recovery;
128
+ if (pending.recovery.family === "solana") {
129
+ if (pending.recovery.solana.network !== ctx.config.solanaNetwork ||
130
+ call.network !== ctx.config.solanaNetwork)
131
+ throw new Error("Pending Solana payment does not match the owner-selected network");
132
+ // The SDK verifies exact signed bytes, local Ed25519 identity and
133
+ // the original bound reservation. Recovery cannot submit a new tx.
134
+ recovery = pending.recovery;
95
135
  }
96
- const paid = await ctx.agent.recoverPaidPayment(pending.recovery, { paymentIssuer: configuredApi });
136
+ else {
137
+ if (pay.name === "solana")
138
+ throw new Error("EVM payment cannot recover on Solana");
139
+ if (pending.recovery.chain === undefined) {
140
+ await assertPreparedV14Recovery(call, { hash: pending.recovery.txRef, serializedTransaction: pending.serializedTransaction }, pay.name, ctx.agent.evmAddress, pending.recovery.quote.quote_id);
141
+ }
142
+ recovery = { ...pending.recovery, chain: pending.recovery.chain ?? pay.name };
143
+ }
144
+ const paid = await ctx.agent
145
+ .recoverPaidPayment(recovery, {
146
+ paymentIssuer: configuredApi,
147
+ ...(pay.name === "solana"
148
+ ? {
149
+ solanaNetwork: ctx.config.solanaNetwork,
150
+ solanaEnvironment: ctx.config.devMode ? "dev" : "prod",
151
+ }
152
+ : {}),
153
+ })
154
+ .catch((error) => {
155
+ if (reconcileFinalizedFailure(error))
156
+ return null;
157
+ throw error;
158
+ });
159
+ if (!paid)
160
+ return finalizedFailureResult();
97
161
  const receipt = {
98
162
  site: pending.site,
99
163
  merchantId: paid.merchant_id,
@@ -116,6 +180,27 @@ export async function runPayableFetch(ctx, args) {
116
180
  const spent = store.spent24h(state);
117
181
  const priorReceiptIds = new Set(state.receipts.map((entry) => entry.receiptId));
118
182
  let price;
183
+ const persistPrepared = (prepared, usd, serializedTransaction) => {
184
+ if (state.pending)
185
+ throw new Error("A payment is already pending");
186
+ if (!Number.isFinite(usd) ||
187
+ usd <= 0 ||
188
+ usd > maximum ||
189
+ store.spent24h(state) + usd > ctx.config.dailyAmountUsd)
190
+ throw new Error("Owner spending limit reached");
191
+ const site = ctx.config.gatewayPathMode === "direct"
192
+ ? `direct:${JSON.stringify([url.origin, prepared.quote.merchant_id])}`
193
+ : parsed.site;
194
+ state.pending = {
195
+ recovery: prepared,
196
+ ...(serializedTransaction ? { serializedTransaction } : {}),
197
+ site,
198
+ amountUsd: usd,
199
+ };
200
+ state.spend.push({ at: Date.now(), usd, tx: prepared.txRef });
201
+ // Durable atomic fsync completes before the SDK may broadcast.
202
+ store.save(state);
203
+ };
119
204
  try {
120
205
  const response = await ctx.agent.fetchPaid(url.href, { method: "GET", redirect: "manual" }, {
121
206
  apiBaseUrl: ctx.config.baseUrl,
@@ -123,7 +208,10 @@ export async function runPayableFetch(ctx, args) {
123
208
  gatewayOrigins: ctx.config.gatewayOrigins,
124
209
  resourcePathMode: ctx.config.gatewayPathMode,
125
210
  scope,
126
- maxAmountUsd: Math.min(maximum, Math.max(0, ctx.config.dailyAmountUsd - spent)),
211
+ // A pending Solana quote pins this owner limit across restarts and
212
+ // rollover. Fresh daily allowance is checked again in persistPrepared
213
+ // under the operation lock, before any broadcast.
214
+ maxAmountUsd: pay.name === "solana" ? maximum : Math.min(maximum, Math.max(0, ctx.config.dailyAmountUsd - spent)),
127
215
  nativeUsdPrice: async () => {
128
216
  // Independent public price, never the quote API's rate: Chainlink
129
217
  // over the agent's own RPC for the pay chain first (no extra
@@ -136,53 +224,59 @@ export async function runPayableFetch(ctx, args) {
136
224
  price = { usd: found.usd, observedAtMs: found.observedAtMs };
137
225
  return price;
138
226
  },
139
- v14: {
140
- chain: pay.name,
141
- ...(payAsset !== pay.native ? { asset: payAsset } : {}),
142
- maxGasWei,
143
- onPrepared: async (prepared) => {
144
- if (state.pending)
145
- throw new Error("A payment is already pending");
146
- // A stablecoin batch is dollars already: the SDK bound the signed
147
- // gross to the quoted USD amount exactly. Only a native batch
148
- // needs the independent native price.
149
- let usd;
150
- if (payAsset !== pay.native) {
151
- if (prepared.asset !== payAsset)
152
- throw new Error("Prepared payment is not in the configured asset");
153
- usd = Number(prepared.quote.amount);
154
- }
155
- else {
156
- if (!price || Date.now() - price.observedAtMs > 60_000)
157
- throw new Error("Independent price expired before preparation");
158
- const native = prepared.quote.native_settlement;
159
- usd = Math.max(Number(prepared.quote.amount), (Number(BigInt(native.total_wei)) / 1e18) * price.usd);
160
- }
161
- if (!Number.isFinite(usd) ||
162
- usd <= 0 ||
163
- usd > maximum ||
164
- store.spent24h(state) + usd > ctx.config.dailyAmountUsd)
165
- throw new Error("Owner spending limit reached");
166
- const site = ctx.config.gatewayPathMode === "direct"
167
- ? `direct:${JSON.stringify([url.origin, prepared.quote.merchant_id])}`
168
- : parsed.site;
169
- state.pending = {
170
- recovery: {
171
- apiBaseUrl: prepared.apiBaseUrl,
172
- quote: prepared.quote,
173
- txRef: prepared.txRef,
174
- asset: prepared.asset,
175
- paymentIssuer: prepared.paymentIssuer,
227
+ ...(pay.name === "solana"
228
+ ? {
229
+ solanaV14: {
230
+ environment: ctx.config.devMode ? "dev" : "prod",
231
+ network: ctx.config.solanaNetwork,
232
+ asset: payAsset,
233
+ maxFeeLamports: feeCap,
234
+ onPrepared: async (prepared) => {
235
+ if (prepared.family !== "solana" ||
236
+ prepared.chain !== "solana" ||
237
+ prepared.solana.network !== ctx.config.solanaNetwork ||
238
+ prepared.quote.payer !== ctx.agent.solanaAddress ||
239
+ prepared.asset !== payAsset)
240
+ throw new Error("Prepared Solana payment disagrees with the owner configuration");
241
+ if (!price || Date.now() - price.observedAtMs > 60_000 || price.observedAtMs > Date.now())
242
+ throw new Error("Independent SOL price expired before preparation");
243
+ const native = prepared.quote.native_settlement;
244
+ const floor = payAsset === "SOL"
245
+ ? Math.max(Number(prepared.quote.amount), (Number(BigInt(native.total_lamports)) / 1e9) * price.usd)
246
+ : Number(prepared.quote.amount);
247
+ if (!Number.isFinite(floor) ||
248
+ floor <= 0 ||
249
+ !Number.isFinite(prepared.reservedAmountUsd) ||
250
+ prepared.reservedAmountUsd < floor)
251
+ throw new Error("Prepared Solana admission amount is inconsistent");
252
+ persistPrepared(prepared, prepared.reservedAmountUsd);
176
253
  },
177
- serializedTransaction: prepared.serializedTransaction,
178
- site,
179
- amountUsd: usd,
180
- };
181
- state.spend.push({ at: Date.now(), usd, tx: prepared.txRef });
182
- // Atomic fsync completes BEFORE the SDK is allowed to broadcast.
183
- store.save(state);
184
- },
185
- },
254
+ },
255
+ }
256
+ : {
257
+ v14: {
258
+ chain: pay.name,
259
+ ...(payAsset !== pay.native ? { asset: payAsset } : {}),
260
+ maxGasWei: feeCap,
261
+ onPrepared: async (prepared) => {
262
+ let usd;
263
+ if (payAsset !== pay.native) {
264
+ if (prepared.asset !== payAsset)
265
+ throw new Error("Prepared payment is not in the configured asset");
266
+ usd = Number(prepared.quote.amount);
267
+ }
268
+ else {
269
+ if (!price || Date.now() - price.observedAtMs > 60_000)
270
+ throw new Error("Independent price expired before preparation");
271
+ const native = prepared.quote.native_settlement;
272
+ usd = Math.max(Number(prepared.quote.amount), (Number(BigInt(native.total_wei)) / 1e18) * price.usd);
273
+ }
274
+ // Copy the full recovery, including the new wallet binding
275
+ // marker and any signed approval; retain legacy byte field.
276
+ persistPrepared(prepared, usd, prepared.serializedTransaction);
277
+ },
278
+ },
279
+ }),
186
280
  });
187
281
  if (response === null)
188
282
  return errorResult("Payment skipped: owner budget reached.");
@@ -218,6 +312,11 @@ export async function runPayableFetch(ctx, args) {
218
312
  ],
219
313
  };
220
314
  }
315
+ catch (error) {
316
+ if (reconcileFinalizedFailure(error))
317
+ return finalizedFailureResult();
318
+ throw error;
319
+ }
221
320
  finally {
222
321
  // Receipt caching precedes content retry in the SDK. Retain it even
223
322
  // when that content request fails; never discard already bought access.