@piprail/sdk 1.3.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHAINS.md +31 -7
- package/CHANGELOG.md +74 -0
- package/ERRORS.md +13 -2
- package/README.md +46 -12
- package/dist/algorand-B67G4335.js +397 -0
- package/dist/algorand-IJJKE35X.cjs +397 -0
- package/dist/{aptos-MKZ5MAGL.cjs → aptos-X3G2UBYW.cjs} +44 -16
- package/dist/{aptos-DTAONNMM.js → aptos-YQWTGFRZ.js} +29 -1
- package/dist/{chunk-YJPWIK5L.cjs → chunk-IQGT65WS.cjs} +4 -2
- package/dist/{chunk-AGKC3C7Y.js → chunk-QDS6FBZP.js} +4 -2
- package/dist/index.cjs +358 -67
- package/dist/index.d.cts +162 -4
- package/dist/index.d.ts +162 -4
- package/dist/index.js +308 -17
- package/dist/{near-YX3XOASO.js → near-7MBBCDUE.js} +51 -1
- package/dist/{near-DISWUB7Y.cjs → near-GGUHLXAF.cjs} +76 -26
- package/dist/{solana-37F2PR5H.js → solana-7WJVZGDW.js} +23 -1
- package/dist/{solana-RJPNEFSN.cjs → solana-W24TCJV4.cjs} +39 -17
- package/dist/{stellar-ALOVOMFD.js → stellar-HV6VGZX3.js} +51 -1
- package/dist/{stellar-SUGNX52Z.cjs → stellar-YMY3K2YB.cjs} +70 -20
- package/dist/{sui-OLC5ID4X.js → sui-2WFWVFJX.js} +24 -1
- package/dist/{sui-HZWPHVU4.cjs → sui-32KVESR5.cjs} +40 -17
- package/dist/{ton-NIDWF77T.js → ton-DGZB7W4U.js} +24 -1
- package/dist/{ton-C4KTFXDL.cjs → ton-FIQGV2LC.cjs} +37 -14
- package/dist/{tron-LPMK57H7.js → tron-RLIL2FDI.js} +29 -1
- package/dist/{tron-DTU7NPEM.cjs → tron-ZSXAPZ2C.cjs} +52 -24
- package/dist/{xrpl-N6ZAJRGC.cjs → xrpl-2PKP7HOI.cjs} +81 -21
- package/dist/{xrpl-6ODQS7JR.js → xrpl-UEC2GYVV.js} +61 -1
- package/package.json +9 -2
package/dist/index.cjs
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
var
|
|
23
|
+
var _chunkIQGT65WScjs = require('./chunk-IQGT65WS.cjs');
|
|
24
24
|
|
|
25
25
|
// src/drivers/registry.ts
|
|
26
26
|
var byFamily = /* @__PURE__ */ new Map();
|
|
@@ -40,6 +40,7 @@ function familyForChain(chain) {
|
|
|
40
40
|
if (chain.startsWith("sui")) return "sui";
|
|
41
41
|
if (chain.startsWith("near")) return "near";
|
|
42
42
|
if (chain.startsWith("aptos")) return "aptos";
|
|
43
|
+
if (chain.startsWith("algorand")) return "algorand";
|
|
43
44
|
return "evm";
|
|
44
45
|
}
|
|
45
46
|
return "evm";
|
|
@@ -48,13 +49,13 @@ function resolveNetwork(opts) {
|
|
|
48
49
|
const family = familyForChain(opts.chain);
|
|
49
50
|
const driver = byFamily.get(family);
|
|
50
51
|
if (!driver) {
|
|
51
|
-
throw new (0,
|
|
52
|
+
throw new (0, _chunkIQGT65WScjs.UnsupportedNetworkError)(
|
|
52
53
|
`No driver registered for the "${family}" family \u2014 it may not be mounted yet (use the async resolveNetwork()).`
|
|
53
54
|
);
|
|
54
55
|
}
|
|
55
56
|
const net = driver.resolve(opts);
|
|
56
57
|
if (!net) {
|
|
57
|
-
throw new (0,
|
|
58
|
+
throw new (0, _chunkIQGT65WScjs.UnsupportedNetworkError)(
|
|
58
59
|
`The ${family} driver didn't recognise this chain input.`
|
|
59
60
|
);
|
|
60
61
|
}
|
|
@@ -298,12 +299,12 @@ function createWalletAdapter(config, resolved) {
|
|
|
298
299
|
}
|
|
299
300
|
const wc = config.walletClient;
|
|
300
301
|
if (!wc.account) {
|
|
301
|
-
throw new (0,
|
|
302
|
+
throw new (0, _chunkIQGT65WScjs.WrongFamilyError)(
|
|
302
303
|
"chain is EVM; the provided walletClient has no attached account. Use `createWalletClient({ account, chain, transport })`, or pass { privateKey }."
|
|
303
304
|
);
|
|
304
305
|
}
|
|
305
306
|
if (wc.chain && wc.chain.id !== resolved.chainId) {
|
|
306
|
-
throw new (0,
|
|
307
|
+
throw new (0, _chunkIQGT65WScjs.WrongChainError)(
|
|
307
308
|
`PipRailClient: walletClient is on chain ${wc.chain.id} but the SDK was configured with chain ${resolved.chainId}. They must match.`
|
|
308
309
|
);
|
|
309
310
|
}
|
|
@@ -606,15 +607,15 @@ function makeEvmNetwork(resolved) {
|
|
|
606
607
|
const info = resolved.tokens[token.toUpperCase()];
|
|
607
608
|
if (!info) {
|
|
608
609
|
const known = Object.keys(resolved.tokens).join(", ") || "(none built in)";
|
|
609
|
-
throw new (0,
|
|
610
|
+
throw new (0, _chunkIQGT65WScjs.UnknownTokenError)(
|
|
610
611
|
`token "${token}" isn't built in for ${resolved.chain.name} (known: ${known}). Pass { address, decimals } instead, or use 'native'.`
|
|
611
612
|
);
|
|
612
613
|
}
|
|
613
614
|
return { asset: info.address, decimals: info.decimals, symbol: info.symbol };
|
|
614
615
|
}
|
|
615
|
-
|
|
616
|
+
_chunkIQGT65WScjs.rejectForeignToken.call(void 0, token, "evm", network);
|
|
616
617
|
if (!("address" in token)) {
|
|
617
|
-
throw new (0,
|
|
618
|
+
throw new (0, _chunkIQGT65WScjs.WrongFamilyError)(
|
|
618
619
|
`chain ${network} is EVM; a custom token must be { address, decimals }.`
|
|
619
620
|
);
|
|
620
621
|
}
|
|
@@ -646,14 +647,14 @@ function makeEvmNetwork(resolved) {
|
|
|
646
647
|
},
|
|
647
648
|
assertValidPayTo(payTo) {
|
|
648
649
|
if (!_viem.isAddress.call(void 0, payTo)) {
|
|
649
|
-
throw new (0,
|
|
650
|
+
throw new (0, _chunkIQGT65WScjs.WrongFamilyError)(
|
|
650
651
|
`chain ${network} is EVM, but payTo "${payTo}" is not a valid 0x address.`
|
|
651
652
|
);
|
|
652
653
|
}
|
|
653
654
|
},
|
|
654
655
|
bindWallet(wallet) {
|
|
655
656
|
if (typeof wallet !== "object" || wallet === null || !("privateKey" in wallet) && !("walletClient" in wallet)) {
|
|
656
|
-
throw new (0,
|
|
657
|
+
throw new (0, _chunkIQGT65WScjs.WrongFamilyError)(
|
|
657
658
|
`chain ${network} is EVM; wallet must be { privateKey } or { walletClient }.`
|
|
658
659
|
);
|
|
659
660
|
}
|
|
@@ -670,12 +671,12 @@ function makeEvmNetwork(resolved) {
|
|
|
670
671
|
});
|
|
671
672
|
} catch (err) {
|
|
672
673
|
if (isViemInsufficientFunds(err)) {
|
|
673
|
-
throw new (0,
|
|
674
|
+
throw new (0, _chunkIQGT65WScjs.InsufficientFundsError)(
|
|
674
675
|
err instanceof Error ? err.message : "Insufficient funds for payment.",
|
|
675
676
|
{ cause: err }
|
|
676
677
|
);
|
|
677
678
|
}
|
|
678
|
-
throw _nullishCoalesce(
|
|
679
|
+
throw _nullishCoalesce(_chunkIQGT65WScjs.toInsufficientFundsError.call(void 0, err), () => ( err));
|
|
679
680
|
}
|
|
680
681
|
},
|
|
681
682
|
async confirm(ref, minConfirmations) {
|
|
@@ -686,7 +687,7 @@ function makeEvmNetwork(resolved) {
|
|
|
686
687
|
});
|
|
687
688
|
return { height: receipt.blockNumber.toString() };
|
|
688
689
|
} catch (err) {
|
|
689
|
-
throw new (0,
|
|
690
|
+
throw new (0, _chunkIQGT65WScjs.ConfirmationTimeoutError)(
|
|
690
691
|
`EVM tx ${ref} did not reach ${minConfirmations} confirmation(s) in time.`,
|
|
691
692
|
{ cause: err }
|
|
692
693
|
);
|
|
@@ -697,7 +698,7 @@ function makeEvmNetwork(resolved) {
|
|
|
697
698
|
const gasLimit = accept.asset === "native" ? 21000n : 65000n;
|
|
698
699
|
try {
|
|
699
700
|
const gasPrice = await publicClient.getGasPrice();
|
|
700
|
-
return
|
|
701
|
+
return _chunkIQGT65WScjs.nativeCost.call(void 0, {
|
|
701
702
|
symbol,
|
|
702
703
|
decimals,
|
|
703
704
|
fee: gasPrice * gasLimit,
|
|
@@ -706,7 +707,7 @@ function makeEvmNetwork(resolved) {
|
|
|
706
707
|
});
|
|
707
708
|
} catch (e10) {
|
|
708
709
|
const gasPrice = 5000000000n;
|
|
709
|
-
return
|
|
710
|
+
return _chunkIQGT65WScjs.nativeCost.call(void 0, {
|
|
710
711
|
symbol,
|
|
711
712
|
decimals,
|
|
712
713
|
fee: gasPrice * gasLimit,
|
|
@@ -715,6 +716,27 @@ function makeEvmNetwork(resolved) {
|
|
|
715
716
|
});
|
|
716
717
|
}
|
|
717
718
|
},
|
|
719
|
+
async balanceOf(wallet, asset) {
|
|
720
|
+
const owner = wallet._native.account.address;
|
|
721
|
+
const native = await publicClient.getBalance({ address: owner }).catch(() => null);
|
|
722
|
+
if (asset === "native") return { token: native, native };
|
|
723
|
+
let token = null;
|
|
724
|
+
try {
|
|
725
|
+
token = await publicClient.readContract({
|
|
726
|
+
address: _viem.getAddress.call(void 0, asset),
|
|
727
|
+
abi: _viem.erc20Abi,
|
|
728
|
+
functionName: "balanceOf",
|
|
729
|
+
args: [owner]
|
|
730
|
+
});
|
|
731
|
+
} catch (e11) {
|
|
732
|
+
token = null;
|
|
733
|
+
}
|
|
734
|
+
return { token, native };
|
|
735
|
+
},
|
|
736
|
+
// EVM has no receive prerequisite — any 0x address receives native or ERC-20 immediately.
|
|
737
|
+
async recipientReady() {
|
|
738
|
+
return { ready: "n/a" };
|
|
739
|
+
},
|
|
718
740
|
async verify(ref, accept) {
|
|
719
741
|
return verifyEvm({
|
|
720
742
|
publicClient,
|
|
@@ -738,9 +760,9 @@ var loaders = {
|
|
|
738
760
|
solana: async () => {
|
|
739
761
|
let mod;
|
|
740
762
|
try {
|
|
741
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./solana-
|
|
763
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./solana-W24TCJV4.cjs")));
|
|
742
764
|
} catch (cause) {
|
|
743
|
-
throw new (0,
|
|
765
|
+
throw new (0, _chunkIQGT65WScjs.MissingDriverError)(
|
|
744
766
|
`Solana selected, but its packages aren't installed. Run: npm install @solana/web3.js @solana/spl-token bs58`,
|
|
745
767
|
{ cause }
|
|
746
768
|
);
|
|
@@ -750,9 +772,9 @@ var loaders = {
|
|
|
750
772
|
ton: async () => {
|
|
751
773
|
let mod;
|
|
752
774
|
try {
|
|
753
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./ton-
|
|
775
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./ton-FIQGV2LC.cjs")));
|
|
754
776
|
} catch (cause) {
|
|
755
|
-
throw new (0,
|
|
777
|
+
throw new (0, _chunkIQGT65WScjs.MissingDriverError)(
|
|
756
778
|
`TON selected, but its packages aren't installed. Run: npm install @ton/ton @ton/core @ton/crypto`,
|
|
757
779
|
{ cause }
|
|
758
780
|
);
|
|
@@ -762,9 +784,9 @@ var loaders = {
|
|
|
762
784
|
stellar: async () => {
|
|
763
785
|
let mod;
|
|
764
786
|
try {
|
|
765
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./stellar-
|
|
787
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./stellar-YMY3K2YB.cjs")));
|
|
766
788
|
} catch (cause) {
|
|
767
|
-
throw new (0,
|
|
789
|
+
throw new (0, _chunkIQGT65WScjs.MissingDriverError)(
|
|
768
790
|
`Stellar selected, but its package isn't installed. Run: npm install @stellar/stellar-sdk`,
|
|
769
791
|
{ cause }
|
|
770
792
|
);
|
|
@@ -774,9 +796,9 @@ var loaders = {
|
|
|
774
796
|
xrpl: async () => {
|
|
775
797
|
let mod;
|
|
776
798
|
try {
|
|
777
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./xrpl-
|
|
799
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./xrpl-2PKP7HOI.cjs")));
|
|
778
800
|
} catch (cause) {
|
|
779
|
-
throw new (0,
|
|
801
|
+
throw new (0, _chunkIQGT65WScjs.MissingDriverError)(
|
|
780
802
|
`XRPL selected, but its package isn't installed. Run: npm install xrpl`,
|
|
781
803
|
{ cause }
|
|
782
804
|
);
|
|
@@ -786,9 +808,9 @@ var loaders = {
|
|
|
786
808
|
tron: async () => {
|
|
787
809
|
let mod;
|
|
788
810
|
try {
|
|
789
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./tron-
|
|
811
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./tron-ZSXAPZ2C.cjs")));
|
|
790
812
|
} catch (cause) {
|
|
791
|
-
throw new (0,
|
|
813
|
+
throw new (0, _chunkIQGT65WScjs.MissingDriverError)(
|
|
792
814
|
`Tron selected, but its package isn't installed. Run: npm install tronweb`,
|
|
793
815
|
{ cause }
|
|
794
816
|
);
|
|
@@ -798,9 +820,9 @@ var loaders = {
|
|
|
798
820
|
sui: async () => {
|
|
799
821
|
let mod;
|
|
800
822
|
try {
|
|
801
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./sui-
|
|
823
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./sui-32KVESR5.cjs")));
|
|
802
824
|
} catch (cause) {
|
|
803
|
-
throw new (0,
|
|
825
|
+
throw new (0, _chunkIQGT65WScjs.MissingDriverError)(
|
|
804
826
|
`Sui selected, but its package isn't installed. Run: npm install @mysten/sui`,
|
|
805
827
|
{ cause }
|
|
806
828
|
);
|
|
@@ -810,9 +832,9 @@ var loaders = {
|
|
|
810
832
|
near: async () => {
|
|
811
833
|
let mod;
|
|
812
834
|
try {
|
|
813
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./near-
|
|
835
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./near-GGUHLXAF.cjs")));
|
|
814
836
|
} catch (cause) {
|
|
815
|
-
throw new (0,
|
|
837
|
+
throw new (0, _chunkIQGT65WScjs.MissingDriverError)(
|
|
816
838
|
`NEAR selected, but its package isn't installed. Run: npm install near-api-js`,
|
|
817
839
|
{ cause }
|
|
818
840
|
);
|
|
@@ -822,14 +844,26 @@ var loaders = {
|
|
|
822
844
|
aptos: async () => {
|
|
823
845
|
let mod;
|
|
824
846
|
try {
|
|
825
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./aptos-
|
|
847
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./aptos-X3G2UBYW.cjs")));
|
|
826
848
|
} catch (cause) {
|
|
827
|
-
throw new (0,
|
|
849
|
+
throw new (0, _chunkIQGT65WScjs.MissingDriverError)(
|
|
828
850
|
`Aptos selected, but its package isn't installed. Run: npm install @aptos-labs/ts-sdk`,
|
|
829
851
|
{ cause }
|
|
830
852
|
);
|
|
831
853
|
}
|
|
832
854
|
registerDriver(mod.aptosDriver);
|
|
855
|
+
},
|
|
856
|
+
algorand: async () => {
|
|
857
|
+
let mod;
|
|
858
|
+
try {
|
|
859
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./algorand-IJJKE35X.cjs")));
|
|
860
|
+
} catch (cause) {
|
|
861
|
+
throw new (0, _chunkIQGT65WScjs.MissingDriverError)(
|
|
862
|
+
`Algorand selected, but its package isn't installed. Run: npm install algosdk`,
|
|
863
|
+
{ cause }
|
|
864
|
+
);
|
|
865
|
+
}
|
|
866
|
+
registerDriver(mod.algorandDriver);
|
|
833
867
|
}
|
|
834
868
|
};
|
|
835
869
|
var inFlight = /* @__PURE__ */ new Map();
|
|
@@ -896,7 +930,7 @@ function evaluatePolicy(intent, policy, spentForAssetBase) {
|
|
|
896
930
|
}
|
|
897
931
|
}
|
|
898
932
|
if (policy.maxAmount !== void 0) {
|
|
899
|
-
const cap =
|
|
933
|
+
const cap = _chunkIQGT65WScjs.floorUnits.call(void 0, policy.maxAmount, intent.decimals);
|
|
900
934
|
if (intent.amountBase > cap) {
|
|
901
935
|
return deny(
|
|
902
936
|
`payment of ${intent.amountBase} base units exceeds policy.maxAmount ` + `(${policy.maxAmount} ${_nullishCoalesce(intent.symbol, () => ( ""))}).`.trimEnd()
|
|
@@ -904,7 +938,7 @@ function evaluatePolicy(intent, policy, spentForAssetBase) {
|
|
|
904
938
|
}
|
|
905
939
|
}
|
|
906
940
|
if (policy.maxTotal !== void 0) {
|
|
907
|
-
const cap =
|
|
941
|
+
const cap = _chunkIQGT65WScjs.floorUnits.call(void 0, policy.maxTotal, intent.decimals);
|
|
908
942
|
if (spentForAssetBase + intent.amountBase > cap) {
|
|
909
943
|
return deny(
|
|
910
944
|
`this payment would push spend on ${_nullishCoalesce(intent.symbol, () => ( intent.asset))} past policy.maxTotal (${policy.maxTotal}); already spent ${spentForAssetBase} base units.`
|
|
@@ -954,7 +988,7 @@ var SpendLedger = (_class = class {constructor() { _class.prototype.__init.call(
|
|
|
954
988
|
symbol: b.symbol,
|
|
955
989
|
decimals: b.decimals,
|
|
956
990
|
totalBase: b.total.toString(),
|
|
957
|
-
totalFormatted:
|
|
991
|
+
totalFormatted: _chunkIQGT65WScjs.formatUnits.call(void 0, b.total, b.decimals),
|
|
958
992
|
count: b.count
|
|
959
993
|
})),
|
|
960
994
|
records: [...this.records]
|
|
@@ -963,6 +997,12 @@ var SpendLedger = (_class = class {constructor() { _class.prototype.__init.call(
|
|
|
963
997
|
}, _class);
|
|
964
998
|
|
|
965
999
|
// src/client.ts
|
|
1000
|
+
var RECIPIENT_FIX = {
|
|
1001
|
+
NO_TRUSTLINE: "the recipient needs a one-time trustline for this asset before it can receive",
|
|
1002
|
+
NOT_REGISTERED: "the recipient must be storage_deposit-registered on this token (NEP-145, one-time)",
|
|
1003
|
+
NOT_OPTED_IN: "the recipient must opt into this asset once (a 0-amount self-transfer)",
|
|
1004
|
+
INACTIVE: "the recipient account doesn't exist yet \u2014 fund it with the chain's base reserve to activate it"
|
|
1005
|
+
};
|
|
966
1006
|
var PipRailClient = (_class2 = class {
|
|
967
1007
|
|
|
968
1008
|
|
|
@@ -985,7 +1025,7 @@ var PipRailClient = (_class2 = class {
|
|
|
985
1025
|
safeEmit(event) {
|
|
986
1026
|
try {
|
|
987
1027
|
this.onEvent(event);
|
|
988
|
-
} catch (
|
|
1028
|
+
} catch (e12) {
|
|
989
1029
|
}
|
|
990
1030
|
}
|
|
991
1031
|
/** Auto-mount the chain's driver, resolve the network, and bind the wallet — once. */
|
|
@@ -1071,6 +1111,44 @@ var PipRailClient = (_class2 = class {
|
|
|
1071
1111
|
spent() {
|
|
1072
1112
|
return this.ledger.summary();
|
|
1073
1113
|
}
|
|
1114
|
+
/**
|
|
1115
|
+
* Plan a payment for a gated URL — WITHOUT paying. The read-only completion of
|
|
1116
|
+
* the `quote()` → `estimateCost()` → **`planPayment()`** trio: it surveys every
|
|
1117
|
+
* rail the 402 offers on this client's chain against the wallet's OWN holdings —
|
|
1118
|
+
* token balance, native-coin gas, and recipient-readiness (trustline / ATA /
|
|
1119
|
+
* storage_deposit / ASA opt-in) — and returns, crystal-clear:
|
|
1120
|
+
* - `payable` + `best` — the cheapest rail the wallet can actually settle
|
|
1121
|
+
* - `options[]` — every rail with typed `blockers` + soft `warnings`
|
|
1122
|
+
* - `fundingHint` — one human sentence on exactly what to top up
|
|
1123
|
+
*
|
|
1124
|
+
* NEVER throws for a read problem (a transient/RPC failure surfaces as a rail in
|
|
1125
|
+
* `state: 'unknown'` + a warning, never a false "unaffordable"); returns `null`
|
|
1126
|
+
* when the URL isn't payment-gated (no 402); and when the 402 offers no rail on
|
|
1127
|
+
* this client's chain it EXPLAINS that (status `blocked` + a hint), rather than
|
|
1128
|
+
* throwing. Throws `InvalidEnvelopeError` only on an unparseable challenge.
|
|
1129
|
+
*
|
|
1130
|
+
* Then pay the chosen rail with `fetch(url, { autoRoute: true })`, or branch on
|
|
1131
|
+
* the plan yourself. No funds move.
|
|
1132
|
+
*/
|
|
1133
|
+
async planPayment(url, init) {
|
|
1134
|
+
const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _9 => _9.method]), () => ( "GET")) });
|
|
1135
|
+
if (res.status !== 402) return null;
|
|
1136
|
+
const challenge = await parseChallenge(res);
|
|
1137
|
+
if (!challenge) {
|
|
1138
|
+
throw new (0, _chunkIQGT65WScjs.InvalidEnvelopeError)("402 response did not include a parseable x402 challenge.");
|
|
1139
|
+
}
|
|
1140
|
+
const { net, wallet } = await this.ensure();
|
|
1141
|
+
return this.planFromChallenge(net, wallet, challenge, url);
|
|
1142
|
+
}
|
|
1143
|
+
/**
|
|
1144
|
+
* Convenience over {@link planPayment}: can the wallet settle this URL right now?
|
|
1145
|
+
* `true` when at least one rail is payable — or when the URL isn't gated (a free
|
|
1146
|
+
* resource is trivially "affordable"). No funds move.
|
|
1147
|
+
*/
|
|
1148
|
+
async canAfford(url, init) {
|
|
1149
|
+
const plan = await this.planPayment(url, init);
|
|
1150
|
+
return plan == null ? true : plan.payable;
|
|
1151
|
+
}
|
|
1074
1152
|
/**
|
|
1075
1153
|
* Lower-level: drive any HTTP method through the 402 flow.
|
|
1076
1154
|
*
|
|
@@ -1079,18 +1157,27 @@ var PipRailClient = (_class2 = class {
|
|
|
1079
1157
|
* streams throw `NonReplayableBodyError`.
|
|
1080
1158
|
*/
|
|
1081
1159
|
async fetch(url, init) {
|
|
1082
|
-
const body = _optionalChain([init, 'optionalAccess',
|
|
1160
|
+
const body = _optionalChain([init, 'optionalAccess', _10 => _10.body]);
|
|
1083
1161
|
if (body !== void 0 && body !== null && !isReplayableBodyInit(body)) {
|
|
1084
|
-
throw new (0,
|
|
1162
|
+
throw new (0, _chunkIQGT65WScjs.NonReplayableBodyError)(
|
|
1085
1163
|
"fetch(): init.body is not replayable. Pass a string, FormData, URLSearchParams, ArrayBuffer, or Blob \u2014 not a ReadableStream."
|
|
1086
1164
|
);
|
|
1087
1165
|
}
|
|
1088
1166
|
const firstResponse = await fetch(url, init);
|
|
1089
1167
|
if (firstResponse.status !== 402) return firstResponse;
|
|
1090
|
-
const
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1168
|
+
const resolved = await this.resolveChallenge(url, firstResponse);
|
|
1169
|
+
const { net, wallet, challenge } = resolved;
|
|
1170
|
+
let accept = resolved.accept;
|
|
1171
|
+
let quote = resolved.quote;
|
|
1172
|
+
const autoRoute = _nullishCoalesce(_nullishCoalesce(_optionalChain([init, 'optionalAccess', _11 => _11.autoRoute]), () => ( this.opts.autoRoute)), () => ( false));
|
|
1173
|
+
if (autoRoute) {
|
|
1174
|
+
const plan = await this.planFromChallenge(net, wallet, challenge, url);
|
|
1175
|
+
if (!plan.best) {
|
|
1176
|
+
throw new (0, _chunkIQGT65WScjs.PaymentDeclinedError)(_nullishCoalesce(plan.fundingHint, () => ( "No rail is settleable for this payment.")));
|
|
1177
|
+
}
|
|
1178
|
+
accept = plan.best.accept;
|
|
1179
|
+
quote = plan.best.quote;
|
|
1180
|
+
}
|
|
1094
1181
|
this.safeEmit({ kind: "payment-required", challenge, accept });
|
|
1095
1182
|
await this.authorize(quote);
|
|
1096
1183
|
const { ref, confirmed } = await this.payAndConfirm(net, wallet, accept);
|
|
@@ -1107,17 +1194,15 @@ var PipRailClient = (_class2 = class {
|
|
|
1107
1194
|
async resolveChallenge(url, response) {
|
|
1108
1195
|
const challenge = await parseChallenge(response);
|
|
1109
1196
|
if (!challenge) {
|
|
1110
|
-
throw new (0,
|
|
1197
|
+
throw new (0, _chunkIQGT65WScjs.InvalidEnvelopeError)(
|
|
1111
1198
|
"402 response did not include a parseable x402 challenge."
|
|
1112
1199
|
);
|
|
1113
1200
|
}
|
|
1114
1201
|
const { net, wallet } = await this.ensure();
|
|
1115
|
-
const candidates =
|
|
1116
|
-
(a) => a.scheme === "onchain-proof" && net.supports(a.network)
|
|
1117
|
-
);
|
|
1202
|
+
const candidates = this.gatherCandidates(net, challenge);
|
|
1118
1203
|
if (candidates.length === 0) {
|
|
1119
1204
|
const networks = challenge.accepts.map((a) => a.network).join(", ");
|
|
1120
|
-
throw new (0,
|
|
1205
|
+
throw new (0, _chunkIQGT65WScjs.NoCompatibleAcceptError)(
|
|
1121
1206
|
`No accepts[] entry for ${net.network} (challenge offered: ${networks || "none"}).`
|
|
1122
1207
|
);
|
|
1123
1208
|
}
|
|
@@ -1128,19 +1213,124 @@ var PipRailClient = (_class2 = class {
|
|
|
1128
1213
|
const chosen = _nullishCoalesce(priced.find((p) => p.quote.withinPolicy), () => ( priced[0]));
|
|
1129
1214
|
return { net, wallet, accept: chosen.accept, challenge, quote: chosen.quote };
|
|
1130
1215
|
}
|
|
1216
|
+
/** The candidate accepts this client could pay: our scheme, on the bound network. */
|
|
1217
|
+
gatherCandidates(net, challenge) {
|
|
1218
|
+
return challenge.accepts.filter(
|
|
1219
|
+
(a) => a.scheme === "onchain-proof" && net.supports(a.network)
|
|
1220
|
+
);
|
|
1221
|
+
}
|
|
1222
|
+
/** Build the full {@link PaymentPlan} from an already-parsed challenge + bound
|
|
1223
|
+
* net/wallet. Shared by `planPayment` (read-only) and `fetch`'s autoRoute. */
|
|
1224
|
+
async planFromChallenge(net, wallet, challenge, url) {
|
|
1225
|
+
const chainLabel = typeof this.opts.chain === "string" ? this.opts.chain : net.network;
|
|
1226
|
+
const candidates = this.gatherCandidates(net, challenge);
|
|
1227
|
+
if (candidates.length === 0) {
|
|
1228
|
+
const offered = [...new Set(challenge.accepts.map((a) => a.network))].join(", ") || "none";
|
|
1229
|
+
return {
|
|
1230
|
+
url,
|
|
1231
|
+
network: net.network,
|
|
1232
|
+
status: "blocked",
|
|
1233
|
+
payable: false,
|
|
1234
|
+
best: null,
|
|
1235
|
+
options: [],
|
|
1236
|
+
fundingHint: `This 402 isn't offered on your chain (${chainLabel}); it's payable on: ${offered}.`
|
|
1237
|
+
};
|
|
1238
|
+
}
|
|
1239
|
+
const analysed = await Promise.all(
|
|
1240
|
+
candidates.map(
|
|
1241
|
+
(accept) => this.analyzeRail(net, wallet, accept, url, challenge.resource.description)
|
|
1242
|
+
)
|
|
1243
|
+
);
|
|
1244
|
+
const options = rankOptions(analysed);
|
|
1245
|
+
const best = _nullishCoalesce(options.find((o) => o.state === "payable"), () => ( null));
|
|
1246
|
+
const status = best ? "ready" : options.some((o) => o.state === "unknown") ? "unknown" : "blocked";
|
|
1247
|
+
return {
|
|
1248
|
+
url,
|
|
1249
|
+
network: net.network,
|
|
1250
|
+
status,
|
|
1251
|
+
payable: best !== null,
|
|
1252
|
+
best,
|
|
1253
|
+
options,
|
|
1254
|
+
fundingHint: best ? null : buildFundingHint(options, chainLabel)
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
/** Analyse ONE rail against the wallet's holdings — quote (existing) + gas
|
|
1258
|
+
* (estimateCost, existing) + balanceOf + recipientReady → a {@link PayOption}. */
|
|
1259
|
+
async analyzeRail(net, wallet, accept, url, description) {
|
|
1260
|
+
const quote = this.buildQuote(net, accept, url, description);
|
|
1261
|
+
const cost = await net.estimateCost(accept);
|
|
1262
|
+
const bal = await net.balanceOf(wallet, accept.asset).catch(() => ({ token: null, native: null }));
|
|
1263
|
+
const rr = await net.recipientReady(accept.payTo, accept.asset).catch(() => ({ ready: "unknown" }));
|
|
1264
|
+
const amount = BigInt(accept.amount);
|
|
1265
|
+
const fee = safeBig(cost.fee);
|
|
1266
|
+
const isNative = accept.asset === "native";
|
|
1267
|
+
const blockers = [];
|
|
1268
|
+
const warnings = [];
|
|
1269
|
+
const shortfall = {};
|
|
1270
|
+
if (!quote.withinPolicy) blockers.push("OUTSIDE_POLICY");
|
|
1271
|
+
if (quote.symbolMismatch) warnings.push("SYMBOL_MISMATCH");
|
|
1272
|
+
if (cost.basis === "heuristic") warnings.push("GAS_HEURISTIC");
|
|
1273
|
+
const tokenKnown = bal.token != null;
|
|
1274
|
+
const nativeKnown = bal.native != null;
|
|
1275
|
+
if (!tokenKnown || !nativeKnown) warnings.push("BALANCE_UNREADABLE");
|
|
1276
|
+
if (isNative) {
|
|
1277
|
+
if (nativeKnown && bal.native < amount + fee) {
|
|
1278
|
+
blockers.push("INSUFFICIENT_TOKEN");
|
|
1279
|
+
shortfall.token = _chunkIQGT65WScjs.formatUnits.call(void 0, amount + fee - bal.native, quote.decimals);
|
|
1280
|
+
}
|
|
1281
|
+
} else {
|
|
1282
|
+
if (tokenKnown && bal.token < amount) {
|
|
1283
|
+
blockers.push("INSUFFICIENT_TOKEN");
|
|
1284
|
+
shortfall.token = _chunkIQGT65WScjs.formatUnits.call(void 0, amount - bal.token, quote.decimals);
|
|
1285
|
+
}
|
|
1286
|
+
if (nativeKnown && bal.native < fee) {
|
|
1287
|
+
blockers.push("INSUFFICIENT_GAS");
|
|
1288
|
+
shortfall.native = _chunkIQGT65WScjs.formatUnits.call(void 0, fee - bal.native, cost.feeDecimals);
|
|
1289
|
+
} else if (nativeKnown && fee > 0n && bal.native < fee * 3n / 2n) {
|
|
1290
|
+
warnings.push("THIN_GAS_MARGIN");
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
let recipient;
|
|
1294
|
+
if (rr.ready === false) {
|
|
1295
|
+
blockers.push("RECIPIENT_NOT_READY");
|
|
1296
|
+
recipient = rr.reason ? { ready: false, reason: rr.reason, fix: RECIPIENT_FIX[rr.reason] } : { ready: false };
|
|
1297
|
+
} else if (rr.ready === "unknown") {
|
|
1298
|
+
warnings.push("RECIPIENT_READINESS_UNKNOWN");
|
|
1299
|
+
recipient = { ready: "unknown" };
|
|
1300
|
+
} else {
|
|
1301
|
+
recipient = { ready: rr.ready };
|
|
1302
|
+
}
|
|
1303
|
+
const unreadable = isNative ? !nativeKnown : !tokenKnown || !nativeKnown;
|
|
1304
|
+
const state = blockers.length ? "blocked" : unreadable || rr.ready === "unknown" ? "unknown" : "payable";
|
|
1305
|
+
return {
|
|
1306
|
+
accept,
|
|
1307
|
+
quote,
|
|
1308
|
+
cost,
|
|
1309
|
+
state,
|
|
1310
|
+
blockers,
|
|
1311
|
+
warnings,
|
|
1312
|
+
balance: {
|
|
1313
|
+
token: bal.token != null ? _chunkIQGT65WScjs.formatUnits.call(void 0, bal.token, quote.decimals) : null,
|
|
1314
|
+
native: bal.native != null ? _chunkIQGT65WScjs.formatUnits.call(void 0, bal.native, cost.feeDecimals) : null
|
|
1315
|
+
},
|
|
1316
|
+
need: { token: quote.amountFormatted, native: cost.feeFormatted },
|
|
1317
|
+
...shortfall.token || shortfall.native ? { shortfall } : {},
|
|
1318
|
+
recipient
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1131
1321
|
/** Build the agent-facing quote for an accept: TRUE decimals/symbol (via the
|
|
1132
1322
|
* driver's describeAsset) + the policy verdict + a symbol-mismatch flag. */
|
|
1133
1323
|
buildQuote(net, accept, url, description) {
|
|
1134
1324
|
if (!/^\d+$/.test(accept.amount)) {
|
|
1135
|
-
throw new (0,
|
|
1325
|
+
throw new (0, _chunkIQGT65WScjs.InvalidEnvelopeError)(
|
|
1136
1326
|
`challenge amount "${accept.amount}" is not a base-unit integer.`
|
|
1137
1327
|
);
|
|
1138
1328
|
}
|
|
1139
1329
|
const amountBase = BigInt(accept.amount);
|
|
1140
1330
|
const described = net.describeAsset(accept.asset);
|
|
1141
|
-
const decimals = _nullishCoalesce(_optionalChain([described, 'optionalAccess',
|
|
1142
|
-
const symbol = _nullishCoalesce(_optionalChain([described, 'optionalAccess',
|
|
1143
|
-
const amountFormatted =
|
|
1331
|
+
const decimals = _nullishCoalesce(_optionalChain([described, 'optionalAccess', _12 => _12.decimals]), () => ( accept.extra.decimals));
|
|
1332
|
+
const symbol = _nullishCoalesce(_optionalChain([described, 'optionalAccess', _13 => _13.symbol]), () => ( accept.extra.symbol));
|
|
1333
|
+
const amountFormatted = _chunkIQGT65WScjs.formatUnits.call(void 0, amountBase, decimals);
|
|
1144
1334
|
const intent = {
|
|
1145
1335
|
host: hostOf(url),
|
|
1146
1336
|
chain: this.opts.chain,
|
|
@@ -1180,7 +1370,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1180
1370
|
* throwing PaymentDeclinedError, before any funds move. */
|
|
1181
1371
|
async authorize(quote) {
|
|
1182
1372
|
if (!quote.withinPolicy) {
|
|
1183
|
-
throw new (0,
|
|
1373
|
+
throw new (0, _chunkIQGT65WScjs.PaymentDeclinedError)(
|
|
1184
1374
|
`Payment refused by policy: ${_nullishCoalesce(quote.policyReason, () => ( "not allowed"))}`
|
|
1185
1375
|
);
|
|
1186
1376
|
}
|
|
@@ -1190,12 +1380,12 @@ var PipRailClient = (_class2 = class {
|
|
|
1190
1380
|
try {
|
|
1191
1381
|
approved = await hook(quote);
|
|
1192
1382
|
} catch (err) {
|
|
1193
|
-
throw new (0,
|
|
1383
|
+
throw new (0, _chunkIQGT65WScjs.PaymentDeclinedError)("onBeforePay threw \u2014 refusing to pay.", {
|
|
1194
1384
|
cause: err
|
|
1195
1385
|
});
|
|
1196
1386
|
}
|
|
1197
1387
|
if (!approved) {
|
|
1198
|
-
throw new (0,
|
|
1388
|
+
throw new (0, _chunkIQGT65WScjs.PaymentDeclinedError)(
|
|
1199
1389
|
`onBeforePay declined ${quote.amountFormatted} ${_nullishCoalesce(quote.symbol, () => ( ""))}`.trimEnd() + ` on ${quote.network}.`
|
|
1200
1390
|
);
|
|
1201
1391
|
}
|
|
@@ -1219,7 +1409,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1219
1409
|
}
|
|
1220
1410
|
async payAndConfirm(net, wallet, accept) {
|
|
1221
1411
|
if (!net.supports(accept.network)) {
|
|
1222
|
-
throw new (0,
|
|
1412
|
+
throw new (0, _chunkIQGT65WScjs.WrongChainError)(
|
|
1223
1413
|
`Challenge expects ${accept.network} but client is on ${net.network}.`
|
|
1224
1414
|
);
|
|
1225
1415
|
}
|
|
@@ -1248,7 +1438,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1248
1438
|
accepted: accept,
|
|
1249
1439
|
payload: { nonce: accept.extra.nonce, txHash: ref }
|
|
1250
1440
|
};
|
|
1251
|
-
const headers = new Headers(_optionalChain([originalInit, 'optionalAccess',
|
|
1441
|
+
const headers = new Headers(_optionalChain([originalInit, 'optionalAccess', _14 => _14.headers]));
|
|
1252
1442
|
headers.set(HEADER_SIGNATURE, buildSignatureHeader(signature));
|
|
1253
1443
|
let lastResponse = null;
|
|
1254
1444
|
let lastReason = null;
|
|
@@ -1263,7 +1453,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1263
1453
|
() => timeoutController.abort(),
|
|
1264
1454
|
this.retryTimeoutMs
|
|
1265
1455
|
);
|
|
1266
|
-
const signal = _optionalChain([originalInit, 'optionalAccess',
|
|
1456
|
+
const signal = _optionalChain([originalInit, 'optionalAccess', _15 => _15.signal]) && typeof AbortSignal.any === "function" ? AbortSignal.any([timeoutController.signal, originalInit.signal]) : timeoutController.signal;
|
|
1267
1457
|
try {
|
|
1268
1458
|
lastResponse = await fetch(url, {
|
|
1269
1459
|
..._nullishCoalesce(originalInit, () => ( {})),
|
|
@@ -1272,7 +1462,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1272
1462
|
});
|
|
1273
1463
|
} catch (err) {
|
|
1274
1464
|
if (timeoutController.signal.aborted) {
|
|
1275
|
-
throw new (0,
|
|
1465
|
+
throw new (0, _chunkIQGT65WScjs.PaymentTimeoutError)(
|
|
1276
1466
|
`Server did not respond within ${this.retryTimeoutMs}ms after broadcasting payment ${ref}. Re-verify or re-submit ref=${ref} \u2014 do NOT re-pay.`,
|
|
1277
1467
|
{ cause: err, ref }
|
|
1278
1468
|
);
|
|
@@ -1294,16 +1484,78 @@ var PipRailClient = (_class2 = class {
|
|
|
1294
1484
|
kind: "payment-failed",
|
|
1295
1485
|
reason: `server returned 402 after broadcasting payment ${ref}${unconfirmedNote} (${why})`
|
|
1296
1486
|
});
|
|
1297
|
-
throw new (0,
|
|
1487
|
+
throw new (0, _chunkIQGT65WScjs.MaxRetriesExceededError)(
|
|
1298
1488
|
`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).`,
|
|
1299
1489
|
{ ref }
|
|
1300
1490
|
);
|
|
1301
1491
|
}
|
|
1302
1492
|
}, _class2);
|
|
1493
|
+
function safeBig(s) {
|
|
1494
|
+
try {
|
|
1495
|
+
return BigInt(s);
|
|
1496
|
+
} catch (e13) {
|
|
1497
|
+
return 0n;
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
function shortAddr(a) {
|
|
1501
|
+
return a.length > 14 ? `${a.slice(0, 8)}\u2026${a.slice(-4)}` : a;
|
|
1502
|
+
}
|
|
1503
|
+
function rankOptions(options) {
|
|
1504
|
+
const rank = { payable: 0, unknown: 1, blocked: 2 };
|
|
1505
|
+
return [...options].sort((a, b) => {
|
|
1506
|
+
if (rank[a.state] !== rank[b.state]) return rank[a.state] - rank[b.state];
|
|
1507
|
+
if (a.state === "payable") {
|
|
1508
|
+
const fa = safeBig(a.cost.fee);
|
|
1509
|
+
const fb = safeBig(b.cost.fee);
|
|
1510
|
+
if (fa !== fb) return fa < fb ? -1 : 1;
|
|
1511
|
+
}
|
|
1512
|
+
return 0;
|
|
1513
|
+
});
|
|
1514
|
+
}
|
|
1515
|
+
function buildFundingHint(options, chainLabel) {
|
|
1516
|
+
if (options.length === 0) return null;
|
|
1517
|
+
const target = [...options].sort((a, b) => a.blockers.length - b.blockers.length)[0];
|
|
1518
|
+
const sym = _nullishCoalesce(target.quote.symbol, () => ( "the token"));
|
|
1519
|
+
if (target.blockers.includes("RECIPIENT_NOT_READY")) {
|
|
1520
|
+
return `Recipient ${shortAddr(target.accept.payTo)} can't receive on ${chainLabel} yet \u2014 ${_nullishCoalesce(target.recipient.fix, () => ( "recipient not ready"))}.`;
|
|
1521
|
+
}
|
|
1522
|
+
if (target.blockers.includes("OUTSIDE_POLICY")) {
|
|
1523
|
+
return `Refused by spend policy: ${_nullishCoalesce(target.quote.policyReason, () => ( "not allowed"))}.`;
|
|
1524
|
+
}
|
|
1525
|
+
if (target.state === "unknown") {
|
|
1526
|
+
return `Couldn't fully read your wallet on ${chainLabel} (RPC throttled) \u2014 retry; you may already be able to pay ${target.quote.amountFormatted} ${sym}.`;
|
|
1527
|
+
}
|
|
1528
|
+
const parts = [];
|
|
1529
|
+
if (target.blockers.includes("INSUFFICIENT_TOKEN") && _optionalChain([target, 'access', _16 => _16.shortfall, 'optionalAccess', _17 => _17.token])) {
|
|
1530
|
+
parts.push(`top up ${target.shortfall.token} ${sym}`);
|
|
1531
|
+
}
|
|
1532
|
+
if (target.blockers.includes("INSUFFICIENT_GAS") && _optionalChain([target, 'access', _18 => _18.shortfall, 'optionalAccess', _19 => _19.native])) {
|
|
1533
|
+
parts.push(`add ~${target.shortfall.native} ${target.cost.feeSymbol} for gas`);
|
|
1534
|
+
}
|
|
1535
|
+
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}.`;
|
|
1536
|
+
}
|
|
1537
|
+
async function planAcross(clients, url, init) {
|
|
1538
|
+
const plans = await Promise.all(clients.map((c) => c.planPayment(url, init).catch(() => null)));
|
|
1539
|
+
const live = plans.filter((p) => p != null);
|
|
1540
|
+
if (live.length === 0) return null;
|
|
1541
|
+
const options = rankOptions(live.flatMap((p) => p.options));
|
|
1542
|
+
const best = _nullishCoalesce(options.find((o) => o.state === "payable"), () => ( null));
|
|
1543
|
+
const status = best ? "ready" : options.some((o) => o.state === "unknown") ? "unknown" : "blocked";
|
|
1544
|
+
return {
|
|
1545
|
+
url,
|
|
1546
|
+
network: _nullishCoalesce(_optionalChain([best, 'optionalAccess', _20 => _20.accept, 'access', _21 => _21.network]), () => ( live[0].network)),
|
|
1547
|
+
status,
|
|
1548
|
+
payable: best !== null,
|
|
1549
|
+
best,
|
|
1550
|
+
options,
|
|
1551
|
+
// First non-null hint across clients — each already names its chain.
|
|
1552
|
+
fundingHint: best ? null : _nullishCoalesce(live.map((p) => p.fundingHint).find(Boolean), () => ( null))
|
|
1553
|
+
};
|
|
1554
|
+
}
|
|
1303
1555
|
function hostOf(url) {
|
|
1304
1556
|
try {
|
|
1305
1557
|
return new URL(url).hostname;
|
|
1306
|
-
} catch (
|
|
1558
|
+
} catch (e14) {
|
|
1307
1559
|
return url;
|
|
1308
1560
|
}
|
|
1309
1561
|
}
|
|
@@ -1326,7 +1578,7 @@ async function readInvalidReason(response) {
|
|
|
1326
1578
|
detail: typeof body.detail === "string" ? body.detail : ""
|
|
1327
1579
|
};
|
|
1328
1580
|
}
|
|
1329
|
-
} catch (
|
|
1581
|
+
} catch (e15) {
|
|
1330
1582
|
}
|
|
1331
1583
|
return null;
|
|
1332
1584
|
}
|
|
@@ -1337,7 +1589,7 @@ async function readBody(res) {
|
|
|
1337
1589
|
if (!text) return null;
|
|
1338
1590
|
try {
|
|
1339
1591
|
return JSON.parse(text);
|
|
1340
|
-
} catch (
|
|
1592
|
+
} catch (e16) {
|
|
1341
1593
|
return text;
|
|
1342
1594
|
}
|
|
1343
1595
|
}
|
|
@@ -1359,6 +1611,44 @@ function paymentTools(client) {
|
|
|
1359
1611
|
return quote ? { gated: true, ...quote } : { gated: false, url: String(args.url) };
|
|
1360
1612
|
}
|
|
1361
1613
|
},
|
|
1614
|
+
{
|
|
1615
|
+
name: "piprail_plan_payment",
|
|
1616
|
+
description: "Check whether you CAN pay an x402-gated URL before paying. Reads your wallet balance, native gas, and whether the recipient can receive \u2014 across every rail the URL offers on your chain \u2014 and returns { gated, payable, best, options, fundingHint }. payable:false means do NOT attempt the payment; fundingHint says exactly what to top up. Call this before piprail_pay_request so you never commit to a payment you cannot finish. Returns { gated: false } when no payment is needed.",
|
|
1617
|
+
parameters: {
|
|
1618
|
+
type: "object",
|
|
1619
|
+
properties: {
|
|
1620
|
+
url: { type: "string", description: "Full URL of the gated resource." }
|
|
1621
|
+
},
|
|
1622
|
+
required: ["url"],
|
|
1623
|
+
additionalProperties: false
|
|
1624
|
+
},
|
|
1625
|
+
invoke: async (args) => {
|
|
1626
|
+
const plan = await client.planPayment(String(args.url));
|
|
1627
|
+
if (plan == null) return { gated: false, url: String(args.url) };
|
|
1628
|
+
return {
|
|
1629
|
+
gated: true,
|
|
1630
|
+
payable: plan.payable,
|
|
1631
|
+
status: plan.status,
|
|
1632
|
+
fundingHint: plan.fundingHint,
|
|
1633
|
+
best: plan.best ? {
|
|
1634
|
+
network: plan.best.accept.network,
|
|
1635
|
+
symbol: plan.best.quote.symbol,
|
|
1636
|
+
amount: plan.best.quote.amountFormatted,
|
|
1637
|
+
gasCoin: plan.best.cost.feeSymbol,
|
|
1638
|
+
gas: plan.best.cost.feeFormatted
|
|
1639
|
+
} : null,
|
|
1640
|
+
options: plan.options.map((o) => ({
|
|
1641
|
+
network: o.accept.network,
|
|
1642
|
+
symbol: o.quote.symbol,
|
|
1643
|
+
amount: o.quote.amountFormatted,
|
|
1644
|
+
state: o.state,
|
|
1645
|
+
blockers: o.blockers,
|
|
1646
|
+
warnings: o.warnings,
|
|
1647
|
+
recipientReady: o.recipient.ready
|
|
1648
|
+
}))
|
|
1649
|
+
};
|
|
1650
|
+
}
|
|
1651
|
+
},
|
|
1362
1652
|
{
|
|
1363
1653
|
name: "piprail_pay_request",
|
|
1364
1654
|
description: "Fetch an x402 payment-gated URL, automatically paying the required on-chain payment if needed (subject to the spend policy + approval hook). Returns the HTTP status, the response body, and a payment receipt if one settled. If the payment is refused by policy or the approval hook, returns { declined: true, reason } \u2014 no funds moved.",
|
|
@@ -1402,7 +1692,7 @@ function paymentTools(client) {
|
|
|
1402
1692
|
receipt: parseReceipt(res)
|
|
1403
1693
|
};
|
|
1404
1694
|
} catch (err) {
|
|
1405
|
-
if (err instanceof
|
|
1695
|
+
if (err instanceof _chunkIQGT65WScjs.PaymentDeclinedError) {
|
|
1406
1696
|
return { declined: true, reason: err.message };
|
|
1407
1697
|
}
|
|
1408
1698
|
throw err;
|
|
@@ -1451,7 +1741,7 @@ function createPaymentGate(options) {
|
|
|
1451
1741
|
}
|
|
1452
1742
|
net.assertValidPayTo(payTo);
|
|
1453
1743
|
const { asset, decimals, symbol } = net.resolveToken(a.token);
|
|
1454
|
-
const amountBase =
|
|
1744
|
+
const amountBase = _chunkIQGT65WScjs.parseUnits.call(void 0, a.amount, decimals);
|
|
1455
1745
|
return { net, asset, decimals, symbol, amountBase, amountFormatted: a.amount, payTo };
|
|
1456
1746
|
})
|
|
1457
1747
|
);
|
|
@@ -1552,7 +1842,7 @@ function createPaymentGate(options) {
|
|
|
1552
1842
|
if (options.onPaid) {
|
|
1553
1843
|
try {
|
|
1554
1844
|
options.onPaid(result.receipt);
|
|
1555
|
-
} catch (
|
|
1845
|
+
} catch (e17) {
|
|
1556
1846
|
}
|
|
1557
1847
|
}
|
|
1558
1848
|
return {
|
|
@@ -1659,8 +1949,8 @@ async function buildExactAuthorization(params) {
|
|
|
1659
1949
|
};
|
|
1660
1950
|
const signature = await account.signTypedData({
|
|
1661
1951
|
domain: {
|
|
1662
|
-
name: _nullishCoalesce(_optionalChain([accept, 'access',
|
|
1663
|
-
version: _nullishCoalesce(_optionalChain([accept, 'access',
|
|
1952
|
+
name: _nullishCoalesce(_optionalChain([accept, 'access', _22 => _22.extra, 'optionalAccess', _23 => _23.name]), () => ( "USD Coin")),
|
|
1953
|
+
version: _nullishCoalesce(_optionalChain([accept, 'access', _24 => _24.extra, 'optionalAccess', _25 => _25.version]), () => ( "2")),
|
|
1664
1954
|
chainId,
|
|
1665
1955
|
verifyingContract: accept.asset
|
|
1666
1956
|
},
|
|
@@ -1730,4 +2020,5 @@ function encodeXPaymentHeader(input) {
|
|
|
1730
2020
|
|
|
1731
2021
|
|
|
1732
2022
|
|
|
1733
|
-
|
|
2023
|
+
|
|
2024
|
+
exports.CHAINS = CHAINS; exports.ConfirmationTimeoutError = _chunkIQGT65WScjs.ConfirmationTimeoutError; exports.EIP3009_TYPES = EIP3009_TYPES; exports.EXACT_NETWORK_SLUGS = EXACT_NETWORK_SLUGS; exports.InsufficientFundsError = _chunkIQGT65WScjs.InsufficientFundsError; exports.InvalidEnvelopeError = _chunkIQGT65WScjs.InvalidEnvelopeError; exports.MaxRetriesExceededError = _chunkIQGT65WScjs.MaxRetriesExceededError; exports.MissingDriverError = _chunkIQGT65WScjs.MissingDriverError; exports.NoCompatibleAcceptError = _chunkIQGT65WScjs.NoCompatibleAcceptError; exports.NonReplayableBodyError = _chunkIQGT65WScjs.NonReplayableBodyError; exports.PaymentDeclinedError = _chunkIQGT65WScjs.PaymentDeclinedError; exports.PaymentTimeoutError = _chunkIQGT65WScjs.PaymentTimeoutError; exports.PipRailClient = PipRailClient; exports.PipRailError = _chunkIQGT65WScjs.PipRailError; exports.RecipientNotReadyError = _chunkIQGT65WScjs.RecipientNotReadyError; exports.UnknownTokenError = _chunkIQGT65WScjs.UnknownTokenError; exports.UnsupportedNetworkError = _chunkIQGT65WScjs.UnsupportedNetworkError; exports.WrongChainError = _chunkIQGT65WScjs.WrongChainError; exports.WrongFamilyError = _chunkIQGT65WScjs.WrongFamilyError; exports.buildChallengeHeader = buildChallengeHeader; exports.buildExactAuthorization = buildExactAuthorization; exports.buildReceiptHeader = buildReceiptHeader; exports.buildSignatureHeader = buildSignatureHeader; exports.chainIdForExactNetwork = chainIdForExactNetwork; exports.createPaymentGate = createPaymentGate; exports.encodeXPaymentHeader = encodeXPaymentHeader; exports.evaluatePolicy = evaluatePolicy; exports.parseChallenge = parseChallenge; exports.parseExactRequirements = parseExactRequirements; exports.parseReceipt = parseReceipt; exports.parseSignatureHeader = parseSignatureHeader; exports.paymentTools = paymentTools; exports.pickAccept = pickAccept; exports.planAcross = planAcross; exports.registerDriver = registerDriver; exports.requirePayment = requirePayment; exports.resolveChain = resolveChain; exports.toInsufficientFundsError = _chunkIQGT65WScjs.toInsufficientFundsError; exports.toInvalidBody = toInvalidBody;
|