@piprail/sdk 1.9.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/CHANGELOG.md +42 -0
- package/ERRORS.md +21 -8
- package/README.md +20 -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 +811 -253
- package/dist/index.d.cts +400 -31
- package/dist/index.d.ts +400 -31
- package/dist/index.js +734 -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 +1 -1
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
|
}
|
|
@@ -311,12 +312,12 @@ function createWalletAdapter(config, resolved) {
|
|
|
311
312
|
}
|
|
312
313
|
const wc = config.walletClient;
|
|
313
314
|
if (!wc.account) {
|
|
314
|
-
throw new (0,
|
|
315
|
+
throw new (0, _chunkMDLZJGLYcjs.WrongFamilyError)(
|
|
315
316
|
"chain is EVM; the provided walletClient has no attached account. Use `createWalletClient({ account, chain, transport })`, or pass { privateKey }."
|
|
316
317
|
);
|
|
317
318
|
}
|
|
318
319
|
if (wc.chain && wc.chain.id !== resolved.chainId) {
|
|
319
|
-
throw new (0,
|
|
320
|
+
throw new (0, _chunkMDLZJGLYcjs.WrongChainError)(
|
|
320
321
|
`PipRailClient: walletClient is on chain ${wc.chain.id} but the SDK was configured with chain ${resolved.chainId}. They must match.`
|
|
321
322
|
);
|
|
322
323
|
}
|
|
@@ -483,24 +484,371 @@ function sumTransfersTo(logs, asset, payTo) {
|
|
|
483
484
|
return { total, from };
|
|
484
485
|
}
|
|
485
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
|
+
|
|
486
822
|
// src/x402.ts
|
|
487
823
|
var HEADER_REQUIRED = "payment-required";
|
|
488
824
|
var HEADER_SIGNATURE = "payment-signature";
|
|
489
825
|
var HEADER_RESPONSE = "payment-response";
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
if (typeof Buffer !== "undefined") return Buffer.from(b64, "base64").toString("utf8");
|
|
493
|
-
throw new Error("No base64 decoder available in this runtime.");
|
|
494
|
-
}
|
|
826
|
+
var HEADER_SIGNATURE_V1 = "x-payment";
|
|
827
|
+
var HEADER_RESPONSE_V1 = "x-payment-response";
|
|
495
828
|
function encodeBase64(str) {
|
|
496
|
-
if (typeof btoa === "function") return btoa(str);
|
|
497
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
|
+
}
|
|
498
836
|
throw new Error("No base64 encoder available in this runtime.");
|
|
499
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
|
+
}
|
|
500
848
|
function fromBase64Json(b64) {
|
|
501
849
|
try {
|
|
502
850
|
return JSON.parse(decodeBase64(b64));
|
|
503
|
-
} catch (
|
|
851
|
+
} catch (e10) {
|
|
504
852
|
return null;
|
|
505
853
|
}
|
|
506
854
|
}
|
|
@@ -534,7 +882,7 @@ async function parseChallenge(response) {
|
|
|
534
882
|
try {
|
|
535
883
|
const body = await response.clone().json();
|
|
536
884
|
if (isValidChallenge(body)) return body;
|
|
537
|
-
} catch (
|
|
885
|
+
} catch (e11) {
|
|
538
886
|
}
|
|
539
887
|
return null;
|
|
540
888
|
}
|
|
@@ -549,7 +897,7 @@ function parseSignatureHeader(value) {
|
|
|
549
897
|
if (!parsed || typeof parsed !== "object") return null;
|
|
550
898
|
const v = parsed;
|
|
551
899
|
const accepted = v.accepted;
|
|
552
|
-
const scheme = _nullishCoalesce(_optionalChain([accepted, 'optionalAccess',
|
|
900
|
+
const scheme = _nullishCoalesce(_optionalChain([accepted, 'optionalAccess', _5 => _5.scheme]), () => ( v.scheme));
|
|
553
901
|
if (scheme !== "onchain-proof") return null;
|
|
554
902
|
const payload = v.payload;
|
|
555
903
|
if (!payload || typeof payload.txHash !== "string" || typeof payload.nonce !== "string") {
|
|
@@ -557,6 +905,36 @@ function parseSignatureHeader(value) {
|
|
|
557
905
|
}
|
|
558
906
|
return parsed;
|
|
559
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
|
+
}
|
|
560
938
|
function isValidChallenge(value) {
|
|
561
939
|
if (!value || typeof value !== "object") return false;
|
|
562
940
|
const v = value;
|
|
@@ -568,7 +946,7 @@ function isValidChallenge(value) {
|
|
|
568
946
|
function isValidReceipt(value) {
|
|
569
947
|
if (!value || typeof value !== "object") return false;
|
|
570
948
|
const v = value;
|
|
571
|
-
if (v.scheme !== "onchain-proof") return false;
|
|
949
|
+
if (v.scheme !== "onchain-proof" && v.scheme !== "exact") return false;
|
|
572
950
|
if (typeof v.transaction !== "string" && typeof v.txHash !== "string") return false;
|
|
573
951
|
if (typeof v.payer !== "string") return false;
|
|
574
952
|
return true;
|
|
@@ -591,7 +969,7 @@ var evmDriver = {
|
|
|
591
969
|
let resolved;
|
|
592
970
|
try {
|
|
593
971
|
resolved = resolveChain(opts.chain, opts.rpcUrl);
|
|
594
|
-
} catch (
|
|
972
|
+
} catch (e12) {
|
|
595
973
|
return null;
|
|
596
974
|
}
|
|
597
975
|
return makeEvmNetwork(resolved);
|
|
@@ -619,15 +997,15 @@ function makeEvmNetwork(resolved) {
|
|
|
619
997
|
const info = resolved.tokens[token.toUpperCase()];
|
|
620
998
|
if (!info) {
|
|
621
999
|
const known = Object.keys(resolved.tokens).join(", ") || "(none built in)";
|
|
622
|
-
throw new (0,
|
|
1000
|
+
throw new (0, _chunkMDLZJGLYcjs.UnknownTokenError)(
|
|
623
1001
|
`token "${token}" isn't built in for ${resolved.chain.name} (known: ${known}). Pass { address, decimals } instead, or use 'native'.`
|
|
624
1002
|
);
|
|
625
1003
|
}
|
|
626
1004
|
return { asset: info.address, decimals: info.decimals, symbol: info.symbol };
|
|
627
1005
|
}
|
|
628
|
-
|
|
1006
|
+
_chunkMDLZJGLYcjs.rejectForeignToken.call(void 0, token, "evm", network);
|
|
629
1007
|
if (!("address" in token)) {
|
|
630
|
-
throw new (0,
|
|
1008
|
+
throw new (0, _chunkMDLZJGLYcjs.WrongFamilyError)(
|
|
631
1009
|
`chain ${network} is EVM; a custom token must be { address, decimals }.`
|
|
632
1010
|
);
|
|
633
1011
|
}
|
|
@@ -647,7 +1025,7 @@ function makeEvmNetwork(resolved) {
|
|
|
647
1025
|
let normalized;
|
|
648
1026
|
try {
|
|
649
1027
|
normalized = _viem.getAddress.call(void 0, asset);
|
|
650
|
-
} catch (
|
|
1028
|
+
} catch (e13) {
|
|
651
1029
|
return null;
|
|
652
1030
|
}
|
|
653
1031
|
for (const info of Object.values(resolved.tokens)) {
|
|
@@ -659,14 +1037,14 @@ function makeEvmNetwork(resolved) {
|
|
|
659
1037
|
},
|
|
660
1038
|
assertValidPayTo(payTo) {
|
|
661
1039
|
if (!_viem.isAddress.call(void 0, payTo)) {
|
|
662
|
-
throw new (0,
|
|
1040
|
+
throw new (0, _chunkMDLZJGLYcjs.WrongFamilyError)(
|
|
663
1041
|
`chain ${network} is EVM, but payTo "${payTo}" is not a valid 0x address.`
|
|
664
1042
|
);
|
|
665
1043
|
}
|
|
666
1044
|
},
|
|
667
1045
|
bindWallet(wallet) {
|
|
668
1046
|
if (typeof wallet !== "object" || wallet === null || !("privateKey" in wallet) && !("walletClient" in wallet)) {
|
|
669
|
-
throw new (0,
|
|
1047
|
+
throw new (0, _chunkMDLZJGLYcjs.WrongFamilyError)(
|
|
670
1048
|
`chain ${network} is EVM; wallet must be { privateKey } or { walletClient }.`
|
|
671
1049
|
);
|
|
672
1050
|
}
|
|
@@ -683,12 +1061,12 @@ function makeEvmNetwork(resolved) {
|
|
|
683
1061
|
});
|
|
684
1062
|
} catch (err) {
|
|
685
1063
|
if (isViemInsufficientFunds(err)) {
|
|
686
|
-
throw new (0,
|
|
1064
|
+
throw new (0, _chunkMDLZJGLYcjs.InsufficientFundsError)(
|
|
687
1065
|
err instanceof Error ? err.message : "Insufficient funds for payment.",
|
|
688
1066
|
{ cause: err }
|
|
689
1067
|
);
|
|
690
1068
|
}
|
|
691
|
-
throw _nullishCoalesce(
|
|
1069
|
+
throw _nullishCoalesce(_chunkMDLZJGLYcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
|
|
692
1070
|
}
|
|
693
1071
|
},
|
|
694
1072
|
async confirm(ref, minConfirmations) {
|
|
@@ -699,7 +1077,7 @@ function makeEvmNetwork(resolved) {
|
|
|
699
1077
|
});
|
|
700
1078
|
return { height: receipt.blockNumber.toString() };
|
|
701
1079
|
} catch (err) {
|
|
702
|
-
throw new (0,
|
|
1080
|
+
throw new (0, _chunkMDLZJGLYcjs.ConfirmationTimeoutError)(
|
|
703
1081
|
`EVM tx ${ref} did not reach ${minConfirmations} confirmation(s) in time.`,
|
|
704
1082
|
{ cause: err }
|
|
705
1083
|
);
|
|
@@ -710,16 +1088,16 @@ function makeEvmNetwork(resolved) {
|
|
|
710
1088
|
const gasLimit = accept.asset === "native" ? 21000n : 65000n;
|
|
711
1089
|
try {
|
|
712
1090
|
const gasPrice = await publicClient.getGasPrice();
|
|
713
|
-
return
|
|
1091
|
+
return _chunkMDLZJGLYcjs.nativeCost.call(void 0, {
|
|
714
1092
|
symbol,
|
|
715
1093
|
decimals,
|
|
716
1094
|
fee: gasPrice * gasLimit,
|
|
717
1095
|
basis: "estimated",
|
|
718
1096
|
detail: `~${gasLimit} gas @ ${gasPrice} wei/gas`
|
|
719
1097
|
});
|
|
720
|
-
} catch (
|
|
1098
|
+
} catch (e14) {
|
|
721
1099
|
const gasPrice = 5000000000n;
|
|
722
|
-
return
|
|
1100
|
+
return _chunkMDLZJGLYcjs.nativeCost.call(void 0, {
|
|
723
1101
|
symbol,
|
|
724
1102
|
decimals,
|
|
725
1103
|
fee: gasPrice * gasLimit,
|
|
@@ -740,7 +1118,7 @@ function makeEvmNetwork(resolved) {
|
|
|
740
1118
|
functionName: "balanceOf",
|
|
741
1119
|
args: [owner]
|
|
742
1120
|
});
|
|
743
|
-
} catch (
|
|
1121
|
+
} catch (e15) {
|
|
744
1122
|
token = null;
|
|
745
1123
|
}
|
|
746
1124
|
return { token, native };
|
|
@@ -767,6 +1145,21 @@ function makeEvmNetwork(resolved) {
|
|
|
767
1145
|
accept,
|
|
768
1146
|
minConfirmations: accept.extra.minConfirmations
|
|
769
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
|
+
});
|
|
770
1163
|
}
|
|
771
1164
|
};
|
|
772
1165
|
}
|
|
@@ -783,9 +1176,9 @@ var loaders = {
|
|
|
783
1176
|
solana: async () => {
|
|
784
1177
|
let mod;
|
|
785
1178
|
try {
|
|
786
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./solana-
|
|
1179
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./solana-PU7N2M64.cjs")));
|
|
787
1180
|
} catch (cause) {
|
|
788
|
-
throw new (0,
|
|
1181
|
+
throw new (0, _chunkMDLZJGLYcjs.MissingDriverError)(
|
|
789
1182
|
`Solana selected, but its packages aren't installed. Run: npm install @solana/web3.js @solana/spl-token bs58`,
|
|
790
1183
|
{ cause }
|
|
791
1184
|
);
|
|
@@ -795,9 +1188,9 @@ var loaders = {
|
|
|
795
1188
|
ton: async () => {
|
|
796
1189
|
let mod;
|
|
797
1190
|
try {
|
|
798
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./ton-
|
|
1191
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./ton-VK6KRJHP.cjs")));
|
|
799
1192
|
} catch (cause) {
|
|
800
|
-
throw new (0,
|
|
1193
|
+
throw new (0, _chunkMDLZJGLYcjs.MissingDriverError)(
|
|
801
1194
|
`TON selected, but its packages aren't installed. Run: npm install @ton/ton @ton/core @ton/crypto`,
|
|
802
1195
|
{ cause }
|
|
803
1196
|
);
|
|
@@ -807,9 +1200,9 @@ var loaders = {
|
|
|
807
1200
|
stellar: async () => {
|
|
808
1201
|
let mod;
|
|
809
1202
|
try {
|
|
810
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./stellar-
|
|
1203
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./stellar-VDQOFQEO.cjs")));
|
|
811
1204
|
} catch (cause) {
|
|
812
|
-
throw new (0,
|
|
1205
|
+
throw new (0, _chunkMDLZJGLYcjs.MissingDriverError)(
|
|
813
1206
|
`Stellar selected, but its package isn't installed. Run: npm install @stellar/stellar-sdk`,
|
|
814
1207
|
{ cause }
|
|
815
1208
|
);
|
|
@@ -819,9 +1212,9 @@ var loaders = {
|
|
|
819
1212
|
xrpl: async () => {
|
|
820
1213
|
let mod;
|
|
821
1214
|
try {
|
|
822
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./xrpl-
|
|
1215
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./xrpl-CMNI25BV.cjs")));
|
|
823
1216
|
} catch (cause) {
|
|
824
|
-
throw new (0,
|
|
1217
|
+
throw new (0, _chunkMDLZJGLYcjs.MissingDriverError)(
|
|
825
1218
|
`XRPL selected, but its package isn't installed. Run: npm install xrpl`,
|
|
826
1219
|
{ cause }
|
|
827
1220
|
);
|
|
@@ -831,9 +1224,9 @@ var loaders = {
|
|
|
831
1224
|
tron: async () => {
|
|
832
1225
|
let mod;
|
|
833
1226
|
try {
|
|
834
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./tron-
|
|
1227
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./tron-WLOF5OUV.cjs")));
|
|
835
1228
|
} catch (cause) {
|
|
836
|
-
throw new (0,
|
|
1229
|
+
throw new (0, _chunkMDLZJGLYcjs.MissingDriverError)(
|
|
837
1230
|
`Tron selected, but its package isn't installed. Run: npm install tronweb`,
|
|
838
1231
|
{ cause }
|
|
839
1232
|
);
|
|
@@ -843,9 +1236,9 @@ var loaders = {
|
|
|
843
1236
|
sui: async () => {
|
|
844
1237
|
let mod;
|
|
845
1238
|
try {
|
|
846
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./sui-
|
|
1239
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./sui-FKSMLKRF.cjs")));
|
|
847
1240
|
} catch (cause) {
|
|
848
|
-
throw new (0,
|
|
1241
|
+
throw new (0, _chunkMDLZJGLYcjs.MissingDriverError)(
|
|
849
1242
|
`Sui selected, but its package isn't installed. Run: npm install @mysten/sui`,
|
|
850
1243
|
{ cause }
|
|
851
1244
|
);
|
|
@@ -855,9 +1248,9 @@ var loaders = {
|
|
|
855
1248
|
near: async () => {
|
|
856
1249
|
let mod;
|
|
857
1250
|
try {
|
|
858
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./near-
|
|
1251
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./near-7ZDNISUX.cjs")));
|
|
859
1252
|
} catch (cause) {
|
|
860
|
-
throw new (0,
|
|
1253
|
+
throw new (0, _chunkMDLZJGLYcjs.MissingDriverError)(
|
|
861
1254
|
`NEAR selected, but its package isn't installed. Run: npm install near-api-js`,
|
|
862
1255
|
{ cause }
|
|
863
1256
|
);
|
|
@@ -867,9 +1260,9 @@ var loaders = {
|
|
|
867
1260
|
aptos: async () => {
|
|
868
1261
|
let mod;
|
|
869
1262
|
try {
|
|
870
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./aptos-
|
|
1263
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./aptos-YT7SXWPF.cjs")));
|
|
871
1264
|
} catch (cause) {
|
|
872
|
-
throw new (0,
|
|
1265
|
+
throw new (0, _chunkMDLZJGLYcjs.MissingDriverError)(
|
|
873
1266
|
`Aptos selected, but its package isn't installed. Run: npm install @aptos-labs/ts-sdk`,
|
|
874
1267
|
{ cause }
|
|
875
1268
|
);
|
|
@@ -879,9 +1272,9 @@ var loaders = {
|
|
|
879
1272
|
algorand: async () => {
|
|
880
1273
|
let mod;
|
|
881
1274
|
try {
|
|
882
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./algorand-
|
|
1275
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./algorand-MXUSKX46.cjs")));
|
|
883
1276
|
} catch (cause) {
|
|
884
|
-
throw new (0,
|
|
1277
|
+
throw new (0, _chunkMDLZJGLYcjs.MissingDriverError)(
|
|
885
1278
|
`Algorand selected, but its package isn't installed. Run: npm install algosdk`,
|
|
886
1279
|
{ cause }
|
|
887
1280
|
);
|
|
@@ -960,7 +1353,7 @@ async function searchOpenIndexes(opts = {}) {
|
|
|
960
1353
|
async function safeSearch(run) {
|
|
961
1354
|
try {
|
|
962
1355
|
return await run();
|
|
963
|
-
} catch (
|
|
1356
|
+
} catch (e16) {
|
|
964
1357
|
return [];
|
|
965
1358
|
}
|
|
966
1359
|
}
|
|
@@ -1084,7 +1477,7 @@ async function readIndexError(res) {
|
|
|
1084
1477
|
(p) => typeof p === "string" && p.length > 0
|
|
1085
1478
|
);
|
|
1086
1479
|
return parts.length ? [...new Set(parts)].join(" \u2014 ") : void 0;
|
|
1087
|
-
} catch (
|
|
1480
|
+
} catch (e17) {
|
|
1088
1481
|
return void 0;
|
|
1089
1482
|
}
|
|
1090
1483
|
}
|
|
@@ -1140,13 +1533,13 @@ async function readSiwxInfo(res) {
|
|
|
1140
1533
|
try {
|
|
1141
1534
|
const body = await res.json();
|
|
1142
1535
|
const ext = body.extensions;
|
|
1143
|
-
const siwx = _optionalChain([ext, 'optionalAccess',
|
|
1144
|
-
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));
|
|
1145
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) {
|
|
1146
1539
|
return info;
|
|
1147
1540
|
}
|
|
1148
1541
|
return null;
|
|
1149
|
-
} catch (
|
|
1542
|
+
} catch (e18) {
|
|
1150
1543
|
return null;
|
|
1151
1544
|
}
|
|
1152
1545
|
}
|
|
@@ -1194,7 +1587,7 @@ function mapRails(accepts) {
|
|
|
1194
1587
|
}
|
|
1195
1588
|
function matchesQuery(r, query) {
|
|
1196
1589
|
const q = query.toLowerCase();
|
|
1197
|
-
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)));
|
|
1198
1591
|
}
|
|
1199
1592
|
function pickString(o, ...keys) {
|
|
1200
1593
|
for (const k of keys) {
|
|
@@ -1226,7 +1619,7 @@ function firstArray(o, ...keys) {
|
|
|
1226
1619
|
function hostOf(url) {
|
|
1227
1620
|
try {
|
|
1228
1621
|
return new URL(url).hostname;
|
|
1229
|
-
} catch (
|
|
1622
|
+
} catch (e19) {
|
|
1230
1623
|
return url;
|
|
1231
1624
|
}
|
|
1232
1625
|
}
|
|
@@ -1286,7 +1679,7 @@ function evaluatePolicy(intent, policy, spentForAssetBase) {
|
|
|
1286
1679
|
}
|
|
1287
1680
|
}
|
|
1288
1681
|
if (policy.maxAmount !== void 0) {
|
|
1289
|
-
const cap =
|
|
1682
|
+
const cap = _chunkMDLZJGLYcjs.floorUnits.call(void 0, policy.maxAmount, intent.decimals);
|
|
1290
1683
|
if (intent.amountBase > cap) {
|
|
1291
1684
|
return deny(
|
|
1292
1685
|
`payment of ${intent.amountBase} base units exceeds policy.maxAmount ` + `(${policy.maxAmount} ${_nullishCoalesce(intent.symbol, () => ( ""))}).`.trimEnd()
|
|
@@ -1294,7 +1687,7 @@ function evaluatePolicy(intent, policy, spentForAssetBase) {
|
|
|
1294
1687
|
}
|
|
1295
1688
|
}
|
|
1296
1689
|
if (policy.maxTotal !== void 0) {
|
|
1297
|
-
const cap =
|
|
1690
|
+
const cap = _chunkMDLZJGLYcjs.floorUnits.call(void 0, policy.maxTotal, intent.decimals);
|
|
1298
1691
|
if (spentForAssetBase + intent.amountBase > cap) {
|
|
1299
1692
|
return deny(
|
|
1300
1693
|
`this payment would push spend on ${_nullishCoalesce(intent.symbol, () => ( intent.asset))} past policy.maxTotal (${policy.maxTotal}); already spent ${spentForAssetBase} base units.`
|
|
@@ -1332,7 +1725,7 @@ var SpendLedger = (_class = class {constructor() { _class.prototype.__init.call(
|
|
|
1332
1725
|
}
|
|
1333
1726
|
/** Running total (base units) already spent on this (network, asset). */
|
|
1334
1727
|
totalFor(network, asset) {
|
|
1335
|
-
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));
|
|
1336
1729
|
}
|
|
1337
1730
|
/** An immutable snapshot of all spend so far. */
|
|
1338
1731
|
summary() {
|
|
@@ -1344,7 +1737,7 @@ var SpendLedger = (_class = class {constructor() { _class.prototype.__init.call(
|
|
|
1344
1737
|
symbol: b.symbol,
|
|
1345
1738
|
decimals: b.decimals,
|
|
1346
1739
|
totalBase: b.total.toString(),
|
|
1347
|
-
totalFormatted:
|
|
1740
|
+
totalFormatted: _chunkMDLZJGLYcjs.formatUnits.call(void 0, b.total, b.decimals),
|
|
1348
1741
|
count: b.count
|
|
1349
1742
|
})),
|
|
1350
1743
|
records: [...this.records]
|
|
@@ -1381,7 +1774,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1381
1774
|
safeEmit(event) {
|
|
1382
1775
|
try {
|
|
1383
1776
|
this.onEvent(event);
|
|
1384
|
-
} catch (
|
|
1777
|
+
} catch (e20) {
|
|
1385
1778
|
}
|
|
1386
1779
|
}
|
|
1387
1780
|
/** Auto-mount the chain's driver, resolve the network, and bind the wallet — once. */
|
|
@@ -1406,7 +1799,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1406
1799
|
* as-is) or a plain object (serialised as JSON).
|
|
1407
1800
|
*/
|
|
1408
1801
|
post(url, body, init) {
|
|
1409
|
-
const headers = new Headers(_optionalChain([init, 'optionalAccess',
|
|
1802
|
+
const headers = new Headers(_optionalChain([init, 'optionalAccess', _24 => _24.headers]));
|
|
1410
1803
|
let payload;
|
|
1411
1804
|
if (body === void 0 || body === null) {
|
|
1412
1805
|
payload = void 0;
|
|
@@ -1437,7 +1830,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1437
1830
|
* "0.05 USDC on Base, within budget → pay it." No funds move.
|
|
1438
1831
|
*/
|
|
1439
1832
|
async quote(url, init) {
|
|
1440
|
-
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")) });
|
|
1441
1834
|
if (res.status !== 402) return null;
|
|
1442
1835
|
const { quote } = await this.resolveChallenge(url, res);
|
|
1443
1836
|
return quote;
|
|
@@ -1456,7 +1849,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1456
1849
|
* on Tron, where a USD₮ transfer can cost real TRX.
|
|
1457
1850
|
*/
|
|
1458
1851
|
async estimateCost(url, init) {
|
|
1459
|
-
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")) });
|
|
1460
1853
|
if (res.status !== 402) return null;
|
|
1461
1854
|
const { net, accept, quote } = await this.resolveChallenge(url, res);
|
|
1462
1855
|
const cost = await net.estimateCost(accept);
|
|
@@ -1487,11 +1880,11 @@ var PipRailClient = (_class2 = class {
|
|
|
1487
1880
|
* the plan yourself. No funds move.
|
|
1488
1881
|
*/
|
|
1489
1882
|
async planPayment(url, init) {
|
|
1490
|
-
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")) });
|
|
1491
1884
|
if (res.status !== 402) return null;
|
|
1492
1885
|
const challenge = await parseChallenge(res);
|
|
1493
1886
|
if (!challenge) {
|
|
1494
|
-
throw new (0,
|
|
1887
|
+
throw new (0, _chunkMDLZJGLYcjs.InvalidEnvelopeError)("402 response did not include a parseable x402 challenge.");
|
|
1495
1888
|
}
|
|
1496
1889
|
const { net, wallet } = await this.ensure();
|
|
1497
1890
|
return this.planFromChallenge(net, wallet, challenge, url);
|
|
@@ -1607,9 +2000,9 @@ var PipRailClient = (_class2 = class {
|
|
|
1607
2000
|
* streams throw `NonReplayableBodyError`.
|
|
1608
2001
|
*/
|
|
1609
2002
|
async fetch(url, init) {
|
|
1610
|
-
const body = _optionalChain([init, 'optionalAccess',
|
|
2003
|
+
const body = _optionalChain([init, 'optionalAccess', _28 => _28.body]);
|
|
1611
2004
|
if (body !== void 0 && body !== null && !isReplayableBodyInit(body)) {
|
|
1612
|
-
throw new (0,
|
|
2005
|
+
throw new (0, _chunkMDLZJGLYcjs.NonReplayableBodyError)(
|
|
1613
2006
|
"fetch(): init.body is not replayable. Pass a string, FormData, URLSearchParams, ArrayBuffer, or Blob \u2014 not a ReadableStream."
|
|
1614
2007
|
);
|
|
1615
2008
|
}
|
|
@@ -1619,11 +2012,11 @@ var PipRailClient = (_class2 = class {
|
|
|
1619
2012
|
const { net, wallet, challenge } = resolved;
|
|
1620
2013
|
let accept = resolved.accept;
|
|
1621
2014
|
let quote = resolved.quote;
|
|
1622
|
-
const autoRoute = _nullishCoalesce(_nullishCoalesce(_optionalChain([init, 'optionalAccess',
|
|
2015
|
+
const autoRoute = _nullishCoalesce(_nullishCoalesce(_optionalChain([init, 'optionalAccess', _29 => _29.autoRoute]), () => ( this.opts.autoRoute)), () => ( false));
|
|
1623
2016
|
if (autoRoute) {
|
|
1624
2017
|
const plan = await this.planFromChallenge(net, wallet, challenge, url);
|
|
1625
2018
|
if (!plan.best) {
|
|
1626
|
-
throw new (0,
|
|
2019
|
+
throw new (0, _chunkMDLZJGLYcjs.PaymentDeclinedError)(_nullishCoalesce(plan.fundingHint, () => ( "No rail is settleable for this payment.")));
|
|
1627
2020
|
}
|
|
1628
2021
|
accept = plan.best.accept;
|
|
1629
2022
|
quote = plan.best.quote;
|
|
@@ -1644,7 +2037,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1644
2037
|
async resolveChallenge(url, response) {
|
|
1645
2038
|
const challenge = await parseChallenge(response);
|
|
1646
2039
|
if (!challenge) {
|
|
1647
|
-
throw new (0,
|
|
2040
|
+
throw new (0, _chunkMDLZJGLYcjs.InvalidEnvelopeError)(
|
|
1648
2041
|
"402 response did not include a parseable x402 challenge."
|
|
1649
2042
|
);
|
|
1650
2043
|
}
|
|
@@ -1652,7 +2045,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1652
2045
|
const candidates = this.gatherCandidates(net, challenge);
|
|
1653
2046
|
if (candidates.length === 0) {
|
|
1654
2047
|
const networks = challenge.accepts.map((a) => a.network).join(", ");
|
|
1655
|
-
throw new (0,
|
|
2048
|
+
throw new (0, _chunkMDLZJGLYcjs.NoCompatibleAcceptError)(
|
|
1656
2049
|
`No accepts[] entry for ${net.network} (challenge offered: ${networks || "none"}).`
|
|
1657
2050
|
);
|
|
1658
2051
|
}
|
|
@@ -1663,7 +2056,10 @@ var PipRailClient = (_class2 = class {
|
|
|
1663
2056
|
const chosen = _nullishCoalesce(priced.find((p) => p.quote.withinPolicy), () => ( priced[0]));
|
|
1664
2057
|
return { net, wallet, accept: chosen.accept, challenge, quote: chosen.quote };
|
|
1665
2058
|
}
|
|
1666
|
-
/** 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. */
|
|
1667
2063
|
gatherCandidates(net, challenge) {
|
|
1668
2064
|
return challenge.accepts.filter(
|
|
1669
2065
|
(a) => a.scheme === "onchain-proof" && net.supports(a.network)
|
|
@@ -1726,16 +2122,16 @@ var PipRailClient = (_class2 = class {
|
|
|
1726
2122
|
if (isNative) {
|
|
1727
2123
|
if (nativeKnown && bal.native < amount + fee) {
|
|
1728
2124
|
blockers.push("INSUFFICIENT_TOKEN");
|
|
1729
|
-
shortfall.token =
|
|
2125
|
+
shortfall.token = _chunkMDLZJGLYcjs.formatUnits.call(void 0, amount + fee - bal.native, quote.decimals);
|
|
1730
2126
|
}
|
|
1731
2127
|
} else {
|
|
1732
2128
|
if (tokenKnown && bal.token < amount) {
|
|
1733
2129
|
blockers.push("INSUFFICIENT_TOKEN");
|
|
1734
|
-
shortfall.token =
|
|
2130
|
+
shortfall.token = _chunkMDLZJGLYcjs.formatUnits.call(void 0, amount - bal.token, quote.decimals);
|
|
1735
2131
|
}
|
|
1736
2132
|
if (nativeKnown && bal.native < fee) {
|
|
1737
2133
|
blockers.push("INSUFFICIENT_GAS");
|
|
1738
|
-
shortfall.native =
|
|
2134
|
+
shortfall.native = _chunkMDLZJGLYcjs.formatUnits.call(void 0, fee - bal.native, cost.feeDecimals);
|
|
1739
2135
|
} else if (nativeKnown && fee > 0n && bal.native < fee * 3n / 2n) {
|
|
1740
2136
|
warnings.push("THIN_GAS_MARGIN");
|
|
1741
2137
|
}
|
|
@@ -1760,8 +2156,8 @@ var PipRailClient = (_class2 = class {
|
|
|
1760
2156
|
blockers,
|
|
1761
2157
|
warnings,
|
|
1762
2158
|
balance: {
|
|
1763
|
-
token: bal.token != null ?
|
|
1764
|
-
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
|
|
1765
2161
|
},
|
|
1766
2162
|
need: { token: quote.amountFormatted, native: cost.feeFormatted },
|
|
1767
2163
|
...shortfall.token || shortfall.native ? { shortfall } : {},
|
|
@@ -1772,15 +2168,15 @@ var PipRailClient = (_class2 = class {
|
|
|
1772
2168
|
* driver's describeAsset) + the policy verdict + a symbol-mismatch flag. */
|
|
1773
2169
|
buildQuote(net, accept, url, description) {
|
|
1774
2170
|
if (!/^\d+$/.test(accept.amount)) {
|
|
1775
|
-
throw new (0,
|
|
2171
|
+
throw new (0, _chunkMDLZJGLYcjs.InvalidEnvelopeError)(
|
|
1776
2172
|
`challenge amount "${accept.amount}" is not a base-unit integer.`
|
|
1777
2173
|
);
|
|
1778
2174
|
}
|
|
1779
2175
|
const amountBase = BigInt(accept.amount);
|
|
1780
2176
|
const described = net.describeAsset(accept.asset);
|
|
1781
|
-
const decimals = _nullishCoalesce(_optionalChain([described, 'optionalAccess',
|
|
1782
|
-
const symbol = _nullishCoalesce(_optionalChain([described, 'optionalAccess',
|
|
1783
|
-
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);
|
|
1784
2180
|
const intent = {
|
|
1785
2181
|
host: hostOf2(url),
|
|
1786
2182
|
chain: this.opts.chain,
|
|
@@ -1820,7 +2216,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1820
2216
|
* throwing PaymentDeclinedError, before any funds move. */
|
|
1821
2217
|
async authorize(quote) {
|
|
1822
2218
|
if (!quote.withinPolicy) {
|
|
1823
|
-
throw new (0,
|
|
2219
|
+
throw new (0, _chunkMDLZJGLYcjs.PaymentDeclinedError)(
|
|
1824
2220
|
`Payment refused by policy: ${_nullishCoalesce(quote.policyReason, () => ( "not allowed"))}`
|
|
1825
2221
|
);
|
|
1826
2222
|
}
|
|
@@ -1830,12 +2226,12 @@ var PipRailClient = (_class2 = class {
|
|
|
1830
2226
|
try {
|
|
1831
2227
|
approved = await hook(quote);
|
|
1832
2228
|
} catch (err) {
|
|
1833
|
-
throw new (0,
|
|
2229
|
+
throw new (0, _chunkMDLZJGLYcjs.PaymentDeclinedError)("onBeforePay threw \u2014 refusing to pay.", {
|
|
1834
2230
|
cause: err
|
|
1835
2231
|
});
|
|
1836
2232
|
}
|
|
1837
2233
|
if (!approved) {
|
|
1838
|
-
throw new (0,
|
|
2234
|
+
throw new (0, _chunkMDLZJGLYcjs.PaymentDeclinedError)(
|
|
1839
2235
|
`onBeforePay declined ${quote.amountFormatted} ${_nullishCoalesce(quote.symbol, () => ( ""))}`.trimEnd() + ` on ${quote.network}.`
|
|
1840
2236
|
);
|
|
1841
2237
|
}
|
|
@@ -1859,7 +2255,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1859
2255
|
}
|
|
1860
2256
|
async payAndConfirm(net, wallet, accept) {
|
|
1861
2257
|
if (!net.supports(accept.network)) {
|
|
1862
|
-
throw new (0,
|
|
2258
|
+
throw new (0, _chunkMDLZJGLYcjs.WrongChainError)(
|
|
1863
2259
|
`Challenge expects ${accept.network} but client is on ${net.network}.`
|
|
1864
2260
|
);
|
|
1865
2261
|
}
|
|
@@ -1888,7 +2284,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1888
2284
|
accepted: accept,
|
|
1889
2285
|
payload: { nonce: accept.extra.nonce, txHash: ref }
|
|
1890
2286
|
};
|
|
1891
|
-
const headers = new Headers(_optionalChain([originalInit, 'optionalAccess',
|
|
2287
|
+
const headers = new Headers(_optionalChain([originalInit, 'optionalAccess', _32 => _32.headers]));
|
|
1892
2288
|
headers.set(HEADER_SIGNATURE, buildSignatureHeader(signature));
|
|
1893
2289
|
let lastResponse = null;
|
|
1894
2290
|
let lastReason = null;
|
|
@@ -1903,7 +2299,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1903
2299
|
() => timeoutController.abort(),
|
|
1904
2300
|
this.retryTimeoutMs
|
|
1905
2301
|
);
|
|
1906
|
-
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;
|
|
1907
2303
|
try {
|
|
1908
2304
|
lastResponse = await fetch(url, {
|
|
1909
2305
|
..._nullishCoalesce(originalInit, () => ( {})),
|
|
@@ -1912,7 +2308,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1912
2308
|
});
|
|
1913
2309
|
} catch (err) {
|
|
1914
2310
|
if (timeoutController.signal.aborted) {
|
|
1915
|
-
throw new (0,
|
|
2311
|
+
throw new (0, _chunkMDLZJGLYcjs.PaymentTimeoutError)(
|
|
1916
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.`,
|
|
1917
2313
|
{ cause: err, ref }
|
|
1918
2314
|
);
|
|
@@ -1934,7 +2330,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1934
2330
|
kind: "payment-failed",
|
|
1935
2331
|
reason: `server returned 402 after broadcasting payment ${ref}${unconfirmedNote} (${why})`
|
|
1936
2332
|
});
|
|
1937
|
-
throw new (0,
|
|
2333
|
+
throw new (0, _chunkMDLZJGLYcjs.MaxRetriesExceededError)(
|
|
1938
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).`,
|
|
1939
2335
|
{ ref }
|
|
1940
2336
|
);
|
|
@@ -1943,7 +2339,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1943
2339
|
function safeBig(s) {
|
|
1944
2340
|
try {
|
|
1945
2341
|
return BigInt(s);
|
|
1946
|
-
} catch (
|
|
2342
|
+
} catch (e21) {
|
|
1947
2343
|
return 0n;
|
|
1948
2344
|
}
|
|
1949
2345
|
}
|
|
@@ -1976,10 +2372,10 @@ function buildFundingHint(options, chainLabel) {
|
|
|
1976
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}.`;
|
|
1977
2373
|
}
|
|
1978
2374
|
const parts = [];
|
|
1979
|
-
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])) {
|
|
1980
2376
|
parts.push(`top up ${target.shortfall.token} ${sym}`);
|
|
1981
2377
|
}
|
|
1982
|
-
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])) {
|
|
1983
2379
|
parts.push(`add ~${target.shortfall.native} ${target.cost.feeSymbol} for gas`);
|
|
1984
2380
|
}
|
|
1985
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}.`;
|
|
@@ -1993,7 +2389,7 @@ async function planAcross(clients, url, init) {
|
|
|
1993
2389
|
const status = best ? "ready" : options.some((o) => o.state === "unknown") ? "unknown" : "blocked";
|
|
1994
2390
|
return {
|
|
1995
2391
|
url,
|
|
1996
|
-
network: _nullishCoalesce(_optionalChain([best, 'optionalAccess',
|
|
2392
|
+
network: _nullishCoalesce(_optionalChain([best, 'optionalAccess', _38 => _38.accept, 'access', _39 => _39.network]), () => ( live[0].network)),
|
|
1997
2393
|
status,
|
|
1998
2394
|
payable: best !== null,
|
|
1999
2395
|
best,
|
|
@@ -2009,7 +2405,7 @@ function railOnNetwork(rail, matches) {
|
|
|
2009
2405
|
function hostOf2(url) {
|
|
2010
2406
|
try {
|
|
2011
2407
|
return new URL(url).hostname;
|
|
2012
|
-
} catch (
|
|
2408
|
+
} catch (e22) {
|
|
2013
2409
|
return url;
|
|
2014
2410
|
}
|
|
2015
2411
|
}
|
|
@@ -2026,13 +2422,21 @@ function isReplayableBodyInit(value) {
|
|
|
2026
2422
|
async function readInvalidReason(response) {
|
|
2027
2423
|
try {
|
|
2028
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
|
+
}
|
|
2029
2433
|
if (body && (body.status === "invalid" || typeof body.error === "string")) {
|
|
2030
2434
|
return {
|
|
2031
2435
|
error: typeof body.error === "string" ? body.error : "no error code",
|
|
2032
2436
|
detail: typeof body.detail === "string" ? body.detail : ""
|
|
2033
2437
|
};
|
|
2034
2438
|
}
|
|
2035
|
-
} catch (
|
|
2439
|
+
} catch (e23) {
|
|
2036
2440
|
}
|
|
2037
2441
|
return null;
|
|
2038
2442
|
}
|
|
@@ -2043,7 +2447,7 @@ async function readBody(res) {
|
|
|
2043
2447
|
if (!text) return null;
|
|
2044
2448
|
try {
|
|
2045
2449
|
return JSON.parse(text);
|
|
2046
|
-
} catch (
|
|
2450
|
+
} catch (e24) {
|
|
2047
2451
|
return text;
|
|
2048
2452
|
}
|
|
2049
2453
|
}
|
|
@@ -2214,7 +2618,7 @@ function paymentTools(client) {
|
|
|
2214
2618
|
receipt: parseReceipt(res)
|
|
2215
2619
|
};
|
|
2216
2620
|
} catch (err) {
|
|
2217
|
-
if (err instanceof
|
|
2621
|
+
if (err instanceof _chunkMDLZJGLYcjs.PaymentDeclinedError) {
|
|
2218
2622
|
return { declined: true, reason: err.message };
|
|
2219
2623
|
}
|
|
2220
2624
|
throw err;
|
|
@@ -2257,6 +2661,100 @@ function paymentTools(client) {
|
|
|
2257
2661
|
];
|
|
2258
2662
|
}
|
|
2259
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
|
+
|
|
2260
2758
|
// src/server.ts
|
|
2261
2759
|
function toInvalidBody(result) {
|
|
2262
2760
|
return { x402Version: 2, status: "invalid", error: result.error, detail: result.detail };
|
|
@@ -2283,9 +2781,10 @@ function createPaymentGate(options) {
|
|
|
2283
2781
|
const genNonce = _nullishCoalesce(options.generateNonce, () => ( (() => globalThis.crypto.randomUUID())));
|
|
2284
2782
|
let resolved;
|
|
2285
2783
|
function ready() {
|
|
2286
|
-
|
|
2784
|
+
if (resolved) return resolved;
|
|
2785
|
+
const p = (async () => {
|
|
2287
2786
|
const accepts = normaliseAccepts(options);
|
|
2288
|
-
|
|
2787
|
+
const specs = await Promise.all(
|
|
2289
2788
|
accepts.map(async (a) => {
|
|
2290
2789
|
const net = await resolveNetwork2({ chain: a.chain, rpcUrl: _nullishCoalesce(a.rpcUrl, () => ( options.rpcUrl)) });
|
|
2291
2790
|
const payTo = _nullishCoalesce(a.payTo, () => ( options.payTo));
|
|
@@ -2296,11 +2795,53 @@ function createPaymentGate(options) {
|
|
|
2296
2795
|
}
|
|
2297
2796
|
net.assertValidPayTo(payTo);
|
|
2298
2797
|
const { asset, decimals, symbol } = net.resolveToken(a.token);
|
|
2299
|
-
const amountBase =
|
|
2300
|
-
|
|
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;
|
|
2301
2802
|
})
|
|
2302
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;
|
|
2303
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
|
+
};
|
|
2304
2845
|
}
|
|
2305
2846
|
const hasCustomStore = Boolean(options.isUsed || options.markUsed);
|
|
2306
2847
|
const localUsed = /* @__PURE__ */ new Set();
|
|
@@ -2337,93 +2878,191 @@ function createPaymentGate(options) {
|
|
|
2337
2878
|
}
|
|
2338
2879
|
};
|
|
2339
2880
|
}
|
|
2340
|
-
|
|
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) {
|
|
2341
2910
|
const specs = await ready();
|
|
2342
2911
|
const nonce = genNonce();
|
|
2343
2912
|
const challenge2 = {
|
|
2344
2913
|
x402Version: 2,
|
|
2345
|
-
error: null,
|
|
2346
2914
|
resource: {
|
|
2347
2915
|
url: resourceUrl,
|
|
2348
2916
|
...options.description ? { description: options.description } : {}
|
|
2349
2917
|
},
|
|
2350
|
-
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 } : {}
|
|
2351
2921
|
};
|
|
2352
2922
|
return { challenge: challenge2, requiredHeader: buildChallengeHeader(challenge2) };
|
|
2353
2923
|
}
|
|
2924
|
+
async function challenge(resourceUrl = "") {
|
|
2925
|
+
return makeChallenge(resourceUrl);
|
|
2926
|
+
}
|
|
2354
2927
|
async function asChallenge() {
|
|
2355
|
-
const { challenge: c, requiredHeader } = await
|
|
2928
|
+
const { challenge: c, requiredHeader } = await makeChallenge("");
|
|
2356
2929
|
return { kind: "challenge", challenge: c, requiredHeader, statusCode: 402 };
|
|
2357
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
|
+
}
|
|
2358
2946
|
async function describe(resourceUrl = "") {
|
|
2359
2947
|
const specs = await ready();
|
|
2360
|
-
const accepts =
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
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
|
+
}
|
|
2371
2963
|
return {
|
|
2372
2964
|
url: resourceUrl,
|
|
2373
2965
|
...options.description ? { description: options.description } : {},
|
|
2374
2966
|
accepts
|
|
2375
2967
|
};
|
|
2376
2968
|
}
|
|
2377
|
-
async function
|
|
2378
|
-
const raw = normaliseHeader(paymentSignature);
|
|
2379
|
-
if (!raw) return asChallenge();
|
|
2380
|
-
const sig = parseSignatureHeader(raw);
|
|
2381
|
-
if (!sig || !sig.accepted || typeof sig.accepted.network !== "string" || typeof sig.accepted.asset !== "string") {
|
|
2382
|
-
return asChallenge();
|
|
2383
|
-
}
|
|
2969
|
+
async function verifyOnchainProof(sig) {
|
|
2384
2970
|
const specs = await ready();
|
|
2385
2971
|
const spec = specs.find(
|
|
2386
2972
|
(s) => s.net.network === sig.accepted.network && s.asset === sig.accepted.asset
|
|
2387
2973
|
);
|
|
2388
2974
|
if (!spec) {
|
|
2389
|
-
return
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
statusCode: 402
|
|
2394
|
-
};
|
|
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
|
+
);
|
|
2395
2979
|
}
|
|
2396
2980
|
const ref = sig.payload.txHash;
|
|
2397
|
-
if (await claimTx(ref)) {
|
|
2398
|
-
return {
|
|
2399
|
-
kind: "invalid",
|
|
2400
|
-
error: "tx_already_used",
|
|
2401
|
-
detail: `Proof ${ref} was already redeemed.`,
|
|
2402
|
-
statusCode: 402
|
|
2403
|
-
};
|
|
2404
|
-
}
|
|
2981
|
+
if (await claimTx(ref)) return rejection("tx_already_used", `Proof ${ref} was already redeemed.`);
|
|
2405
2982
|
const result = await spec.net.verify(ref, buildAccept(spec, sig.payload.nonce));
|
|
2406
2983
|
if (!result.ok) {
|
|
2407
2984
|
await settleTx(ref, false);
|
|
2408
|
-
return
|
|
2409
|
-
kind: "invalid",
|
|
2410
|
-
error: result.error,
|
|
2411
|
-
detail: result.detail,
|
|
2412
|
-
statusCode: 402
|
|
2413
|
-
};
|
|
2985
|
+
return rejection(result.error, result.detail);
|
|
2414
2986
|
}
|
|
2415
2987
|
await settleTx(ref, true);
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
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
|
+
});
|
|
2420
3043
|
}
|
|
3044
|
+
} catch (err) {
|
|
3045
|
+
await settleTx(nonce, false);
|
|
3046
|
+
throw err;
|
|
2421
3047
|
}
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
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();
|
|
2427
3066
|
}
|
|
2428
3067
|
return { challenge, verify, describe };
|
|
2429
3068
|
}
|
|
@@ -2432,14 +3071,20 @@ function requirePayment(options) {
|
|
|
2432
3071
|
return async (req, res, next) => {
|
|
2433
3072
|
let result;
|
|
2434
3073
|
try {
|
|
2435
|
-
result = await gate.verify(req.headers[HEADER_SIGNATURE]);
|
|
3074
|
+
result = await gate.verify(_nullishCoalesce(req.headers[HEADER_SIGNATURE], () => ( req.headers[HEADER_SIGNATURE_V1])));
|
|
2436
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
|
+
}
|
|
2437
3081
|
next(err);
|
|
2438
3082
|
return;
|
|
2439
3083
|
}
|
|
2440
3084
|
switch (result.kind) {
|
|
2441
3085
|
case "paid":
|
|
2442
3086
|
res.setHeader(HEADER_RESPONSE, result.receiptHeader);
|
|
3087
|
+
res.setHeader(HEADER_RESPONSE_V1, result.receiptHeader);
|
|
2443
3088
|
return next();
|
|
2444
3089
|
case "challenge":
|
|
2445
3090
|
res.setHeader(HEADER_REQUIRED, result.requiredHeader);
|
|
@@ -2447,8 +3092,9 @@ function requirePayment(options) {
|
|
|
2447
3092
|
res.json(result.challenge);
|
|
2448
3093
|
return;
|
|
2449
3094
|
case "invalid":
|
|
3095
|
+
res.setHeader(HEADER_REQUIRED, result.requiredHeader);
|
|
2450
3096
|
res.status(result.statusCode);
|
|
2451
|
-
res.json(
|
|
3097
|
+
res.json(result.challenge);
|
|
2452
3098
|
return;
|
|
2453
3099
|
}
|
|
2454
3100
|
};
|
|
@@ -2458,110 +3104,12 @@ function normaliseHeader(value) {
|
|
|
2458
3104
|
return value;
|
|
2459
3105
|
}
|
|
2460
3106
|
|
|
2461
|
-
// src/drivers/evm/exact.ts
|
|
2462
|
-
var EXACT_NETWORK_SLUGS = {
|
|
2463
|
-
ethereum: 1,
|
|
2464
|
-
base: 8453,
|
|
2465
|
-
"base-sepolia": 84532,
|
|
2466
|
-
arbitrum: 42161,
|
|
2467
|
-
optimism: 10,
|
|
2468
|
-
polygon: 137,
|
|
2469
|
-
avalanche: 43114
|
|
2470
|
-
};
|
|
2471
|
-
function chainIdForExactNetwork(slug) {
|
|
2472
|
-
return _nullishCoalesce(EXACT_NETWORK_SLUGS[slug], () => ( null));
|
|
2473
|
-
}
|
|
2474
|
-
var EIP3009_TYPES = {
|
|
2475
|
-
TransferWithAuthorization: [
|
|
2476
|
-
{ name: "from", type: "address" },
|
|
2477
|
-
{ name: "to", type: "address" },
|
|
2478
|
-
{ name: "value", type: "uint256" },
|
|
2479
|
-
{ name: "validAfter", type: "uint256" },
|
|
2480
|
-
{ name: "validBefore", type: "uint256" },
|
|
2481
|
-
{ name: "nonce", type: "bytes32" }
|
|
2482
|
-
]
|
|
2483
|
-
};
|
|
2484
|
-
function parseExactRequirements(body) {
|
|
2485
|
-
if (!body || typeof body !== "object") return null;
|
|
2486
|
-
const accepts = body.accepts;
|
|
2487
|
-
if (!Array.isArray(accepts)) return null;
|
|
2488
|
-
const out = [];
|
|
2489
|
-
for (const raw of accepts) {
|
|
2490
|
-
if (!raw || typeof raw !== "object") continue;
|
|
2491
|
-
const a = raw;
|
|
2492
|
-
if (a.scheme !== "exact") continue;
|
|
2493
|
-
const amount = _nullishCoalesce(a.maxAmountRequired, () => ( a.amount));
|
|
2494
|
-
if (typeof a.network !== "string" || typeof amount !== "string" || typeof a.asset !== "string" || typeof a.payTo !== "string") {
|
|
2495
|
-
continue;
|
|
2496
|
-
}
|
|
2497
|
-
out.push({
|
|
2498
|
-
scheme: "exact",
|
|
2499
|
-
network: a.network,
|
|
2500
|
-
maxAmountRequired: amount,
|
|
2501
|
-
asset: a.asset,
|
|
2502
|
-
payTo: a.payTo,
|
|
2503
|
-
maxTimeoutSeconds: typeof a.maxTimeoutSeconds === "number" ? a.maxTimeoutSeconds : 600,
|
|
2504
|
-
...a.extra && typeof a.extra === "object" ? { extra: a.extra } : {},
|
|
2505
|
-
...typeof a.description === "string" ? { description: a.description } : {},
|
|
2506
|
-
...typeof a.resource === "string" ? { resource: a.resource } : {}
|
|
2507
|
-
});
|
|
2508
|
-
}
|
|
2509
|
-
return out;
|
|
2510
|
-
}
|
|
2511
|
-
async function buildExactAuthorization(params) {
|
|
2512
|
-
const { account, accept, chainId, now, nonce } = params;
|
|
2513
|
-
if (!account.signTypedData) {
|
|
2514
|
-
throw new Error("buildExactAuthorization: the account cannot sign EIP-712 typed data.");
|
|
2515
|
-
}
|
|
2516
|
-
const authorization = {
|
|
2517
|
-
from: account.address,
|
|
2518
|
-
to: accept.payTo,
|
|
2519
|
-
value: accept.maxAmountRequired,
|
|
2520
|
-
validAfter: "0",
|
|
2521
|
-
validBefore: String(now + accept.maxTimeoutSeconds),
|
|
2522
|
-
nonce
|
|
2523
|
-
};
|
|
2524
|
-
const signature = await account.signTypedData({
|
|
2525
|
-
domain: {
|
|
2526
|
-
name: _nullishCoalesce(_optionalChain([accept, 'access', _34 => _34.extra, 'optionalAccess', _35 => _35.name]), () => ( "USD Coin")),
|
|
2527
|
-
version: _nullishCoalesce(_optionalChain([accept, 'access', _36 => _36.extra, 'optionalAccess', _37 => _37.version]), () => ( "2")),
|
|
2528
|
-
chainId,
|
|
2529
|
-
verifyingContract: accept.asset
|
|
2530
|
-
},
|
|
2531
|
-
types: EIP3009_TYPES,
|
|
2532
|
-
primaryType: "TransferWithAuthorization",
|
|
2533
|
-
message: {
|
|
2534
|
-
from: authorization.from,
|
|
2535
|
-
to: authorization.to,
|
|
2536
|
-
value: BigInt(authorization.value),
|
|
2537
|
-
validAfter: BigInt(authorization.validAfter),
|
|
2538
|
-
validBefore: BigInt(authorization.validBefore),
|
|
2539
|
-
nonce: authorization.nonce
|
|
2540
|
-
}
|
|
2541
|
-
});
|
|
2542
|
-
return { authorization, signature };
|
|
2543
|
-
}
|
|
2544
|
-
function base64(str) {
|
|
2545
|
-
if (typeof btoa === "function") return btoa(str);
|
|
2546
|
-
if (typeof Buffer !== "undefined") return Buffer.from(str, "utf8").toString("base64");
|
|
2547
|
-
throw new Error("No base64 encoder available in this runtime.");
|
|
2548
|
-
}
|
|
2549
|
-
function encodeXPaymentHeader(input) {
|
|
2550
|
-
const payload = {
|
|
2551
|
-
x402Version: _nullishCoalesce(input.x402Version, () => ( 1)),
|
|
2552
|
-
scheme: "exact",
|
|
2553
|
-
network: input.network,
|
|
2554
|
-
payload: { signature: input.signature, authorization: input.authorization }
|
|
2555
|
-
};
|
|
2556
|
-
return base64(JSON.stringify(payload));
|
|
2557
|
-
}
|
|
2558
|
-
|
|
2559
3107
|
// src/discovery.ts
|
|
2560
3108
|
var GENERATOR = "@piprail/sdk \xB7 https://piprail.com";
|
|
2561
3109
|
function pathOf(url) {
|
|
2562
3110
|
try {
|
|
2563
3111
|
return new URL(url).pathname || "/";
|
|
2564
|
-
} catch (
|
|
3112
|
+
} catch (e27) {
|
|
2565
3113
|
return url.startsWith("/") ? url : `/${url}`;
|
|
2566
3114
|
}
|
|
2567
3115
|
}
|
|
@@ -2658,4 +3206,14 @@ function buildX402DnsTxt(input) {
|
|
|
2658
3206
|
|
|
2659
3207
|
|
|
2660
3208
|
|
|
2661
|
-
|
|
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;
|