@aifinpay/mcp 2.4.1 → 2.5.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.
- package/README.md +62 -23
- package/dist/config.d.ts +10 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +28 -5
- package/dist/config.js.map +1 -1
- package/dist/directory.d.ts +55 -0
- package/dist/directory.d.ts.map +1 -0
- package/dist/directory.js +56 -0
- package/dist/directory.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/native-price.d.ts +18 -9
- package/dist/native-price.d.ts.map +1 -1
- package/dist/native-price.js +34 -29
- package/dist/native-price.js.map +1 -1
- package/dist/pay-chains.d.ts +31 -0
- package/dist/pay-chains.d.ts.map +1 -0
- package/dist/pay-chains.js +37 -0
- package/dist/pay-chains.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +9 -1
- package/dist/server.js.map +1 -1
- package/dist/tools/agent-address.d.ts.map +1 -1
- package/dist/tools/agent-address.js +1 -1
- package/dist/tools/agent-address.js.map +1 -1
- package/dist/tools/agent-call.d.ts +68 -0
- package/dist/tools/agent-call.d.ts.map +1 -0
- package/dist/tools/agent-call.js +129 -0
- package/dist/tools/agent-call.js.map +1 -0
- package/dist/tools/agent-quote.d.ts +41 -0
- package/dist/tools/agent-quote.d.ts.map +1 -0
- package/dist/tools/agent-quote.js +81 -0
- package/dist/tools/agent-quote.js.map +1 -0
- package/dist/tools/pay-with-split.d.ts +93 -0
- package/dist/tools/pay-with-split.d.ts.map +1 -0
- package/dist/tools/pay-with-split.js +138 -0
- package/dist/tools/pay-with-split.js.map +1 -0
- package/dist/tools/payable-fetch.d.ts.map +1 -1
- package/dist/tools/payable-fetch.js +30 -17
- package/dist/tools/payable-fetch.js.map +1 -1
- package/package.json +3 -3
- package/skills/SKILL.md +27 -15
- package/smithery.yaml +72 -40
package/README.md
CHANGED
|
@@ -4,9 +4,9 @@ AiFinPay MCP server for persistent agent identity, Agent Passport resolution,
|
|
|
4
4
|
route discovery and non-signing settlement invoices. Canonical domain:
|
|
5
5
|
**aifinpay.io**.
|
|
6
6
|
|
|
7
|
-
Version **2.
|
|
8
|
-
|
|
9
|
-
`scope: "merchant"` since 2.4.1. Without payment configuration the server keeps
|
|
7
|
+
Version **2.5.0**. Owner-enabled v1.4 purchases with `payable_fetch` are
|
|
8
|
+
released: on Polygon since 2.2.0, on Base (ETH or USDC) since 2.5.0; site-wide
|
|
9
|
+
batches with `scope: "merchant"` since 2.4.1. Without payment configuration the server keeps
|
|
10
10
|
its inspection-only tool inventory.
|
|
11
11
|
|
|
12
12
|
## Enable native paid GET requests
|
|
@@ -47,13 +47,40 @@ To pay in USDC instead of native POL, the owner also sets
|
|
|
47
47
|
POL for gas: an exact-amount token approval plus the settlement, both within
|
|
48
48
|
`AIFINPAY_MAX_GAS_POL` together. Unset or `"POL"` keeps native POL.
|
|
49
49
|
|
|
50
|
+
### Paying on another chain
|
|
51
|
+
|
|
52
|
+
`AIFINPAY_PAY_CHAIN` picks the chain `payable_fetch` settles on: `polygon`
|
|
53
|
+
(default) or `base`. Only the owner sets it, and a merchant is paid on a chain
|
|
54
|
+
only if its quote is for that chain; a quote for any other chain is refused,
|
|
55
|
+
never followed. On Base the batch is paid in ETH (or `AIFINPAY_PAY_ASSET:
|
|
56
|
+
"USDC"`) and gas is ETH, so the cap is `AIFINPAY_MAX_GAS`, in ETH:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"AIFINPAY_PAY_CHAIN": "base",
|
|
61
|
+
"AIFINPAY_MAX_GAS": "0.0002"
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`AIFINPAY_MAX_GAS` is the gas cap in the pay chain's native currency;
|
|
66
|
+
`AIFINPAY_MAX_GAS_POL` remains accepted on Polygon and is refused on Base rather
|
|
67
|
+
than read as ETH (0.3 POL is about $0.04; 0.3 ETH is several hundred dollars).
|
|
68
|
+
On Base the worst case includes the L1 data fee, typically well under 0.0001 ETH
|
|
69
|
+
for one settlement. The wallet's EVM address is the same on every chain, so
|
|
70
|
+
fund it with ETH on Base, not on Ethereum mainnet. `AIFINPAY_RPC_URL` optionally
|
|
71
|
+
replaces the chain's public RPC (`https://mainnet.base.org`,
|
|
72
|
+
`https://polygon.drpc.org`).
|
|
73
|
+
|
|
74
|
+
A payment still pending on one chain is recovered only with that chain
|
|
75
|
+
configured; switching chains never re-sends or forgets it.
|
|
76
|
+
|
|
50
77
|
Call `payable_fetch({"url":"https://merchant.example/api/data"})`. The tool
|
|
51
|
-
uses the original signed v1.4 quote, independent fresh
|
|
78
|
+
uses the original signed v1.4 quote, independent fresh native/USD pricing, SDK
|
|
52
79
|
runtime/signer verification and owner limits. It persists the prepared transaction
|
|
53
80
|
before sending, verifies the receipt, and reuses the purchased batch. No special
|
|
54
|
-
merchant script, alternate contract or facilitator fallback is used. GET,
|
|
55
|
-
|
|
56
|
-
receipts are not supported. The smallest batch is $0.10 plus gas, so keep `AIFINPAY_MAX_USD`
|
|
81
|
+
merchant script, alternate contract or facilitator fallback is used. GET, live
|
|
82
|
+
mode only, on the configured chain, in its native currency or the configured
|
|
83
|
+
stablecoin; Amoy payment receipts are not supported. The smallest batch is $0.10 plus gas, so keep `AIFINPAY_MAX_USD`
|
|
57
84
|
a little above the batch you expect to buy.
|
|
58
85
|
|
|
59
86
|
To buy access to a whole site rather than one endpoint, call
|
|
@@ -67,9 +94,9 @@ owner can add it.
|
|
|
67
94
|
### Network access
|
|
68
95
|
|
|
69
96
|
A sandbox that allowlists outbound hosts must allow `api.aifinpay.io` (quotes and
|
|
70
|
-
receipts) and
|
|
71
|
-
on
|
|
72
|
-
one of them is enough. If none answers, `payable_fetch` stops before paying and
|
|
97
|
+
receipts) and an RPC for the pay chain. The independent POL/USD or ETH/USD rate
|
|
98
|
+
comes from Chainlink on that chain over the same RPC, then `api.coinbase.com`,
|
|
99
|
+
then `api.coingecko.com`; one of them is enough. If none answers, `payable_fetch` stops before paying and
|
|
73
100
|
the error names each host it tried.
|
|
74
101
|
|
|
75
102
|
## Link the agent to its owner's dashboard
|
|
@@ -100,10 +127,18 @@ state file in chat. Unconfirmed payments consume the budget conservatively.
|
|
|
100
127
|
| `agent_passport_resolve` | Resolve the global Agent Passport identity. |
|
|
101
128
|
| `settlement_routes` | Read the available verified settlement routes. |
|
|
102
129
|
| `settlement_invoice` | Prepare a non-signing settlement invoice. |
|
|
103
|
-
|
|
104
|
-
`
|
|
105
|
-
|
|
106
|
-
|
|
130
|
+
| `agent_history` | Read indexed settlements or retained receipt batches. |
|
|
131
|
+
| `settlement_solana` | Build a non-signing Solana settlement invoice. |
|
|
132
|
+
| `settlement_casper` | Build a non-signing Casper settlement invoice. |
|
|
133
|
+
| `deployment_info` | Read deployments: addresses, assets, settlement status. |
|
|
134
|
+
|
|
135
|
+
`payable_fetch` is registered when the owner sets `AIFINPAY_PAYMENTS_ENABLED=1`
|
|
136
|
+
with a persistent wallet. With payments enabled and any owner limit missing or
|
|
137
|
+
invalid, the server refuses to start rather than hiding the tool. It accepts
|
|
138
|
+
only `url`, `max_amount_usd` and `scope`; `max_amount_usd` can lower the owner's
|
|
139
|
+
per-payment cap for one call, never raise it. `dev_payment_quote` is registered
|
|
140
|
+
only with `AIFINPAY_MODE=dev`. Legacy `agent_call`, `agent_quote`,
|
|
141
|
+
`pay_with_split` and `quote_split` remain unregistered.
|
|
107
142
|
|
|
108
143
|
## Persistent wallet selection
|
|
109
144
|
|
|
@@ -162,7 +197,7 @@ A client configuration can use the keystore without embedding its secret:
|
|
|
162
197
|
"mcpServers": {
|
|
163
198
|
"aifinpay": {
|
|
164
199
|
"command": "npx",
|
|
165
|
-
"args": ["-y", "@aifinpay/mcp@2.
|
|
200
|
+
"args": ["-y", "@aifinpay/mcp@2.5.0"],
|
|
166
201
|
"env": {
|
|
167
202
|
"AIFINPAY_AGENTS_FILE": "/absolute/project/aifinpay/agents.json",
|
|
168
203
|
"AIFINPAY_AGENT_ID": "research-agent"
|
|
@@ -197,13 +232,17 @@ snapshot. Verify `agent_address` against the wallet you intend to use.
|
|
|
197
232
|
|
|
198
233
|
## Other environment variables
|
|
199
234
|
|
|
200
|
-
| Variable | Default | Purpose
|
|
201
|
-
| ---------------------------- | --------------------- |
|
|
202
|
-
| `AIFINPAY_BASE_URL` | `https://aifinpay.io` | Backend URL.
|
|
203
|
-
| `AIFINPAY_TIMEOUT_MS` | `30000` | Request timeout.
|
|
204
|
-
| `AIFINPAY_MAX_USD` | — |
|
|
205
|
-
| `AIFINPAY_GATEWAY_ORIGINS` |
|
|
206
|
-
| `AIFINPAY_GATEWAY_PATH_MODE` | `gateway` | Use `gateway` for merchant-slug identity or `direct` for full request-path identity.
|
|
235
|
+
| Variable | Default | Purpose |
|
|
236
|
+
| ---------------------------- | --------------------- | ------------------------------------------------------------------------------------- |
|
|
237
|
+
| `AIFINPAY_BASE_URL` | `https://aifinpay.io` | Backend URL. Unset, `payable_fetch` quotes and verifies at `https://api.aifinpay.io`. |
|
|
238
|
+
| `AIFINPAY_TIMEOUT_MS` | `30000` | Request timeout. |
|
|
239
|
+
| `AIFINPAY_MAX_USD` | — | Per-payment USD cap for `payable_fetch`; required when payments are enabled. |
|
|
240
|
+
| `AIFINPAY_GATEWAY_ORIGINS` | — | Comma-separated exact HTTPS origins the agent may pay; required with payments. |
|
|
241
|
+
| `AIFINPAY_GATEWAY_PATH_MODE` | `gateway` | Use `gateway` for merchant-slug identity or `direct` for full request-path identity. |
|
|
242
|
+
| `AIFINPAY_PAY_CHAIN` | `polygon` | Chain `payable_fetch` settles on: `polygon` or `base`. |
|
|
243
|
+
| `AIFINPAY_MAX_GAS` | — | Gas cap per payment in the pay chain's native currency (POL, ETH). |
|
|
244
|
+
| `AIFINPAY_RPC_URL` | chain's public RPC | HTTPS RPC for the pay chain. |
|
|
245
|
+
| `AIFINPAY_CLAIM_ORIGINS` | AiFinPay dashboards | Exact origins `agent_claim_self` may link the agent to. |
|
|
207
246
|
|
|
208
247
|
`agent_history({address, source:"transactions"})` reads indexed Polygon
|
|
209
248
|
settlements; `source:"receipts"` reads retained batches, including test-mode
|
|
@@ -228,7 +267,7 @@ The programmatic equivalents of identity environment options are `seedHash`,
|
|
|
228
267
|
- AIFINPAY_MODE=dev: expose dev_payment_quote; requires a separate dev base URL.
|
|
229
268
|
|
|
230
269
|
- AIFINPAY_TIMEOUT_MS: SDK request timeout.
|
|
231
|
-
- AIFINPAY_MAX_USD:
|
|
270
|
+
- AIFINPAY_MAX_USD: per-payment USD cap for payable_fetch; required with payments.
|
|
232
271
|
- AIFINPAY_TRUSTED_HOSTS: exact hosts allowed to bypass the DNS pre-check.
|
|
233
272
|
- AIFINPAY_ALLOW_PRIVATE_FETCH=1: explicit local-development network access.
|
|
234
273
|
Never enable this on the public hosted MCP.
|
package/dist/config.d.ts
CHANGED
|
@@ -17,9 +17,17 @@ export interface McpConfig {
|
|
|
17
17
|
/** Owner opt-in; never accepted from tool arguments. */
|
|
18
18
|
paymentsEnabled?: boolean;
|
|
19
19
|
dailyAmountUsd?: number;
|
|
20
|
+
/** Chain payable_fetch settles on: "polygon" (default) or "base". Set by
|
|
21
|
+
* the owner only; never inferred from a quote or a tool argument. */
|
|
22
|
+
payChain?: string;
|
|
23
|
+
/** RPC for the pay chain; defaults to the chain's public RPC. */
|
|
24
|
+
rpcUrl?: string;
|
|
25
|
+
/** Gas cap per payment, in the pay chain's native currency (POL, ETH). */
|
|
26
|
+
maxGas?: string;
|
|
27
|
+
/** Same cap under its original name; accepted on Polygon only. */
|
|
20
28
|
maxGasPol?: string;
|
|
21
|
-
/** What payable_fetch pays with:
|
|
22
|
-
* pins for
|
|
29
|
+
/** What payable_fetch pays with: the chain's native currency (default) or a
|
|
30
|
+
* stablecoin the SDK pins for that chain, e.g. "USDC". Gas is native either way. */
|
|
23
31
|
payAsset?: string;
|
|
24
32
|
/** Hard cap on a single payment to prevent runaway agents. */
|
|
25
33
|
maxAmountUsd?: number;
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,6CAA6C;AAC7C,MAAM,WAAW,SAAS;IACxB,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4EAA4E;IAC5E,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,wDAAwD;IACxD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;0EACsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;yFACqF;IACrF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;;;;;;;;+CAW2C;IAC3C,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAE1B,2EAA2E;IAC3E,eAAe,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAEvC;;;;;;;;;8CAS0C;IAC1C,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAExB,qDAAqD;IACrD,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACjE;AAED,wBAAgB,iBAAiB,IAAI,SAAS,CA6B7C;AA0DD,oFAAoF;AACpF,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAuD/D"}
|
package/dist/config.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { payChain } from "./pay-chains.js";
|
|
1
2
|
export function loadConfigFromEnv() {
|
|
2
3
|
if (process.env.AIFINPAY_MODE && !["live", "dev"].includes(process.env.AIFINPAY_MODE)) {
|
|
3
4
|
throw new Error("AIFINPAY_MODE must be live or dev");
|
|
@@ -8,6 +9,9 @@ export function loadConfigFromEnv() {
|
|
|
8
9
|
return {
|
|
9
10
|
paymentsEnabled: process.env.AIFINPAY_PAYMENTS_ENABLED === "1",
|
|
10
11
|
dailyAmountUsd: process.env.AIFINPAY_DAILY_USD ? Number(process.env.AIFINPAY_DAILY_USD) : undefined,
|
|
12
|
+
payChain: process.env.AIFINPAY_PAY_CHAIN || undefined,
|
|
13
|
+
rpcUrl: process.env.AIFINPAY_RPC_URL || undefined,
|
|
14
|
+
maxGas: process.env.AIFINPAY_MAX_GAS || undefined,
|
|
11
15
|
maxGasPol: process.env.AIFINPAY_MAX_GAS_POL || undefined,
|
|
12
16
|
payAsset: process.env.AIFINPAY_PAY_ASSET || undefined,
|
|
13
17
|
devMode: process.env.AIFINPAY_MODE === "dev",
|
|
@@ -84,7 +88,19 @@ export function validatePaymentConfig(config) {
|
|
|
84
88
|
if (!config.paymentsEnabled)
|
|
85
89
|
throw new Error("Payments disabled; owner must set AIFINPAY_PAYMENTS_ENABLED=1");
|
|
86
90
|
if (config.devMode)
|
|
87
|
-
throw new Error("MCP receipt payments
|
|
91
|
+
throw new Error("MCP receipt payments support live mode only");
|
|
92
|
+
const chain = payChain(config.payChain);
|
|
93
|
+
if (config.rpcUrl !== undefined) {
|
|
94
|
+
let rpc;
|
|
95
|
+
try {
|
|
96
|
+
rpc = new URL(config.rpcUrl);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
rpc = undefined;
|
|
100
|
+
}
|
|
101
|
+
if (!rpc || rpc.protocol !== "https:" || rpc.username || rpc.password)
|
|
102
|
+
throw new Error("AIFINPAY_RPC_URL must be an https URL without credentials");
|
|
103
|
+
}
|
|
88
104
|
for (const [name, value] of [
|
|
89
105
|
["AIFINPAY_MAX_USD", config.maxAmountUsd],
|
|
90
106
|
["AIFINPAY_DAILY_USD", config.dailyAmountUsd],
|
|
@@ -104,14 +120,21 @@ export function validatePaymentConfig(config) {
|
|
|
104
120
|
}))
|
|
105
121
|
throw new Error("Payments require explicit exact HTTPS AIFINPAY_GATEWAY_ORIGINS");
|
|
106
122
|
if (config.payAsset !== undefined && !/^[A-Z][A-Z0-9.]{1,11}$/.test(config.payAsset))
|
|
107
|
-
throw new Error(
|
|
108
|
-
|
|
123
|
+
throw new Error(`AIFINPAY_PAY_ASSET must be "${chain.native}" or a stablecoin symbol such as "USDC"`);
|
|
124
|
+
// The POL-named cap means POL. Read on another chain it would silently cap
|
|
125
|
+
// ETH gas at a number chosen for POL — 0.3 POL is ~$0.04, 0.3 ETH is ~$800.
|
|
126
|
+
if (config.maxGasPol !== undefined && chain.name !== "polygon")
|
|
127
|
+
throw new Error(`AIFINPAY_MAX_GAS_POL caps POL gas and does not apply on ${chain.name}; set AIFINPAY_MAX_GAS in ${chain.native}`);
|
|
128
|
+
if (config.maxGas !== undefined && config.maxGasPol !== undefined && config.maxGas !== config.maxGasPol)
|
|
129
|
+
throw new Error("AIFINPAY_MAX_GAS and AIFINPAY_MAX_GAS_POL disagree; set one");
|
|
130
|
+
const name = config.maxGas !== undefined ? "AIFINPAY_MAX_GAS" : "AIFINPAY_MAX_GAS_POL";
|
|
131
|
+
const gas = config.maxGas ?? config.maxGasPol;
|
|
109
132
|
if (typeof gas !== "string" || !/^(?:0|[1-9][0-9]*)(?:\.[0-9]{1,18})?$/.test(gas))
|
|
110
|
-
throw new Error(
|
|
133
|
+
throw new Error(`${name} must be a positive decimal with at most 18 places: the gas cap per payment in ${chain.native}`);
|
|
111
134
|
const [whole, fraction = ""] = gas.split(".");
|
|
112
135
|
const wei = BigInt(whole) * 10n ** 18n + BigInt(fraction.padEnd(18, "0"));
|
|
113
136
|
if (wei <= 0n || wei >= 2n ** 256n)
|
|
114
|
-
throw new Error(
|
|
137
|
+
throw new Error(`${name} is outside the supported range`);
|
|
115
138
|
return wei;
|
|
116
139
|
}
|
|
117
140
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createDirectoryServer — the READ-ONLY MCP server submitted to the OpenAI
|
|
3
|
+
* ChatGPT App Directory. Distinct from `createServer` (the full BYO-MCP
|
|
4
|
+
* connector with payment execution): this one exposes ONLY the read-only
|
|
5
|
+
* directory tools, requires NO agent identity and NO auth, and never moves
|
|
6
|
+
* money — so it is reviewable under OpenAI's directory policy (Obsidian/32 /34).
|
|
7
|
+
*
|
|
8
|
+
* One codebase, two profiles: the HTTP wrapper picks this when
|
|
9
|
+
* AIFINPAY_MCP_PROFILE=directory.
|
|
10
|
+
*/
|
|
11
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
12
|
+
export interface DirectoryServerConfig {
|
|
13
|
+
/** Public API base for the wrapped GET endpoints. Defaults to production. */
|
|
14
|
+
apiBase?: string;
|
|
15
|
+
/** Per-request timeout (ms). */
|
|
16
|
+
timeoutMs?: number;
|
|
17
|
+
log?: (level: "info" | "warn" | "error", msg: string) => void;
|
|
18
|
+
}
|
|
19
|
+
export declare function createDirectoryServer(config?: DirectoryServerConfig): Promise<{
|
|
20
|
+
server: Server<{
|
|
21
|
+
method: string;
|
|
22
|
+
params?: {
|
|
23
|
+
[x: string]: unknown;
|
|
24
|
+
_meta?: {
|
|
25
|
+
[x: string]: unknown;
|
|
26
|
+
progressToken?: string | number | undefined;
|
|
27
|
+
"io.modelcontextprotocol/related-task"?: {
|
|
28
|
+
taskId: string;
|
|
29
|
+
} | undefined;
|
|
30
|
+
} | undefined;
|
|
31
|
+
} | undefined;
|
|
32
|
+
}, {
|
|
33
|
+
method: string;
|
|
34
|
+
params?: {
|
|
35
|
+
[x: string]: unknown;
|
|
36
|
+
_meta?: {
|
|
37
|
+
[x: string]: unknown;
|
|
38
|
+
progressToken?: string | number | undefined;
|
|
39
|
+
"io.modelcontextprotocol/related-task"?: {
|
|
40
|
+
taskId: string;
|
|
41
|
+
} | undefined;
|
|
42
|
+
} | undefined;
|
|
43
|
+
} | undefined;
|
|
44
|
+
}, {
|
|
45
|
+
[x: string]: unknown;
|
|
46
|
+
_meta?: {
|
|
47
|
+
[x: string]: unknown;
|
|
48
|
+
progressToken?: string | number | undefined;
|
|
49
|
+
"io.modelcontextprotocol/related-task"?: {
|
|
50
|
+
taskId: string;
|
|
51
|
+
} | undefined;
|
|
52
|
+
} | undefined;
|
|
53
|
+
}>;
|
|
54
|
+
}>;
|
|
55
|
+
//# sourceMappingURL=directory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory.d.ts","sourceRoot":"","sources":["../src/directory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAYnE,MAAM,WAAW,qBAAqB;IACpC,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/D;AAwBD,wBAAsB,qBAAqB,CAAC,MAAM,GAAE,qBAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2B7E"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createDirectoryServer — the READ-ONLY MCP server submitted to the OpenAI
|
|
3
|
+
* ChatGPT App Directory. Distinct from `createServer` (the full BYO-MCP
|
|
4
|
+
* connector with payment execution): this one exposes ONLY the read-only
|
|
5
|
+
* directory tools, requires NO agent identity and NO auth, and never moves
|
|
6
|
+
* money — so it is reviewable under OpenAI's directory policy (Obsidian/32 /34).
|
|
7
|
+
*
|
|
8
|
+
* One codebase, two profiles: the HTTP wrapper picks this when
|
|
9
|
+
* AIFINPAY_MCP_PROFILE=directory.
|
|
10
|
+
*/
|
|
11
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
12
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
13
|
+
import { directoryTools, runDirectoryTool, DIRECTORY_API_BASE, } from "./tools/directory.js";
|
|
14
|
+
// Server-wide instructions returned at initialize. ChatGPT/Codex use these as a
|
|
15
|
+
// cross-tool guide (OpenAI readiness checklist item; the audit found it ABSENT
|
|
16
|
+
// on the connector server). States the read-only contract, networks, and limits.
|
|
17
|
+
const DIRECTORY_INSTRUCTIONS = [
|
|
18
|
+
"AiFinPay is payment infrastructure for AI agents. THIS server is the",
|
|
19
|
+
"read-only directory surface: it answers questions about the AiFinPay agent",
|
|
20
|
+
"economy and prices AI services — it does NOT move money, hold funds, sign",
|
|
21
|
+
"transactions, or execute any payment. Every tool is read-only.",
|
|
22
|
+
"",
|
|
23
|
+
"Use it to: list available AI providers and their per-call prices",
|
|
24
|
+
"(list_providers / provider_info / provider_status / service_coverage),",
|
|
25
|
+
"preview a fee-on-top cost breakdown without paying (quote_cost), read public",
|
|
26
|
+
"protocol stats (network_stats) and the on-chain agent leaderboard",
|
|
27
|
+
"(leaderboard), verify an agent's AgentPassport (verify_passport), and look up",
|
|
28
|
+
"a public agent profile (agent_profile).",
|
|
29
|
+
"",
|
|
30
|
+
"Networks: Polygon and Solana mainnet. Data is public on-chain / registry",
|
|
31
|
+
"information. To actually execute a payment, an agent uses the separate",
|
|
32
|
+
"AiFinPay connector or SDK — not this directory app. Requests are rate limited;",
|
|
33
|
+
"on HTTP 429 (rate_limit_exceeded), back off and retry.",
|
|
34
|
+
].join("\n");
|
|
35
|
+
export async function createDirectoryServer(config = {}) {
|
|
36
|
+
const log = config.log ?? ((lvl, msg) => process.stderr.write(`[${lvl}] ${msg}\n`));
|
|
37
|
+
const ctx = {
|
|
38
|
+
apiBase: (config.apiBase || DIRECTORY_API_BASE).replace(/\/$/, ""),
|
|
39
|
+
timeoutMs: config.timeoutMs ?? 15000,
|
|
40
|
+
log,
|
|
41
|
+
};
|
|
42
|
+
const server = new Server({ name: "@aifinpay/mcp-directory", version: "1.0.0" }, {
|
|
43
|
+
capabilities: { tools: {} },
|
|
44
|
+
instructions: DIRECTORY_INSTRUCTIONS,
|
|
45
|
+
});
|
|
46
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
47
|
+
tools: directoryTools(),
|
|
48
|
+
}));
|
|
49
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
50
|
+
const { name, arguments: args } = request.params;
|
|
51
|
+
return runDirectoryTool(ctx, name, args ?? {});
|
|
52
|
+
});
|
|
53
|
+
log("info", `[aifinpay-mcp-directory] read-only profile · api=${ctx.apiBase}`);
|
|
54
|
+
return { server };
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=directory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory.js","sourceRoot":"","sources":["../src/directory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,kBAAkB,GAEnB,MAAM,sBAAsB,CAAC;AAU9B,gFAAgF;AAChF,+EAA+E;AAC/E,iFAAiF;AACjF,MAAM,sBAAsB,GAAG;IAC7B,sEAAsE;IACtE,4EAA4E;IAC5E,2EAA2E;IAC3E,gEAAgE;IAChE,EAAE;IACF,kEAAkE;IAClE,wEAAwE;IACxE,8EAA8E;IAC9E,mEAAmE;IACnE,+EAA+E;IAC/E,yCAAyC;IACzC,EAAE;IACF,0EAA0E;IAC1E,wEAAwE;IACxE,gFAAgF;IAChF,wDAAwD;CACzD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,SAAgC,EAAE;IAC5E,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC;IACpF,MAAM,GAAG,GAAqB;QAC5B,OAAO,EAAE,CAAC,MAAM,CAAC,OAAO,IAAI,kBAAkB,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;QAClE,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,KAAK;QACpC,GAAG;KACJ,CAAC;IAEF,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,EAAE,IAAI,EAAE,yBAAyB,EAAE,OAAO,EAAE,OAAO,EAAE,EACrD;QACE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QAC3B,YAAY,EAAE,sBAAsB;KACrC,CACF,CAAC;IAEF,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;QAC5D,KAAK,EAAE,cAAc,EAAE;KACxB,CAAC,CAAC,CAAC;IAEJ,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAChE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;QACjD,OAAO,gBAAgB,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,MAAM,EAAE,oDAAoD,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/E,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Tools: public addresses, history, quotas, passport resolution, non-signing
|
|
6
6
|
* settlement invoices, local wallet reload, and opt-in dev batch quoting.
|
|
7
|
-
*
|
|
7
|
+
* The one signing tool, payable_fetch, is registered only when the owner
|
|
8
|
+
* enables payments with every limit set.
|
|
8
9
|
*
|
|
9
10
|
* Quick start (stdio transport for Claude Desktop / MCP-aware runtimes):
|
|
10
11
|
*
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Tools: public addresses, history, quotas, passport resolution, non-signing
|
|
6
6
|
* settlement invoices, local wallet reload, and opt-in dev batch quoting.
|
|
7
|
-
*
|
|
7
|
+
* The one signing tool, payable_fetch, is registered only when the owner
|
|
8
|
+
* enables payments with every limit set.
|
|
8
9
|
*
|
|
9
10
|
* Quick start (stdio transport for Claude Desktop / MCP-aware runtimes):
|
|
10
11
|
*
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/native-price.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { type PayChain } from "./pay-chains.js";
|
|
1
2
|
/**
|
|
2
|
-
* Independent
|
|
3
|
+
* Independent native/USD rate for payable_fetch: POL on Polygon, ETH on Base.
|
|
3
4
|
*
|
|
4
5
|
* payable_fetch values a v1.4 quote in USD with a rate it fetches itself —
|
|
5
6
|
* never the quote API's own — so the owner's per-payment and daily USD limits
|
|
@@ -9,23 +10,31 @@
|
|
|
9
10
|
* it began, with nothing to try instead.
|
|
10
11
|
*
|
|
11
12
|
* Sources, in order; the first fresh, sane answer wins:
|
|
12
|
-
* 1. Chainlink
|
|
13
|
-
* the host the payment already needs, so no extra
|
|
13
|
+
* 1. Chainlink <native>/USD on the payment chain, read over the agent's own
|
|
14
|
+
* RPC for that chain — the host the payment already needs, so no extra
|
|
15
|
+
* allowlist entry.
|
|
14
16
|
* 2. api.coinbase.com spot price.
|
|
15
|
-
* 3. api.coingecko.com
|
|
16
|
-
*
|
|
17
|
+
* 3. api.coingecko.com.
|
|
18
|
+
* Feed addresses and ids live in pay-chains.ts.
|
|
17
19
|
*/
|
|
18
|
-
export declare const CHAINLINK_POL_USD_POLYGON
|
|
20
|
+
export declare const CHAINLINK_POL_USD_POLYGON: `0x${string}`;
|
|
19
21
|
export interface NativePrice {
|
|
20
22
|
usd: number;
|
|
21
23
|
observedAtMs: number;
|
|
22
|
-
source:
|
|
24
|
+
source: `chainlink-${string}` | "coinbase" | "coingecko";
|
|
23
25
|
}
|
|
24
26
|
type FetchImpl = (input: string, init?: RequestInit) => Promise<Response>;
|
|
25
27
|
/**
|
|
26
|
-
* The first independent
|
|
27
|
-
* every source tried, so an agent in a
|
|
28
|
+
* The first independent native/USD rate any source gives for the payment
|
|
29
|
+
* chain. Throws one error naming every source tried, so an agent in a
|
|
30
|
+
* restricted sandbox knows what to allow.
|
|
28
31
|
*/
|
|
32
|
+
export declare function independentNativeUsd(opts: {
|
|
33
|
+
fetchImpl: FetchImpl;
|
|
34
|
+
chain: PayChain;
|
|
35
|
+
rpc?: string;
|
|
36
|
+
}): Promise<NativePrice>;
|
|
37
|
+
/** The Polygon rate, as before chains were configurable. */
|
|
29
38
|
export declare function independentPolUsd(opts: {
|
|
30
39
|
fetchImpl: FetchImpl;
|
|
31
40
|
polygonRpc?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-price.d.ts","sourceRoot":"","sources":["../src/native-price.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"native-price.d.ts","sourceRoot":"","sources":["../src/native-price.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE5D;;;;;;;;;;;;;;;;;GAiBG;AAEH,eAAO,MAAM,yBAAyB,eAAwC,CAAC;AAO/E,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,aAAa,MAAM,EAAE,GAAG,UAAU,GAAG,WAAW,CAAC;CAC1D;AAED,KAAK,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAoE1E;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,IAAI,EAAE;IAC/C,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,QAAQ,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,WAAW,CAAC,CAsBvB;AAED,4DAA4D;AAC5D,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IAAE,SAAS,EAAE,SAAS,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAE3G"}
|
package/dist/native-price.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { PAY_CHAINS } from "./pay-chains.js";
|
|
1
2
|
/**
|
|
2
|
-
* Independent
|
|
3
|
+
* Independent native/USD rate for payable_fetch: POL on Polygon, ETH on Base.
|
|
3
4
|
*
|
|
4
5
|
* payable_fetch values a v1.4 quote in USD with a rate it fetches itself —
|
|
5
6
|
* never the quote API's own — so the owner's per-payment and daily USD limits
|
|
@@ -9,29 +10,27 @@
|
|
|
9
10
|
* it began, with nothing to try instead.
|
|
10
11
|
*
|
|
11
12
|
* Sources, in order; the first fresh, sane answer wins:
|
|
12
|
-
* 1. Chainlink
|
|
13
|
-
* the host the payment already needs, so no extra
|
|
13
|
+
* 1. Chainlink <native>/USD on the payment chain, read over the agent's own
|
|
14
|
+
* RPC for that chain — the host the payment already needs, so no extra
|
|
15
|
+
* allowlist entry.
|
|
14
16
|
* 2. api.coinbase.com spot price.
|
|
15
|
-
* 3. api.coingecko.com
|
|
16
|
-
*
|
|
17
|
+
* 3. api.coingecko.com.
|
|
18
|
+
* Feed addresses and ids live in pay-chains.ts.
|
|
17
19
|
*/
|
|
18
|
-
|
|
19
|
-
// 1:1 and the feed kept its name ("MATIC / USD"); 8 decimals. Read 2026-09-23:
|
|
20
|
-
// 0.1064, updated 3 s earlier, within 0.1% of Coinbase.
|
|
21
|
-
export const CHAINLINK_POL_USD_POLYGON = "0xAB594600376Ec9fD91F8e885dADF0CE036862dE0";
|
|
20
|
+
export const CHAINLINK_POL_USD_POLYGON = PAY_CHAINS.polygon.chainlinkNativeUsd;
|
|
22
21
|
const LATEST_ROUND_DATA = "0xfeaf968c"; // latestRoundData()
|
|
23
22
|
const CHAINLINK_DECIMALS = 8;
|
|
24
23
|
// The feed updates on a 0.5% deviation or its heartbeat; a quiet market can
|
|
25
24
|
// leave it for a while. Older than this and it is not trusted as "current".
|
|
26
25
|
const MAX_FEED_AGE_S = 3600;
|
|
27
|
-
const sane = (usd) => Number.isFinite(usd) && usd > 0 && usd <
|
|
26
|
+
const sane = (usd, chain) => Number.isFinite(usd) && usd > 0 && usd < chain.maxSaneUsd;
|
|
28
27
|
async function boundedJson(response, limit = 16 * 1024) {
|
|
29
28
|
const text = await response.text();
|
|
30
29
|
if (text.length > limit)
|
|
31
30
|
throw new Error("price response exceeds limit");
|
|
32
31
|
return JSON.parse(text);
|
|
33
32
|
}
|
|
34
|
-
async function fromChainlink(fetchImpl, rpc) {
|
|
33
|
+
async function fromChainlink(fetchImpl, rpc, chain) {
|
|
35
34
|
const response = await fetchImpl(rpc, {
|
|
36
35
|
method: "POST",
|
|
37
36
|
headers: { "content-type": "application/json" },
|
|
@@ -39,7 +38,7 @@ async function fromChainlink(fetchImpl, rpc) {
|
|
|
39
38
|
jsonrpc: "2.0",
|
|
40
39
|
id: 1,
|
|
41
40
|
method: "eth_call",
|
|
42
|
-
params: [{ to:
|
|
41
|
+
params: [{ to: chain.chainlinkNativeUsd, data: LATEST_ROUND_DATA }, "latest"],
|
|
43
42
|
}),
|
|
44
43
|
signal: AbortSignal.timeout(10_000),
|
|
45
44
|
redirect: "manual",
|
|
@@ -60,12 +59,12 @@ async function fromChainlink(fetchImpl, rpc) {
|
|
|
60
59
|
if (ageS > MAX_FEED_AGE_S)
|
|
61
60
|
throw new Error(`feed is ${ageS}s old`);
|
|
62
61
|
const usd = Number(answer) / 10 ** CHAINLINK_DECIMALS;
|
|
63
|
-
if (!sane(usd))
|
|
62
|
+
if (!sane(usd, chain))
|
|
64
63
|
throw new Error("implausible answer");
|
|
65
|
-
return { usd, observedAtMs: Date.now(), source:
|
|
64
|
+
return { usd, observedAtMs: Date.now(), source: `chainlink-${chain.name}` };
|
|
66
65
|
}
|
|
67
|
-
async function fromCoinbase(fetchImpl) {
|
|
68
|
-
const response = await fetchImpl(
|
|
66
|
+
async function fromCoinbase(fetchImpl, chain) {
|
|
67
|
+
const response = await fetchImpl(`https://api.coinbase.com/v2/prices/${chain.coinbasePair}/spot`, {
|
|
69
68
|
signal: AbortSignal.timeout(10_000),
|
|
70
69
|
redirect: "manual",
|
|
71
70
|
});
|
|
@@ -73,36 +72,38 @@ async function fromCoinbase(fetchImpl) {
|
|
|
73
72
|
throw new Error(`http ${response.status}`);
|
|
74
73
|
const data = (await boundedJson(response));
|
|
75
74
|
const usd = Number(data.data?.amount);
|
|
76
|
-
if (data.data?.base !==
|
|
75
|
+
if (data.data?.base !== chain.native || data.data?.currency !== "USD" || !sane(usd, chain)) {
|
|
77
76
|
throw new Error("invalid response");
|
|
78
77
|
}
|
|
79
78
|
return { usd, observedAtMs: Date.now(), source: "coinbase" };
|
|
80
79
|
}
|
|
81
|
-
async function fromCoinGecko(fetchImpl) {
|
|
82
|
-
const response = await fetchImpl(
|
|
80
|
+
async function fromCoinGecko(fetchImpl, chain) {
|
|
81
|
+
const response = await fetchImpl(`https://api.coingecko.com/api/v3/simple/price?ids=${chain.coingeckoId}&vs_currencies=usd&include_last_updated_at=true`, { signal: AbortSignal.timeout(10_000), redirect: "manual" });
|
|
83
82
|
if (!response.ok)
|
|
84
83
|
throw new Error(`http ${response.status}`);
|
|
85
84
|
const data = (await boundedJson(response));
|
|
86
|
-
const entry = data[
|
|
85
|
+
const entry = data[chain.coingeckoId];
|
|
87
86
|
const usd = Number(entry?.usd);
|
|
88
87
|
const ageS = Math.floor(Date.now() / 1000) - Number(entry?.last_updated_at ?? 0);
|
|
89
|
-
if (!sane(usd))
|
|
88
|
+
if (!sane(usd, chain))
|
|
90
89
|
throw new Error("invalid response");
|
|
91
90
|
if (!(ageS <= MAX_FEED_AGE_S))
|
|
92
91
|
throw new Error(`price is ${ageS}s old`);
|
|
93
92
|
return { usd, observedAtMs: Date.now(), source: "coingecko" };
|
|
94
93
|
}
|
|
95
94
|
/**
|
|
96
|
-
* The first independent
|
|
97
|
-
* every source tried, so an agent in a
|
|
95
|
+
* The first independent native/USD rate any source gives for the payment
|
|
96
|
+
* chain. Throws one error naming every source tried, so an agent in a
|
|
97
|
+
* restricted sandbox knows what to allow.
|
|
98
98
|
*/
|
|
99
|
-
export async function
|
|
99
|
+
export async function independentNativeUsd(opts) {
|
|
100
|
+
const { chain } = opts;
|
|
100
101
|
const attempts = [];
|
|
101
|
-
const rpc = opts.
|
|
102
|
+
const rpc = opts.rpc;
|
|
102
103
|
if (rpc)
|
|
103
|
-
attempts.push([`Chainlink on
|
|
104
|
-
attempts.push(["api.coinbase.com", () => fromCoinbase(opts.fetchImpl)]);
|
|
105
|
-
attempts.push(["api.coingecko.com", () => fromCoinGecko(opts.fetchImpl)]);
|
|
104
|
+
attempts.push([`Chainlink on ${chain.label} via ${hostOf(rpc)}`, () => fromChainlink(opts.fetchImpl, rpc, chain)]);
|
|
105
|
+
attempts.push(["api.coinbase.com", () => fromCoinbase(opts.fetchImpl, chain)]);
|
|
106
|
+
attempts.push(["api.coingecko.com", () => fromCoinGecko(opts.fetchImpl, chain)]);
|
|
106
107
|
const failures = [];
|
|
107
108
|
for (const [label, attempt] of attempts) {
|
|
108
109
|
try {
|
|
@@ -112,10 +113,14 @@ export async function independentPolUsd(opts) {
|
|
|
112
113
|
failures.push(`${label}: ${e instanceof Error ? e.message : String(e)}`);
|
|
113
114
|
}
|
|
114
115
|
}
|
|
115
|
-
throw new Error(
|
|
116
|
+
throw new Error(`Independent ${chain.native}/USD price unavailable — nothing was paid. Tried ` +
|
|
116
117
|
failures.join("; ") +
|
|
117
118
|
". Allow outbound access to one of these hosts.");
|
|
118
119
|
}
|
|
120
|
+
/** The Polygon rate, as before chains were configurable. */
|
|
121
|
+
export function independentPolUsd(opts) {
|
|
122
|
+
return independentNativeUsd({ fetchImpl: opts.fetchImpl, chain: PAY_CHAINS.polygon, rpc: opts.polygonRpc });
|
|
123
|
+
}
|
|
119
124
|
function hostOf(url) {
|
|
120
125
|
try {
|
|
121
126
|
return new URL(url).host;
|