@piprail/sdk 2.13.1 → 2.14.1
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/CHANGELOG.md +109 -0
- package/dist/{algorand-AQK5EAUF.cjs → algorand-ICJNXO5V.cjs} +43 -42
- package/dist/{algorand-TQCYK2XT.js → algorand-RM7MP4PK.js} +12 -11
- package/dist/{aptos-RYQOSFBQ.js → aptos-2FIRTMQX.js} +11 -10
- package/dist/{aptos-65UX7GKA.cjs → aptos-MVEG5ZPS.cjs} +41 -40
- package/dist/{chunk-DCOUJZPL.cjs → chunk-57V5DNJT.cjs} +45 -19
- package/dist/{chunk-O32N6MFN.js → chunk-NUPCFNC5.js} +27 -1
- package/dist/index.cjs +503 -239
- package/dist/index.d.cts +279 -7
- package/dist/index.d.ts +279 -7
- package/dist/index.js +299 -35
- package/dist/{ledger-mF_SoiDB.d.ts → ledger-uFtXlIHY.d.cts} +31 -1
- package/dist/{ledger-mF_SoiDB.d.cts → ledger-uFtXlIHY.d.ts} +31 -1
- package/dist/{near-UDPFA6SV.cjs → near-C2IS4RCH.cjs} +39 -30
- package/dist/{near-VDATC5AV.js → near-L2OWD7M6.js} +14 -5
- package/dist/node.d.cts +2 -2
- package/dist/node.d.ts +2 -2
- package/dist/{solana-RQNXFCZO.cjs → solana-B424IQ5I.cjs} +54 -39
- package/dist/{solana-VYLWFNAH.js → solana-V2TGLHJ4.js} +22 -7
- package/dist/{stellar-OK2HW5PZ.cjs → stellar-4YR4UZQX.cjs} +23 -23
- package/dist/{stellar-KBR4V77T.js → stellar-J7VE7QP7.js} +4 -4
- package/dist/{sui-SVFBJFW5.cjs → sui-F7UW6JXJ.cjs} +35 -27
- package/dist/{sui-BXHB6D3W.js → sui-GMRQAAJH.js} +20 -12
- package/dist/{ton-D7YN6BGR.cjs → ton-3SHFVDLP.cjs} +33 -22
- package/dist/{ton-NNKQFQ6U.js → ton-PEBYBNWJ.js} +18 -7
- package/dist/{tron-WZFU57NX.cjs → tron-BS5EID2U.cjs} +39 -39
- package/dist/{tron-W2D5PQXV.js → tron-ZYJHHROT.js} +10 -10
- package/dist/{xrpl-37E23W53.js → xrpl-P2D6TS6I.js} +13 -13
- package/dist/{xrpl-5NHY3NEL.cjs → xrpl-SUEFOOKW.cjs} +31 -31
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
ConfirmationTimeoutError,
|
|
9
9
|
InsufficientFundsError,
|
|
10
|
+
InvalidConfigError,
|
|
10
11
|
InvalidEnvelopeError,
|
|
11
12
|
MAX_DECIMALS,
|
|
12
13
|
MaxRetriesExceededError,
|
|
@@ -31,7 +32,7 @@ import {
|
|
|
31
32
|
parseUnits,
|
|
32
33
|
rejectForeignToken,
|
|
33
34
|
toInsufficientFundsError
|
|
34
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-NUPCFNC5.js";
|
|
35
36
|
|
|
36
37
|
// src/drivers/registry.ts
|
|
37
38
|
var byFamily = /* @__PURE__ */ new Map();
|
|
@@ -1780,6 +1781,37 @@ function buildReceiptExtension(bundle) {
|
|
|
1780
1781
|
if (bundle.attestation) info.receipt = bundle.attestation;
|
|
1781
1782
|
return { [EXT_OFFER_RECEIPT]: { info } };
|
|
1782
1783
|
}
|
|
1784
|
+
var EXT_PAYMENT_IDENTIFIER = "payment-identifier";
|
|
1785
|
+
var PAYMENT_ID_MIN = 16;
|
|
1786
|
+
var PAYMENT_ID_MAX = 128;
|
|
1787
|
+
var PAYMENT_ID_RE = /^[A-Za-z0-9_-]+$/;
|
|
1788
|
+
function buildPaymentIdentifierAdvertisement() {
|
|
1789
|
+
return {
|
|
1790
|
+
[EXT_PAYMENT_IDENTIFIER]: {
|
|
1791
|
+
info: { required: false },
|
|
1792
|
+
schema: { properties: { id: { type: "string", minLength: PAYMENT_ID_MIN, maxLength: PAYMENT_ID_MAX } } }
|
|
1793
|
+
}
|
|
1794
|
+
};
|
|
1795
|
+
}
|
|
1796
|
+
function readPaymentIdentifier(payload) {
|
|
1797
|
+
if (typeof payload !== "object" || payload === null) return null;
|
|
1798
|
+
const ext = payload.extensions;
|
|
1799
|
+
if (typeof ext !== "object" || ext === null) return null;
|
|
1800
|
+
const block = ext[EXT_PAYMENT_IDENTIFIER];
|
|
1801
|
+
if (typeof block !== "object" || block === null) return null;
|
|
1802
|
+
const info = block.info;
|
|
1803
|
+
if (typeof info !== "object" || info === null) return null;
|
|
1804
|
+
const id = info.id;
|
|
1805
|
+
if (id === void 0) return null;
|
|
1806
|
+
if (typeof id !== "string") return { invalid: "payment-identifier id must be a string" };
|
|
1807
|
+
if (id.length < PAYMENT_ID_MIN || id.length > PAYMENT_ID_MAX) {
|
|
1808
|
+
return { invalid: `payment-identifier id must be ${PAYMENT_ID_MIN}\u2013${PAYMENT_ID_MAX} chars (got ${id.length})` };
|
|
1809
|
+
}
|
|
1810
|
+
if (!PAYMENT_ID_RE.test(id)) {
|
|
1811
|
+
return { invalid: "payment-identifier id must match [A-Za-z0-9_-]" };
|
|
1812
|
+
}
|
|
1813
|
+
return id;
|
|
1814
|
+
}
|
|
1783
1815
|
function buildSignatureHeader(signature) {
|
|
1784
1816
|
return toBase64Json(signature);
|
|
1785
1817
|
}
|
|
@@ -1806,7 +1838,10 @@ function parseReceipt(response) {
|
|
|
1806
1838
|
const headerValue = response.headers.get(HEADER_RESPONSE) ?? response.headers.get(HEADER_RESPONSE_V1);
|
|
1807
1839
|
if (!headerValue) return null;
|
|
1808
1840
|
const parsed = fromBase64Json(headerValue);
|
|
1809
|
-
|
|
1841
|
+
if (!isValidReceipt(parsed)) return null;
|
|
1842
|
+
const r = parsed;
|
|
1843
|
+
if (typeof r.transaction !== "string" && typeof r.txHash === "string") r.transaction = r.txHash;
|
|
1844
|
+
return r;
|
|
1810
1845
|
}
|
|
1811
1846
|
function parseReceiptExtension(response) {
|
|
1812
1847
|
const headerValue = response.headers.get(HEADER_RESPONSE) ?? response.headers.get(HEADER_RESPONSE_V1);
|
|
@@ -1836,7 +1871,8 @@ function parseSettleResponse(response) {
|
|
|
1836
1871
|
if (!parsed || typeof parsed !== "object" || typeof parsed.success !== "boolean") return null;
|
|
1837
1872
|
return {
|
|
1838
1873
|
success: parsed.success,
|
|
1839
|
-
|
|
1874
|
+
// Tolerate the legacy v1 `txHash` alias for `transaction` (mirrors isValidReceipt/parseReceipt).
|
|
1875
|
+
...typeof parsed.transaction === "string" ? { transaction: parsed.transaction } : typeof parsed.txHash === "string" ? { transaction: parsed.txHash } : {},
|
|
1840
1876
|
...typeof parsed.network === "string" ? { network: parsed.network } : {},
|
|
1841
1877
|
...typeof parsed.payer === "string" ? { payer: parsed.payer } : {},
|
|
1842
1878
|
...typeof parsed.errorReason === "string" ? { errorReason: parsed.errorReason } : {},
|
|
@@ -1855,6 +1891,14 @@ function parseSignatureObject(parsed) {
|
|
|
1855
1891
|
if (!payload || typeof payload.txHash !== "string" || typeof payload.nonce !== "string") {
|
|
1856
1892
|
return null;
|
|
1857
1893
|
}
|
|
1894
|
+
if (!accepted) {
|
|
1895
|
+
const synthesized = {
|
|
1896
|
+
scheme: "onchain-proof",
|
|
1897
|
+
...typeof v.network === "string" ? { network: v.network } : {},
|
|
1898
|
+
...typeof v.asset === "string" ? { asset: v.asset } : {}
|
|
1899
|
+
};
|
|
1900
|
+
return { ...v, accepted: synthesized, payload };
|
|
1901
|
+
}
|
|
1858
1902
|
return parsed;
|
|
1859
1903
|
}
|
|
1860
1904
|
function parseSignatureHeader(value) {
|
|
@@ -1994,7 +2038,11 @@ var evmDriver = {
|
|
|
1994
2038
|
resolve(opts) {
|
|
1995
2039
|
if (typeof opts.chain === "string" && /^(solana|ton|stellar)/.test(opts.chain)) return null;
|
|
1996
2040
|
if (typeof opts.chain === "string") {
|
|
1997
|
-
|
|
2041
|
+
try {
|
|
2042
|
+
return makeEvmNetwork(resolveChain(opts.chain, opts.rpcUrl));
|
|
2043
|
+
} catch (err) {
|
|
2044
|
+
throw new UnsupportedNetworkError(err instanceof Error ? err.message : String(err), { cause: err });
|
|
2045
|
+
}
|
|
1998
2046
|
}
|
|
1999
2047
|
let resolved;
|
|
2000
2048
|
try {
|
|
@@ -2039,8 +2087,13 @@ function makeEvmNetwork(resolved) {
|
|
|
2039
2087
|
`chain ${network} is EVM; a custom token must be { address, decimals }.`
|
|
2040
2088
|
);
|
|
2041
2089
|
}
|
|
2090
|
+
if (!isAddress(token.address)) {
|
|
2091
|
+
throw new WrongFamilyError(
|
|
2092
|
+
`chain ${network} is EVM, but token address "${token.address}" is not a valid 0x address.`
|
|
2093
|
+
);
|
|
2094
|
+
}
|
|
2042
2095
|
return {
|
|
2043
|
-
asset: token.address,
|
|
2096
|
+
asset: getAddress5(token.address),
|
|
2044
2097
|
decimals: token.decimals,
|
|
2045
2098
|
...token.symbol ? { symbol: token.symbol } : {}
|
|
2046
2099
|
};
|
|
@@ -2121,9 +2174,9 @@ function makeEvmNetwork(resolved) {
|
|
|
2121
2174
|
},
|
|
2122
2175
|
async estimateCost(accept) {
|
|
2123
2176
|
const { decimals, symbol } = resolved.chain.nativeCurrency;
|
|
2124
|
-
if (accept.scheme === "exact") {
|
|
2125
|
-
const m = accept.extra
|
|
2126
|
-
const permit2 = m === "permit2" || m === "permit2-exact";
|
|
2177
|
+
if (accept.scheme === "exact" || accept.scheme === "upto") {
|
|
2178
|
+
const m = accept.extra?.assetTransferMethod;
|
|
2179
|
+
const permit2 = m === "permit2" || m === "permit2-exact" || m === "permit2-upto";
|
|
2127
2180
|
return nativeCost({
|
|
2128
2181
|
symbol,
|
|
2129
2182
|
decimals,
|
|
@@ -2329,7 +2382,7 @@ var loaders = {
|
|
|
2329
2382
|
solana: async () => {
|
|
2330
2383
|
let mod;
|
|
2331
2384
|
try {
|
|
2332
|
-
mod = await import("./solana-
|
|
2385
|
+
mod = await import("./solana-V2TGLHJ4.js");
|
|
2333
2386
|
} catch (cause) {
|
|
2334
2387
|
throw new MissingDriverError(
|
|
2335
2388
|
`Solana selected, but its packages aren't installed. Run: npm install @solana/web3.js @solana/spl-token bs58`,
|
|
@@ -2341,7 +2394,7 @@ var loaders = {
|
|
|
2341
2394
|
ton: async () => {
|
|
2342
2395
|
let mod;
|
|
2343
2396
|
try {
|
|
2344
|
-
mod = await import("./ton-
|
|
2397
|
+
mod = await import("./ton-PEBYBNWJ.js");
|
|
2345
2398
|
} catch (cause) {
|
|
2346
2399
|
throw new MissingDriverError(
|
|
2347
2400
|
`TON selected, but its packages aren't installed. Run: npm install @ton/ton @ton/core @ton/crypto`,
|
|
@@ -2353,7 +2406,7 @@ var loaders = {
|
|
|
2353
2406
|
stellar: async () => {
|
|
2354
2407
|
let mod;
|
|
2355
2408
|
try {
|
|
2356
|
-
mod = await import("./stellar-
|
|
2409
|
+
mod = await import("./stellar-J7VE7QP7.js");
|
|
2357
2410
|
} catch (cause) {
|
|
2358
2411
|
throw new MissingDriverError(
|
|
2359
2412
|
`Stellar selected, but its package isn't installed. Run: npm install @stellar/stellar-sdk`,
|
|
@@ -2365,7 +2418,7 @@ var loaders = {
|
|
|
2365
2418
|
xrpl: async () => {
|
|
2366
2419
|
let mod;
|
|
2367
2420
|
try {
|
|
2368
|
-
mod = await import("./xrpl-
|
|
2421
|
+
mod = await import("./xrpl-P2D6TS6I.js");
|
|
2369
2422
|
} catch (cause) {
|
|
2370
2423
|
throw new MissingDriverError(
|
|
2371
2424
|
`XRPL selected, but its package isn't installed. Run: npm install xrpl`,
|
|
@@ -2377,7 +2430,7 @@ var loaders = {
|
|
|
2377
2430
|
tron: async () => {
|
|
2378
2431
|
let mod;
|
|
2379
2432
|
try {
|
|
2380
|
-
mod = await import("./tron-
|
|
2433
|
+
mod = await import("./tron-ZYJHHROT.js");
|
|
2381
2434
|
} catch (cause) {
|
|
2382
2435
|
throw new MissingDriverError(
|
|
2383
2436
|
`Tron selected, but its package isn't installed. Run: npm install tronweb`,
|
|
@@ -2389,7 +2442,7 @@ var loaders = {
|
|
|
2389
2442
|
sui: async () => {
|
|
2390
2443
|
let mod;
|
|
2391
2444
|
try {
|
|
2392
|
-
mod = await import("./sui-
|
|
2445
|
+
mod = await import("./sui-GMRQAAJH.js");
|
|
2393
2446
|
} catch (cause) {
|
|
2394
2447
|
throw new MissingDriverError(
|
|
2395
2448
|
`Sui selected, but its package isn't installed. Run: npm install @mysten/sui`,
|
|
@@ -2401,7 +2454,7 @@ var loaders = {
|
|
|
2401
2454
|
near: async () => {
|
|
2402
2455
|
let mod;
|
|
2403
2456
|
try {
|
|
2404
|
-
mod = await import("./near-
|
|
2457
|
+
mod = await import("./near-L2OWD7M6.js");
|
|
2405
2458
|
} catch (cause) {
|
|
2406
2459
|
throw new MissingDriverError(
|
|
2407
2460
|
`NEAR selected, but its package isn't installed. Run: npm install near-api-js`,
|
|
@@ -2413,7 +2466,7 @@ var loaders = {
|
|
|
2413
2466
|
aptos: async () => {
|
|
2414
2467
|
let mod;
|
|
2415
2468
|
try {
|
|
2416
|
-
mod = await import("./aptos-
|
|
2469
|
+
mod = await import("./aptos-2FIRTMQX.js");
|
|
2417
2470
|
} catch (cause) {
|
|
2418
2471
|
throw new MissingDriverError(
|
|
2419
2472
|
`Aptos selected, but its package isn't installed. Run: npm install @aptos-labs/ts-sdk`,
|
|
@@ -2425,7 +2478,7 @@ var loaders = {
|
|
|
2425
2478
|
algorand: async () => {
|
|
2426
2479
|
let mod;
|
|
2427
2480
|
try {
|
|
2428
|
-
mod = await import("./algorand-
|
|
2481
|
+
mod = await import("./algorand-RM7MP4PK.js");
|
|
2429
2482
|
} catch (cause) {
|
|
2430
2483
|
throw new MissingDriverError(
|
|
2431
2484
|
`Algorand selected, but its package isn't installed. Run: npm install algosdk`,
|
|
@@ -2458,7 +2511,7 @@ async function resolveNetwork2(opts) {
|
|
|
2458
2511
|
}
|
|
2459
2512
|
|
|
2460
2513
|
// src/indexes.ts
|
|
2461
|
-
var DIRECTORY_INFO = {
|
|
2514
|
+
var DIRECTORY_INFO = Object.freeze({
|
|
2462
2515
|
"402index": {
|
|
2463
2516
|
source: "402index",
|
|
2464
2517
|
review: "probe-sync",
|
|
@@ -2486,7 +2539,7 @@ var DIRECTORY_INFO = {
|
|
|
2486
2539
|
readByDiscover: true,
|
|
2487
2540
|
caveat: "CDP Bazaar has no register endpoint \u2014 it catalogs a resource only when its own facilitator settles a payment. PipRail verifies locally with no facilitator, so a PipRail resource cannot be listed here (you can still READ Bazaar to find others). List on 402 Index or x402scan instead."
|
|
2488
2541
|
}
|
|
2489
|
-
};
|
|
2542
|
+
});
|
|
2490
2543
|
function getDirectoryInfo(source) {
|
|
2491
2544
|
return DIRECTORY_INFO[source];
|
|
2492
2545
|
}
|
|
@@ -4032,7 +4085,8 @@ var PipRailClient = class {
|
|
|
4032
4085
|
* before publishing, so retry with a brief backoff if a fresh listing is missing.
|
|
4033
4086
|
* - Results are cross-scheme (mostly the mainstream `exact` scheme); `fetch()` pays
|
|
4034
4087
|
* `onchain-proof` rails by default, and standard `exact` rails too once you opt in
|
|
4035
|
-
* with `schemes: ['onchain-proof', 'exact']` (EVM EIP-3009/Permit2 + Solana SVM + Algorand
|
|
4088
|
+
* with `schemes: ['onchain-proof', 'exact']` (EVM EIP-3009/Permit2 + Solana SVM + Algorand
|
|
4089
|
+
* + Aptos + NEAR).
|
|
4036
4090
|
*/
|
|
4037
4091
|
async discover(opts = {}) {
|
|
4038
4092
|
const found = await searchOpenIndexes({
|
|
@@ -4240,7 +4294,7 @@ var PipRailClient = class {
|
|
|
4240
4294
|
);
|
|
4241
4295
|
if (schemes.includes("exact") && exactOnNet && typeof net.payExact !== "function") {
|
|
4242
4296
|
throw new UnsupportedSchemeError(
|
|
4243
|
-
`This 402 offers a standard 'exact' rail on ${net.network}, but the ${net.family} family can't pay 'exact' (supported on EVM, Solana, Algorand + NEAR today), and no 'onchain-proof' rail was offered.`
|
|
4297
|
+
`This 402 offers a standard 'exact' rail on ${net.network}, but the ${net.family} family can't pay 'exact' (supported on EVM, Solana, Algorand, Aptos + NEAR today), and no 'onchain-proof' rail was offered.`
|
|
4244
4298
|
);
|
|
4245
4299
|
}
|
|
4246
4300
|
if (!schemes.includes("exact") && exactOnNet && typeof net.payExact === "function") {
|
|
@@ -4293,7 +4347,15 @@ var PipRailClient = class {
|
|
|
4293
4347
|
if (schemes.includes("exact")) {
|
|
4294
4348
|
out.push(
|
|
4295
4349
|
...challenge.accepts.filter(
|
|
4296
|
-
(a) => a.scheme === "exact" && this.supportsNetwork(net, a.network) && typeof net.payExact === "function" &&
|
|
4350
|
+
(a) => a.scheme === "exact" && this.supportsNetwork(net, a.network) && typeof net.payExact === "function" && // `native` is never `exact`-payable on ANY family (exact = an EIP-3009/Permit2-style
|
|
4351
|
+
// signed-authorization scheme a native coin can't support; every driver's payExact
|
|
4352
|
+
// throws/returns-null for it). describeAsset('native') IS non-null (onchain-proof needs
|
|
4353
|
+
// it), so without this guard a malformed 402 advertising a native `exact` rail would be
|
|
4354
|
+
// gathered, planned `payable`, even chosen by autoRoute — then throw at pay time.
|
|
4355
|
+
a.asset !== "native" && // the exact pay path (payExact → driver) reads `extra.assetTransferMethod`; a malformed
|
|
4356
|
+
// 402 offering an exact rail for a RECOGNISED token but omitting `extra` would otherwise
|
|
4357
|
+
// be planned payable then throw a raw TypeError mid-pay. Require it at gather time.
|
|
4358
|
+
typeof a.extra?.assetTransferMethod === "string" && net.describeAsset(a.asset) != null && // a foreign rail's maxTimeoutSeconds must be a usable positive integer, or
|
|
4297
4359
|
// signing it would build a NaN/garbage validBefore — drop it silently
|
|
4298
4360
|
// (symmetric with an unrecognised token) rather than leak a raw SyntaxError.
|
|
4299
4361
|
Number.isInteger(a.maxTimeoutSeconds) && a.maxTimeoutSeconds > 0
|
|
@@ -4303,7 +4365,8 @@ var PipRailClient = class {
|
|
|
4303
4365
|
if (schemes.includes("upto")) {
|
|
4304
4366
|
out.push(
|
|
4305
4367
|
...challenge.accepts.filter(
|
|
4306
|
-
(a) => a.scheme === "upto" && this.supportsNetwork(net, a.network) && typeof net.payUpto === "function" &&
|
|
4368
|
+
(a) => a.scheme === "upto" && this.supportsNetwork(net, a.network) && typeof net.payUpto === "function" && a.asset !== "native" && // native is not upto-payable either (same reason as exact)
|
|
4369
|
+
net.describeAsset(a.asset) != null && typeof a.extra?.facilitatorAddress === "string" && a.extra.facilitatorAddress.length > 0 && Number.isInteger(a.maxTimeoutSeconds) && a.maxTimeoutSeconds > 0
|
|
4307
4370
|
)
|
|
4308
4371
|
);
|
|
4309
4372
|
}
|
|
@@ -5474,14 +5537,15 @@ function formatSpendReport(summary) {
|
|
|
5474
5537
|
return `${perAsset} \u2014 grand total: ${grand}`;
|
|
5475
5538
|
}
|
|
5476
5539
|
function describeChallenge(challenge) {
|
|
5477
|
-
const
|
|
5540
|
+
const accepts = Array.isArray(challenge?.accepts) ? challenge.accepts : [];
|
|
5541
|
+
const first = accepts[0];
|
|
5478
5542
|
if (!first) {
|
|
5479
5543
|
return `${BRAND.name} x402 payment endpoint. Pay with @piprail/sdk (${BRAND.sdkInstall}). Docs: ${BRAND.home}.`;
|
|
5480
5544
|
}
|
|
5481
5545
|
const extra = first.extra ?? {};
|
|
5482
5546
|
const amount = extra.amountFormatted ?? first.amount;
|
|
5483
5547
|
const token = extra.symbol ?? first.asset;
|
|
5484
|
-
const hasExact =
|
|
5548
|
+
const hasExact = accepts.some((a) => a.scheme === "exact");
|
|
5485
5549
|
const standard = hasExact ? "; or any standard x402 client (an exact rail is offered)" : "";
|
|
5486
5550
|
return `${BRAND.name} x402 payment endpoint \u2014 pay ${amount} ${token} on ${first.network} to ${first.payTo}. Programmatic: ${BRAND.sdkInstall} then client.fetch(url)${standard}. Docs: ${BRAND.home}.`;
|
|
5487
5551
|
}
|
|
@@ -5517,8 +5581,8 @@ A 402 may offer up to three rails; you don't choose per payment \u2014 the clien
|
|
|
5517
5581
|
(the native coin \u2014 ETH/SOL/\u2026). Works on every chain.
|
|
5518
5582
|
- exact (the ratified x402 rail, opt-in): you only SIGN; the server \u2014 or a facilitator it chose
|
|
5519
5583
|
(e.g. PayAI) \u2014 broadcasts it, so you pay ZERO gas (you need only the token, no native coin). It
|
|
5520
|
-
works on EVM, Solana +
|
|
5521
|
-
fee-pooled group) is picked automatically.
|
|
5584
|
+
works on EVM, Solana, Algorand, Aptos + NEAR, and the on-chain method (EIP-3009 / Permit2 / SVM /
|
|
5585
|
+
Algorand fee-pooled group / Aptos fee-payer / NEAR SignedDelegateAction) is picked automatically.
|
|
5522
5586
|
- upto (the metered/variable x402 rail, opt-in, EVM): the amount you see is a MAXIMUM \u2014 you sign
|
|
5523
5587
|
a ceiling, the server meters real usage and settles the ACTUAL (<= the max). BUDGET AGAINST THE MAX:
|
|
5524
5588
|
the plan/policy treat the ceiling as the spend (a server may charge up to it), so a payable plan
|
|
@@ -5973,12 +6037,14 @@ function paymentTools(client) {
|
|
|
5973
6037
|
|
|
5974
6038
|
// src/classify.ts
|
|
5975
6039
|
function classifyChallenge(challenge, opts) {
|
|
5976
|
-
const accepts = challenge.accepts
|
|
6040
|
+
const accepts = Array.isArray(challenge?.accepts) ? challenge.accepts : [];
|
|
6041
|
+
const network = opts?.network;
|
|
6042
|
+
const schemes = opts?.schemes ?? [];
|
|
5977
6043
|
const offeredSchemes = [...new Set(accepts.map((a) => a.scheme))];
|
|
5978
6044
|
const offeredNetworks = [...new Set(accepts.map((a) => a.network))];
|
|
5979
|
-
const onClientChain = accepts.some((a) => a.network ===
|
|
6045
|
+
const onClientChain = accepts.some((a) => a.network === network);
|
|
5980
6046
|
const payableScheme = accepts.some(
|
|
5981
|
-
(a) => a.network ===
|
|
6047
|
+
(a) => a.network === network && schemes.includes(a.scheme)
|
|
5982
6048
|
);
|
|
5983
6049
|
const verdict = accepts.length === 0 ? "NO_RAIL" : payableScheme ? "PAYABLE_RAIL" : onClientChain ? "UNPAYABLE_SCHEME" : "WRONG_CHAIN";
|
|
5984
6050
|
return { onClientChain, payableScheme, offeredSchemes, offeredNetworks, verdict };
|
|
@@ -6063,6 +6129,29 @@ function buildWellKnownX402(input) {
|
|
|
6063
6129
|
...input.ownershipProofs && input.ownershipProofs.length > 0 ? { ownershipProofs: input.ownershipProofs } : {}
|
|
6064
6130
|
};
|
|
6065
6131
|
}
|
|
6132
|
+
function buildWellKnownX402Manifest(input) {
|
|
6133
|
+
if (!Array.isArray(input?.resources)) {
|
|
6134
|
+
throw new InvalidConfigError(
|
|
6135
|
+
"buildWellKnownX402Manifest: `resources` must be an array of ResourceDescription."
|
|
6136
|
+
);
|
|
6137
|
+
}
|
|
6138
|
+
const lastUpdated = typeof input.lastUpdated === "number" && Number.isFinite(input.lastUpdated) ? input.lastUpdated : Math.floor(Date.now() / 1e3);
|
|
6139
|
+
return {
|
|
6140
|
+
x402Version: 2,
|
|
6141
|
+
lastUpdated,
|
|
6142
|
+
items: input.resources.map((r) => ({
|
|
6143
|
+
resource: {
|
|
6144
|
+
url: r.url,
|
|
6145
|
+
...r.description ? { description: r.description } : {},
|
|
6146
|
+
...r.mimeType ? { mimeType: r.mimeType } : {}
|
|
6147
|
+
},
|
|
6148
|
+
type: "http",
|
|
6149
|
+
accepts: r.accepts,
|
|
6150
|
+
input: { method: (r.method ?? "GET").toUpperCase() },
|
|
6151
|
+
...r.mimeType ? { output: { mimeType: r.mimeType } } : {}
|
|
6152
|
+
}))
|
|
6153
|
+
};
|
|
6154
|
+
}
|
|
6066
6155
|
function buildX402DnsTxt(input) {
|
|
6067
6156
|
const descriptor = input.descriptor ? `descriptor=${input.descriptor};` : "";
|
|
6068
6157
|
return {
|
|
@@ -6655,7 +6744,7 @@ function createPaymentGate(options) {
|
|
|
6655
6744
|
const net = await resolveNetwork2({ chain: a.chain, rpcUrl: a.rpcUrl ?? options.rpcUrl });
|
|
6656
6745
|
const payTo = a.payTo ?? options.payTo;
|
|
6657
6746
|
if (!payTo) {
|
|
6658
|
-
throw new
|
|
6747
|
+
throw new InvalidConfigError(
|
|
6659
6748
|
`requirePayment: no payTo for chain ${net.network}. Set it on the accept entry or pass a top-level payTo.`
|
|
6660
6749
|
);
|
|
6661
6750
|
}
|
|
@@ -6793,7 +6882,7 @@ function createPaymentGate(options) {
|
|
|
6793
6882
|
if (hasCustomStore) {
|
|
6794
6883
|
return options.isUsed ? Boolean(await options.isUsed(ref)) : false;
|
|
6795
6884
|
}
|
|
6796
|
-
const key = ref.toLowerCase();
|
|
6885
|
+
const key = ref.startsWith("pid:") ? ref : ref.toLowerCase();
|
|
6797
6886
|
const now = Date.now();
|
|
6798
6887
|
pruneUsed(now);
|
|
6799
6888
|
if (localUsed.has(key)) return true;
|
|
@@ -6805,7 +6894,7 @@ function createPaymentGate(options) {
|
|
|
6805
6894
|
if (ok && options.markUsed) await options.markUsed(ref);
|
|
6806
6895
|
return;
|
|
6807
6896
|
}
|
|
6808
|
-
if (!ok) localUsed.delete(ref.toLowerCase());
|
|
6897
|
+
if (!ok) localUsed.delete(ref.startsWith("pid:") ? ref : ref.toLowerCase());
|
|
6809
6898
|
}
|
|
6810
6899
|
function buildAccept(s, nonce) {
|
|
6811
6900
|
return {
|
|
@@ -6878,6 +6967,7 @@ function createPaymentGate(options) {
|
|
|
6878
6967
|
const specs = await ready();
|
|
6879
6968
|
const nonce = genNonce();
|
|
6880
6969
|
const bazaar = options.discovery ? { bazaar: buildBazaarExtension(options.discovery === true ? {} : options.discovery) } : void 0;
|
|
6970
|
+
const paymentIdAd = options.paymentIdentifier ? buildPaymentIdentifierAdvertisement() : void 0;
|
|
6881
6971
|
const accepts = buildAccepts(specs, nonce);
|
|
6882
6972
|
const endpointInfo = buildEndpointInfo({
|
|
6883
6973
|
...options.description ? { description: options.description } : {},
|
|
@@ -6895,11 +6985,13 @@ function createPaymentGate(options) {
|
|
|
6895
6985
|
const bodyPiprail = { ...selfDescribe ?? {}, ...rejectionPiprail };
|
|
6896
6986
|
const bodyExtensions = {
|
|
6897
6987
|
...bazaar,
|
|
6988
|
+
...paymentIdAd,
|
|
6898
6989
|
...rejectionExt,
|
|
6899
6990
|
...Object.keys(bodyPiprail).length > 0 ? { piprail: bodyPiprail } : {}
|
|
6900
6991
|
};
|
|
6901
6992
|
const headerExtensions = {
|
|
6902
6993
|
...bazaar,
|
|
6994
|
+
...paymentIdAd,
|
|
6903
6995
|
...Object.keys(rejectionPiprail).length > 0 ? { piprail: rejectionPiprail } : {}
|
|
6904
6996
|
};
|
|
6905
6997
|
const challenge2 = {
|
|
@@ -7109,7 +7201,17 @@ function createPaymentGate(options) {
|
|
|
7109
7201
|
await settleTx(ref, false);
|
|
7110
7202
|
return rejection(result.error, result.detail);
|
|
7111
7203
|
}
|
|
7112
|
-
|
|
7204
|
+
const verified = result.receipt.transaction;
|
|
7205
|
+
if (verified && verified !== ref) {
|
|
7206
|
+
if (await claimTx(verified)) {
|
|
7207
|
+
await settleTx(ref, false);
|
|
7208
|
+
return rejection("tx_already_used", `Payment ${verified} was already redeemed.`);
|
|
7209
|
+
}
|
|
7210
|
+
await settleTx(ref, false);
|
|
7211
|
+
await settleTx(verified, true);
|
|
7212
|
+
} else {
|
|
7213
|
+
await settleTx(ref, true);
|
|
7214
|
+
}
|
|
7113
7215
|
await deliverOnPaid(spec, result.receipt);
|
|
7114
7216
|
return await buildPaidResult(spec, result.receipt, sig.payload.nonce);
|
|
7115
7217
|
}
|
|
@@ -7315,7 +7417,7 @@ function createPaymentGate(options) {
|
|
|
7315
7417
|
if (result.kind === "invalid") await deliverOnFailed(result);
|
|
7316
7418
|
return result;
|
|
7317
7419
|
}
|
|
7318
|
-
async function
|
|
7420
|
+
async function routeVerdictObject(obj) {
|
|
7319
7421
|
if (obj === void 0 || obj === null) return asChallenge();
|
|
7320
7422
|
const sig = parseSignatureObject(obj);
|
|
7321
7423
|
if (sig && sig.accepted && typeof sig.accepted.network === "string" && typeof sig.accepted.asset === "string") {
|
|
@@ -7327,6 +7429,44 @@ function createPaymentGate(options) {
|
|
|
7327
7429
|
if (exact) return verifyExact(exact);
|
|
7328
7430
|
return asChallenge();
|
|
7329
7431
|
}
|
|
7432
|
+
function echoPaymentIdentifier(result, id) {
|
|
7433
|
+
try {
|
|
7434
|
+
const decoded = decodeBase64Json(result.receiptHeader);
|
|
7435
|
+
if (!decoded) return result;
|
|
7436
|
+
const { extensions: existing, ...receiptOnly } = decoded;
|
|
7437
|
+
const merged = {
|
|
7438
|
+
...existing ?? {},
|
|
7439
|
+
[EXT_PAYMENT_IDENTIFIER]: { info: { required: false, id } }
|
|
7440
|
+
};
|
|
7441
|
+
return { ...result, receiptHeader: buildReceiptHeader(receiptOnly, merged) };
|
|
7442
|
+
} catch {
|
|
7443
|
+
return result;
|
|
7444
|
+
}
|
|
7445
|
+
}
|
|
7446
|
+
async function resolveVerdictObject(obj) {
|
|
7447
|
+
if (!options.paymentIdentifier) return routeVerdictObject(obj);
|
|
7448
|
+
const id = readPaymentIdentifier(obj);
|
|
7449
|
+
if (id !== null && typeof id === "object") {
|
|
7450
|
+
return rejection("signature_invalid", `payment-identifier: ${id.invalid}.`);
|
|
7451
|
+
}
|
|
7452
|
+
if (id === null) return routeVerdictObject(obj);
|
|
7453
|
+
const idKey = "pid:" + id;
|
|
7454
|
+
if (await claimTx(idKey)) {
|
|
7455
|
+
return rejection(
|
|
7456
|
+
"tx_already_used",
|
|
7457
|
+
`Idempotency id "${id}" is already bound to a settled payment; use a fresh id for a new payment.`
|
|
7458
|
+
);
|
|
7459
|
+
}
|
|
7460
|
+
let result;
|
|
7461
|
+
try {
|
|
7462
|
+
result = await routeVerdictObject(obj);
|
|
7463
|
+
} catch (err) {
|
|
7464
|
+
await settleTx(idKey, false);
|
|
7465
|
+
throw err;
|
|
7466
|
+
}
|
|
7467
|
+
await settleTx(idKey, result.kind === "paid");
|
|
7468
|
+
return result.kind === "paid" ? echoPaymentIdentifier(result, id) : result;
|
|
7469
|
+
}
|
|
7330
7470
|
return { challenge, verify, verifyObject, describe, landingPage };
|
|
7331
7471
|
}
|
|
7332
7472
|
function requirePayment(options) {
|
|
@@ -7726,6 +7866,115 @@ function resourceUrlFromMessage(message) {
|
|
|
7726
7866
|
}
|
|
7727
7867
|
return "";
|
|
7728
7868
|
}
|
|
7869
|
+
|
|
7870
|
+
// src/transports/mcp-types.ts
|
|
7871
|
+
var MCP_PAYMENT_META_KEY = "x402/payment";
|
|
7872
|
+
var MCP_PAYMENT_RESPONSE_META_KEY = "x402/payment-response";
|
|
7873
|
+
|
|
7874
|
+
// src/transports/mcp.ts
|
|
7875
|
+
function toMcpPaymentRequired(challenge) {
|
|
7876
|
+
const text = JSON.stringify(challenge);
|
|
7877
|
+
return {
|
|
7878
|
+
isError: true,
|
|
7879
|
+
structuredContent: challenge,
|
|
7880
|
+
content: [{ type: "text", text }]
|
|
7881
|
+
};
|
|
7882
|
+
}
|
|
7883
|
+
function toMcpPaymentResponse(content, receipt) {
|
|
7884
|
+
return {
|
|
7885
|
+
content,
|
|
7886
|
+
_meta: {
|
|
7887
|
+
[MCP_PAYMENT_RESPONSE_META_KEY]: {
|
|
7888
|
+
success: true,
|
|
7889
|
+
transaction: receipt.transaction,
|
|
7890
|
+
network: receipt.network,
|
|
7891
|
+
payer: receipt.payer
|
|
7892
|
+
}
|
|
7893
|
+
}
|
|
7894
|
+
};
|
|
7895
|
+
}
|
|
7896
|
+
function fromMcpPayment(params) {
|
|
7897
|
+
const meta = params?._meta?.[MCP_PAYMENT_META_KEY];
|
|
7898
|
+
return meta == null ? null : meta;
|
|
7899
|
+
}
|
|
7900
|
+
function fromMcpPaymentRequired(result) {
|
|
7901
|
+
if (!result || result.isError !== true) return null;
|
|
7902
|
+
const sc = result.structuredContent;
|
|
7903
|
+
if (sc && typeof sc === "object" && typeof sc.x402Version === "number") {
|
|
7904
|
+
return sc;
|
|
7905
|
+
}
|
|
7906
|
+
const text = result.content?.[0]?.text;
|
|
7907
|
+
if (typeof text === "string") {
|
|
7908
|
+
try {
|
|
7909
|
+
const parsed = JSON.parse(text);
|
|
7910
|
+
if (parsed && typeof parsed === "object" && typeof parsed.x402Version === "number") {
|
|
7911
|
+
return parsed;
|
|
7912
|
+
}
|
|
7913
|
+
} catch {
|
|
7914
|
+
}
|
|
7915
|
+
}
|
|
7916
|
+
return null;
|
|
7917
|
+
}
|
|
7918
|
+
function isMcpPaymentRequired(result) {
|
|
7919
|
+
return fromMcpPaymentRequired(result) != null;
|
|
7920
|
+
}
|
|
7921
|
+
function fromMcpPaymentResponse(result) {
|
|
7922
|
+
const meta = result?._meta?.[MCP_PAYMENT_RESPONSE_META_KEY];
|
|
7923
|
+
if (!meta || typeof meta !== "object") return null;
|
|
7924
|
+
return meta;
|
|
7925
|
+
}
|
|
7926
|
+
function buildMcpPaymentMeta(input) {
|
|
7927
|
+
return {
|
|
7928
|
+
[MCP_PAYMENT_META_KEY]: {
|
|
7929
|
+
x402Version: input.x402Version ?? 2,
|
|
7930
|
+
...input.resource ? { resource: input.resource } : {},
|
|
7931
|
+
accepted: input.accepted,
|
|
7932
|
+
payload: input.payload
|
|
7933
|
+
}
|
|
7934
|
+
};
|
|
7935
|
+
}
|
|
7936
|
+
function createMcpPaymentTool(options) {
|
|
7937
|
+
const gate = options.gate ?? createPaymentGate(options);
|
|
7938
|
+
function settlementFailed(code, detail) {
|
|
7939
|
+
return {
|
|
7940
|
+
isError: true,
|
|
7941
|
+
content: [
|
|
7942
|
+
{
|
|
7943
|
+
type: "text",
|
|
7944
|
+
text: `x402 settlement failed (${toA2AErrorCode(code)}): ${detail}. The buyer can retry, or pay the onchain-proof rail directly.`
|
|
7945
|
+
}
|
|
7946
|
+
]
|
|
7947
|
+
};
|
|
7948
|
+
}
|
|
7949
|
+
async function handleToolCall(params) {
|
|
7950
|
+
const raw = fromMcpPayment(params);
|
|
7951
|
+
if (raw == null) {
|
|
7952
|
+
const { challenge } = await gate.challenge(options.resourceUrl ?? "");
|
|
7953
|
+
return toMcpPaymentRequired(challenge);
|
|
7954
|
+
}
|
|
7955
|
+
let result;
|
|
7956
|
+
try {
|
|
7957
|
+
result = await gate.verifyObject(raw);
|
|
7958
|
+
} catch (err) {
|
|
7959
|
+
if (err instanceof SettlementError) return settlementFailed("settlement_failed", err.message);
|
|
7960
|
+
throw err;
|
|
7961
|
+
}
|
|
7962
|
+
if (result.kind === "paid") {
|
|
7963
|
+
try {
|
|
7964
|
+
const content = await options.fulfill({ receipt: result.receipt, params });
|
|
7965
|
+
return toMcpPaymentResponse(content, result.receipt);
|
|
7966
|
+
} catch (err) {
|
|
7967
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
7968
|
+
return toMcpPaymentResponse(
|
|
7969
|
+
[{ type: "text", text: `Payment settled (tx ${result.receipt.transaction}), but serving the result failed: ${detail}` }],
|
|
7970
|
+
result.receipt
|
|
7971
|
+
);
|
|
7972
|
+
}
|
|
7973
|
+
}
|
|
7974
|
+
return toMcpPaymentRequired(result.challenge);
|
|
7975
|
+
}
|
|
7976
|
+
return { handleToolCall, gate };
|
|
7977
|
+
}
|
|
7729
7978
|
export {
|
|
7730
7979
|
A2A_ERROR_KEY,
|
|
7731
7980
|
A2A_EXTENSIONS_HEADER,
|
|
@@ -7744,6 +7993,7 @@ export {
|
|
|
7744
7993
|
EIP3009_TYPES,
|
|
7745
7994
|
EXACT_NETWORK_SLUGS,
|
|
7746
7995
|
EXT_OFFER_RECEIPT,
|
|
7996
|
+
EXT_PAYMENT_IDENTIFIER,
|
|
7747
7997
|
GENERATOR,
|
|
7748
7998
|
HEADER_REQUIRED,
|
|
7749
7999
|
HEADER_RESPONSE,
|
|
@@ -7751,8 +8001,11 @@ export {
|
|
|
7751
8001
|
HEADER_SIGNATURE,
|
|
7752
8002
|
HEADER_SIGNATURE_V1,
|
|
7753
8003
|
InsufficientFundsError,
|
|
8004
|
+
InvalidConfigError,
|
|
7754
8005
|
InvalidEnvelopeError,
|
|
7755
8006
|
KNOWN_FACILITATORS,
|
|
8007
|
+
MCP_PAYMENT_META_KEY,
|
|
8008
|
+
MCP_PAYMENT_RESPONSE_META_KEY,
|
|
7756
8009
|
MaxRetriesExceededError,
|
|
7757
8010
|
MissingDriverError,
|
|
7758
8011
|
MultiChainPayer,
|
|
@@ -7790,18 +8043,22 @@ export {
|
|
|
7790
8043
|
buildEndpointInfo,
|
|
7791
8044
|
buildExactAuthorization,
|
|
7792
8045
|
buildExactSignatureHeader,
|
|
8046
|
+
buildMcpPaymentMeta,
|
|
7793
8047
|
buildOpenApi,
|
|
8048
|
+
buildPaymentIdentifierAdvertisement,
|
|
7794
8049
|
buildReceiptExtension,
|
|
7795
8050
|
buildReceiptHeader,
|
|
7796
8051
|
buildSelfDescription,
|
|
7797
8052
|
buildSignatureHeader,
|
|
7798
8053
|
buildUptoSignatureHeader,
|
|
7799
8054
|
buildWellKnownX402,
|
|
8055
|
+
buildWellKnownX402Manifest,
|
|
7800
8056
|
buildX402DnsTxt,
|
|
7801
8057
|
chainIdForExactNetwork,
|
|
7802
8058
|
claim402IndexDomain,
|
|
7803
8059
|
classifyChallenge,
|
|
7804
8060
|
createA2APaymentHandler,
|
|
8061
|
+
createMcpPaymentTool,
|
|
7805
8062
|
createPaymentGate,
|
|
7806
8063
|
decodeBase64Json,
|
|
7807
8064
|
decorateOutcome,
|
|
@@ -7819,7 +8076,11 @@ export {
|
|
|
7819
8076
|
formatSpendReport,
|
|
7820
8077
|
fromA2APaymentPayload,
|
|
7821
8078
|
fromA2APaymentRequired,
|
|
8079
|
+
fromMcpPayment,
|
|
8080
|
+
fromMcpPaymentRequired,
|
|
8081
|
+
fromMcpPaymentResponse,
|
|
7822
8082
|
getDirectoryInfo,
|
|
8083
|
+
isMcpPaymentRequired,
|
|
7823
8084
|
isPermit2ProxyChain,
|
|
7824
8085
|
isUptoProxyChain,
|
|
7825
8086
|
knownFacilitatorsFor,
|
|
@@ -7842,6 +8103,7 @@ export {
|
|
|
7842
8103
|
planAcross,
|
|
7843
8104
|
rankResources,
|
|
7844
8105
|
readExactDomain,
|
|
8106
|
+
readPaymentIdentifier,
|
|
7845
8107
|
register402Index,
|
|
7846
8108
|
registerDriver,
|
|
7847
8109
|
registerX402Scan,
|
|
@@ -7858,5 +8120,7 @@ export {
|
|
|
7858
8120
|
toA2APaymentRequired,
|
|
7859
8121
|
toInsufficientFundsError,
|
|
7860
8122
|
toInvalidBody,
|
|
8123
|
+
toMcpPaymentRequired,
|
|
8124
|
+
toMcpPaymentResponse,
|
|
7861
8125
|
verify402IndexDomain
|
|
7862
8126
|
};
|