@piprail/sdk 1.8.0 → 1.10.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/CHAINS.md +5 -3
- package/CHANGELOG.md +59 -0
- package/ERRORS.md +21 -8
- package/README.md +23 -0
- package/STANDARDS.md +5 -2
- package/dist/{algorand-IJJKE35X.cjs → algorand-MXUSKX46.cjs} +17 -17
- package/dist/{algorand-B67G4335.js → algorand-WGVF4KTU.js} +1 -1
- package/dist/{aptos-YQWTGFRZ.js → aptos-LPBLSEIQ.js} +1 -1
- package/dist/{aptos-X3G2UBYW.cjs → aptos-YT7SXWPF.cjs} +16 -16
- package/dist/{chunk-IQGT65WS.cjs → chunk-MDLZJGLY.cjs} +20 -16
- package/dist/{chunk-QDS6FBZP.js → chunk-SVMGHASK.js} +4 -0
- package/dist/index.cjs +823 -253
- package/dist/index.d.cts +458 -35
- package/dist/index.d.ts +458 -35
- package/dist/index.js +746 -176
- package/dist/{near-GGUHLXAF.cjs → near-7ZDNISUX.cjs} +19 -19
- package/dist/{near-7MBBCDUE.js → near-K6BDBABG.js} +1 -1
- package/dist/{solana-W24TCJV4.cjs → solana-PU7N2M64.cjs} +14 -14
- package/dist/{solana-7WJVZGDW.js → solana-S3UFI3FE.js} +1 -1
- package/dist/{stellar-HV6VGZX3.js → stellar-Q5PO23SC.js} +1 -1
- package/dist/{stellar-YMY3K2YB.cjs → stellar-VDQOFQEO.cjs} +21 -21
- package/dist/{sui-32KVESR5.cjs → sui-FKSMLKRF.cjs} +17 -17
- package/dist/{sui-2WFWVFJX.js → sui-WOXRKJXS.js} +1 -1
- package/dist/{ton-FIQGV2LC.cjs → ton-VK6KRJHP.cjs} +14 -14
- package/dist/{ton-DGZB7W4U.js → ton-WPTXGLVK.js} +1 -1
- package/dist/{tron-RLIL2FDI.js → tron-6GXBXTR4.js} +1 -1
- package/dist/{tron-ZSXAPZ2C.cjs → tron-WLOF5OUV.cjs} +24 -24
- package/dist/{xrpl-2PKP7HOI.cjs → xrpl-CMNI25BV.cjs} +21 -21
- package/dist/{xrpl-UEC2GYVV.js → xrpl-HEAPEXAM.js} +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
|
|
24
|
+
var _chunkMDLZJGLYcjs = require('./chunk-MDLZJGLY.cjs');
|
|
24
25
|
|
|
25
26
|
// src/drivers/registry.ts
|
|
26
27
|
var byFamily = /* @__PURE__ */ new Map();
|
|
@@ -49,13 +50,13 @@ function resolveNetwork(opts) {
|
|
|
49
50
|
const family = familyForChain(opts.chain);
|
|
50
51
|
const driver = byFamily.get(family);
|
|
51
52
|
if (!driver) {
|
|
52
|
-
throw new (0,
|
|
53
|
+
throw new (0, _chunkMDLZJGLYcjs.UnsupportedNetworkError)(
|
|
53
54
|
`No driver registered for the "${family}" family \u2014 it may not be mounted yet (use the async resolveNetwork()).`
|
|
54
55
|
);
|
|
55
56
|
}
|
|
56
57
|
const net = driver.resolve(opts);
|
|
57
58
|
if (!net) {
|
|
58
|
-
throw new (0,
|
|
59
|
+
throw new (0, _chunkMDLZJGLYcjs.UnsupportedNetworkError)(
|
|
59
60
|
`The ${family} driver didn't recognise this chain input.`
|
|
60
61
|
);
|
|
61
62
|
}
|
|
@@ -85,6 +86,7 @@ var _viem = require('viem');
|
|
|
85
86
|
|
|
86
87
|
|
|
87
88
|
|
|
89
|
+
|
|
88
90
|
|
|
89
91
|
|
|
90
92
|
var _chains = require('viem/chains');
|
|
@@ -236,6 +238,17 @@ var CHAINS = {
|
|
|
236
238
|
tokens: {
|
|
237
239
|
USDC: { address: "0x754704Bc059F8C67012fEd69BC8A327a5aafb603", decimals: 6, symbol: "USDC" }
|
|
238
240
|
}
|
|
241
|
+
},
|
|
242
|
+
// Kaia (ex-Klaytn, chainId 8217) — Tether-native USD₮ verified on-chain 2026-06-08
|
|
243
|
+
// (0xd077…4fDb: symbol "USD₮", name "Tether USD", 6 dp, no bridge markers). Circle issues
|
|
244
|
+
// NO native USDC on Kaia (absent from Circle's list), so USDC is intentionally omitted —
|
|
245
|
+
// pay native KAIA or USD₮ (or pass a custom { address, decimals }). Asia's stablecoin-
|
|
246
|
+
// settlement chain, born from Kakao + LINE.
|
|
247
|
+
kaia: {
|
|
248
|
+
chain: _chains.kaia,
|
|
249
|
+
tokens: {
|
|
250
|
+
USDT: { address: "0xd077A400968890Eacc75cdc901F0356c943e4fDb", decimals: 6, symbol: "USDT" }
|
|
251
|
+
}
|
|
239
252
|
}
|
|
240
253
|
};
|
|
241
254
|
function isViemChain(input) {
|
|
@@ -299,12 +312,12 @@ function createWalletAdapter(config, resolved) {
|
|
|
299
312
|
}
|
|
300
313
|
const wc = config.walletClient;
|
|
301
314
|
if (!wc.account) {
|
|
302
|
-
throw new (0,
|
|
315
|
+
throw new (0, _chunkMDLZJGLYcjs.WrongFamilyError)(
|
|
303
316
|
"chain is EVM; the provided walletClient has no attached account. Use `createWalletClient({ account, chain, transport })`, or pass { privateKey }."
|
|
304
317
|
);
|
|
305
318
|
}
|
|
306
319
|
if (wc.chain && wc.chain.id !== resolved.chainId) {
|
|
307
|
-
throw new (0,
|
|
320
|
+
throw new (0, _chunkMDLZJGLYcjs.WrongChainError)(
|
|
308
321
|
`PipRailClient: walletClient is on chain ${wc.chain.id} but the SDK was configured with chain ${resolved.chainId}. They must match.`
|
|
309
322
|
);
|
|
310
323
|
}
|
|
@@ -471,24 +484,371 @@ function sumTransfersTo(logs, asset, payTo) {
|
|
|
471
484
|
return { total, from };
|
|
472
485
|
}
|
|
473
486
|
|
|
487
|
+
// src/drivers/evm/exact.ts
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
var EXACT_NETWORK_SLUGS = {
|
|
494
|
+
ethereum: 1,
|
|
495
|
+
base: 8453,
|
|
496
|
+
"base-sepolia": 84532,
|
|
497
|
+
arbitrum: 42161,
|
|
498
|
+
optimism: 10,
|
|
499
|
+
polygon: 137,
|
|
500
|
+
avalanche: 43114
|
|
501
|
+
};
|
|
502
|
+
function chainIdForExactNetwork(slug) {
|
|
503
|
+
return _nullishCoalesce(EXACT_NETWORK_SLUGS[slug], () => ( null));
|
|
504
|
+
}
|
|
505
|
+
var EIP3009_TYPES = {
|
|
506
|
+
TransferWithAuthorization: [
|
|
507
|
+
{ name: "from", type: "address" },
|
|
508
|
+
{ name: "to", type: "address" },
|
|
509
|
+
{ name: "value", type: "uint256" },
|
|
510
|
+
{ name: "validAfter", type: "uint256" },
|
|
511
|
+
{ name: "validBefore", type: "uint256" },
|
|
512
|
+
{ name: "nonce", type: "bytes32" }
|
|
513
|
+
]
|
|
514
|
+
};
|
|
515
|
+
function parseExactRequirements(body) {
|
|
516
|
+
if (!body || typeof body !== "object") return null;
|
|
517
|
+
const accepts = body.accepts;
|
|
518
|
+
if (!Array.isArray(accepts)) return null;
|
|
519
|
+
const out = [];
|
|
520
|
+
for (const raw of accepts) {
|
|
521
|
+
if (!raw || typeof raw !== "object") continue;
|
|
522
|
+
const a = raw;
|
|
523
|
+
if (a.scheme !== "exact") continue;
|
|
524
|
+
const amount = _nullishCoalesce(a.maxAmountRequired, () => ( a.amount));
|
|
525
|
+
if (typeof a.network !== "string" || typeof amount !== "string" || typeof a.asset !== "string" || typeof a.payTo !== "string") {
|
|
526
|
+
continue;
|
|
527
|
+
}
|
|
528
|
+
out.push({
|
|
529
|
+
scheme: "exact",
|
|
530
|
+
network: a.network,
|
|
531
|
+
maxAmountRequired: amount,
|
|
532
|
+
asset: a.asset,
|
|
533
|
+
payTo: a.payTo,
|
|
534
|
+
maxTimeoutSeconds: typeof a.maxTimeoutSeconds === "number" ? a.maxTimeoutSeconds : 600,
|
|
535
|
+
...a.extra && typeof a.extra === "object" ? { extra: a.extra } : {},
|
|
536
|
+
...typeof a.description === "string" ? { description: a.description } : {},
|
|
537
|
+
...typeof a.resource === "string" ? { resource: a.resource } : {}
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
return out;
|
|
541
|
+
}
|
|
542
|
+
async function buildExactAuthorization(params) {
|
|
543
|
+
const { account, accept, chainId, now, nonce } = params;
|
|
544
|
+
if (!account.signTypedData) {
|
|
545
|
+
throw new Error("buildExactAuthorization: the account cannot sign EIP-712 typed data.");
|
|
546
|
+
}
|
|
547
|
+
const authorization = {
|
|
548
|
+
from: account.address,
|
|
549
|
+
to: accept.payTo,
|
|
550
|
+
value: accept.maxAmountRequired,
|
|
551
|
+
validAfter: "0",
|
|
552
|
+
validBefore: String(now + accept.maxTimeoutSeconds),
|
|
553
|
+
nonce
|
|
554
|
+
};
|
|
555
|
+
const signature = await account.signTypedData({
|
|
556
|
+
domain: {
|
|
557
|
+
name: _nullishCoalesce(_optionalChain([accept, 'access', _ => _.extra, 'optionalAccess', _2 => _2.name]), () => ( "USD Coin")),
|
|
558
|
+
version: _nullishCoalesce(_optionalChain([accept, 'access', _3 => _3.extra, 'optionalAccess', _4 => _4.version]), () => ( "2")),
|
|
559
|
+
chainId,
|
|
560
|
+
verifyingContract: accept.asset
|
|
561
|
+
},
|
|
562
|
+
types: EIP3009_TYPES,
|
|
563
|
+
primaryType: "TransferWithAuthorization",
|
|
564
|
+
message: {
|
|
565
|
+
from: authorization.from,
|
|
566
|
+
to: authorization.to,
|
|
567
|
+
value: BigInt(authorization.value),
|
|
568
|
+
validAfter: BigInt(authorization.validAfter),
|
|
569
|
+
validBefore: BigInt(authorization.validBefore),
|
|
570
|
+
nonce: authorization.nonce
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
return { authorization, signature };
|
|
574
|
+
}
|
|
575
|
+
function base64(str) {
|
|
576
|
+
if (typeof Buffer !== "undefined") return Buffer.from(str, "utf8").toString("base64");
|
|
577
|
+
if (typeof btoa === "function" && typeof TextEncoder !== "undefined") {
|
|
578
|
+
const bytes = new TextEncoder().encode(str);
|
|
579
|
+
let binary = "";
|
|
580
|
+
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
581
|
+
return btoa(binary);
|
|
582
|
+
}
|
|
583
|
+
throw new Error("No base64 encoder available in this runtime.");
|
|
584
|
+
}
|
|
585
|
+
function encodeXPaymentHeader(input) {
|
|
586
|
+
const payload = {
|
|
587
|
+
x402Version: _nullishCoalesce(input.x402Version, () => ( 1)),
|
|
588
|
+
scheme: "exact",
|
|
589
|
+
network: input.network,
|
|
590
|
+
payload: { signature: input.signature, authorization: input.authorization }
|
|
591
|
+
};
|
|
592
|
+
return base64(JSON.stringify(payload));
|
|
593
|
+
}
|
|
594
|
+
var eip3009Abi = [
|
|
595
|
+
{
|
|
596
|
+
type: "function",
|
|
597
|
+
name: "transferWithAuthorization",
|
|
598
|
+
stateMutability: "nonpayable",
|
|
599
|
+
outputs: [],
|
|
600
|
+
inputs: [
|
|
601
|
+
{ name: "from", type: "address" },
|
|
602
|
+
{ name: "to", type: "address" },
|
|
603
|
+
{ name: "value", type: "uint256" },
|
|
604
|
+
{ name: "validAfter", type: "uint256" },
|
|
605
|
+
{ name: "validBefore", type: "uint256" },
|
|
606
|
+
{ name: "nonce", type: "bytes32" },
|
|
607
|
+
{ name: "v", type: "uint8" },
|
|
608
|
+
{ name: "r", type: "bytes32" },
|
|
609
|
+
{ name: "s", type: "bytes32" }
|
|
610
|
+
]
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
type: "function",
|
|
614
|
+
name: "transferWithAuthorization",
|
|
615
|
+
stateMutability: "nonpayable",
|
|
616
|
+
outputs: [],
|
|
617
|
+
inputs: [
|
|
618
|
+
{ name: "from", type: "address" },
|
|
619
|
+
{ name: "to", type: "address" },
|
|
620
|
+
{ name: "value", type: "uint256" },
|
|
621
|
+
{ name: "validAfter", type: "uint256" },
|
|
622
|
+
{ name: "validBefore", type: "uint256" },
|
|
623
|
+
{ name: "nonce", type: "bytes32" },
|
|
624
|
+
{ name: "signature", type: "bytes" }
|
|
625
|
+
]
|
|
626
|
+
},
|
|
627
|
+
{
|
|
628
|
+
type: "function",
|
|
629
|
+
name: "authorizationState",
|
|
630
|
+
stateMutability: "view",
|
|
631
|
+
inputs: [
|
|
632
|
+
{ name: "authorizer", type: "address" },
|
|
633
|
+
{ name: "nonce", type: "bytes32" }
|
|
634
|
+
],
|
|
635
|
+
outputs: [{ type: "bool" }]
|
|
636
|
+
},
|
|
637
|
+
{ type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ type: "string" }] },
|
|
638
|
+
{ type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ type: "string" }] }
|
|
639
|
+
];
|
|
640
|
+
var ZERO_ADDR = "0x0000000000000000000000000000000000000000";
|
|
641
|
+
var ZERO_NONCE = `0x${"00".repeat(32)}`;
|
|
642
|
+
async function readExactDomain(publicClient, asset) {
|
|
643
|
+
if (asset === "native") return null;
|
|
644
|
+
let token;
|
|
645
|
+
try {
|
|
646
|
+
token = _viem.getAddress.call(void 0, asset);
|
|
647
|
+
} catch (e6) {
|
|
648
|
+
return null;
|
|
649
|
+
}
|
|
650
|
+
try {
|
|
651
|
+
const [name, version] = await Promise.all([
|
|
652
|
+
publicClient.readContract({ address: token, abi: eip3009Abi, functionName: "name" }),
|
|
653
|
+
publicClient.readContract({ address: token, abi: eip3009Abi, functionName: "version" }),
|
|
654
|
+
// The EIP-3009 probe: this view exists only on EIP-3009 tokens; it reverts on
|
|
655
|
+
// a plain ERC-20 / USDT, marking the token as not exact-payable.
|
|
656
|
+
publicClient.readContract({
|
|
657
|
+
address: token,
|
|
658
|
+
abi: eip3009Abi,
|
|
659
|
+
functionName: "authorizationState",
|
|
660
|
+
args: [ZERO_ADDR, ZERO_NONCE]
|
|
661
|
+
})
|
|
662
|
+
]);
|
|
663
|
+
if (typeof name !== "string" || typeof version !== "string" || !name || !version) return null;
|
|
664
|
+
return { name, version };
|
|
665
|
+
} catch (e7) {
|
|
666
|
+
return null;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
function shorten(msg) {
|
|
670
|
+
const oneLine = msg.replace(/\s+/g, " ").trim();
|
|
671
|
+
return oneLine.length > 200 ? `${oneLine.slice(0, 200)}\u2026` : oneLine;
|
|
672
|
+
}
|
|
673
|
+
async function verifyAndSettleExactEvm(input) {
|
|
674
|
+
const { publicClient, walletClient, account, chain, payload, accept } = input;
|
|
675
|
+
const token = _viem.getAddress.call(void 0, accept.asset);
|
|
676
|
+
const payTo = _viem.getAddress.call(void 0, accept.payTo);
|
|
677
|
+
const requiredAmount = BigInt(accept.amount);
|
|
678
|
+
let from;
|
|
679
|
+
let to;
|
|
680
|
+
let value;
|
|
681
|
+
let validAfter;
|
|
682
|
+
let validBefore;
|
|
683
|
+
let nonce;
|
|
684
|
+
try {
|
|
685
|
+
from = _viem.getAddress.call(void 0, payload.authorization.from);
|
|
686
|
+
to = _viem.getAddress.call(void 0, payload.authorization.to);
|
|
687
|
+
value = BigInt(payload.authorization.value);
|
|
688
|
+
validAfter = BigInt(payload.authorization.validAfter);
|
|
689
|
+
validBefore = BigInt(payload.authorization.validBefore);
|
|
690
|
+
nonce = payload.authorization.nonce;
|
|
691
|
+
if (!/^0x[0-9a-fA-F]{64}$/.test(nonce)) throw new Error("nonce must be 32-byte hex");
|
|
692
|
+
if (!/^0x[0-9a-fA-F]+$/.test(payload.signature)) throw new Error("signature must be hex");
|
|
693
|
+
} catch (err) {
|
|
694
|
+
return {
|
|
695
|
+
ok: false,
|
|
696
|
+
error: "signature_invalid",
|
|
697
|
+
detail: `Malformed exact authorization: ${err instanceof Error ? err.message : String(err)}.`
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
if (to !== payTo) {
|
|
701
|
+
return { ok: false, error: "wrong_recipient", detail: `Authorization pays ${to}, not ${payTo}.` };
|
|
702
|
+
}
|
|
703
|
+
if (value < requiredAmount) {
|
|
704
|
+
return { ok: false, error: "amount_too_low", detail: `Authorized ${value}, required ${requiredAmount}.` };
|
|
705
|
+
}
|
|
706
|
+
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
707
|
+
if (validBefore <= now) {
|
|
708
|
+
return { ok: false, error: "payment_expired", detail: `Authorization expired: validBefore ${validBefore} <= now ${now}.` };
|
|
709
|
+
}
|
|
710
|
+
let fromCode;
|
|
711
|
+
try {
|
|
712
|
+
fromCode = await publicClient.getCode({ address: from });
|
|
713
|
+
} catch (e8) {
|
|
714
|
+
return { ok: false, error: "tx_not_found", detail: `Could not read code at ${from} (transient RPC) \u2014 retry.` };
|
|
715
|
+
}
|
|
716
|
+
const isContractWallet = Boolean(fromCode && fromCode !== "0x");
|
|
717
|
+
if (!isContractWallet) {
|
|
718
|
+
let recovered;
|
|
719
|
+
try {
|
|
720
|
+
recovered = await _viem.recoverTypedDataAddress.call(void 0, {
|
|
721
|
+
domain: {
|
|
722
|
+
name: accept.extra.name,
|
|
723
|
+
version: accept.extra.version,
|
|
724
|
+
chainId: chain.id,
|
|
725
|
+
verifyingContract: token
|
|
726
|
+
},
|
|
727
|
+
types: EIP3009_TYPES,
|
|
728
|
+
primaryType: "TransferWithAuthorization",
|
|
729
|
+
message: { from, to, value, validAfter, validBefore, nonce },
|
|
730
|
+
signature: payload.signature
|
|
731
|
+
});
|
|
732
|
+
} catch (err) {
|
|
733
|
+
return { ok: false, error: "signature_invalid", detail: `Not a valid EIP-712 signature: ${shorten(err instanceof Error ? err.message : String(err))}.` };
|
|
734
|
+
}
|
|
735
|
+
if (recovered !== from) {
|
|
736
|
+
return { ok: false, error: "signature_invalid", detail: `Signature recovered to ${recovered}, not the authorizer ${from}.` };
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
try {
|
|
740
|
+
const used = await publicClient.readContract({
|
|
741
|
+
address: token,
|
|
742
|
+
abi: eip3009Abi,
|
|
743
|
+
functionName: "authorizationState",
|
|
744
|
+
args: [from, nonce]
|
|
745
|
+
});
|
|
746
|
+
if (used) {
|
|
747
|
+
return { ok: false, error: "tx_already_used", detail: `Authorization nonce ${nonce} already used or canceled on-chain.` };
|
|
748
|
+
}
|
|
749
|
+
} catch (e9) {
|
|
750
|
+
return { ok: false, error: "tx_not_found", detail: "Could not read authorizationState (transient RPC) \u2014 retry." };
|
|
751
|
+
}
|
|
752
|
+
const baseArgs = [from, to, value, validAfter, validBefore, nonce];
|
|
753
|
+
const isEcdsa = !isContractWallet && payload.signature.length - 2 === 130;
|
|
754
|
+
let writeArgs;
|
|
755
|
+
if (isEcdsa) {
|
|
756
|
+
const { r, s, yParity } = _viem.parseSignature.call(void 0, payload.signature);
|
|
757
|
+
writeArgs = [...baseArgs, BigInt(yParity + 27), r, s];
|
|
758
|
+
} else {
|
|
759
|
+
writeArgs = [...baseArgs, payload.signature];
|
|
760
|
+
}
|
|
761
|
+
try {
|
|
762
|
+
await publicClient.simulateContract({
|
|
763
|
+
account,
|
|
764
|
+
address: token,
|
|
765
|
+
abi: eip3009Abi,
|
|
766
|
+
functionName: "transferWithAuthorization",
|
|
767
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
768
|
+
args: writeArgs
|
|
769
|
+
});
|
|
770
|
+
} catch (err) {
|
|
771
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
772
|
+
if (/used or canceled/i.test(msg)) return { ok: false, error: "tx_already_used", detail: "Authorization is used or canceled." };
|
|
773
|
+
if (/expired|not yet valid/i.test(msg)) return { ok: false, error: "payment_expired", detail: shorten(msg) };
|
|
774
|
+
if (/invalid signature/i.test(msg)) return { ok: false, error: "signature_invalid", detail: shorten(msg) };
|
|
775
|
+
return { ok: false, error: "tx_reverted", detail: `transferWithAuthorization would revert: ${shorten(msg)}` };
|
|
776
|
+
}
|
|
777
|
+
let txHash;
|
|
778
|
+
try {
|
|
779
|
+
txHash = await walletClient.writeContract({
|
|
780
|
+
account,
|
|
781
|
+
chain,
|
|
782
|
+
address: token,
|
|
783
|
+
abi: eip3009Abi,
|
|
784
|
+
functionName: "transferWithAuthorization",
|
|
785
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
786
|
+
args: writeArgs
|
|
787
|
+
});
|
|
788
|
+
} catch (err) {
|
|
789
|
+
throw new (0, _chunkMDLZJGLYcjs.SettlementError)(
|
|
790
|
+
`exact settle: the merchant relayer failed to broadcast transferWithAuthorization (${shorten(err instanceof Error ? err.message : String(err))}). The payer's authorization is still valid and unused \u2014 fund/fix the relayer and the payer can retry.`,
|
|
791
|
+
{ cause: err }
|
|
792
|
+
);
|
|
793
|
+
}
|
|
794
|
+
try {
|
|
795
|
+
const confirmations = _nullishCoalesce(accept.extra.minConfirmations, () => ( 1));
|
|
796
|
+
const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash, confirmations });
|
|
797
|
+
if (receipt.status !== "success") {
|
|
798
|
+
return { ok: false, error: "tx_reverted", detail: `Settlement tx ${txHash} reverted on-chain.` };
|
|
799
|
+
}
|
|
800
|
+
} catch (err) {
|
|
801
|
+
throw new (0, _chunkMDLZJGLYcjs.SettlementError)(
|
|
802
|
+
`exact settle: broadcast ${txHash} but couldn't confirm it (${shorten(err instanceof Error ? err.message : String(err))}).`,
|
|
803
|
+
{ cause: err }
|
|
804
|
+
);
|
|
805
|
+
}
|
|
806
|
+
return {
|
|
807
|
+
ok: true,
|
|
808
|
+
receipt: {
|
|
809
|
+
scheme: "exact",
|
|
810
|
+
success: true,
|
|
811
|
+
network: accept.network,
|
|
812
|
+
transaction: txHash,
|
|
813
|
+
asset: accept.asset,
|
|
814
|
+
amount: accept.amount,
|
|
815
|
+
payer: from,
|
|
816
|
+
payTo: accept.payTo,
|
|
817
|
+
verifiedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
818
|
+
}
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
|
|
474
822
|
// src/x402.ts
|
|
475
823
|
var HEADER_REQUIRED = "payment-required";
|
|
476
824
|
var HEADER_SIGNATURE = "payment-signature";
|
|
477
825
|
var HEADER_RESPONSE = "payment-response";
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
if (typeof Buffer !== "undefined") return Buffer.from(b64, "base64").toString("utf8");
|
|
481
|
-
throw new Error("No base64 decoder available in this runtime.");
|
|
482
|
-
}
|
|
826
|
+
var HEADER_SIGNATURE_V1 = "x-payment";
|
|
827
|
+
var HEADER_RESPONSE_V1 = "x-payment-response";
|
|
483
828
|
function encodeBase64(str) {
|
|
484
|
-
if (typeof btoa === "function") return btoa(str);
|
|
485
829
|
if (typeof Buffer !== "undefined") return Buffer.from(str, "utf8").toString("base64");
|
|
830
|
+
if (typeof btoa === "function" && typeof TextEncoder !== "undefined") {
|
|
831
|
+
const bytes = new TextEncoder().encode(str);
|
|
832
|
+
let binary = "";
|
|
833
|
+
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
834
|
+
return btoa(binary);
|
|
835
|
+
}
|
|
486
836
|
throw new Error("No base64 encoder available in this runtime.");
|
|
487
837
|
}
|
|
838
|
+
function decodeBase64(b64) {
|
|
839
|
+
if (typeof Buffer !== "undefined") return Buffer.from(b64, "base64").toString("utf8");
|
|
840
|
+
if (typeof atob === "function" && typeof TextDecoder !== "undefined") {
|
|
841
|
+
const binary = atob(b64);
|
|
842
|
+
const bytes = new Uint8Array(binary.length);
|
|
843
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
844
|
+
return new TextDecoder().decode(bytes);
|
|
845
|
+
}
|
|
846
|
+
throw new Error("No base64 decoder available in this runtime.");
|
|
847
|
+
}
|
|
488
848
|
function fromBase64Json(b64) {
|
|
489
849
|
try {
|
|
490
850
|
return JSON.parse(decodeBase64(b64));
|
|
491
|
-
} catch (
|
|
851
|
+
} catch (e10) {
|
|
492
852
|
return null;
|
|
493
853
|
}
|
|
494
854
|
}
|
|
@@ -522,7 +882,7 @@ async function parseChallenge(response) {
|
|
|
522
882
|
try {
|
|
523
883
|
const body = await response.clone().json();
|
|
524
884
|
if (isValidChallenge(body)) return body;
|
|
525
|
-
} catch (
|
|
885
|
+
} catch (e11) {
|
|
526
886
|
}
|
|
527
887
|
return null;
|
|
528
888
|
}
|
|
@@ -537,7 +897,7 @@ function parseSignatureHeader(value) {
|
|
|
537
897
|
if (!parsed || typeof parsed !== "object") return null;
|
|
538
898
|
const v = parsed;
|
|
539
899
|
const accepted = v.accepted;
|
|
540
|
-
const scheme = _nullishCoalesce(_optionalChain([accepted, 'optionalAccess',
|
|
900
|
+
const scheme = _nullishCoalesce(_optionalChain([accepted, 'optionalAccess', _5 => _5.scheme]), () => ( v.scheme));
|
|
541
901
|
if (scheme !== "onchain-proof") return null;
|
|
542
902
|
const payload = v.payload;
|
|
543
903
|
if (!payload || typeof payload.txHash !== "string" || typeof payload.nonce !== "string") {
|
|
@@ -545,6 +905,36 @@ function parseSignatureHeader(value) {
|
|
|
545
905
|
}
|
|
546
906
|
return parsed;
|
|
547
907
|
}
|
|
908
|
+
function parseExactPaymentHeader(value) {
|
|
909
|
+
const parsed = fromBase64Json(value);
|
|
910
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
911
|
+
const v = parsed;
|
|
912
|
+
const accepted = _nullishCoalesce(v.accepted, () => ( null));
|
|
913
|
+
const scheme = _nullishCoalesce(_optionalChain([accepted, 'optionalAccess', _6 => _6.scheme]), () => ( v.scheme));
|
|
914
|
+
if (scheme !== "exact") return null;
|
|
915
|
+
const network = _nullishCoalesce(_optionalChain([accepted, 'optionalAccess', _7 => _7.network]), () => ( v.network));
|
|
916
|
+
if (typeof network !== "string") return null;
|
|
917
|
+
const payload = v.payload;
|
|
918
|
+
if (!payload || typeof payload !== "object") return null;
|
|
919
|
+
const signature = payload.signature;
|
|
920
|
+
const authorization = payload.authorization;
|
|
921
|
+
if (typeof signature !== "string" || !authorization || typeof authorization !== "object") return null;
|
|
922
|
+
for (const k of ["from", "to", "value", "validAfter", "validBefore", "nonce"]) {
|
|
923
|
+
if (typeof authorization[k] !== "string") return null;
|
|
924
|
+
}
|
|
925
|
+
const x402Version = typeof v.x402Version === "number" ? v.x402Version : 2;
|
|
926
|
+
const asset = accepted && typeof accepted.asset === "string" ? accepted.asset : void 0;
|
|
927
|
+
return {
|
|
928
|
+
x402Version,
|
|
929
|
+
network,
|
|
930
|
+
...asset ? { asset } : {},
|
|
931
|
+
payload: {
|
|
932
|
+
signature,
|
|
933
|
+
authorization
|
|
934
|
+
},
|
|
935
|
+
raw: v
|
|
936
|
+
};
|
|
937
|
+
}
|
|
548
938
|
function isValidChallenge(value) {
|
|
549
939
|
if (!value || typeof value !== "object") return false;
|
|
550
940
|
const v = value;
|
|
@@ -556,7 +946,7 @@ function isValidChallenge(value) {
|
|
|
556
946
|
function isValidReceipt(value) {
|
|
557
947
|
if (!value || typeof value !== "object") return false;
|
|
558
948
|
const v = value;
|
|
559
|
-
if (v.scheme !== "onchain-proof") return false;
|
|
949
|
+
if (v.scheme !== "onchain-proof" && v.scheme !== "exact") return false;
|
|
560
950
|
if (typeof v.transaction !== "string" && typeof v.txHash !== "string") return false;
|
|
561
951
|
if (typeof v.payer !== "string") return false;
|
|
562
952
|
return true;
|
|
@@ -579,7 +969,7 @@ var evmDriver = {
|
|
|
579
969
|
let resolved;
|
|
580
970
|
try {
|
|
581
971
|
resolved = resolveChain(opts.chain, opts.rpcUrl);
|
|
582
|
-
} catch (
|
|
972
|
+
} catch (e12) {
|
|
583
973
|
return null;
|
|
584
974
|
}
|
|
585
975
|
return makeEvmNetwork(resolved);
|
|
@@ -607,15 +997,15 @@ function makeEvmNetwork(resolved) {
|
|
|
607
997
|
const info = resolved.tokens[token.toUpperCase()];
|
|
608
998
|
if (!info) {
|
|
609
999
|
const known = Object.keys(resolved.tokens).join(", ") || "(none built in)";
|
|
610
|
-
throw new (0,
|
|
1000
|
+
throw new (0, _chunkMDLZJGLYcjs.UnknownTokenError)(
|
|
611
1001
|
`token "${token}" isn't built in for ${resolved.chain.name} (known: ${known}). Pass { address, decimals } instead, or use 'native'.`
|
|
612
1002
|
);
|
|
613
1003
|
}
|
|
614
1004
|
return { asset: info.address, decimals: info.decimals, symbol: info.symbol };
|
|
615
1005
|
}
|
|
616
|
-
|
|
1006
|
+
_chunkMDLZJGLYcjs.rejectForeignToken.call(void 0, token, "evm", network);
|
|
617
1007
|
if (!("address" in token)) {
|
|
618
|
-
throw new (0,
|
|
1008
|
+
throw new (0, _chunkMDLZJGLYcjs.WrongFamilyError)(
|
|
619
1009
|
`chain ${network} is EVM; a custom token must be { address, decimals }.`
|
|
620
1010
|
);
|
|
621
1011
|
}
|
|
@@ -635,7 +1025,7 @@ function makeEvmNetwork(resolved) {
|
|
|
635
1025
|
let normalized;
|
|
636
1026
|
try {
|
|
637
1027
|
normalized = _viem.getAddress.call(void 0, asset);
|
|
638
|
-
} catch (
|
|
1028
|
+
} catch (e13) {
|
|
639
1029
|
return null;
|
|
640
1030
|
}
|
|
641
1031
|
for (const info of Object.values(resolved.tokens)) {
|
|
@@ -647,14 +1037,14 @@ function makeEvmNetwork(resolved) {
|
|
|
647
1037
|
},
|
|
648
1038
|
assertValidPayTo(payTo) {
|
|
649
1039
|
if (!_viem.isAddress.call(void 0, payTo)) {
|
|
650
|
-
throw new (0,
|
|
1040
|
+
throw new (0, _chunkMDLZJGLYcjs.WrongFamilyError)(
|
|
651
1041
|
`chain ${network} is EVM, but payTo "${payTo}" is not a valid 0x address.`
|
|
652
1042
|
);
|
|
653
1043
|
}
|
|
654
1044
|
},
|
|
655
1045
|
bindWallet(wallet) {
|
|
656
1046
|
if (typeof wallet !== "object" || wallet === null || !("privateKey" in wallet) && !("walletClient" in wallet)) {
|
|
657
|
-
throw new (0,
|
|
1047
|
+
throw new (0, _chunkMDLZJGLYcjs.WrongFamilyError)(
|
|
658
1048
|
`chain ${network} is EVM; wallet must be { privateKey } or { walletClient }.`
|
|
659
1049
|
);
|
|
660
1050
|
}
|
|
@@ -671,12 +1061,12 @@ function makeEvmNetwork(resolved) {
|
|
|
671
1061
|
});
|
|
672
1062
|
} catch (err) {
|
|
673
1063
|
if (isViemInsufficientFunds(err)) {
|
|
674
|
-
throw new (0,
|
|
1064
|
+
throw new (0, _chunkMDLZJGLYcjs.InsufficientFundsError)(
|
|
675
1065
|
err instanceof Error ? err.message : "Insufficient funds for payment.",
|
|
676
1066
|
{ cause: err }
|
|
677
1067
|
);
|
|
678
1068
|
}
|
|
679
|
-
throw _nullishCoalesce(
|
|
1069
|
+
throw _nullishCoalesce(_chunkMDLZJGLYcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
|
|
680
1070
|
}
|
|
681
1071
|
},
|
|
682
1072
|
async confirm(ref, minConfirmations) {
|
|
@@ -687,7 +1077,7 @@ function makeEvmNetwork(resolved) {
|
|
|
687
1077
|
});
|
|
688
1078
|
return { height: receipt.blockNumber.toString() };
|
|
689
1079
|
} catch (err) {
|
|
690
|
-
throw new (0,
|
|
1080
|
+
throw new (0, _chunkMDLZJGLYcjs.ConfirmationTimeoutError)(
|
|
691
1081
|
`EVM tx ${ref} did not reach ${minConfirmations} confirmation(s) in time.`,
|
|
692
1082
|
{ cause: err }
|
|
693
1083
|
);
|
|
@@ -698,16 +1088,16 @@ function makeEvmNetwork(resolved) {
|
|
|
698
1088
|
const gasLimit = accept.asset === "native" ? 21000n : 65000n;
|
|
699
1089
|
try {
|
|
700
1090
|
const gasPrice = await publicClient.getGasPrice();
|
|
701
|
-
return
|
|
1091
|
+
return _chunkMDLZJGLYcjs.nativeCost.call(void 0, {
|
|
702
1092
|
symbol,
|
|
703
1093
|
decimals,
|
|
704
1094
|
fee: gasPrice * gasLimit,
|
|
705
1095
|
basis: "estimated",
|
|
706
1096
|
detail: `~${gasLimit} gas @ ${gasPrice} wei/gas`
|
|
707
1097
|
});
|
|
708
|
-
} catch (
|
|
1098
|
+
} catch (e14) {
|
|
709
1099
|
const gasPrice = 5000000000n;
|
|
710
|
-
return
|
|
1100
|
+
return _chunkMDLZJGLYcjs.nativeCost.call(void 0, {
|
|
711
1101
|
symbol,
|
|
712
1102
|
decimals,
|
|
713
1103
|
fee: gasPrice * gasLimit,
|
|
@@ -728,7 +1118,7 @@ function makeEvmNetwork(resolved) {
|
|
|
728
1118
|
functionName: "balanceOf",
|
|
729
1119
|
args: [owner]
|
|
730
1120
|
});
|
|
731
|
-
} catch (
|
|
1121
|
+
} catch (e15) {
|
|
732
1122
|
token = null;
|
|
733
1123
|
}
|
|
734
1124
|
return { token, native };
|
|
@@ -755,6 +1145,21 @@ function makeEvmNetwork(resolved) {
|
|
|
755
1145
|
accept,
|
|
756
1146
|
minConfirmations: accept.extra.minConfirmations
|
|
757
1147
|
});
|
|
1148
|
+
},
|
|
1149
|
+
// Standard x402 `exact` rail (EIP-3009), seller side — EVM only.
|
|
1150
|
+
async exactDomain(asset) {
|
|
1151
|
+
return readExactDomain(publicClient, asset);
|
|
1152
|
+
},
|
|
1153
|
+
async settleExactSelf({ relayer, payload, accept }) {
|
|
1154
|
+
const a = relayer._native;
|
|
1155
|
+
return verifyAndSettleExactEvm({
|
|
1156
|
+
publicClient,
|
|
1157
|
+
walletClient: a.walletClient,
|
|
1158
|
+
account: a.account,
|
|
1159
|
+
chain: resolved.chain,
|
|
1160
|
+
payload,
|
|
1161
|
+
accept
|
|
1162
|
+
});
|
|
758
1163
|
}
|
|
759
1164
|
};
|
|
760
1165
|
}
|
|
@@ -771,9 +1176,9 @@ var loaders = {
|
|
|
771
1176
|
solana: async () => {
|
|
772
1177
|
let mod;
|
|
773
1178
|
try {
|
|
774
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./solana-
|
|
1179
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./solana-PU7N2M64.cjs")));
|
|
775
1180
|
} catch (cause) {
|
|
776
|
-
throw new (0,
|
|
1181
|
+
throw new (0, _chunkMDLZJGLYcjs.MissingDriverError)(
|
|
777
1182
|
`Solana selected, but its packages aren't installed. Run: npm install @solana/web3.js @solana/spl-token bs58`,
|
|
778
1183
|
{ cause }
|
|
779
1184
|
);
|
|
@@ -783,9 +1188,9 @@ var loaders = {
|
|
|
783
1188
|
ton: async () => {
|
|
784
1189
|
let mod;
|
|
785
1190
|
try {
|
|
786
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./ton-
|
|
1191
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./ton-VK6KRJHP.cjs")));
|
|
787
1192
|
} catch (cause) {
|
|
788
|
-
throw new (0,
|
|
1193
|
+
throw new (0, _chunkMDLZJGLYcjs.MissingDriverError)(
|
|
789
1194
|
`TON selected, but its packages aren't installed. Run: npm install @ton/ton @ton/core @ton/crypto`,
|
|
790
1195
|
{ cause }
|
|
791
1196
|
);
|
|
@@ -795,9 +1200,9 @@ var loaders = {
|
|
|
795
1200
|
stellar: async () => {
|
|
796
1201
|
let mod;
|
|
797
1202
|
try {
|
|
798
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./stellar-
|
|
1203
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./stellar-VDQOFQEO.cjs")));
|
|
799
1204
|
} catch (cause) {
|
|
800
|
-
throw new (0,
|
|
1205
|
+
throw new (0, _chunkMDLZJGLYcjs.MissingDriverError)(
|
|
801
1206
|
`Stellar selected, but its package isn't installed. Run: npm install @stellar/stellar-sdk`,
|
|
802
1207
|
{ cause }
|
|
803
1208
|
);
|
|
@@ -807,9 +1212,9 @@ var loaders = {
|
|
|
807
1212
|
xrpl: async () => {
|
|
808
1213
|
let mod;
|
|
809
1214
|
try {
|
|
810
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./xrpl-
|
|
1215
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./xrpl-CMNI25BV.cjs")));
|
|
811
1216
|
} catch (cause) {
|
|
812
|
-
throw new (0,
|
|
1217
|
+
throw new (0, _chunkMDLZJGLYcjs.MissingDriverError)(
|
|
813
1218
|
`XRPL selected, but its package isn't installed. Run: npm install xrpl`,
|
|
814
1219
|
{ cause }
|
|
815
1220
|
);
|
|
@@ -819,9 +1224,9 @@ var loaders = {
|
|
|
819
1224
|
tron: async () => {
|
|
820
1225
|
let mod;
|
|
821
1226
|
try {
|
|
822
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./tron-
|
|
1227
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./tron-WLOF5OUV.cjs")));
|
|
823
1228
|
} catch (cause) {
|
|
824
|
-
throw new (0,
|
|
1229
|
+
throw new (0, _chunkMDLZJGLYcjs.MissingDriverError)(
|
|
825
1230
|
`Tron selected, but its package isn't installed. Run: npm install tronweb`,
|
|
826
1231
|
{ cause }
|
|
827
1232
|
);
|
|
@@ -831,9 +1236,9 @@ var loaders = {
|
|
|
831
1236
|
sui: async () => {
|
|
832
1237
|
let mod;
|
|
833
1238
|
try {
|
|
834
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./sui-
|
|
1239
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./sui-FKSMLKRF.cjs")));
|
|
835
1240
|
} catch (cause) {
|
|
836
|
-
throw new (0,
|
|
1241
|
+
throw new (0, _chunkMDLZJGLYcjs.MissingDriverError)(
|
|
837
1242
|
`Sui selected, but its package isn't installed. Run: npm install @mysten/sui`,
|
|
838
1243
|
{ cause }
|
|
839
1244
|
);
|
|
@@ -843,9 +1248,9 @@ var loaders = {
|
|
|
843
1248
|
near: async () => {
|
|
844
1249
|
let mod;
|
|
845
1250
|
try {
|
|
846
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./near-
|
|
1251
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./near-7ZDNISUX.cjs")));
|
|
847
1252
|
} catch (cause) {
|
|
848
|
-
throw new (0,
|
|
1253
|
+
throw new (0, _chunkMDLZJGLYcjs.MissingDriverError)(
|
|
849
1254
|
`NEAR selected, but its package isn't installed. Run: npm install near-api-js`,
|
|
850
1255
|
{ cause }
|
|
851
1256
|
);
|
|
@@ -855,9 +1260,9 @@ var loaders = {
|
|
|
855
1260
|
aptos: async () => {
|
|
856
1261
|
let mod;
|
|
857
1262
|
try {
|
|
858
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./aptos-
|
|
1263
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./aptos-YT7SXWPF.cjs")));
|
|
859
1264
|
} catch (cause) {
|
|
860
|
-
throw new (0,
|
|
1265
|
+
throw new (0, _chunkMDLZJGLYcjs.MissingDriverError)(
|
|
861
1266
|
`Aptos selected, but its package isn't installed. Run: npm install @aptos-labs/ts-sdk`,
|
|
862
1267
|
{ cause }
|
|
863
1268
|
);
|
|
@@ -867,9 +1272,9 @@ var loaders = {
|
|
|
867
1272
|
algorand: async () => {
|
|
868
1273
|
let mod;
|
|
869
1274
|
try {
|
|
870
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./algorand-
|
|
1275
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./algorand-MXUSKX46.cjs")));
|
|
871
1276
|
} catch (cause) {
|
|
872
|
-
throw new (0,
|
|
1277
|
+
throw new (0, _chunkMDLZJGLYcjs.MissingDriverError)(
|
|
873
1278
|
`Algorand selected, but its package isn't installed. Run: npm install algosdk`,
|
|
874
1279
|
{ cause }
|
|
875
1280
|
);
|
|
@@ -948,7 +1353,7 @@ async function searchOpenIndexes(opts = {}) {
|
|
|
948
1353
|
async function safeSearch(run) {
|
|
949
1354
|
try {
|
|
950
1355
|
return await run();
|
|
951
|
-
} catch (
|
|
1356
|
+
} catch (e16) {
|
|
952
1357
|
return [];
|
|
953
1358
|
}
|
|
954
1359
|
}
|
|
@@ -1072,7 +1477,7 @@ async function readIndexError(res) {
|
|
|
1072
1477
|
(p) => typeof p === "string" && p.length > 0
|
|
1073
1478
|
);
|
|
1074
1479
|
return parts.length ? [...new Set(parts)].join(" \u2014 ") : void 0;
|
|
1075
|
-
} catch (
|
|
1480
|
+
} catch (e17) {
|
|
1076
1481
|
return void 0;
|
|
1077
1482
|
}
|
|
1078
1483
|
}
|
|
@@ -1128,13 +1533,13 @@ async function readSiwxInfo(res) {
|
|
|
1128
1533
|
try {
|
|
1129
1534
|
const body = await res.json();
|
|
1130
1535
|
const ext = body.extensions;
|
|
1131
|
-
const siwx = _optionalChain([ext, 'optionalAccess',
|
|
1132
|
-
const info = _nullishCoalesce(_optionalChain([siwx, 'optionalAccess',
|
|
1536
|
+
const siwx = _optionalChain([ext, 'optionalAccess', _8 => _8["sign-in-with-x"]]);
|
|
1537
|
+
const info = _nullishCoalesce(_optionalChain([siwx, 'optionalAccess', _9 => _9.info]), () => ( siwx));
|
|
1133
1538
|
if (info && typeof info.domain === "string" && info.domain.length > 0 && typeof info.nonce === "string" && info.nonce.length > 0 && typeof info.uri === "string" && info.uri.length > 0) {
|
|
1134
1539
|
return info;
|
|
1135
1540
|
}
|
|
1136
1541
|
return null;
|
|
1137
|
-
} catch (
|
|
1542
|
+
} catch (e18) {
|
|
1138
1543
|
return null;
|
|
1139
1544
|
}
|
|
1140
1545
|
}
|
|
@@ -1182,7 +1587,7 @@ function mapRails(accepts) {
|
|
|
1182
1587
|
}
|
|
1183
1588
|
function matchesQuery(r, query) {
|
|
1184
1589
|
const q = query.toLowerCase();
|
|
1185
|
-
return r.resource.toLowerCase().includes(q) || (_nullishCoalesce(_optionalChain([r, 'access',
|
|
1590
|
+
return r.resource.toLowerCase().includes(q) || (_nullishCoalesce(_optionalChain([r, 'access', _10 => _10.name, 'optionalAccess', _11 => _11.toLowerCase, 'call', _12 => _12(), 'access', _13 => _13.includes, 'call', _14 => _14(q)]), () => ( false))) || (_nullishCoalesce(_optionalChain([r, 'access', _15 => _15.description, 'optionalAccess', _16 => _16.toLowerCase, 'call', _17 => _17(), 'access', _18 => _18.includes, 'call', _19 => _19(q)]), () => ( false)));
|
|
1186
1591
|
}
|
|
1187
1592
|
function pickString(o, ...keys) {
|
|
1188
1593
|
for (const k of keys) {
|
|
@@ -1214,7 +1619,7 @@ function firstArray(o, ...keys) {
|
|
|
1214
1619
|
function hostOf(url) {
|
|
1215
1620
|
try {
|
|
1216
1621
|
return new URL(url).hostname;
|
|
1217
|
-
} catch (
|
|
1622
|
+
} catch (e19) {
|
|
1218
1623
|
return url;
|
|
1219
1624
|
}
|
|
1220
1625
|
}
|
|
@@ -1274,7 +1679,7 @@ function evaluatePolicy(intent, policy, spentForAssetBase) {
|
|
|
1274
1679
|
}
|
|
1275
1680
|
}
|
|
1276
1681
|
if (policy.maxAmount !== void 0) {
|
|
1277
|
-
const cap =
|
|
1682
|
+
const cap = _chunkMDLZJGLYcjs.floorUnits.call(void 0, policy.maxAmount, intent.decimals);
|
|
1278
1683
|
if (intent.amountBase > cap) {
|
|
1279
1684
|
return deny(
|
|
1280
1685
|
`payment of ${intent.amountBase} base units exceeds policy.maxAmount ` + `(${policy.maxAmount} ${_nullishCoalesce(intent.symbol, () => ( ""))}).`.trimEnd()
|
|
@@ -1282,7 +1687,7 @@ function evaluatePolicy(intent, policy, spentForAssetBase) {
|
|
|
1282
1687
|
}
|
|
1283
1688
|
}
|
|
1284
1689
|
if (policy.maxTotal !== void 0) {
|
|
1285
|
-
const cap =
|
|
1690
|
+
const cap = _chunkMDLZJGLYcjs.floorUnits.call(void 0, policy.maxTotal, intent.decimals);
|
|
1286
1691
|
if (spentForAssetBase + intent.amountBase > cap) {
|
|
1287
1692
|
return deny(
|
|
1288
1693
|
`this payment would push spend on ${_nullishCoalesce(intent.symbol, () => ( intent.asset))} past policy.maxTotal (${policy.maxTotal}); already spent ${spentForAssetBase} base units.`
|
|
@@ -1320,7 +1725,7 @@ var SpendLedger = (_class = class {constructor() { _class.prototype.__init.call(
|
|
|
1320
1725
|
}
|
|
1321
1726
|
/** Running total (base units) already spent on this (network, asset). */
|
|
1322
1727
|
totalFor(network, asset) {
|
|
1323
|
-
return _nullishCoalesce(_optionalChain([this, 'access',
|
|
1728
|
+
return _nullishCoalesce(_optionalChain([this, 'access', _20 => _20.buckets, 'access', _21 => _21.get, 'call', _22 => _22(keyFor(network, asset)), 'optionalAccess', _23 => _23.total]), () => ( 0n));
|
|
1324
1729
|
}
|
|
1325
1730
|
/** An immutable snapshot of all spend so far. */
|
|
1326
1731
|
summary() {
|
|
@@ -1332,7 +1737,7 @@ var SpendLedger = (_class = class {constructor() { _class.prototype.__init.call(
|
|
|
1332
1737
|
symbol: b.symbol,
|
|
1333
1738
|
decimals: b.decimals,
|
|
1334
1739
|
totalBase: b.total.toString(),
|
|
1335
|
-
totalFormatted:
|
|
1740
|
+
totalFormatted: _chunkMDLZJGLYcjs.formatUnits.call(void 0, b.total, b.decimals),
|
|
1336
1741
|
count: b.count
|
|
1337
1742
|
})),
|
|
1338
1743
|
records: [...this.records]
|
|
@@ -1369,7 +1774,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1369
1774
|
safeEmit(event) {
|
|
1370
1775
|
try {
|
|
1371
1776
|
this.onEvent(event);
|
|
1372
|
-
} catch (
|
|
1777
|
+
} catch (e20) {
|
|
1373
1778
|
}
|
|
1374
1779
|
}
|
|
1375
1780
|
/** Auto-mount the chain's driver, resolve the network, and bind the wallet — once. */
|
|
@@ -1394,7 +1799,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1394
1799
|
* as-is) or a plain object (serialised as JSON).
|
|
1395
1800
|
*/
|
|
1396
1801
|
post(url, body, init) {
|
|
1397
|
-
const headers = new Headers(_optionalChain([init, 'optionalAccess',
|
|
1802
|
+
const headers = new Headers(_optionalChain([init, 'optionalAccess', _24 => _24.headers]));
|
|
1398
1803
|
let payload;
|
|
1399
1804
|
if (body === void 0 || body === null) {
|
|
1400
1805
|
payload = void 0;
|
|
@@ -1425,7 +1830,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1425
1830
|
* "0.05 USDC on Base, within budget → pay it." No funds move.
|
|
1426
1831
|
*/
|
|
1427
1832
|
async quote(url, init) {
|
|
1428
|
-
const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess',
|
|
1833
|
+
const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _25 => _25.method]), () => ( "GET")) });
|
|
1429
1834
|
if (res.status !== 402) return null;
|
|
1430
1835
|
const { quote } = await this.resolveChallenge(url, res);
|
|
1431
1836
|
return quote;
|
|
@@ -1444,7 +1849,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1444
1849
|
* on Tron, where a USD₮ transfer can cost real TRX.
|
|
1445
1850
|
*/
|
|
1446
1851
|
async estimateCost(url, init) {
|
|
1447
|
-
const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess',
|
|
1852
|
+
const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _26 => _26.method]), () => ( "GET")) });
|
|
1448
1853
|
if (res.status !== 402) return null;
|
|
1449
1854
|
const { net, accept, quote } = await this.resolveChallenge(url, res);
|
|
1450
1855
|
const cost = await net.estimateCost(accept);
|
|
@@ -1475,11 +1880,11 @@ var PipRailClient = (_class2 = class {
|
|
|
1475
1880
|
* the plan yourself. No funds move.
|
|
1476
1881
|
*/
|
|
1477
1882
|
async planPayment(url, init) {
|
|
1478
|
-
const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess',
|
|
1883
|
+
const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _27 => _27.method]), () => ( "GET")) });
|
|
1479
1884
|
if (res.status !== 402) return null;
|
|
1480
1885
|
const challenge = await parseChallenge(res);
|
|
1481
1886
|
if (!challenge) {
|
|
1482
|
-
throw new (0,
|
|
1887
|
+
throw new (0, _chunkMDLZJGLYcjs.InvalidEnvelopeError)("402 response did not include a parseable x402 challenge.");
|
|
1483
1888
|
}
|
|
1484
1889
|
const { net, wallet } = await this.ensure();
|
|
1485
1890
|
return this.planFromChallenge(net, wallet, challenge, url);
|
|
@@ -1595,9 +2000,9 @@ var PipRailClient = (_class2 = class {
|
|
|
1595
2000
|
* streams throw `NonReplayableBodyError`.
|
|
1596
2001
|
*/
|
|
1597
2002
|
async fetch(url, init) {
|
|
1598
|
-
const body = _optionalChain([init, 'optionalAccess',
|
|
2003
|
+
const body = _optionalChain([init, 'optionalAccess', _28 => _28.body]);
|
|
1599
2004
|
if (body !== void 0 && body !== null && !isReplayableBodyInit(body)) {
|
|
1600
|
-
throw new (0,
|
|
2005
|
+
throw new (0, _chunkMDLZJGLYcjs.NonReplayableBodyError)(
|
|
1601
2006
|
"fetch(): init.body is not replayable. Pass a string, FormData, URLSearchParams, ArrayBuffer, or Blob \u2014 not a ReadableStream."
|
|
1602
2007
|
);
|
|
1603
2008
|
}
|
|
@@ -1607,11 +2012,11 @@ var PipRailClient = (_class2 = class {
|
|
|
1607
2012
|
const { net, wallet, challenge } = resolved;
|
|
1608
2013
|
let accept = resolved.accept;
|
|
1609
2014
|
let quote = resolved.quote;
|
|
1610
|
-
const autoRoute = _nullishCoalesce(_nullishCoalesce(_optionalChain([init, 'optionalAccess',
|
|
2015
|
+
const autoRoute = _nullishCoalesce(_nullishCoalesce(_optionalChain([init, 'optionalAccess', _29 => _29.autoRoute]), () => ( this.opts.autoRoute)), () => ( false));
|
|
1611
2016
|
if (autoRoute) {
|
|
1612
2017
|
const plan = await this.planFromChallenge(net, wallet, challenge, url);
|
|
1613
2018
|
if (!plan.best) {
|
|
1614
|
-
throw new (0,
|
|
2019
|
+
throw new (0, _chunkMDLZJGLYcjs.PaymentDeclinedError)(_nullishCoalesce(plan.fundingHint, () => ( "No rail is settleable for this payment.")));
|
|
1615
2020
|
}
|
|
1616
2021
|
accept = plan.best.accept;
|
|
1617
2022
|
quote = plan.best.quote;
|
|
@@ -1632,7 +2037,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1632
2037
|
async resolveChallenge(url, response) {
|
|
1633
2038
|
const challenge = await parseChallenge(response);
|
|
1634
2039
|
if (!challenge) {
|
|
1635
|
-
throw new (0,
|
|
2040
|
+
throw new (0, _chunkMDLZJGLYcjs.InvalidEnvelopeError)(
|
|
1636
2041
|
"402 response did not include a parseable x402 challenge."
|
|
1637
2042
|
);
|
|
1638
2043
|
}
|
|
@@ -1640,7 +2045,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1640
2045
|
const candidates = this.gatherCandidates(net, challenge);
|
|
1641
2046
|
if (candidates.length === 0) {
|
|
1642
2047
|
const networks = challenge.accepts.map((a) => a.network).join(", ");
|
|
1643
|
-
throw new (0,
|
|
2048
|
+
throw new (0, _chunkMDLZJGLYcjs.NoCompatibleAcceptError)(
|
|
1644
2049
|
`No accepts[] entry for ${net.network} (challenge offered: ${networks || "none"}).`
|
|
1645
2050
|
);
|
|
1646
2051
|
}
|
|
@@ -1651,7 +2056,10 @@ var PipRailClient = (_class2 = class {
|
|
|
1651
2056
|
const chosen = _nullishCoalesce(priced.find((p) => p.quote.withinPolicy), () => ( priced[0]));
|
|
1652
2057
|
return { net, wallet, accept: chosen.accept, challenge, quote: chosen.quote };
|
|
1653
2058
|
}
|
|
1654
|
-
/** The candidate accepts this client could pay: our scheme, on the bound network.
|
|
2059
|
+
/** The candidate accepts this client could pay: our scheme, on the bound network.
|
|
2060
|
+
* A dual-advertised challenge may also carry standard `exact` rails — the PipRail
|
|
2061
|
+
* client ignores those (it pays the backendless `onchain-proof` rail); the type
|
|
2062
|
+
* predicate narrows the `X402AnyAccept` union to the rails we settle. */
|
|
1655
2063
|
gatherCandidates(net, challenge) {
|
|
1656
2064
|
return challenge.accepts.filter(
|
|
1657
2065
|
(a) => a.scheme === "onchain-proof" && net.supports(a.network)
|
|
@@ -1714,16 +2122,16 @@ var PipRailClient = (_class2 = class {
|
|
|
1714
2122
|
if (isNative) {
|
|
1715
2123
|
if (nativeKnown && bal.native < amount + fee) {
|
|
1716
2124
|
blockers.push("INSUFFICIENT_TOKEN");
|
|
1717
|
-
shortfall.token =
|
|
2125
|
+
shortfall.token = _chunkMDLZJGLYcjs.formatUnits.call(void 0, amount + fee - bal.native, quote.decimals);
|
|
1718
2126
|
}
|
|
1719
2127
|
} else {
|
|
1720
2128
|
if (tokenKnown && bal.token < amount) {
|
|
1721
2129
|
blockers.push("INSUFFICIENT_TOKEN");
|
|
1722
|
-
shortfall.token =
|
|
2130
|
+
shortfall.token = _chunkMDLZJGLYcjs.formatUnits.call(void 0, amount - bal.token, quote.decimals);
|
|
1723
2131
|
}
|
|
1724
2132
|
if (nativeKnown && bal.native < fee) {
|
|
1725
2133
|
blockers.push("INSUFFICIENT_GAS");
|
|
1726
|
-
shortfall.native =
|
|
2134
|
+
shortfall.native = _chunkMDLZJGLYcjs.formatUnits.call(void 0, fee - bal.native, cost.feeDecimals);
|
|
1727
2135
|
} else if (nativeKnown && fee > 0n && bal.native < fee * 3n / 2n) {
|
|
1728
2136
|
warnings.push("THIN_GAS_MARGIN");
|
|
1729
2137
|
}
|
|
@@ -1748,8 +2156,8 @@ var PipRailClient = (_class2 = class {
|
|
|
1748
2156
|
blockers,
|
|
1749
2157
|
warnings,
|
|
1750
2158
|
balance: {
|
|
1751
|
-
token: bal.token != null ?
|
|
1752
|
-
native: bal.native != null ?
|
|
2159
|
+
token: bal.token != null ? _chunkMDLZJGLYcjs.formatUnits.call(void 0, bal.token, quote.decimals) : null,
|
|
2160
|
+
native: bal.native != null ? _chunkMDLZJGLYcjs.formatUnits.call(void 0, bal.native, cost.feeDecimals) : null
|
|
1753
2161
|
},
|
|
1754
2162
|
need: { token: quote.amountFormatted, native: cost.feeFormatted },
|
|
1755
2163
|
...shortfall.token || shortfall.native ? { shortfall } : {},
|
|
@@ -1760,15 +2168,15 @@ var PipRailClient = (_class2 = class {
|
|
|
1760
2168
|
* driver's describeAsset) + the policy verdict + a symbol-mismatch flag. */
|
|
1761
2169
|
buildQuote(net, accept, url, description) {
|
|
1762
2170
|
if (!/^\d+$/.test(accept.amount)) {
|
|
1763
|
-
throw new (0,
|
|
2171
|
+
throw new (0, _chunkMDLZJGLYcjs.InvalidEnvelopeError)(
|
|
1764
2172
|
`challenge amount "${accept.amount}" is not a base-unit integer.`
|
|
1765
2173
|
);
|
|
1766
2174
|
}
|
|
1767
2175
|
const amountBase = BigInt(accept.amount);
|
|
1768
2176
|
const described = net.describeAsset(accept.asset);
|
|
1769
|
-
const decimals = _nullishCoalesce(_optionalChain([described, 'optionalAccess',
|
|
1770
|
-
const symbol = _nullishCoalesce(_optionalChain([described, 'optionalAccess',
|
|
1771
|
-
const amountFormatted =
|
|
2177
|
+
const decimals = _nullishCoalesce(_optionalChain([described, 'optionalAccess', _30 => _30.decimals]), () => ( accept.extra.decimals));
|
|
2178
|
+
const symbol = _nullishCoalesce(_optionalChain([described, 'optionalAccess', _31 => _31.symbol]), () => ( accept.extra.symbol));
|
|
2179
|
+
const amountFormatted = _chunkMDLZJGLYcjs.formatUnits.call(void 0, amountBase, decimals);
|
|
1772
2180
|
const intent = {
|
|
1773
2181
|
host: hostOf2(url),
|
|
1774
2182
|
chain: this.opts.chain,
|
|
@@ -1808,7 +2216,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1808
2216
|
* throwing PaymentDeclinedError, before any funds move. */
|
|
1809
2217
|
async authorize(quote) {
|
|
1810
2218
|
if (!quote.withinPolicy) {
|
|
1811
|
-
throw new (0,
|
|
2219
|
+
throw new (0, _chunkMDLZJGLYcjs.PaymentDeclinedError)(
|
|
1812
2220
|
`Payment refused by policy: ${_nullishCoalesce(quote.policyReason, () => ( "not allowed"))}`
|
|
1813
2221
|
);
|
|
1814
2222
|
}
|
|
@@ -1818,12 +2226,12 @@ var PipRailClient = (_class2 = class {
|
|
|
1818
2226
|
try {
|
|
1819
2227
|
approved = await hook(quote);
|
|
1820
2228
|
} catch (err) {
|
|
1821
|
-
throw new (0,
|
|
2229
|
+
throw new (0, _chunkMDLZJGLYcjs.PaymentDeclinedError)("onBeforePay threw \u2014 refusing to pay.", {
|
|
1822
2230
|
cause: err
|
|
1823
2231
|
});
|
|
1824
2232
|
}
|
|
1825
2233
|
if (!approved) {
|
|
1826
|
-
throw new (0,
|
|
2234
|
+
throw new (0, _chunkMDLZJGLYcjs.PaymentDeclinedError)(
|
|
1827
2235
|
`onBeforePay declined ${quote.amountFormatted} ${_nullishCoalesce(quote.symbol, () => ( ""))}`.trimEnd() + ` on ${quote.network}.`
|
|
1828
2236
|
);
|
|
1829
2237
|
}
|
|
@@ -1847,7 +2255,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1847
2255
|
}
|
|
1848
2256
|
async payAndConfirm(net, wallet, accept) {
|
|
1849
2257
|
if (!net.supports(accept.network)) {
|
|
1850
|
-
throw new (0,
|
|
2258
|
+
throw new (0, _chunkMDLZJGLYcjs.WrongChainError)(
|
|
1851
2259
|
`Challenge expects ${accept.network} but client is on ${net.network}.`
|
|
1852
2260
|
);
|
|
1853
2261
|
}
|
|
@@ -1876,7 +2284,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1876
2284
|
accepted: accept,
|
|
1877
2285
|
payload: { nonce: accept.extra.nonce, txHash: ref }
|
|
1878
2286
|
};
|
|
1879
|
-
const headers = new Headers(_optionalChain([originalInit, 'optionalAccess',
|
|
2287
|
+
const headers = new Headers(_optionalChain([originalInit, 'optionalAccess', _32 => _32.headers]));
|
|
1880
2288
|
headers.set(HEADER_SIGNATURE, buildSignatureHeader(signature));
|
|
1881
2289
|
let lastResponse = null;
|
|
1882
2290
|
let lastReason = null;
|
|
@@ -1891,7 +2299,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1891
2299
|
() => timeoutController.abort(),
|
|
1892
2300
|
this.retryTimeoutMs
|
|
1893
2301
|
);
|
|
1894
|
-
const signal = _optionalChain([originalInit, 'optionalAccess',
|
|
2302
|
+
const signal = _optionalChain([originalInit, 'optionalAccess', _33 => _33.signal]) && typeof AbortSignal.any === "function" ? AbortSignal.any([timeoutController.signal, originalInit.signal]) : timeoutController.signal;
|
|
1895
2303
|
try {
|
|
1896
2304
|
lastResponse = await fetch(url, {
|
|
1897
2305
|
..._nullishCoalesce(originalInit, () => ( {})),
|
|
@@ -1900,7 +2308,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1900
2308
|
});
|
|
1901
2309
|
} catch (err) {
|
|
1902
2310
|
if (timeoutController.signal.aborted) {
|
|
1903
|
-
throw new (0,
|
|
2311
|
+
throw new (0, _chunkMDLZJGLYcjs.PaymentTimeoutError)(
|
|
1904
2312
|
`Server did not respond within ${this.retryTimeoutMs}ms after broadcasting payment ${ref}. Re-verify or re-submit ref=${ref} \u2014 do NOT re-pay.`,
|
|
1905
2313
|
{ cause: err, ref }
|
|
1906
2314
|
);
|
|
@@ -1922,7 +2330,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1922
2330
|
kind: "payment-failed",
|
|
1923
2331
|
reason: `server returned 402 after broadcasting payment ${ref}${unconfirmedNote} (${why})`
|
|
1924
2332
|
});
|
|
1925
|
-
throw new (0,
|
|
2333
|
+
throw new (0, _chunkMDLZJGLYcjs.MaxRetriesExceededError)(
|
|
1926
2334
|
`Server still returned 402 after ${attempts} attempt(s) with on-chain proof ref=${ref}${unconfirmedNote}. Last server rejection: ${why}. Re-verify or re-submit ref=${ref} before retrying \u2014 never re-pay (it would double-spend).`,
|
|
1927
2335
|
{ ref }
|
|
1928
2336
|
);
|
|
@@ -1931,7 +2339,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1931
2339
|
function safeBig(s) {
|
|
1932
2340
|
try {
|
|
1933
2341
|
return BigInt(s);
|
|
1934
|
-
} catch (
|
|
2342
|
+
} catch (e21) {
|
|
1935
2343
|
return 0n;
|
|
1936
2344
|
}
|
|
1937
2345
|
}
|
|
@@ -1964,10 +2372,10 @@ function buildFundingHint(options, chainLabel) {
|
|
|
1964
2372
|
return `Couldn't fully read your wallet on ${chainLabel} (RPC throttled) \u2014 retry; you may already be able to pay ${target.quote.amountFormatted} ${sym}.`;
|
|
1965
2373
|
}
|
|
1966
2374
|
const parts = [];
|
|
1967
|
-
if (target.blockers.includes("INSUFFICIENT_TOKEN") && _optionalChain([target, 'access',
|
|
2375
|
+
if (target.blockers.includes("INSUFFICIENT_TOKEN") && _optionalChain([target, 'access', _34 => _34.shortfall, 'optionalAccess', _35 => _35.token])) {
|
|
1968
2376
|
parts.push(`top up ${target.shortfall.token} ${sym}`);
|
|
1969
2377
|
}
|
|
1970
|
-
if (target.blockers.includes("INSUFFICIENT_GAS") && _optionalChain([target, 'access',
|
|
2378
|
+
if (target.blockers.includes("INSUFFICIENT_GAS") && _optionalChain([target, 'access', _36 => _36.shortfall, 'optionalAccess', _37 => _37.native])) {
|
|
1971
2379
|
parts.push(`add ~${target.shortfall.native} ${target.cost.feeSymbol} for gas`);
|
|
1972
2380
|
}
|
|
1973
2381
|
return parts.length ? `Can't settle on ${chainLabel}: ${parts.join(" and ")} (to pay ${target.quote.amountFormatted} ${sym}).` : `Can't settle on ${chainLabel} for ${target.quote.amountFormatted} ${sym}.`;
|
|
@@ -1981,7 +2389,7 @@ async function planAcross(clients, url, init) {
|
|
|
1981
2389
|
const status = best ? "ready" : options.some((o) => o.state === "unknown") ? "unknown" : "blocked";
|
|
1982
2390
|
return {
|
|
1983
2391
|
url,
|
|
1984
|
-
network: _nullishCoalesce(_optionalChain([best, 'optionalAccess',
|
|
2392
|
+
network: _nullishCoalesce(_optionalChain([best, 'optionalAccess', _38 => _38.accept, 'access', _39 => _39.network]), () => ( live[0].network)),
|
|
1985
2393
|
status,
|
|
1986
2394
|
payable: best !== null,
|
|
1987
2395
|
best,
|
|
@@ -1997,7 +2405,7 @@ function railOnNetwork(rail, matches) {
|
|
|
1997
2405
|
function hostOf2(url) {
|
|
1998
2406
|
try {
|
|
1999
2407
|
return new URL(url).hostname;
|
|
2000
|
-
} catch (
|
|
2408
|
+
} catch (e22) {
|
|
2001
2409
|
return url;
|
|
2002
2410
|
}
|
|
2003
2411
|
}
|
|
@@ -2014,13 +2422,21 @@ function isReplayableBodyInit(value) {
|
|
|
2014
2422
|
async function readInvalidReason(response) {
|
|
2015
2423
|
try {
|
|
2016
2424
|
const body = await response.clone().json();
|
|
2425
|
+
const ext = _optionalChain([body, 'optionalAccess', _40 => _40.extensions]);
|
|
2426
|
+
const piprail = _optionalChain([ext, 'optionalAccess', _41 => _41.piprail]);
|
|
2427
|
+
if (piprail && typeof piprail.code === "string") {
|
|
2428
|
+
return {
|
|
2429
|
+
error: piprail.code,
|
|
2430
|
+
detail: typeof piprail.detail === "string" ? piprail.detail : ""
|
|
2431
|
+
};
|
|
2432
|
+
}
|
|
2017
2433
|
if (body && (body.status === "invalid" || typeof body.error === "string")) {
|
|
2018
2434
|
return {
|
|
2019
2435
|
error: typeof body.error === "string" ? body.error : "no error code",
|
|
2020
2436
|
detail: typeof body.detail === "string" ? body.detail : ""
|
|
2021
2437
|
};
|
|
2022
2438
|
}
|
|
2023
|
-
} catch (
|
|
2439
|
+
} catch (e23) {
|
|
2024
2440
|
}
|
|
2025
2441
|
return null;
|
|
2026
2442
|
}
|
|
@@ -2031,7 +2447,7 @@ async function readBody(res) {
|
|
|
2031
2447
|
if (!text) return null;
|
|
2032
2448
|
try {
|
|
2033
2449
|
return JSON.parse(text);
|
|
2034
|
-
} catch (
|
|
2450
|
+
} catch (e24) {
|
|
2035
2451
|
return text;
|
|
2036
2452
|
}
|
|
2037
2453
|
}
|
|
@@ -2202,7 +2618,7 @@ function paymentTools(client) {
|
|
|
2202
2618
|
receipt: parseReceipt(res)
|
|
2203
2619
|
};
|
|
2204
2620
|
} catch (err) {
|
|
2205
|
-
if (err instanceof
|
|
2621
|
+
if (err instanceof _chunkMDLZJGLYcjs.PaymentDeclinedError) {
|
|
2206
2622
|
return { declined: true, reason: err.message };
|
|
2207
2623
|
}
|
|
2208
2624
|
throw err;
|
|
@@ -2245,6 +2661,100 @@ function paymentTools(client) {
|
|
|
2245
2661
|
];
|
|
2246
2662
|
}
|
|
2247
2663
|
|
|
2664
|
+
// src/facilitator.ts
|
|
2665
|
+
function safeStringify(value) {
|
|
2666
|
+
return JSON.stringify(value, (_k, v) => typeof v === "bigint" ? v.toString() : v);
|
|
2667
|
+
}
|
|
2668
|
+
function mapReason(reason) {
|
|
2669
|
+
const r = (_nullishCoalesce(reason, () => ( ""))).toLowerCase();
|
|
2670
|
+
if (r.includes("signature")) return "signature_invalid";
|
|
2671
|
+
if (r.includes("recipient")) return "wrong_recipient";
|
|
2672
|
+
if (r.includes("value") || r.includes("amount")) return "amount_too_low";
|
|
2673
|
+
if (r.includes("valid_before") || r.includes("valid_after") || r.includes("expired")) return "payment_expired";
|
|
2674
|
+
if (r.includes("used") || r.includes("replay") || r.includes("nonce") || r.includes("transaction_state")) {
|
|
2675
|
+
return "tx_already_used";
|
|
2676
|
+
}
|
|
2677
|
+
return "tx_reverted";
|
|
2678
|
+
}
|
|
2679
|
+
async function post(url, body, headers) {
|
|
2680
|
+
const res = await fetch(url, {
|
|
2681
|
+
method: "POST",
|
|
2682
|
+
headers: { "content-type": "application/json", ...headers },
|
|
2683
|
+
body: safeStringify(body)
|
|
2684
|
+
});
|
|
2685
|
+
let json = null;
|
|
2686
|
+
try {
|
|
2687
|
+
json = await res.json();
|
|
2688
|
+
} catch (e25) {
|
|
2689
|
+
}
|
|
2690
|
+
return { status: res.status, json };
|
|
2691
|
+
}
|
|
2692
|
+
async function settleViaFacilitator(input) {
|
|
2693
|
+
const base2 = input.url.replace(/\/+$/, "");
|
|
2694
|
+
const body = {
|
|
2695
|
+
x402Version: input.x402Version,
|
|
2696
|
+
paymentPayload: input.paymentPayload,
|
|
2697
|
+
paymentRequirements: input.paymentRequirements
|
|
2698
|
+
};
|
|
2699
|
+
const auth = input.authHeaders ? await input.authHeaders() : {};
|
|
2700
|
+
let verify;
|
|
2701
|
+
try {
|
|
2702
|
+
verify = await post(`${base2}/verify`, body, auth);
|
|
2703
|
+
} catch (err) {
|
|
2704
|
+
throw new (0, _chunkMDLZJGLYcjs.SettlementError)(
|
|
2705
|
+
`exact settle (facilitator ${base2}): /verify request failed (${err instanceof Error ? err.message : String(err)}).`,
|
|
2706
|
+
{ cause: err }
|
|
2707
|
+
);
|
|
2708
|
+
}
|
|
2709
|
+
if (verify.status !== 200) {
|
|
2710
|
+
throw new (0, _chunkMDLZJGLYcjs.SettlementError)(
|
|
2711
|
+
`exact settle (facilitator ${base2}): /verify returned HTTP ${verify.status} (transport/auth error).`
|
|
2712
|
+
);
|
|
2713
|
+
}
|
|
2714
|
+
const vr = _nullishCoalesce(verify.json, () => ( {}));
|
|
2715
|
+
if (vr.isValid === false) {
|
|
2716
|
+
return {
|
|
2717
|
+
ok: false,
|
|
2718
|
+
error: mapReason(vr.invalidReason),
|
|
2719
|
+
detail: `Facilitator rejected the payment: ${_nullishCoalesce(vr.invalidReason, () => ( "invalid"))}${vr.invalidMessage ? ` \u2014 ${vr.invalidMessage}` : ""}.`
|
|
2720
|
+
};
|
|
2721
|
+
}
|
|
2722
|
+
let settle;
|
|
2723
|
+
try {
|
|
2724
|
+
settle = await post(`${base2}/settle`, body, auth);
|
|
2725
|
+
} catch (err) {
|
|
2726
|
+
throw new (0, _chunkMDLZJGLYcjs.SettlementError)(
|
|
2727
|
+
`exact settle (facilitator ${base2}): /settle request failed (${err instanceof Error ? err.message : String(err)}).`,
|
|
2728
|
+
{ cause: err }
|
|
2729
|
+
);
|
|
2730
|
+
}
|
|
2731
|
+
if (settle.status !== 200) {
|
|
2732
|
+
throw new (0, _chunkMDLZJGLYcjs.SettlementError)(
|
|
2733
|
+
`exact settle (facilitator ${base2}): /settle returned HTTP ${settle.status} (transport/auth error).`
|
|
2734
|
+
);
|
|
2735
|
+
}
|
|
2736
|
+
const sr = _nullishCoalesce(settle.json, () => ( {}));
|
|
2737
|
+
if (!sr.success) {
|
|
2738
|
+
return {
|
|
2739
|
+
ok: false,
|
|
2740
|
+
error: mapReason(sr.errorReason),
|
|
2741
|
+
detail: `Facilitator settlement failed: ${_nullishCoalesce(sr.errorReason, () => ( "unknown"))}${sr.errorMessage ? ` \u2014 ${sr.errorMessage}` : ""}.`
|
|
2742
|
+
};
|
|
2743
|
+
}
|
|
2744
|
+
const receipt = {
|
|
2745
|
+
scheme: "exact",
|
|
2746
|
+
success: true,
|
|
2747
|
+
network: input.receipt.network,
|
|
2748
|
+
transaction: sr.transaction,
|
|
2749
|
+
asset: input.receipt.asset,
|
|
2750
|
+
amount: input.receipt.amount,
|
|
2751
|
+
payer: _nullishCoalesce(_nullishCoalesce(sr.payer, () => ( input.payerHint)), () => ( "")),
|
|
2752
|
+
payTo: input.receipt.payTo,
|
|
2753
|
+
verifiedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2754
|
+
};
|
|
2755
|
+
return { ok: true, receipt };
|
|
2756
|
+
}
|
|
2757
|
+
|
|
2248
2758
|
// src/server.ts
|
|
2249
2759
|
function toInvalidBody(result) {
|
|
2250
2760
|
return { x402Version: 2, status: "invalid", error: result.error, detail: result.detail };
|
|
@@ -2271,9 +2781,10 @@ function createPaymentGate(options) {
|
|
|
2271
2781
|
const genNonce = _nullishCoalesce(options.generateNonce, () => ( (() => globalThis.crypto.randomUUID())));
|
|
2272
2782
|
let resolved;
|
|
2273
2783
|
function ready() {
|
|
2274
|
-
|
|
2784
|
+
if (resolved) return resolved;
|
|
2785
|
+
const p = (async () => {
|
|
2275
2786
|
const accepts = normaliseAccepts(options);
|
|
2276
|
-
|
|
2787
|
+
const specs = await Promise.all(
|
|
2277
2788
|
accepts.map(async (a) => {
|
|
2278
2789
|
const net = await resolveNetwork2({ chain: a.chain, rpcUrl: _nullishCoalesce(a.rpcUrl, () => ( options.rpcUrl)) });
|
|
2279
2790
|
const payTo = _nullishCoalesce(a.payTo, () => ( options.payTo));
|
|
@@ -2284,11 +2795,53 @@ function createPaymentGate(options) {
|
|
|
2284
2795
|
}
|
|
2285
2796
|
net.assertValidPayTo(payTo);
|
|
2286
2797
|
const { asset, decimals, symbol } = net.resolveToken(a.token);
|
|
2287
|
-
const amountBase =
|
|
2288
|
-
|
|
2798
|
+
const amountBase = _chunkMDLZJGLYcjs.parseUnits.call(void 0, a.amount, decimals);
|
|
2799
|
+
const spec = { net, asset, decimals, symbol, amountBase, amountFormatted: a.amount, payTo };
|
|
2800
|
+
if (options.exact) spec.exact = await resolveExactRail(net, asset);
|
|
2801
|
+
return spec;
|
|
2289
2802
|
})
|
|
2290
2803
|
);
|
|
2804
|
+
if (options.exact && !specs.some((s) => s.exact)) {
|
|
2805
|
+
throw new Error(
|
|
2806
|
+
"requirePayment: `exact` was requested but none of the offered rails support it. The standard `exact` rail is EVM + EIP-3009 only (USDC / EURC) \u2014 not native coins, not USDT, not non-EVM chains. Offer an EVM EIP-3009 token, or drop `exact`."
|
|
2807
|
+
);
|
|
2808
|
+
}
|
|
2809
|
+
return specs;
|
|
2291
2810
|
})();
|
|
2811
|
+
p.catch(() => {
|
|
2812
|
+
if (resolved === p) resolved = void 0;
|
|
2813
|
+
});
|
|
2814
|
+
resolved = p;
|
|
2815
|
+
return p;
|
|
2816
|
+
}
|
|
2817
|
+
async function resolveExactRail(net, asset) {
|
|
2818
|
+
const cfg = options.exact;
|
|
2819
|
+
if (net.family !== "evm" || asset === "native" || !net.exactDomain || !net.settleExactSelf) {
|
|
2820
|
+
return void 0;
|
|
2821
|
+
}
|
|
2822
|
+
const domain = await net.exactDomain(asset);
|
|
2823
|
+
if (!domain) {
|
|
2824
|
+
throw new Error(
|
|
2825
|
+
`requirePayment: \`exact\` requested for asset ${asset} on ${net.network}, but it isn't an EIP-3009 token (couldn't read name()/version()/authorizationState). The exact rail supports USDC / EURC and other EIP-3009 tokens \u2014 USDT and native coins need onchain-proof. (Or check your rpcUrl is reachable.)`
|
|
2826
|
+
);
|
|
2827
|
+
}
|
|
2828
|
+
if (cfg.settle === "self") {
|
|
2829
|
+
if (cfg.relayer === void 0) {
|
|
2830
|
+
throw new Error(
|
|
2831
|
+
"requirePayment: exact `settle: 'self'` needs a `relayer` wallet (the gas-paying key that broadcasts transferWithAuthorization), e.g. exact: { settle: 'self', relayer: { privateKey } }."
|
|
2832
|
+
);
|
|
2833
|
+
}
|
|
2834
|
+
const relayer = net.bindWallet(cfg.relayer);
|
|
2835
|
+
return { domain, mode: { kind: "self", relayer } };
|
|
2836
|
+
}
|
|
2837
|
+
return {
|
|
2838
|
+
domain,
|
|
2839
|
+
mode: {
|
|
2840
|
+
kind: "facilitator",
|
|
2841
|
+
url: cfg.settle.facilitator,
|
|
2842
|
+
...cfg.settle.authHeaders ? { authHeaders: cfg.settle.authHeaders } : {}
|
|
2843
|
+
}
|
|
2844
|
+
};
|
|
2292
2845
|
}
|
|
2293
2846
|
const hasCustomStore = Boolean(options.isUsed || options.markUsed);
|
|
2294
2847
|
const localUsed = /* @__PURE__ */ new Set();
|
|
@@ -2325,93 +2878,191 @@ function createPaymentGate(options) {
|
|
|
2325
2878
|
}
|
|
2326
2879
|
};
|
|
2327
2880
|
}
|
|
2328
|
-
|
|
2881
|
+
function buildExactAccept(s) {
|
|
2882
|
+
const d = s.exact.domain;
|
|
2883
|
+
return {
|
|
2884
|
+
scheme: "exact",
|
|
2885
|
+
network: s.net.network,
|
|
2886
|
+
amount: s.amountBase.toString(),
|
|
2887
|
+
asset: s.asset,
|
|
2888
|
+
payTo: s.payTo,
|
|
2889
|
+
maxTimeoutSeconds,
|
|
2890
|
+
extra: {
|
|
2891
|
+
assetTransferMethod: "eip3009",
|
|
2892
|
+
name: d.name,
|
|
2893
|
+
version: d.version,
|
|
2894
|
+
minConfirmations,
|
|
2895
|
+
decimals: s.decimals,
|
|
2896
|
+
amountFormatted: s.amountFormatted,
|
|
2897
|
+
...s.symbol ? { symbol: s.symbol } : {}
|
|
2898
|
+
}
|
|
2899
|
+
};
|
|
2900
|
+
}
|
|
2901
|
+
function buildAccepts(specs, nonce) {
|
|
2902
|
+
const out = [];
|
|
2903
|
+
for (const s of specs) {
|
|
2904
|
+
if (s.exact) out.push(buildExactAccept(s));
|
|
2905
|
+
out.push(buildAccept(s, nonce));
|
|
2906
|
+
}
|
|
2907
|
+
return out;
|
|
2908
|
+
}
|
|
2909
|
+
async function makeChallenge(resourceUrl, opts) {
|
|
2329
2910
|
const specs = await ready();
|
|
2330
2911
|
const nonce = genNonce();
|
|
2331
2912
|
const challenge2 = {
|
|
2332
2913
|
x402Version: 2,
|
|
2333
|
-
error: null,
|
|
2334
2914
|
resource: {
|
|
2335
2915
|
url: resourceUrl,
|
|
2336
2916
|
...options.description ? { description: options.description } : {}
|
|
2337
2917
|
},
|
|
2338
|
-
accepts: specs
|
|
2918
|
+
accepts: buildAccepts(specs, nonce),
|
|
2919
|
+
..._optionalChain([opts, 'optionalAccess', _42 => _42.error]) ? { error: opts.error } : {},
|
|
2920
|
+
..._optionalChain([opts, 'optionalAccess', _43 => _43.extensions]) ? { extensions: opts.extensions } : {}
|
|
2339
2921
|
};
|
|
2340
2922
|
return { challenge: challenge2, requiredHeader: buildChallengeHeader(challenge2) };
|
|
2341
2923
|
}
|
|
2924
|
+
async function challenge(resourceUrl = "") {
|
|
2925
|
+
return makeChallenge(resourceUrl);
|
|
2926
|
+
}
|
|
2342
2927
|
async function asChallenge() {
|
|
2343
|
-
const { challenge: c, requiredHeader } = await
|
|
2928
|
+
const { challenge: c, requiredHeader } = await makeChallenge("");
|
|
2344
2929
|
return { kind: "challenge", challenge: c, requiredHeader, statusCode: 402 };
|
|
2345
2930
|
}
|
|
2931
|
+
async function rejection(code, detail) {
|
|
2932
|
+
const { challenge: c, requiredHeader } = await makeChallenge("", {
|
|
2933
|
+
error: `${code}: ${detail}`,
|
|
2934
|
+
extensions: { piprail: { code, detail } }
|
|
2935
|
+
});
|
|
2936
|
+
return { kind: "invalid", error: code, detail, challenge: c, requiredHeader, statusCode: 402 };
|
|
2937
|
+
}
|
|
2938
|
+
function fireOnPaid(receipt) {
|
|
2939
|
+
if (options.onPaid) {
|
|
2940
|
+
try {
|
|
2941
|
+
options.onPaid(receipt);
|
|
2942
|
+
} catch (e26) {
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
2346
2946
|
async function describe(resourceUrl = "") {
|
|
2347
2947
|
const specs = await ready();
|
|
2348
|
-
const accepts =
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2948
|
+
const accepts = [];
|
|
2949
|
+
for (const s of specs) {
|
|
2950
|
+
const base2 = {
|
|
2951
|
+
network: s.net.network,
|
|
2952
|
+
asset: s.asset,
|
|
2953
|
+
payTo: s.payTo,
|
|
2954
|
+
amount: s.amountBase.toString(),
|
|
2955
|
+
amountFormatted: s.amountFormatted,
|
|
2956
|
+
decimals: s.decimals,
|
|
2957
|
+
maxTimeoutSeconds,
|
|
2958
|
+
...s.symbol ? { symbol: s.symbol } : {}
|
|
2959
|
+
};
|
|
2960
|
+
if (s.exact) accepts.push({ scheme: "exact", ...base2 });
|
|
2961
|
+
accepts.push({ scheme: "onchain-proof", ...base2 });
|
|
2962
|
+
}
|
|
2359
2963
|
return {
|
|
2360
2964
|
url: resourceUrl,
|
|
2361
2965
|
...options.description ? { description: options.description } : {},
|
|
2362
2966
|
accepts
|
|
2363
2967
|
};
|
|
2364
2968
|
}
|
|
2365
|
-
async function
|
|
2366
|
-
const raw = normaliseHeader(paymentSignature);
|
|
2367
|
-
if (!raw) return asChallenge();
|
|
2368
|
-
const sig = parseSignatureHeader(raw);
|
|
2369
|
-
if (!sig || !sig.accepted || typeof sig.accepted.network !== "string" || typeof sig.accepted.asset !== "string") {
|
|
2370
|
-
return asChallenge();
|
|
2371
|
-
}
|
|
2969
|
+
async function verifyOnchainProof(sig) {
|
|
2372
2970
|
const specs = await ready();
|
|
2373
2971
|
const spec = specs.find(
|
|
2374
2972
|
(s) => s.net.network === sig.accepted.network && s.asset === sig.accepted.asset
|
|
2375
2973
|
);
|
|
2376
2974
|
if (!spec) {
|
|
2377
|
-
return
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
statusCode: 402
|
|
2382
|
-
};
|
|
2975
|
+
return rejection(
|
|
2976
|
+
"transfer_not_found",
|
|
2977
|
+
`Proof claims ${sig.accepted.asset} on ${sig.accepted.network}, which this resource doesn't accept (offered: ${specs.map((s) => `${s.asset}@${s.net.network}`).join(", ")}).`
|
|
2978
|
+
);
|
|
2383
2979
|
}
|
|
2384
2980
|
const ref = sig.payload.txHash;
|
|
2385
|
-
if (await claimTx(ref)) {
|
|
2386
|
-
return {
|
|
2387
|
-
kind: "invalid",
|
|
2388
|
-
error: "tx_already_used",
|
|
2389
|
-
detail: `Proof ${ref} was already redeemed.`,
|
|
2390
|
-
statusCode: 402
|
|
2391
|
-
};
|
|
2392
|
-
}
|
|
2981
|
+
if (await claimTx(ref)) return rejection("tx_already_used", `Proof ${ref} was already redeemed.`);
|
|
2393
2982
|
const result = await spec.net.verify(ref, buildAccept(spec, sig.payload.nonce));
|
|
2394
2983
|
if (!result.ok) {
|
|
2395
2984
|
await settleTx(ref, false);
|
|
2396
|
-
return
|
|
2397
|
-
kind: "invalid",
|
|
2398
|
-
error: result.error,
|
|
2399
|
-
detail: result.detail,
|
|
2400
|
-
statusCode: 402
|
|
2401
|
-
};
|
|
2985
|
+
return rejection(result.error, result.detail);
|
|
2402
2986
|
}
|
|
2403
2987
|
await settleTx(ref, true);
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2988
|
+
fireOnPaid(result.receipt);
|
|
2989
|
+
return { kind: "paid", receipt: result.receipt, receiptHeader: buildReceiptHeader(result.receipt) };
|
|
2990
|
+
}
|
|
2991
|
+
async function verifyExact(exact) {
|
|
2992
|
+
const specs = await ready();
|
|
2993
|
+
const exactSpecs = specs.filter((s) => s.exact);
|
|
2994
|
+
if (exactSpecs.length === 0) {
|
|
2995
|
+
return rejection("transfer_not_found", "This resource offers no standard `exact` rail.");
|
|
2996
|
+
}
|
|
2997
|
+
const isCaip = exact.network.startsWith("eip155:");
|
|
2998
|
+
let candidates = isCaip ? exactSpecs.filter((s) => s.net.network === exact.network) : exactSpecs;
|
|
2999
|
+
if (exact.asset) {
|
|
3000
|
+
candidates = candidates.filter((s) => s.asset.toLowerCase() === exact.asset.toLowerCase());
|
|
3001
|
+
}
|
|
3002
|
+
let spec = candidates[0];
|
|
3003
|
+
if (!isCaip && !exact.asset && exactSpecs.length > 1) spec = void 0;
|
|
3004
|
+
if (!spec && !isCaip && !exact.asset && exactSpecs.length === 1) spec = exactSpecs[0];
|
|
3005
|
+
if (!spec || !spec.exact) {
|
|
3006
|
+
return rejection(
|
|
3007
|
+
"transfer_not_found",
|
|
3008
|
+
`No \`exact\` rail offered for ${exact.network}${exact.asset ? `/${exact.asset}` : ""} (offered: ${exactSpecs.map((s) => `${s.asset}@${s.net.network}`).join(", ")}).`
|
|
3009
|
+
);
|
|
3010
|
+
}
|
|
3011
|
+
const nonce = exact.payload.authorization.nonce;
|
|
3012
|
+
if (await claimTx(nonce)) {
|
|
3013
|
+
return rejection("tx_already_used", `Authorization nonce ${nonce} was already redeemed.`);
|
|
3014
|
+
}
|
|
3015
|
+
const accept = buildExactAccept(spec);
|
|
3016
|
+
const mode = spec.exact.mode;
|
|
3017
|
+
let result;
|
|
3018
|
+
try {
|
|
3019
|
+
if (mode.kind === "self") {
|
|
3020
|
+
result = await spec.net.settleExactSelf({ relayer: mode.relayer, payload: exact.payload, accept });
|
|
3021
|
+
} else {
|
|
3022
|
+
result = await settleViaFacilitator({
|
|
3023
|
+
url: mode.url,
|
|
3024
|
+
...mode.authHeaders ? { authHeaders: mode.authHeaders } : {},
|
|
3025
|
+
// PipRail always builds a v2-shaped paymentRequirements (CAIP-2 network + `amount`),
|
|
3026
|
+
// so force x402Version:2 — echoing a v1 client's version here would hand the facilitator
|
|
3027
|
+
// a self-inconsistent request (v1 envelope, v2 requirements). The inner payload is
|
|
3028
|
+
// byte-identical across versions, so forwarding it verbatim is fine.
|
|
3029
|
+
x402Version: 2,
|
|
3030
|
+
paymentPayload: exact.raw,
|
|
3031
|
+
paymentRequirements: {
|
|
3032
|
+
scheme: "exact",
|
|
3033
|
+
network: accept.network,
|
|
3034
|
+
asset: accept.asset,
|
|
3035
|
+
amount: accept.amount,
|
|
3036
|
+
payTo: accept.payTo,
|
|
3037
|
+
maxTimeoutSeconds: accept.maxTimeoutSeconds,
|
|
3038
|
+
extra: { name: accept.extra.name, version: accept.extra.version }
|
|
3039
|
+
},
|
|
3040
|
+
receipt: { network: accept.network, asset: accept.asset, payTo: accept.payTo, amount: accept.amount },
|
|
3041
|
+
payerHint: exact.payload.authorization.from
|
|
3042
|
+
});
|
|
2408
3043
|
}
|
|
3044
|
+
} catch (err) {
|
|
3045
|
+
await settleTx(nonce, false);
|
|
3046
|
+
throw err;
|
|
2409
3047
|
}
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
3048
|
+
if (!result.ok) {
|
|
3049
|
+
await settleTx(nonce, false);
|
|
3050
|
+
return rejection(result.error, result.detail);
|
|
3051
|
+
}
|
|
3052
|
+
await settleTx(nonce, true);
|
|
3053
|
+
fireOnPaid(result.receipt);
|
|
3054
|
+
return { kind: "paid", receipt: result.receipt, receiptHeader: buildReceiptHeader(result.receipt) };
|
|
3055
|
+
}
|
|
3056
|
+
async function verify(paymentSignature) {
|
|
3057
|
+
const raw = normaliseHeader(paymentSignature);
|
|
3058
|
+
if (!raw) return asChallenge();
|
|
3059
|
+
const sig = parseSignatureHeader(raw);
|
|
3060
|
+
if (sig && sig.accepted && typeof sig.accepted.network === "string" && typeof sig.accepted.asset === "string") {
|
|
3061
|
+
return verifyOnchainProof(sig);
|
|
3062
|
+
}
|
|
3063
|
+
const exact = parseExactPaymentHeader(raw);
|
|
3064
|
+
if (exact) return verifyExact(exact);
|
|
3065
|
+
return asChallenge();
|
|
2415
3066
|
}
|
|
2416
3067
|
return { challenge, verify, describe };
|
|
2417
3068
|
}
|
|
@@ -2420,14 +3071,20 @@ function requirePayment(options) {
|
|
|
2420
3071
|
return async (req, res, next) => {
|
|
2421
3072
|
let result;
|
|
2422
3073
|
try {
|
|
2423
|
-
result = await gate.verify(req.headers[HEADER_SIGNATURE]);
|
|
3074
|
+
result = await gate.verify(_nullishCoalesce(req.headers[HEADER_SIGNATURE], () => ( req.headers[HEADER_SIGNATURE_V1])));
|
|
2424
3075
|
} catch (err) {
|
|
3076
|
+
if (err instanceof _chunkMDLZJGLYcjs.SettlementError) {
|
|
3077
|
+
res.status(502);
|
|
3078
|
+
res.json({ x402Version: 2, error: "settlement_failed", detail: err.message });
|
|
3079
|
+
return;
|
|
3080
|
+
}
|
|
2425
3081
|
next(err);
|
|
2426
3082
|
return;
|
|
2427
3083
|
}
|
|
2428
3084
|
switch (result.kind) {
|
|
2429
3085
|
case "paid":
|
|
2430
3086
|
res.setHeader(HEADER_RESPONSE, result.receiptHeader);
|
|
3087
|
+
res.setHeader(HEADER_RESPONSE_V1, result.receiptHeader);
|
|
2431
3088
|
return next();
|
|
2432
3089
|
case "challenge":
|
|
2433
3090
|
res.setHeader(HEADER_REQUIRED, result.requiredHeader);
|
|
@@ -2435,8 +3092,9 @@ function requirePayment(options) {
|
|
|
2435
3092
|
res.json(result.challenge);
|
|
2436
3093
|
return;
|
|
2437
3094
|
case "invalid":
|
|
3095
|
+
res.setHeader(HEADER_REQUIRED, result.requiredHeader);
|
|
2438
3096
|
res.status(result.statusCode);
|
|
2439
|
-
res.json(
|
|
3097
|
+
res.json(result.challenge);
|
|
2440
3098
|
return;
|
|
2441
3099
|
}
|
|
2442
3100
|
};
|
|
@@ -2446,110 +3104,12 @@ function normaliseHeader(value) {
|
|
|
2446
3104
|
return value;
|
|
2447
3105
|
}
|
|
2448
3106
|
|
|
2449
|
-
// src/drivers/evm/exact.ts
|
|
2450
|
-
var EXACT_NETWORK_SLUGS = {
|
|
2451
|
-
ethereum: 1,
|
|
2452
|
-
base: 8453,
|
|
2453
|
-
"base-sepolia": 84532,
|
|
2454
|
-
arbitrum: 42161,
|
|
2455
|
-
optimism: 10,
|
|
2456
|
-
polygon: 137,
|
|
2457
|
-
avalanche: 43114
|
|
2458
|
-
};
|
|
2459
|
-
function chainIdForExactNetwork(slug) {
|
|
2460
|
-
return _nullishCoalesce(EXACT_NETWORK_SLUGS[slug], () => ( null));
|
|
2461
|
-
}
|
|
2462
|
-
var EIP3009_TYPES = {
|
|
2463
|
-
TransferWithAuthorization: [
|
|
2464
|
-
{ name: "from", type: "address" },
|
|
2465
|
-
{ name: "to", type: "address" },
|
|
2466
|
-
{ name: "value", type: "uint256" },
|
|
2467
|
-
{ name: "validAfter", type: "uint256" },
|
|
2468
|
-
{ name: "validBefore", type: "uint256" },
|
|
2469
|
-
{ name: "nonce", type: "bytes32" }
|
|
2470
|
-
]
|
|
2471
|
-
};
|
|
2472
|
-
function parseExactRequirements(body) {
|
|
2473
|
-
if (!body || typeof body !== "object") return null;
|
|
2474
|
-
const accepts = body.accepts;
|
|
2475
|
-
if (!Array.isArray(accepts)) return null;
|
|
2476
|
-
const out = [];
|
|
2477
|
-
for (const raw of accepts) {
|
|
2478
|
-
if (!raw || typeof raw !== "object") continue;
|
|
2479
|
-
const a = raw;
|
|
2480
|
-
if (a.scheme !== "exact") continue;
|
|
2481
|
-
const amount = _nullishCoalesce(a.maxAmountRequired, () => ( a.amount));
|
|
2482
|
-
if (typeof a.network !== "string" || typeof amount !== "string" || typeof a.asset !== "string" || typeof a.payTo !== "string") {
|
|
2483
|
-
continue;
|
|
2484
|
-
}
|
|
2485
|
-
out.push({
|
|
2486
|
-
scheme: "exact",
|
|
2487
|
-
network: a.network,
|
|
2488
|
-
maxAmountRequired: amount,
|
|
2489
|
-
asset: a.asset,
|
|
2490
|
-
payTo: a.payTo,
|
|
2491
|
-
maxTimeoutSeconds: typeof a.maxTimeoutSeconds === "number" ? a.maxTimeoutSeconds : 600,
|
|
2492
|
-
...a.extra && typeof a.extra === "object" ? { extra: a.extra } : {},
|
|
2493
|
-
...typeof a.description === "string" ? { description: a.description } : {},
|
|
2494
|
-
...typeof a.resource === "string" ? { resource: a.resource } : {}
|
|
2495
|
-
});
|
|
2496
|
-
}
|
|
2497
|
-
return out;
|
|
2498
|
-
}
|
|
2499
|
-
async function buildExactAuthorization(params) {
|
|
2500
|
-
const { account, accept, chainId, now, nonce } = params;
|
|
2501
|
-
if (!account.signTypedData) {
|
|
2502
|
-
throw new Error("buildExactAuthorization: the account cannot sign EIP-712 typed data.");
|
|
2503
|
-
}
|
|
2504
|
-
const authorization = {
|
|
2505
|
-
from: account.address,
|
|
2506
|
-
to: accept.payTo,
|
|
2507
|
-
value: accept.maxAmountRequired,
|
|
2508
|
-
validAfter: "0",
|
|
2509
|
-
validBefore: String(now + accept.maxTimeoutSeconds),
|
|
2510
|
-
nonce
|
|
2511
|
-
};
|
|
2512
|
-
const signature = await account.signTypedData({
|
|
2513
|
-
domain: {
|
|
2514
|
-
name: _nullishCoalesce(_optionalChain([accept, 'access', _34 => _34.extra, 'optionalAccess', _35 => _35.name]), () => ( "USD Coin")),
|
|
2515
|
-
version: _nullishCoalesce(_optionalChain([accept, 'access', _36 => _36.extra, 'optionalAccess', _37 => _37.version]), () => ( "2")),
|
|
2516
|
-
chainId,
|
|
2517
|
-
verifyingContract: accept.asset
|
|
2518
|
-
},
|
|
2519
|
-
types: EIP3009_TYPES,
|
|
2520
|
-
primaryType: "TransferWithAuthorization",
|
|
2521
|
-
message: {
|
|
2522
|
-
from: authorization.from,
|
|
2523
|
-
to: authorization.to,
|
|
2524
|
-
value: BigInt(authorization.value),
|
|
2525
|
-
validAfter: BigInt(authorization.validAfter),
|
|
2526
|
-
validBefore: BigInt(authorization.validBefore),
|
|
2527
|
-
nonce: authorization.nonce
|
|
2528
|
-
}
|
|
2529
|
-
});
|
|
2530
|
-
return { authorization, signature };
|
|
2531
|
-
}
|
|
2532
|
-
function base64(str) {
|
|
2533
|
-
if (typeof btoa === "function") return btoa(str);
|
|
2534
|
-
if (typeof Buffer !== "undefined") return Buffer.from(str, "utf8").toString("base64");
|
|
2535
|
-
throw new Error("No base64 encoder available in this runtime.");
|
|
2536
|
-
}
|
|
2537
|
-
function encodeXPaymentHeader(input) {
|
|
2538
|
-
const payload = {
|
|
2539
|
-
x402Version: _nullishCoalesce(input.x402Version, () => ( 1)),
|
|
2540
|
-
scheme: "exact",
|
|
2541
|
-
network: input.network,
|
|
2542
|
-
payload: { signature: input.signature, authorization: input.authorization }
|
|
2543
|
-
};
|
|
2544
|
-
return base64(JSON.stringify(payload));
|
|
2545
|
-
}
|
|
2546
|
-
|
|
2547
3107
|
// src/discovery.ts
|
|
2548
3108
|
var GENERATOR = "@piprail/sdk \xB7 https://piprail.com";
|
|
2549
3109
|
function pathOf(url) {
|
|
2550
3110
|
try {
|
|
2551
3111
|
return new URL(url).pathname || "/";
|
|
2552
|
-
} catch (
|
|
3112
|
+
} catch (e27) {
|
|
2553
3113
|
return url.startsWith("/") ? url : `/${url}`;
|
|
2554
3114
|
}
|
|
2555
3115
|
}
|
|
@@ -2646,4 +3206,14 @@ function buildX402DnsTxt(input) {
|
|
|
2646
3206
|
|
|
2647
3207
|
|
|
2648
3208
|
|
|
2649
|
-
|
|
3209
|
+
|
|
3210
|
+
|
|
3211
|
+
|
|
3212
|
+
|
|
3213
|
+
|
|
3214
|
+
|
|
3215
|
+
|
|
3216
|
+
|
|
3217
|
+
|
|
3218
|
+
|
|
3219
|
+
exports.CHAINS = CHAINS; exports.ConfirmationTimeoutError = _chunkMDLZJGLYcjs.ConfirmationTimeoutError; exports.EIP3009_TYPES = EIP3009_TYPES; exports.EXACT_NETWORK_SLUGS = EXACT_NETWORK_SLUGS; exports.GENERATOR = GENERATOR; exports.HEADER_REQUIRED = HEADER_REQUIRED; exports.HEADER_RESPONSE = HEADER_RESPONSE; exports.HEADER_RESPONSE_V1 = HEADER_RESPONSE_V1; exports.HEADER_SIGNATURE = HEADER_SIGNATURE; exports.HEADER_SIGNATURE_V1 = HEADER_SIGNATURE_V1; exports.InsufficientFundsError = _chunkMDLZJGLYcjs.InsufficientFundsError; exports.InvalidEnvelopeError = _chunkMDLZJGLYcjs.InvalidEnvelopeError; exports.MaxRetriesExceededError = _chunkMDLZJGLYcjs.MaxRetriesExceededError; exports.MissingDriverError = _chunkMDLZJGLYcjs.MissingDriverError; exports.NoCompatibleAcceptError = _chunkMDLZJGLYcjs.NoCompatibleAcceptError; exports.NonReplayableBodyError = _chunkMDLZJGLYcjs.NonReplayableBodyError; exports.PaymentDeclinedError = _chunkMDLZJGLYcjs.PaymentDeclinedError; exports.PaymentTimeoutError = _chunkMDLZJGLYcjs.PaymentTimeoutError; exports.PipRailClient = PipRailClient; exports.PipRailError = _chunkMDLZJGLYcjs.PipRailError; exports.RecipientNotReadyError = _chunkMDLZJGLYcjs.RecipientNotReadyError; exports.SettlementError = _chunkMDLZJGLYcjs.SettlementError; exports.UnknownTokenError = _chunkMDLZJGLYcjs.UnknownTokenError; exports.UnsupportedNetworkError = _chunkMDLZJGLYcjs.UnsupportedNetworkError; exports.WrongChainError = _chunkMDLZJGLYcjs.WrongChainError; exports.WrongFamilyError = _chunkMDLZJGLYcjs.WrongFamilyError; exports.buildChallengeHeader = buildChallengeHeader; exports.buildExactAuthorization = buildExactAuthorization; exports.buildOpenApi = buildOpenApi; exports.buildReceiptHeader = buildReceiptHeader; exports.buildSignatureHeader = buildSignatureHeader; exports.buildWellKnownX402 = buildWellKnownX402; exports.buildX402DnsTxt = buildX402DnsTxt; exports.chainIdForExactNetwork = chainIdForExactNetwork; exports.createPaymentGate = createPaymentGate; exports.eip3009Abi = eip3009Abi; exports.encodeXPaymentHeader = encodeXPaymentHeader; exports.evaluatePolicy = evaluatePolicy; exports.normalizeNetwork = normalizeNetwork; exports.parseChallenge = parseChallenge; exports.parseExactPaymentHeader = parseExactPaymentHeader; exports.parseExactRequirements = parseExactRequirements; exports.parseReceipt = parseReceipt; exports.parseSignatureHeader = parseSignatureHeader; exports.paymentTools = paymentTools; exports.pickAccept = pickAccept; exports.planAcross = planAcross; exports.readExactDomain = readExactDomain; exports.register402Index = register402Index; exports.registerDriver = registerDriver; exports.registerX402Scan = registerX402Scan; exports.requirePayment = requirePayment; exports.resolveChain = resolveChain; exports.searchOpenIndexes = searchOpenIndexes; exports.settleViaFacilitator = settleViaFacilitator; exports.toInsufficientFundsError = _chunkMDLZJGLYcjs.toInsufficientFundsError; exports.toInvalidBody = toInvalidBody;
|