@piprail/sdk 1.0.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/dist/index.cjs ADDED
@@ -0,0 +1,1681 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2;
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+ var _chunkWQWNPAYQcjs = require('./chunk-WQWNPAYQ.cjs');
23
+
24
+ // src/drivers/registry.ts
25
+ var byFamily = /* @__PURE__ */ new Map();
26
+ function registerDriver(driver) {
27
+ byFamily.set(driver.family, driver);
28
+ }
29
+ function isRegistered(family) {
30
+ return byFamily.has(family);
31
+ }
32
+ function familyForChain(chain) {
33
+ if (typeof chain === "string") {
34
+ if (chain.startsWith("solana")) return "solana";
35
+ if (chain.startsWith("ton")) return "ton";
36
+ if (chain.startsWith("stellar")) return "stellar";
37
+ if (chain.startsWith("xrpl")) return "xrpl";
38
+ if (chain.startsWith("tron")) return "tron";
39
+ if (chain.startsWith("sui")) return "sui";
40
+ if (chain.startsWith("near")) return "near";
41
+ return "evm";
42
+ }
43
+ return "evm";
44
+ }
45
+ function resolveNetwork(opts) {
46
+ const family = familyForChain(opts.chain);
47
+ const driver = byFamily.get(family);
48
+ if (!driver) {
49
+ throw new (0, _chunkWQWNPAYQcjs.UnsupportedNetworkError)(
50
+ `No driver registered for the "${family}" family \u2014 it may not be mounted yet (use the async resolveNetwork()).`
51
+ );
52
+ }
53
+ const net = driver.resolve(opts);
54
+ if (!net) {
55
+ throw new (0, _chunkWQWNPAYQcjs.UnsupportedNetworkError)(
56
+ `The ${family} driver didn't recognise this chain input.`
57
+ );
58
+ }
59
+ return net;
60
+ }
61
+
62
+ // src/drivers/evm/index.ts
63
+ var _viem = require('viem');
64
+
65
+ // src/drivers/evm/chains.ts
66
+
67
+
68
+
69
+
70
+
71
+
72
+
73
+
74
+
75
+
76
+
77
+
78
+
79
+
80
+
81
+
82
+
83
+
84
+
85
+ var _chains = require('viem/chains');
86
+ var CHAINS = {
87
+ ethereum: {
88
+ chain: _chains.mainnet,
89
+ // viem's bundled default (eth.merkle.io) is flaky; pin a reliable public RPC.
90
+ defaultRpc: "https://ethereum-rpc.publicnode.com",
91
+ tokens: {
92
+ USDC: { address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", decimals: 6, symbol: "USDC" },
93
+ USDT: { address: "0xdAC17F958D2ee523a2206206994597C13D831ec7", decimals: 6, symbol: "USDT" }
94
+ }
95
+ },
96
+ base: {
97
+ chain: _chains.base,
98
+ tokens: {
99
+ USDC: { address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", decimals: 6, symbol: "USDC" }
100
+ }
101
+ },
102
+ arbitrum: {
103
+ chain: _chains.arbitrum,
104
+ tokens: {
105
+ USDC: { address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", decimals: 6, symbol: "USDC" },
106
+ USDT: { address: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9", decimals: 6, symbol: "USDT" }
107
+ }
108
+ },
109
+ optimism: {
110
+ chain: _chains.optimism,
111
+ tokens: {
112
+ USDC: { address: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85", decimals: 6, symbol: "USDC" },
113
+ USDT: { address: "0x94b008aA00579c1307B0EF2c499aD98a8ce58e58", decimals: 6, symbol: "USDT" }
114
+ }
115
+ },
116
+ polygon: {
117
+ chain: _chains.polygon,
118
+ tokens: {
119
+ USDC: { address: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", decimals: 6, symbol: "USDC" },
120
+ USDT: { address: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F", decimals: 6, symbol: "USDT" }
121
+ }
122
+ },
123
+ bnb: {
124
+ chain: _chains.bsc,
125
+ tokens: {
126
+ // Binance-Peg tokens on BNB Chain are 18 decimals (not the usual 6).
127
+ USDC: { address: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", decimals: 18, symbol: "USDC" },
128
+ USDT: { address: "0x55d398326f99059fF775485246999027B3197955", decimals: 18, symbol: "USDT" }
129
+ }
130
+ },
131
+ avalanche: {
132
+ chain: _chains.avalanche,
133
+ tokens: {
134
+ USDC: { address: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E", decimals: 6, symbol: "USDC" },
135
+ USDT: { address: "0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7", decimals: 6, symbol: "USDT" }
136
+ }
137
+ },
138
+ // ── More popular EVM mainnets. Every address below was verified on-chain
139
+ // (symbol + decimals read via RPC) before being committed here. ──
140
+ mantle: {
141
+ chain: _chains.mantle,
142
+ tokens: {
143
+ USDC: { address: "0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9", decimals: 6, symbol: "USDC" },
144
+ USDT: { address: "0x201EBa5CC46D216Ce6DC03F6a759e8E766e956aE", decimals: 6, symbol: "USDT" }
145
+ }
146
+ },
147
+ sonic: {
148
+ chain: _chains.sonic,
149
+ tokens: {
150
+ USDC: { address: "0x29219dd400f2Bf60E5a23d13Be72B486D4038894", decimals: 6, symbol: "USDC" },
151
+ USDT: { address: "0x6047828dc181963ba44974801FF68e538dA5eaF9", decimals: 6, symbol: "USDT" }
152
+ }
153
+ },
154
+ linea: {
155
+ chain: _chains.linea,
156
+ tokens: {
157
+ USDC: { address: "0x176211869cA2b568f2A7D4EE941E073a821EE1ff", decimals: 6, symbol: "USDC" },
158
+ USDT: { address: "0xA219439258ca9da29E9Cc4cE5596924745e12B93", decimals: 6, symbol: "USDT" }
159
+ }
160
+ },
161
+ scroll: {
162
+ chain: _chains.scroll,
163
+ tokens: {
164
+ USDC: { address: "0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4", decimals: 6, symbol: "USDC" },
165
+ USDT: { address: "0xf55BEC9cafDbE8730f096Aa55dad6D22d44099Df", decimals: 6, symbol: "USDT" }
166
+ }
167
+ },
168
+ celo: {
169
+ chain: _chains.celo,
170
+ tokens: {
171
+ USDC: { address: "0xcebA9300f2b948710d2653dD7B07f33A8B32118C", decimals: 6, symbol: "USDC" },
172
+ USDT: { address: "0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e", decimals: 6, symbol: "USDT" }
173
+ }
174
+ },
175
+ zksync: {
176
+ chain: _chains.zksync,
177
+ tokens: {
178
+ USDC: { address: "0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4", decimals: 6, symbol: "USDC" },
179
+ USDT: { address: "0x493257fD37EDB34451f62EDf8D2a0C418852bA4C", decimals: 6, symbol: "USDT" }
180
+ }
181
+ },
182
+ unichain: {
183
+ chain: _chains.unichain,
184
+ tokens: {
185
+ USDC: { address: "0x078D782b760474a361dDA0AF3839290b0EF57AD6", decimals: 6, symbol: "USDC" },
186
+ USDT: { address: "0x9151434b16b9763660705744891fA906F660EcC5", decimals: 6, symbol: "USDT" }
187
+ }
188
+ },
189
+ worldchain: {
190
+ chain: _chains.worldchain,
191
+ tokens: {
192
+ USDC: { address: "0x79A02482A880bCE3F13e09Da970dC34db4CD24d1", decimals: 6, symbol: "USDC" }
193
+ }
194
+ },
195
+ // Sei EVM (pacific-1, chainId 1329) — native Circle USDC. Sei's "USDT" is
196
+ // USDT0 (LayerZero/omnichain), not Circle/Tether-native, so it's intentionally
197
+ // omitted; pass it as a custom { address, decimals } if you need it.
198
+ sei: {
199
+ chain: _chains.sei,
200
+ tokens: {
201
+ USDC: { address: "0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392", decimals: 6, symbol: "USDC" }
202
+ }
203
+ },
204
+ // Injective native EVM (chainId 1776) — native Circle USDC + USDT via the
205
+ // MultiVM Token Standard (one address across EVM + Wasm, not bridged).
206
+ injective: {
207
+ chain: _chains.injective,
208
+ tokens: {
209
+ USDC: { address: "0xa00C59fF5a080D2b954d0c75e46E22a0c371235a", decimals: 6, symbol: "USDC" },
210
+ USDT: { address: "0x88f7F2b685F9692caf8c478f5BADF09eE9B1Cc13", decimals: 6, symbol: "USDT" }
211
+ }
212
+ }
213
+ };
214
+ function isViemChain(input) {
215
+ return typeof input === "object" && "rpcUrls" in input;
216
+ }
217
+ function knownTokensForId(chainId) {
218
+ for (const preset of Object.values(CHAINS)) {
219
+ if (preset.chain.id === chainId) return preset.tokens;
220
+ }
221
+ return {};
222
+ }
223
+ function resolveChain(input, rpcUrlOverride) {
224
+ if (typeof input === "string") {
225
+ const preset = CHAINS[input];
226
+ if (!preset) {
227
+ const names = Object.keys(CHAINS).join(", ");
228
+ throw new Error(
229
+ `resolveChain: unknown chain "${input}". Built-in names: ${names}. Or pass a viem Chain or { id, rpcUrl } for any other EVM chain.`
230
+ );
231
+ }
232
+ const rpcUrl2 = _nullishCoalesce(_nullishCoalesce(rpcUrlOverride, () => ( preset.defaultRpc)), () => ( preset.chain.rpcUrls.default.http[0]));
233
+ if (!rpcUrl2) {
234
+ throw new Error(`resolveChain: "${input}" has no default RPC URL \u2014 pass rpcUrl.`);
235
+ }
236
+ return { chain: preset.chain, chainId: preset.chain.id, rpcUrl: rpcUrl2, tokens: preset.tokens };
237
+ }
238
+ if (isViemChain(input)) {
239
+ const rpcUrl2 = _nullishCoalesce(rpcUrlOverride, () => ( input.rpcUrls.default.http[0]));
240
+ if (!rpcUrl2) {
241
+ throw new Error(
242
+ `resolveChain: viem chain ${input.id} has no default RPC URL \u2014 pass rpcUrl explicitly.`
243
+ );
244
+ }
245
+ return { chain: input, chainId: input.id, rpcUrl: rpcUrl2, tokens: knownTokensForId(input.id) };
246
+ }
247
+ const rpcUrl = _nullishCoalesce(rpcUrlOverride, () => ( input.rpcUrl));
248
+ if (!rpcUrl) {
249
+ throw new Error(`resolveChain: chain ${input.id} needs an rpcUrl.`);
250
+ }
251
+ const chain = _viem.defineChain.call(void 0, {
252
+ id: input.id,
253
+ name: _nullishCoalesce(input.name, () => ( `EVM ${input.id}`)),
254
+ nativeCurrency: _nullishCoalesce(input.nativeCurrency, () => ( { name: "Ether", symbol: "ETH", decimals: 18 })),
255
+ rpcUrls: { default: { http: [rpcUrl] } }
256
+ });
257
+ return { chain, chainId: input.id, rpcUrl, tokens: knownTokensForId(input.id) };
258
+ }
259
+
260
+ // src/drivers/evm/wallet.ts
261
+
262
+
263
+
264
+
265
+ var _accounts = require('viem/accounts');
266
+ function createWalletAdapter(config, resolved) {
267
+ if ("privateKey" in config) {
268
+ const account = _accounts.privateKeyToAccount.call(void 0, config.privateKey);
269
+ const transport = _viem.http.call(void 0, resolved.rpcUrl);
270
+ const walletClient = _viem.createWalletClient.call(void 0, { account, chain: resolved.chain, transport });
271
+ return { account, walletClient };
272
+ }
273
+ const wc = config.walletClient;
274
+ if (!wc.account) {
275
+ throw new (0, _chunkWQWNPAYQcjs.WrongFamilyError)(
276
+ "chain is EVM; the provided walletClient has no attached account. Use `createWalletClient({ account, chain, transport })`, or pass { privateKey }."
277
+ );
278
+ }
279
+ if (wc.chain && wc.chain.id !== resolved.chainId) {
280
+ throw new (0, _chunkWQWNPAYQcjs.WrongChainError)(
281
+ `PipRailClient: walletClient is on chain ${wc.chain.id} but the SDK was configured with chain ${resolved.chainId}. They must match.`
282
+ );
283
+ }
284
+ return { account: wc.account, walletClient: wc };
285
+ }
286
+
287
+ // src/drivers/evm/pay.ts
288
+
289
+
290
+
291
+ async function payEvm(input) {
292
+ const { walletClient, account, chain, accept } = input;
293
+ const amount = BigInt(accept.amount);
294
+ const payTo = accept.payTo;
295
+ if (accept.asset === "native") {
296
+ return walletClient.sendTransaction({
297
+ account,
298
+ chain,
299
+ to: payTo,
300
+ value: amount
301
+ });
302
+ }
303
+ return walletClient.writeContract({
304
+ account,
305
+ chain,
306
+ address: accept.asset,
307
+ abi: _viem.erc20Abi,
308
+ functionName: "transfer",
309
+ args: [payTo, amount]
310
+ });
311
+ }
312
+
313
+ // src/drivers/evm/verify.ts
314
+
315
+
316
+
317
+
318
+
319
+ var TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
320
+ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
321
+ async function verifyEvm(params) {
322
+ const { publicClient, txHash, accept, minConfirmations } = params;
323
+ const requiredAmount = BigInt(accept.amount);
324
+ const payTo = _viem.getAddress.call(void 0, accept.payTo);
325
+ let receipt;
326
+ try {
327
+ receipt = await publicClient.getTransactionReceipt({ hash: txHash });
328
+ } catch (e2) {
329
+ return {
330
+ ok: false,
331
+ error: "tx_not_found",
332
+ detail: `Transaction ${txHash} not found or not yet mined.`
333
+ };
334
+ }
335
+ if (receipt.status !== "success") {
336
+ return {
337
+ ok: false,
338
+ error: "tx_reverted",
339
+ detail: `Transaction ${txHash} reverted on-chain.`
340
+ };
341
+ }
342
+ let latestBlock;
343
+ let block;
344
+ try {
345
+ latestBlock = await publicClient.getBlockNumber();
346
+ block = await publicClient.getBlock({ blockNumber: receipt.blockNumber });
347
+ } catch (e3) {
348
+ return {
349
+ ok: false,
350
+ error: "tx_not_found",
351
+ detail: `Could not read chain state for ${txHash} (transient RPC failure) \u2014 retry.`
352
+ };
353
+ }
354
+ const confirmations = latestBlock >= receipt.blockNumber ? latestBlock - receipt.blockNumber + 1n : 0n;
355
+ if (confirmations < BigInt(minConfirmations)) {
356
+ return {
357
+ ok: false,
358
+ error: "insufficient_confirmations",
359
+ detail: `Need ${minConfirmations} confirmation(s), have ${confirmations}.`
360
+ };
361
+ }
362
+ const ageSeconds = Math.floor(Date.now() / 1e3) - Number(block.timestamp);
363
+ if (ageSeconds > accept.maxTimeoutSeconds) {
364
+ return {
365
+ ok: false,
366
+ error: "payment_expired",
367
+ detail: `Payment is ${ageSeconds}s old; max allowed is ${accept.maxTimeoutSeconds}s.`
368
+ };
369
+ }
370
+ let payer;
371
+ if (accept.asset === "native") {
372
+ let tx;
373
+ try {
374
+ tx = await publicClient.getTransaction({ hash: txHash });
375
+ } catch (e4) {
376
+ return {
377
+ ok: false,
378
+ error: "tx_not_found",
379
+ detail: `Could not read ${txHash} (transient RPC failure) \u2014 retry.`
380
+ };
381
+ }
382
+ if (!tx.to || _viem.getAddress.call(void 0, tx.to) !== payTo) {
383
+ return {
384
+ ok: false,
385
+ error: "wrong_recipient",
386
+ detail: `Native payment in ${txHash} was not sent to ${payTo}.`
387
+ };
388
+ }
389
+ if (tx.value < requiredAmount) {
390
+ return {
391
+ ok: false,
392
+ error: "amount_too_low",
393
+ detail: `Sent ${tx.value}, required ${requiredAmount}.`
394
+ };
395
+ }
396
+ payer = _viem.getAddress.call(void 0, tx.from);
397
+ } else {
398
+ const asset = _viem.getAddress.call(void 0, accept.asset);
399
+ const transferred = sumTransfersTo(receipt.logs, asset, payTo);
400
+ if (transferred.total < requiredAmount) {
401
+ return {
402
+ ok: false,
403
+ error: "transfer_not_found",
404
+ detail: `No ERC-20 Transfer of >= ${requiredAmount} (token ${asset}) to ${payTo} in ${txHash}.`
405
+ };
406
+ }
407
+ payer = _nullishCoalesce(transferred.from, () => ( ZERO_ADDRESS));
408
+ }
409
+ return {
410
+ ok: true,
411
+ receipt: {
412
+ scheme: "onchain-proof",
413
+ success: true,
414
+ network: accept.network,
415
+ transaction: txHash,
416
+ asset: accept.asset,
417
+ amount: accept.amount,
418
+ payer,
419
+ payTo: accept.payTo,
420
+ verifiedAt: (/* @__PURE__ */ new Date()).toISOString()
421
+ }
422
+ };
423
+ }
424
+ function sumTransfersTo(logs, asset, payTo) {
425
+ let total = 0n;
426
+ let from = null;
427
+ for (const log of logs) {
428
+ if (_viem.getAddress.call(void 0, log.address) !== asset) continue;
429
+ if (log.topics[0] !== TRANSFER_TOPIC) continue;
430
+ try {
431
+ const decoded = _viem.decodeEventLog.call(void 0, {
432
+ abi: _viem.erc20Abi,
433
+ data: log.data,
434
+ topics: log.topics
435
+ });
436
+ if (decoded.eventName !== "Transfer") continue;
437
+ const args = decoded.args;
438
+ if (_viem.getAddress.call(void 0, args.to) !== payTo) continue;
439
+ total += args.value;
440
+ from = _viem.getAddress.call(void 0, args.from);
441
+ } catch (e5) {
442
+ }
443
+ }
444
+ return { total, from };
445
+ }
446
+
447
+ // src/x402.ts
448
+ var HEADER_REQUIRED = "payment-required";
449
+ var HEADER_SIGNATURE = "payment-signature";
450
+ var HEADER_RESPONSE = "payment-response";
451
+ function decodeBase64(b64) {
452
+ if (typeof atob === "function") return atob(b64);
453
+ if (typeof Buffer !== "undefined") return Buffer.from(b64, "base64").toString("utf8");
454
+ throw new Error("No base64 decoder available in this runtime.");
455
+ }
456
+ function encodeBase64(str) {
457
+ if (typeof btoa === "function") return btoa(str);
458
+ if (typeof Buffer !== "undefined") return Buffer.from(str, "utf8").toString("base64");
459
+ throw new Error("No base64 encoder available in this runtime.");
460
+ }
461
+ function fromBase64Json(b64) {
462
+ try {
463
+ return JSON.parse(decodeBase64(b64));
464
+ } catch (e6) {
465
+ return null;
466
+ }
467
+ }
468
+ function toBase64Json(value) {
469
+ return encodeBase64(JSON.stringify(value));
470
+ }
471
+ function networkForChain(chainId) {
472
+ return `eip155:${chainId}`;
473
+ }
474
+ function chainIdFromNetwork(network) {
475
+ const match = /^eip155:(\d+)$/.exec(network);
476
+ if (!match || !match[1]) return null;
477
+ const n = Number(match[1]);
478
+ return Number.isSafeInteger(n) ? n : null;
479
+ }
480
+ function buildChallengeHeader(challenge) {
481
+ return toBase64Json(challenge);
482
+ }
483
+ function buildReceiptHeader(receipt) {
484
+ return toBase64Json(receipt);
485
+ }
486
+ function buildSignatureHeader(signature) {
487
+ return toBase64Json(signature);
488
+ }
489
+ async function parseChallenge(response) {
490
+ const headerValue = response.headers.get(HEADER_REQUIRED);
491
+ if (headerValue) {
492
+ const parsed = fromBase64Json(headerValue);
493
+ if (isValidChallenge(parsed)) return parsed;
494
+ }
495
+ try {
496
+ const body = await response.clone().json();
497
+ if (isValidChallenge(body)) return body;
498
+ } catch (e7) {
499
+ }
500
+ return null;
501
+ }
502
+ function parseReceipt(response) {
503
+ const headerValue = response.headers.get(HEADER_RESPONSE);
504
+ if (!headerValue) return null;
505
+ const parsed = fromBase64Json(headerValue);
506
+ return isValidReceipt(parsed) ? parsed : null;
507
+ }
508
+ function parseSignatureHeader(value) {
509
+ const parsed = fromBase64Json(value);
510
+ if (!parsed || typeof parsed !== "object") return null;
511
+ const v = parsed;
512
+ const accepted = v.accepted;
513
+ const scheme = _nullishCoalesce(_optionalChain([accepted, 'optionalAccess', _ => _.scheme]), () => ( v.scheme));
514
+ if (scheme !== "onchain-proof") return null;
515
+ const payload = v.payload;
516
+ if (!payload || typeof payload.txHash !== "string" || typeof payload.nonce !== "string") {
517
+ return null;
518
+ }
519
+ return parsed;
520
+ }
521
+ function isValidChallenge(value) {
522
+ if (!value || typeof value !== "object") return false;
523
+ const v = value;
524
+ if (v.x402Version !== 2) return false;
525
+ if (!Array.isArray(v.accepts) || v.accepts.length === 0) return false;
526
+ if (!v.resource || typeof v.resource !== "object") return false;
527
+ return true;
528
+ }
529
+ function isValidReceipt(value) {
530
+ if (!value || typeof value !== "object") return false;
531
+ const v = value;
532
+ if (v.scheme !== "onchain-proof") return false;
533
+ if (typeof v.transaction !== "string" && typeof v.txHash !== "string") return false;
534
+ if (typeof v.payer !== "string") return false;
535
+ return true;
536
+ }
537
+ function pickAccept(challenge, matches) {
538
+ for (const accept of challenge.accepts) {
539
+ if (accept.scheme === "onchain-proof" && matches(accept.network)) return accept;
540
+ }
541
+ return null;
542
+ }
543
+
544
+ // src/drivers/evm/index.ts
545
+ var evmDriver = {
546
+ family: "evm",
547
+ resolve(opts) {
548
+ if (typeof opts.chain === "string" && /^(solana|ton|stellar)/.test(opts.chain)) return null;
549
+ if (typeof opts.chain === "string") {
550
+ return makeEvmNetwork(resolveChain(opts.chain, opts.rpcUrl));
551
+ }
552
+ let resolved;
553
+ try {
554
+ resolved = resolveChain(opts.chain, opts.rpcUrl);
555
+ } catch (e8) {
556
+ return null;
557
+ }
558
+ return makeEvmNetwork(resolved);
559
+ }
560
+ };
561
+ function makeEvmNetwork(resolved) {
562
+ const network = networkForChain(resolved.chainId);
563
+ const publicClient = _viem.createPublicClient.call(void 0, {
564
+ chain: resolved.chain,
565
+ transport: _viem.http.call(void 0, resolved.rpcUrl)
566
+ });
567
+ return {
568
+ family: "evm",
569
+ network,
570
+ supports: (n) => chainIdFromNetwork(n) === resolved.chainId,
571
+ resolveToken(token) {
572
+ if (token === "native") {
573
+ return {
574
+ asset: "native",
575
+ decimals: resolved.chain.nativeCurrency.decimals,
576
+ symbol: resolved.chain.nativeCurrency.symbol
577
+ };
578
+ }
579
+ if (typeof token === "string") {
580
+ const info = resolved.tokens[token.toUpperCase()];
581
+ if (!info) {
582
+ const known = Object.keys(resolved.tokens).join(", ") || "(none built in)";
583
+ throw new (0, _chunkWQWNPAYQcjs.UnknownTokenError)(
584
+ `token "${token}" isn't built in for ${resolved.chain.name} (known: ${known}). Pass { address, decimals } instead, or use 'native'.`
585
+ );
586
+ }
587
+ return { asset: info.address, decimals: info.decimals, symbol: info.symbol };
588
+ }
589
+ _chunkWQWNPAYQcjs.rejectForeignToken.call(void 0, token, "evm", network);
590
+ if (!("address" in token)) {
591
+ throw new (0, _chunkWQWNPAYQcjs.WrongFamilyError)(
592
+ `chain ${network} is EVM; a custom token must be { address, decimals }.`
593
+ );
594
+ }
595
+ return {
596
+ asset: token.address,
597
+ decimals: token.decimals,
598
+ ...token.symbol ? { symbol: token.symbol } : {}
599
+ };
600
+ },
601
+ describeAsset(asset) {
602
+ if (asset === "native") {
603
+ return {
604
+ symbol: resolved.chain.nativeCurrency.symbol,
605
+ decimals: resolved.chain.nativeCurrency.decimals
606
+ };
607
+ }
608
+ let normalized;
609
+ try {
610
+ normalized = _viem.getAddress.call(void 0, asset);
611
+ } catch (e9) {
612
+ return null;
613
+ }
614
+ for (const info of Object.values(resolved.tokens)) {
615
+ if (_viem.getAddress.call(void 0, info.address) === normalized) {
616
+ return { symbol: info.symbol, decimals: info.decimals };
617
+ }
618
+ }
619
+ return null;
620
+ },
621
+ assertValidPayTo(payTo) {
622
+ if (!_viem.isAddress.call(void 0, payTo)) {
623
+ throw new (0, _chunkWQWNPAYQcjs.WrongFamilyError)(
624
+ `chain ${network} is EVM, but payTo "${payTo}" is not a valid 0x address.`
625
+ );
626
+ }
627
+ },
628
+ bindWallet(wallet) {
629
+ if (typeof wallet !== "object" || wallet === null || !("privateKey" in wallet) && !("walletClient" in wallet)) {
630
+ throw new (0, _chunkWQWNPAYQcjs.WrongFamilyError)(
631
+ `chain ${network} is EVM; wallet must be { privateKey } or { walletClient }.`
632
+ );
633
+ }
634
+ return { _native: createWalletAdapter(wallet, resolved) };
635
+ },
636
+ async send(wallet, accept) {
637
+ const a = wallet._native;
638
+ try {
639
+ return await payEvm({
640
+ walletClient: a.walletClient,
641
+ account: a.account,
642
+ chain: resolved.chain,
643
+ accept
644
+ });
645
+ } catch (err) {
646
+ if (isViemInsufficientFunds(err)) {
647
+ throw new (0, _chunkWQWNPAYQcjs.InsufficientFundsError)(
648
+ err instanceof Error ? err.message : "Insufficient funds for payment.",
649
+ { cause: err }
650
+ );
651
+ }
652
+ throw _nullishCoalesce(_chunkWQWNPAYQcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
653
+ }
654
+ },
655
+ async confirm(ref, minConfirmations) {
656
+ try {
657
+ const receipt = await publicClient.waitForTransactionReceipt({
658
+ hash: ref,
659
+ confirmations: minConfirmations
660
+ });
661
+ return { height: receipt.blockNumber.toString() };
662
+ } catch (err) {
663
+ throw new (0, _chunkWQWNPAYQcjs.ConfirmationTimeoutError)(
664
+ `EVM tx ${ref} did not reach ${minConfirmations} confirmation(s) in time.`,
665
+ { cause: err }
666
+ );
667
+ }
668
+ },
669
+ async estimateCost(accept) {
670
+ const { decimals, symbol } = resolved.chain.nativeCurrency;
671
+ const gasLimit = accept.asset === "native" ? 21000n : 65000n;
672
+ try {
673
+ const gasPrice = await publicClient.getGasPrice();
674
+ return _chunkWQWNPAYQcjs.nativeCost.call(void 0, {
675
+ symbol,
676
+ decimals,
677
+ fee: gasPrice * gasLimit,
678
+ basis: "estimated",
679
+ detail: `~${gasLimit} gas @ ${gasPrice} wei/gas`
680
+ });
681
+ } catch (e10) {
682
+ const gasPrice = 5000000000n;
683
+ return _chunkWQWNPAYQcjs.nativeCost.call(void 0, {
684
+ symbol,
685
+ decimals,
686
+ fee: gasPrice * gasLimit,
687
+ basis: "heuristic",
688
+ detail: `~${gasLimit} gas @ assumed 5 gwei (live gas price unavailable)`
689
+ });
690
+ }
691
+ },
692
+ async verify(ref, accept) {
693
+ return verifyEvm({
694
+ publicClient,
695
+ txHash: ref,
696
+ accept,
697
+ minConfirmations: accept.extra.minConfirmations
698
+ });
699
+ }
700
+ };
701
+ }
702
+ function isViemInsufficientFunds(err) {
703
+ if (err instanceof _viem.BaseError) {
704
+ return Boolean(err.walk((e) => e instanceof Error && e.name === "InsufficientFundsError"));
705
+ }
706
+ return err instanceof Error && err.name === "InsufficientFundsError";
707
+ }
708
+
709
+ // src/drivers/index.ts
710
+ registerDriver(evmDriver);
711
+ var loaders = {
712
+ solana: async () => {
713
+ let mod;
714
+ try {
715
+ mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./solana-F7H4YDW5.cjs")));
716
+ } catch (cause) {
717
+ throw new (0, _chunkWQWNPAYQcjs.MissingDriverError)(
718
+ `Solana selected, but its packages aren't installed. Run: npm install @solana/web3.js @solana/spl-token bs58`,
719
+ { cause }
720
+ );
721
+ }
722
+ registerDriver(mod.solanaDriver);
723
+ },
724
+ ton: async () => {
725
+ let mod;
726
+ try {
727
+ mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./ton-E5RLUPD2.cjs")));
728
+ } catch (cause) {
729
+ throw new (0, _chunkWQWNPAYQcjs.MissingDriverError)(
730
+ `TON selected, but its packages aren't installed. Run: npm install @ton/ton @ton/core @ton/crypto`,
731
+ { cause }
732
+ );
733
+ }
734
+ registerDriver(mod.tonDriver);
735
+ },
736
+ stellar: async () => {
737
+ let mod;
738
+ try {
739
+ mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./stellar-BPPQTLNI.cjs")));
740
+ } catch (cause) {
741
+ throw new (0, _chunkWQWNPAYQcjs.MissingDriverError)(
742
+ `Stellar selected, but its package isn't installed. Run: npm install @stellar/stellar-sdk`,
743
+ { cause }
744
+ );
745
+ }
746
+ registerDriver(mod.stellarDriver);
747
+ },
748
+ xrpl: async () => {
749
+ let mod;
750
+ try {
751
+ mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./xrpl-6NRFT5CA.cjs")));
752
+ } catch (cause) {
753
+ throw new (0, _chunkWQWNPAYQcjs.MissingDriverError)(
754
+ `XRPL selected, but its package isn't installed. Run: npm install xrpl`,
755
+ { cause }
756
+ );
757
+ }
758
+ registerDriver(mod.xrplDriver);
759
+ },
760
+ tron: async () => {
761
+ let mod;
762
+ try {
763
+ mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./tron-3UDH7KGF.cjs")));
764
+ } catch (cause) {
765
+ throw new (0, _chunkWQWNPAYQcjs.MissingDriverError)(
766
+ `Tron selected, but its package isn't installed. Run: npm install tronweb`,
767
+ { cause }
768
+ );
769
+ }
770
+ registerDriver(mod.tronDriver);
771
+ },
772
+ sui: async () => {
773
+ let mod;
774
+ try {
775
+ mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./sui-XV4YYSGV.cjs")));
776
+ } catch (cause) {
777
+ throw new (0, _chunkWQWNPAYQcjs.MissingDriverError)(
778
+ `Sui selected, but its package isn't installed. Run: npm install @mysten/sui`,
779
+ { cause }
780
+ );
781
+ }
782
+ registerDriver(mod.suiDriver);
783
+ },
784
+ near: async () => {
785
+ let mod;
786
+ try {
787
+ mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./near-4P5XNMMB.cjs")));
788
+ } catch (cause) {
789
+ throw new (0, _chunkWQWNPAYQcjs.MissingDriverError)(
790
+ `NEAR selected, but its package isn't installed. Run: npm install near-api-js`,
791
+ { cause }
792
+ );
793
+ }
794
+ registerDriver(mod.nearDriver);
795
+ }
796
+ };
797
+ var inFlight = /* @__PURE__ */ new Map();
798
+ async function ensureDriver(family) {
799
+ if (isRegistered(family)) return;
800
+ const load = loaders[family];
801
+ if (!load) return;
802
+ let pending = inFlight.get(family);
803
+ if (!pending) {
804
+ pending = load();
805
+ inFlight.set(family, pending);
806
+ }
807
+ try {
808
+ await pending;
809
+ } catch (err) {
810
+ inFlight.delete(family);
811
+ throw err;
812
+ }
813
+ }
814
+ async function resolveNetwork2(opts) {
815
+ await ensureDriver(familyForChain(opts.chain));
816
+ return resolveNetwork(opts);
817
+ }
818
+
819
+ // src/policy.ts
820
+ var ALLOW = { allowed: true };
821
+ var deny = (reason) => ({ allowed: false, reason });
822
+ function hostMatches(host, pattern) {
823
+ if (pattern.startsWith("*.")) {
824
+ const suffix = pattern.slice(1);
825
+ return host === pattern.slice(2) || host.endsWith(suffix);
826
+ }
827
+ return host === pattern;
828
+ }
829
+ function chainMatches(intent, allowed) {
830
+ if (typeof allowed === "string") {
831
+ if (typeof intent.chain === "string" && intent.chain === allowed) return true;
832
+ return false;
833
+ }
834
+ const id = "id" in allowed ? allowed.id : void 0;
835
+ return id !== void 0 && intent.network === `eip155:${id}`;
836
+ }
837
+ function evaluatePolicy(intent, policy, spentForAssetBase) {
838
+ if (!policy) return ALLOW;
839
+ if (policy.chains && !policy.chains.some((c) => chainMatches(intent, c))) {
840
+ return deny(
841
+ `chain ${intent.network} is not in the allowed set (policy.chains).`
842
+ );
843
+ }
844
+ if (policy.hosts && !policy.hosts.some((h) => hostMatches(intent.host, h))) {
845
+ return deny(`host ${intent.host} is not in the allowed set (policy.hosts).`);
846
+ }
847
+ if (!intent.recognized && !policy.allowUnknownTokens) {
848
+ return deny(
849
+ `asset ${intent.asset} on ${intent.network} isn't a token the SDK can price; refusing to pay it on trust. Set policy.allowUnknownTokens to override.`
850
+ );
851
+ }
852
+ if (policy.tokens) {
853
+ const sym = intent.recognized ? intent.symbol : void 0;
854
+ if (!sym || !policy.tokens.some((t) => t.toUpperCase() === sym.toUpperCase())) {
855
+ return deny(
856
+ `token ${_nullishCoalesce(intent.symbol, () => ( intent.asset))} is not in the allowed set (policy.tokens).`
857
+ );
858
+ }
859
+ }
860
+ if (policy.maxAmount !== void 0) {
861
+ const cap = _chunkWQWNPAYQcjs.floorUnits.call(void 0, policy.maxAmount, intent.decimals);
862
+ if (intent.amountBase > cap) {
863
+ return deny(
864
+ `payment of ${intent.amountBase} base units exceeds policy.maxAmount ` + `(${policy.maxAmount} ${_nullishCoalesce(intent.symbol, () => ( ""))}).`.trimEnd()
865
+ );
866
+ }
867
+ }
868
+ if (policy.maxTotal !== void 0) {
869
+ const cap = _chunkWQWNPAYQcjs.floorUnits.call(void 0, policy.maxTotal, intent.decimals);
870
+ if (spentForAssetBase + intent.amountBase > cap) {
871
+ return deny(
872
+ `this payment would push spend on ${_nullishCoalesce(intent.symbol, () => ( intent.asset))} past policy.maxTotal (${policy.maxTotal}); already spent ${spentForAssetBase} base units.`
873
+ );
874
+ }
875
+ }
876
+ return ALLOW;
877
+ }
878
+
879
+ // src/ledger.ts
880
+ var keyFor = (network, asset) => `${network}|${asset}`;
881
+ var SpendLedger = (_class = class {constructor() { _class.prototype.__init.call(this);_class.prototype.__init2.call(this); }
882
+ __init() {this.records = []}
883
+ __init2() {this.buckets = /* @__PURE__ */ new Map()}
884
+ /** Record a settled payment. `decimals` is the TRUE token decimals (for the
885
+ * per-asset running total used by maxTotal + the formatted summary). */
886
+ record(r, decimals) {
887
+ this.records.push(r);
888
+ const key = keyFor(r.network, r.asset);
889
+ const bucket = this.buckets.get(key);
890
+ if (bucket) {
891
+ bucket.total += BigInt(r.amountBase);
892
+ bucket.count += 1;
893
+ if (!bucket.symbol && r.symbol) bucket.symbol = r.symbol;
894
+ } else {
895
+ this.buckets.set(key, {
896
+ network: r.network,
897
+ asset: r.asset,
898
+ symbol: r.symbol,
899
+ decimals,
900
+ total: BigInt(r.amountBase),
901
+ count: 1
902
+ });
903
+ }
904
+ }
905
+ /** Running total (base units) already spent on this (network, asset). */
906
+ totalFor(network, asset) {
907
+ return _nullishCoalesce(_optionalChain([this, 'access', _2 => _2.buckets, 'access', _3 => _3.get, 'call', _4 => _4(keyFor(network, asset)), 'optionalAccess', _5 => _5.total]), () => ( 0n));
908
+ }
909
+ /** An immutable snapshot of all spend so far. */
910
+ summary() {
911
+ return {
912
+ count: this.records.length,
913
+ byAsset: [...this.buckets.values()].map((b) => ({
914
+ network: b.network,
915
+ asset: b.asset,
916
+ symbol: b.symbol,
917
+ decimals: b.decimals,
918
+ totalBase: b.total.toString(),
919
+ totalFormatted: _chunkWQWNPAYQcjs.formatUnits.call(void 0, b.total, b.decimals),
920
+ count: b.count
921
+ })),
922
+ records: [...this.records]
923
+ };
924
+ }
925
+ }, _class);
926
+
927
+ // src/client.ts
928
+ var PipRailClient = (_class2 = class {
929
+
930
+
931
+
932
+
933
+ // Per-asset tally of everything this client has paid (powers spent() and the
934
+ // policy's maxTotal cap).
935
+ __init3() {this.ledger = new SpendLedger()}
936
+ // Resolved lazily on first request — this is what lets Solana (and future
937
+ // families) auto-mount with no setup call.
938
+
939
+ constructor(opts) {;_class2.prototype.__init3.call(this);
940
+ this.opts = opts;
941
+ this.maxRetries = Math.max(1, _nullishCoalesce(opts.maxPaymentRetries, () => ( 3)));
942
+ this.retryTimeoutMs = _nullishCoalesce(opts.retryTimeoutMs, () => ( 3e4));
943
+ this.onEvent = _nullishCoalesce(opts.onEvent, () => ( (() => void 0)));
944
+ }
945
+ /** Emit an observability event, never letting a throwing handler break the
946
+ * payment flow (mirrors the server gate's `onPaid` isolation). */
947
+ safeEmit(event) {
948
+ try {
949
+ this.onEvent(event);
950
+ } catch (e11) {
951
+ }
952
+ }
953
+ /** Auto-mount the chain's driver, resolve the network, and bind the wallet — once. */
954
+ ensure() {
955
+ return this.bound ??= (async () => {
956
+ const net = await resolveNetwork2({
957
+ chain: this.opts.chain,
958
+ rpcUrl: this.opts.rpcUrl
959
+ });
960
+ const wallet = net.bindWallet(this.opts.wallet);
961
+ return { net, wallet };
962
+ })();
963
+ }
964
+ /** GET that auto-handles 402. Pass a full URL to any x402-gated endpoint. */
965
+ get(url, init) {
966
+ return this.fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: "GET" });
967
+ }
968
+ /**
969
+ * POST that auto-handles 402.
970
+ *
971
+ * `body` can be a string/FormData/URLSearchParams/ArrayBuffer/Blob (sent
972
+ * as-is) or a plain object (serialised as JSON).
973
+ */
974
+ post(url, body, init) {
975
+ const headers = new Headers(_optionalChain([init, 'optionalAccess', _6 => _6.headers]));
976
+ let payload;
977
+ if (body === void 0 || body === null) {
978
+ payload = void 0;
979
+ } else if (isReplayableBodyInit(body)) {
980
+ payload = body;
981
+ } else if (typeof body === "object") {
982
+ payload = JSON.stringify(body);
983
+ if (!headers.has("content-type")) {
984
+ headers.set("content-type", "application/json");
985
+ }
986
+ } else {
987
+ payload = String(body);
988
+ }
989
+ return this.fetch(url, {
990
+ ..._nullishCoalesce(init, () => ( {})),
991
+ method: "POST",
992
+ headers,
993
+ body: payload
994
+ });
995
+ }
996
+ /**
997
+ * Price a gated URL WITHOUT paying. Does the initial request, and if it's a
998
+ * 402, returns a {@link PipRailQuote} — the amount (in the token's TRUE
999
+ * decimals), token, chain, recipient, and whether the configured `policy`
1000
+ * would allow it. Returns `null` when the URL isn't payment-gated (no 402).
1001
+ *
1002
+ * This is what lets an agent (or its planner) decide *before* spending —
1003
+ * "0.05 USDC on Base, within budget → pay it." No funds move.
1004
+ */
1005
+ async quote(url, init) {
1006
+ const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _7 => _7.method]), () => ( "GET")) });
1007
+ if (res.status !== 402) return null;
1008
+ const { quote } = await this.resolveChallenge(url, res);
1009
+ return quote;
1010
+ }
1011
+ /**
1012
+ * Estimate the network fee (gas) to pay a gated URL — WITHOUT paying. Returns
1013
+ * the {@link PipRailQuote} (what the payment is) plus a {@link CostEstimate}
1014
+ * (the gas it will burn, in the chain's NATIVE coin), so an agent can budget
1015
+ * the *total* — payment + gas — before any funds move. Returns `null` when the
1016
+ * URL isn't payment-gated (no 402).
1017
+ *
1018
+ * The estimate is best-effort and labelled (`cost.basis`): live-RPC ('estimated')
1019
+ * where cheap (EVM gas price, XRPL fee), a typical-cost constant ('heuristic')
1020
+ * otherwise. It never throws for a transient RPC issue. Gas is in the native
1021
+ * coin (ETH/SOL/TON/XLM/XRP/TRX), distinct from the payment token — most useful
1022
+ * on Tron, where a USD₮ transfer can cost real TRX.
1023
+ */
1024
+ async estimateCost(url, init) {
1025
+ const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _8 => _8.method]), () => ( "GET")) });
1026
+ if (res.status !== 402) return null;
1027
+ const { net, accept, quote } = await this.resolveChallenge(url, res);
1028
+ const cost = await net.estimateCost(accept);
1029
+ return { quote, cost };
1030
+ }
1031
+ /** Aggregated snapshot of every payment this client has settled — total
1032
+ * count, cumulative spend per token, and the individual records. */
1033
+ spent() {
1034
+ return this.ledger.summary();
1035
+ }
1036
+ /**
1037
+ * Lower-level: drive any HTTP method through the 402 flow.
1038
+ *
1039
+ * `init.body` (if any) must be replayable — the SDK may send the request
1040
+ * twice (once to fetch the 402, once with the proof attached). One-shot
1041
+ * streams throw `NonReplayableBodyError`.
1042
+ */
1043
+ async fetch(url, init) {
1044
+ const body = _optionalChain([init, 'optionalAccess', _9 => _9.body]);
1045
+ if (body !== void 0 && body !== null && !isReplayableBodyInit(body)) {
1046
+ throw new (0, _chunkWQWNPAYQcjs.NonReplayableBodyError)(
1047
+ "fetch(): init.body is not replayable. Pass a string, FormData, URLSearchParams, ArrayBuffer, or Blob \u2014 not a ReadableStream."
1048
+ );
1049
+ }
1050
+ const firstResponse = await fetch(url, init);
1051
+ if (firstResponse.status !== 402) return firstResponse;
1052
+ const { net, wallet, accept, challenge, quote } = await this.resolveChallenge(
1053
+ url,
1054
+ firstResponse
1055
+ );
1056
+ this.safeEmit({ kind: "payment-required", challenge, accept });
1057
+ await this.authorize(quote);
1058
+ const ref = await this.payAndConfirm(net, wallet, accept);
1059
+ const response = await this.retryWithProof(url, init, accept, ref);
1060
+ this.recordSpend(quote, ref);
1061
+ return response;
1062
+ }
1063
+ /* ------------------------- internals ------------------------- */
1064
+ /**
1065
+ * From a confirmed-402 response: parse the challenge, mount + bind the
1066
+ * network, pick the accept the client can pay, and build its quote. Shared by
1067
+ * `quote()` (read-only) and `fetch()` (which then authorises + pays).
1068
+ */
1069
+ async resolveChallenge(url, response) {
1070
+ const challenge = await parseChallenge(response);
1071
+ if (!challenge) {
1072
+ throw new (0, _chunkWQWNPAYQcjs.InvalidEnvelopeError)(
1073
+ "402 response did not include a parseable x402 challenge."
1074
+ );
1075
+ }
1076
+ const { net, wallet } = await this.ensure();
1077
+ const candidates = challenge.accepts.filter(
1078
+ (a) => a.scheme === "onchain-proof" && net.supports(a.network)
1079
+ );
1080
+ if (candidates.length === 0) {
1081
+ const networks = challenge.accepts.map((a) => a.network).join(", ");
1082
+ throw new (0, _chunkWQWNPAYQcjs.NoCompatibleAcceptError)(
1083
+ `No accepts[] entry for ${net.network} (challenge offered: ${networks || "none"}).`
1084
+ );
1085
+ }
1086
+ const priced = candidates.map((accept) => ({
1087
+ accept,
1088
+ quote: this.buildQuote(net, accept, url, challenge.resource.description)
1089
+ }));
1090
+ const chosen = _nullishCoalesce(priced.find((p) => p.quote.withinPolicy), () => ( priced[0]));
1091
+ return { net, wallet, accept: chosen.accept, challenge, quote: chosen.quote };
1092
+ }
1093
+ /** Build the agent-facing quote for an accept: TRUE decimals/symbol (via the
1094
+ * driver's describeAsset) + the policy verdict + a symbol-mismatch flag. */
1095
+ buildQuote(net, accept, url, description) {
1096
+ if (!/^\d+$/.test(accept.amount)) {
1097
+ throw new (0, _chunkWQWNPAYQcjs.InvalidEnvelopeError)(
1098
+ `challenge amount "${accept.amount}" is not a base-unit integer.`
1099
+ );
1100
+ }
1101
+ const amountBase = BigInt(accept.amount);
1102
+ const described = net.describeAsset(accept.asset);
1103
+ const decimals = _nullishCoalesce(_optionalChain([described, 'optionalAccess', _10 => _10.decimals]), () => ( accept.extra.decimals));
1104
+ const symbol = _nullishCoalesce(_optionalChain([described, 'optionalAccess', _11 => _11.symbol]), () => ( accept.extra.symbol));
1105
+ const amountFormatted = _chunkWQWNPAYQcjs.formatUnits.call(void 0, amountBase, decimals);
1106
+ const intent = {
1107
+ host: hostOf(url),
1108
+ chain: this.opts.chain,
1109
+ network: accept.network,
1110
+ asset: accept.asset,
1111
+ amountBase,
1112
+ decimals,
1113
+ symbol,
1114
+ recognized: described != null
1115
+ };
1116
+ const decision = evaluatePolicy(
1117
+ intent,
1118
+ this.opts.policy,
1119
+ this.ledger.totalFor(accept.network, accept.asset)
1120
+ );
1121
+ const serverSymbol = accept.extra.symbol;
1122
+ const symbolMismatch = intent.recognized && !!serverSymbol && !!symbol && serverSymbol.toUpperCase() !== symbol.toUpperCase();
1123
+ return {
1124
+ url,
1125
+ chain: this.opts.chain,
1126
+ network: accept.network,
1127
+ asset: accept.asset,
1128
+ amount: accept.amount,
1129
+ amountFormatted,
1130
+ decimals,
1131
+ symbol,
1132
+ payTo: accept.payTo,
1133
+ ...description ? { description } : {},
1134
+ maxTimeoutSeconds: accept.maxTimeoutSeconds,
1135
+ recognized: intent.recognized,
1136
+ symbolMismatch,
1137
+ withinPolicy: decision.allowed,
1138
+ ...decision.reason ? { policyReason: decision.reason } : {}
1139
+ };
1140
+ }
1141
+ /** Enforce the spend policy and the onBeforePay hook — both refuse by
1142
+ * throwing PaymentDeclinedError, before any funds move. */
1143
+ async authorize(quote) {
1144
+ if (!quote.withinPolicy) {
1145
+ throw new (0, _chunkWQWNPAYQcjs.PaymentDeclinedError)(
1146
+ `Payment refused by policy: ${_nullishCoalesce(quote.policyReason, () => ( "not allowed"))}`
1147
+ );
1148
+ }
1149
+ const hook = this.opts.onBeforePay;
1150
+ if (!hook) return;
1151
+ let approved;
1152
+ try {
1153
+ approved = await hook(quote);
1154
+ } catch (err) {
1155
+ throw new (0, _chunkWQWNPAYQcjs.PaymentDeclinedError)("onBeforePay threw \u2014 refusing to pay.", {
1156
+ cause: err
1157
+ });
1158
+ }
1159
+ if (!approved) {
1160
+ throw new (0, _chunkWQWNPAYQcjs.PaymentDeclinedError)(
1161
+ `onBeforePay declined ${quote.amountFormatted} ${_nullishCoalesce(quote.symbol, () => ( ""))}`.trimEnd() + ` on ${quote.network}.`
1162
+ );
1163
+ }
1164
+ }
1165
+ /** Record a settled payment in the ledger (true decimals for the running total). */
1166
+ recordSpend(quote, ref) {
1167
+ this.ledger.record(
1168
+ {
1169
+ url: quote.url,
1170
+ host: hostOf(quote.url),
1171
+ network: quote.network,
1172
+ asset: quote.asset,
1173
+ amountBase: quote.amount,
1174
+ amountFormatted: quote.amountFormatted,
1175
+ ...quote.symbol ? { symbol: quote.symbol } : {},
1176
+ ref,
1177
+ at: (/* @__PURE__ */ new Date()).toISOString()
1178
+ },
1179
+ quote.decimals
1180
+ );
1181
+ }
1182
+ async payAndConfirm(net, wallet, accept) {
1183
+ if (!net.supports(accept.network)) {
1184
+ throw new (0, _chunkWQWNPAYQcjs.WrongChainError)(
1185
+ `Challenge expects ${accept.network} but client is on ${net.network}.`
1186
+ );
1187
+ }
1188
+ const ref = await net.send(wallet, accept);
1189
+ this.safeEmit({ kind: "payment-broadcast", ref });
1190
+ const { height } = await net.confirm(ref, _nullishCoalesce(accept.extra.minConfirmations, () => ( 1)));
1191
+ this.safeEmit({
1192
+ kind: "payment-confirmed",
1193
+ ref,
1194
+ blockNumber: BigInt(height)
1195
+ });
1196
+ return ref;
1197
+ }
1198
+ async retryWithProof(url, originalInit, accept, ref) {
1199
+ const signature = {
1200
+ x402Version: 2,
1201
+ accepted: accept,
1202
+ payload: { nonce: accept.extra.nonce, txHash: ref }
1203
+ };
1204
+ const headers = new Headers(_optionalChain([originalInit, 'optionalAccess', _12 => _12.headers]));
1205
+ headers.set(HEADER_SIGNATURE, buildSignatureHeader(signature));
1206
+ let lastResponse = null;
1207
+ let lastReason = null;
1208
+ for (let attempt = 0; attempt < this.maxRetries; attempt += 1) {
1209
+ if (attempt > 0) {
1210
+ await new Promise((r) => setTimeout(r, Math.min(2e3, 400 * 2 ** (attempt - 1))));
1211
+ }
1212
+ const timeoutController = new AbortController();
1213
+ const timeoutId = setTimeout(
1214
+ () => timeoutController.abort(),
1215
+ this.retryTimeoutMs
1216
+ );
1217
+ const signal = _optionalChain([originalInit, 'optionalAccess', _13 => _13.signal]) && typeof AbortSignal.any === "function" ? AbortSignal.any([timeoutController.signal, originalInit.signal]) : timeoutController.signal;
1218
+ try {
1219
+ lastResponse = await fetch(url, {
1220
+ ..._nullishCoalesce(originalInit, () => ( {})),
1221
+ headers,
1222
+ signal
1223
+ });
1224
+ } catch (err) {
1225
+ if (timeoutController.signal.aborted) {
1226
+ throw new (0, _chunkWQWNPAYQcjs.PaymentTimeoutError)(
1227
+ `Server did not respond within ${this.retryTimeoutMs}ms after on-chain payment ${ref} confirmed.`,
1228
+ { cause: err }
1229
+ );
1230
+ }
1231
+ throw err;
1232
+ } finally {
1233
+ clearTimeout(timeoutId);
1234
+ }
1235
+ if (lastResponse.status !== 402) {
1236
+ const receipt = parseReceipt(lastResponse);
1237
+ this.safeEmit({ kind: "payment-settled", receipt });
1238
+ return lastResponse;
1239
+ }
1240
+ lastReason = await _asyncNullishCoalesce(await readInvalidReason(lastResponse), async () => ( lastReason));
1241
+ }
1242
+ const why = lastReason ? `${lastReason.error}${lastReason.detail ? ` \u2014 ${lastReason.detail}` : ""}` : "server gave no reason";
1243
+ this.safeEmit({
1244
+ kind: "payment-failed",
1245
+ reason: `server returned 402 after on-chain payment ${ref} confirmed (${why})`
1246
+ });
1247
+ throw new (0, _chunkWQWNPAYQcjs.MaxRetriesExceededError)(
1248
+ `Server still returned 402 after ${this.maxRetries} retry attempt(s) with on-chain proof ref=${ref}. Last server rejection: ${why}.`
1249
+ );
1250
+ }
1251
+ }, _class2);
1252
+ function hostOf(url) {
1253
+ try {
1254
+ return new URL(url).hostname;
1255
+ } catch (e12) {
1256
+ return url;
1257
+ }
1258
+ }
1259
+ function isReplayableBodyInit(value) {
1260
+ if (typeof value === "string") return true;
1261
+ if (value instanceof ArrayBuffer) return true;
1262
+ if (ArrayBuffer.isView(value)) return true;
1263
+ if (typeof URLSearchParams !== "undefined" && value instanceof URLSearchParams)
1264
+ return true;
1265
+ if (typeof FormData !== "undefined" && value instanceof FormData) return true;
1266
+ if (typeof Blob !== "undefined" && value instanceof Blob) return true;
1267
+ return false;
1268
+ }
1269
+ async function readInvalidReason(response) {
1270
+ try {
1271
+ const body = await response.clone().json();
1272
+ if (body && (body.status === "invalid" || typeof body.error === "string")) {
1273
+ return {
1274
+ error: typeof body.error === "string" ? body.error : "no error code",
1275
+ detail: typeof body.detail === "string" ? body.detail : ""
1276
+ };
1277
+ }
1278
+ } catch (e13) {
1279
+ }
1280
+ return null;
1281
+ }
1282
+
1283
+ // src/agent.ts
1284
+ async function readBody(res) {
1285
+ const text = await res.text();
1286
+ if (!text) return null;
1287
+ try {
1288
+ return JSON.parse(text);
1289
+ } catch (e14) {
1290
+ return text;
1291
+ }
1292
+ }
1293
+ function paymentTools(client) {
1294
+ return [
1295
+ {
1296
+ name: "piprail_quote_payment",
1297
+ description: "Get the price of an x402 payment-gated URL WITHOUT paying. Returns the amount, token, chain, recipient, and whether it is within the spend policy. Returns { gated: false } when the URL needs no payment. Call this first to decide whether a resource is worth buying.",
1298
+ parameters: {
1299
+ type: "object",
1300
+ properties: {
1301
+ url: { type: "string", description: "Full URL of the gated resource." }
1302
+ },
1303
+ required: ["url"],
1304
+ additionalProperties: false
1305
+ },
1306
+ invoke: async (args) => {
1307
+ const quote = await client.quote(String(args.url));
1308
+ return quote ? { gated: true, ...quote } : { gated: false, url: String(args.url) };
1309
+ }
1310
+ },
1311
+ {
1312
+ name: "piprail_pay_request",
1313
+ 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.",
1314
+ parameters: {
1315
+ type: "object",
1316
+ properties: {
1317
+ url: { type: "string", description: "Full URL to fetch." },
1318
+ method: { type: "string", description: "HTTP method, default 'GET'." },
1319
+ body: {
1320
+ type: ["object", "string"],
1321
+ description: "Optional request body for POST/PUT (a JSON object or a string)."
1322
+ }
1323
+ },
1324
+ required: ["url"],
1325
+ additionalProperties: false
1326
+ },
1327
+ invoke: async (args) => {
1328
+ const url = String(args.url);
1329
+ const method = (args.method ? String(args.method) : "GET").toUpperCase();
1330
+ try {
1331
+ let res;
1332
+ if (method === "GET") {
1333
+ res = await client.get(url);
1334
+ } else {
1335
+ const headers = {};
1336
+ let body;
1337
+ if (args.body !== void 0 && args.body !== null) {
1338
+ if (typeof args.body === "string") {
1339
+ body = args.body;
1340
+ } else {
1341
+ body = JSON.stringify(args.body);
1342
+ headers["content-type"] = "application/json";
1343
+ }
1344
+ }
1345
+ res = await client.fetch(url, { method, headers, body });
1346
+ }
1347
+ return {
1348
+ status: res.status,
1349
+ ok: res.ok,
1350
+ body: await readBody(res),
1351
+ receipt: parseReceipt(res)
1352
+ };
1353
+ } catch (err) {
1354
+ if (err instanceof _chunkWQWNPAYQcjs.PaymentDeclinedError) {
1355
+ return { declined: true, reason: err.message };
1356
+ }
1357
+ throw err;
1358
+ }
1359
+ }
1360
+ }
1361
+ ];
1362
+ }
1363
+
1364
+ // src/server.ts
1365
+ function toInvalidBody(result) {
1366
+ return { x402Version: 2, status: "invalid", error: result.error, detail: result.detail };
1367
+ }
1368
+ function normaliseAccepts(options) {
1369
+ if (options.accept && options.accept.length > 0) {
1370
+ if (options.chain !== void 0 || options.token !== void 0 || options.amount !== void 0) {
1371
+ throw new Error(
1372
+ "requirePayment: pass EITHER `accept: [...]` (multi-chain) OR `chain`/`token`/`amount` (single) \u2014 not both."
1373
+ );
1374
+ }
1375
+ return options.accept;
1376
+ }
1377
+ if (options.chain !== void 0 && options.token !== void 0 && options.amount !== void 0) {
1378
+ return [{ chain: options.chain, token: options.token, amount: options.amount }];
1379
+ }
1380
+ throw new Error(
1381
+ "requirePayment: provide either { chain, token, amount } or a non-empty `accept: [{ chain, token, amount }, \u2026]`."
1382
+ );
1383
+ }
1384
+ function createPaymentGate(options) {
1385
+ const minConfirmations = _nullishCoalesce(options.minConfirmations, () => ( 1));
1386
+ const maxTimeoutSeconds = _nullishCoalesce(options.maxTimeoutSeconds, () => ( 600));
1387
+ const genNonce = _nullishCoalesce(options.generateNonce, () => ( (() => globalThis.crypto.randomUUID())));
1388
+ let resolved;
1389
+ function ready() {
1390
+ return resolved ??= (async () => {
1391
+ const accepts = normaliseAccepts(options);
1392
+ return Promise.all(
1393
+ accepts.map(async (a) => {
1394
+ const net = await resolveNetwork2({ chain: a.chain, rpcUrl: _nullishCoalesce(a.rpcUrl, () => ( options.rpcUrl)) });
1395
+ const payTo = _nullishCoalesce(a.payTo, () => ( options.payTo));
1396
+ if (!payTo) {
1397
+ throw new Error(
1398
+ `requirePayment: no payTo for chain ${net.network}. Set it on the accept entry or pass a top-level payTo.`
1399
+ );
1400
+ }
1401
+ net.assertValidPayTo(payTo);
1402
+ const { asset, decimals, symbol } = net.resolveToken(a.token);
1403
+ const amountBase = _chunkWQWNPAYQcjs.parseUnits.call(void 0, a.amount, decimals);
1404
+ return { net, asset, decimals, symbol, amountBase, amountFormatted: a.amount, payTo };
1405
+ })
1406
+ );
1407
+ })();
1408
+ }
1409
+ const hasCustomStore = Boolean(options.isUsed || options.markUsed);
1410
+ const localUsed = /* @__PURE__ */ new Set();
1411
+ async function claimTx(ref) {
1412
+ if (hasCustomStore) {
1413
+ return options.isUsed ? Boolean(await options.isUsed(ref)) : false;
1414
+ }
1415
+ const key = ref.toLowerCase();
1416
+ if (localUsed.has(key)) return true;
1417
+ localUsed.add(key);
1418
+ return false;
1419
+ }
1420
+ async function settleTx(ref, ok) {
1421
+ if (hasCustomStore) {
1422
+ if (ok && options.markUsed) await options.markUsed(ref);
1423
+ return;
1424
+ }
1425
+ if (!ok) localUsed.delete(ref.toLowerCase());
1426
+ }
1427
+ function buildAccept(s, nonce) {
1428
+ return {
1429
+ scheme: "onchain-proof",
1430
+ network: s.net.network,
1431
+ amount: s.amountBase.toString(),
1432
+ asset: s.asset,
1433
+ payTo: s.payTo,
1434
+ maxTimeoutSeconds,
1435
+ extra: {
1436
+ nonce,
1437
+ decimals: s.decimals,
1438
+ minConfirmations,
1439
+ amountFormatted: s.amountFormatted,
1440
+ ...s.symbol ? { symbol: s.symbol } : {}
1441
+ }
1442
+ };
1443
+ }
1444
+ async function challenge(resourceUrl = "") {
1445
+ const specs = await ready();
1446
+ const nonce = genNonce();
1447
+ const challenge2 = {
1448
+ x402Version: 2,
1449
+ error: null,
1450
+ resource: {
1451
+ url: resourceUrl,
1452
+ ...options.description ? { description: options.description } : {}
1453
+ },
1454
+ accepts: specs.map((s) => buildAccept(s, nonce))
1455
+ };
1456
+ return { challenge: challenge2, requiredHeader: buildChallengeHeader(challenge2) };
1457
+ }
1458
+ async function asChallenge() {
1459
+ const { challenge: c, requiredHeader } = await challenge();
1460
+ return { kind: "challenge", challenge: c, requiredHeader, statusCode: 402 };
1461
+ }
1462
+ async function verify(paymentSignature) {
1463
+ const raw = normaliseHeader(paymentSignature);
1464
+ if (!raw) return asChallenge();
1465
+ const sig = parseSignatureHeader(raw);
1466
+ if (!sig || !sig.accepted || typeof sig.accepted.network !== "string" || typeof sig.accepted.asset !== "string") {
1467
+ return asChallenge();
1468
+ }
1469
+ const specs = await ready();
1470
+ const spec = specs.find(
1471
+ (s) => s.net.network === sig.accepted.network && s.asset === sig.accepted.asset
1472
+ );
1473
+ if (!spec) {
1474
+ return {
1475
+ kind: "invalid",
1476
+ error: "transfer_not_found",
1477
+ detail: `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(", ")}).`,
1478
+ statusCode: 402
1479
+ };
1480
+ }
1481
+ const ref = sig.payload.txHash;
1482
+ if (await claimTx(ref)) {
1483
+ return {
1484
+ kind: "invalid",
1485
+ error: "tx_already_used",
1486
+ detail: `Proof ${ref} was already redeemed.`,
1487
+ statusCode: 402
1488
+ };
1489
+ }
1490
+ const result = await spec.net.verify(ref, buildAccept(spec, sig.payload.nonce));
1491
+ if (!result.ok) {
1492
+ await settleTx(ref, false);
1493
+ return {
1494
+ kind: "invalid",
1495
+ error: result.error,
1496
+ detail: result.detail,
1497
+ statusCode: 402
1498
+ };
1499
+ }
1500
+ await settleTx(ref, true);
1501
+ if (options.onPaid) {
1502
+ try {
1503
+ options.onPaid(result.receipt);
1504
+ } catch (e15) {
1505
+ }
1506
+ }
1507
+ return {
1508
+ kind: "paid",
1509
+ receipt: result.receipt,
1510
+ receiptHeader: buildReceiptHeader(result.receipt)
1511
+ };
1512
+ }
1513
+ return { challenge, verify };
1514
+ }
1515
+ function requirePayment(options) {
1516
+ const gate = createPaymentGate(options);
1517
+ return async (req, res, next) => {
1518
+ let result;
1519
+ try {
1520
+ result = await gate.verify(req.headers[HEADER_SIGNATURE]);
1521
+ } catch (err) {
1522
+ next(err);
1523
+ return;
1524
+ }
1525
+ switch (result.kind) {
1526
+ case "paid":
1527
+ res.setHeader(HEADER_RESPONSE, result.receiptHeader);
1528
+ return next();
1529
+ case "challenge":
1530
+ res.setHeader(HEADER_REQUIRED, result.requiredHeader);
1531
+ res.status(result.statusCode);
1532
+ res.json(result.challenge);
1533
+ return;
1534
+ case "invalid":
1535
+ res.status(result.statusCode);
1536
+ res.json(toInvalidBody(result));
1537
+ return;
1538
+ }
1539
+ };
1540
+ }
1541
+ function normaliseHeader(value) {
1542
+ if (Array.isArray(value)) return value[0];
1543
+ return value;
1544
+ }
1545
+
1546
+ // src/drivers/evm/exact.ts
1547
+ var EXACT_NETWORK_SLUGS = {
1548
+ ethereum: 1,
1549
+ base: 8453,
1550
+ "base-sepolia": 84532,
1551
+ arbitrum: 42161,
1552
+ optimism: 10,
1553
+ polygon: 137,
1554
+ avalanche: 43114
1555
+ };
1556
+ function chainIdForExactNetwork(slug) {
1557
+ return _nullishCoalesce(EXACT_NETWORK_SLUGS[slug], () => ( null));
1558
+ }
1559
+ var EIP3009_TYPES = {
1560
+ TransferWithAuthorization: [
1561
+ { name: "from", type: "address" },
1562
+ { name: "to", type: "address" },
1563
+ { name: "value", type: "uint256" },
1564
+ { name: "validAfter", type: "uint256" },
1565
+ { name: "validBefore", type: "uint256" },
1566
+ { name: "nonce", type: "bytes32" }
1567
+ ]
1568
+ };
1569
+ function parseExactRequirements(body) {
1570
+ if (!body || typeof body !== "object") return null;
1571
+ const accepts = body.accepts;
1572
+ if (!Array.isArray(accepts)) return null;
1573
+ const out = [];
1574
+ for (const raw of accepts) {
1575
+ if (!raw || typeof raw !== "object") continue;
1576
+ const a = raw;
1577
+ if (a.scheme !== "exact") continue;
1578
+ const amount = _nullishCoalesce(a.maxAmountRequired, () => ( a.amount));
1579
+ if (typeof a.network !== "string" || typeof amount !== "string" || typeof a.asset !== "string" || typeof a.payTo !== "string") {
1580
+ continue;
1581
+ }
1582
+ out.push({
1583
+ scheme: "exact",
1584
+ network: a.network,
1585
+ maxAmountRequired: amount,
1586
+ asset: a.asset,
1587
+ payTo: a.payTo,
1588
+ maxTimeoutSeconds: typeof a.maxTimeoutSeconds === "number" ? a.maxTimeoutSeconds : 600,
1589
+ ...a.extra && typeof a.extra === "object" ? { extra: a.extra } : {},
1590
+ ...typeof a.description === "string" ? { description: a.description } : {},
1591
+ ...typeof a.resource === "string" ? { resource: a.resource } : {}
1592
+ });
1593
+ }
1594
+ return out;
1595
+ }
1596
+ async function buildExactAuthorization(params) {
1597
+ const { account, accept, chainId, now, nonce } = params;
1598
+ if (!account.signTypedData) {
1599
+ throw new Error("buildExactAuthorization: the account cannot sign EIP-712 typed data.");
1600
+ }
1601
+ const authorization = {
1602
+ from: account.address,
1603
+ to: accept.payTo,
1604
+ value: accept.maxAmountRequired,
1605
+ validAfter: "0",
1606
+ validBefore: String(now + accept.maxTimeoutSeconds),
1607
+ nonce
1608
+ };
1609
+ const signature = await account.signTypedData({
1610
+ domain: {
1611
+ name: _nullishCoalesce(_optionalChain([accept, 'access', _14 => _14.extra, 'optionalAccess', _15 => _15.name]), () => ( "USD Coin")),
1612
+ version: _nullishCoalesce(_optionalChain([accept, 'access', _16 => _16.extra, 'optionalAccess', _17 => _17.version]), () => ( "2")),
1613
+ chainId,
1614
+ verifyingContract: accept.asset
1615
+ },
1616
+ types: EIP3009_TYPES,
1617
+ primaryType: "TransferWithAuthorization",
1618
+ message: {
1619
+ from: authorization.from,
1620
+ to: authorization.to,
1621
+ value: BigInt(authorization.value),
1622
+ validAfter: BigInt(authorization.validAfter),
1623
+ validBefore: BigInt(authorization.validBefore),
1624
+ nonce: authorization.nonce
1625
+ }
1626
+ });
1627
+ return { authorization, signature };
1628
+ }
1629
+ function base64(str) {
1630
+ if (typeof btoa === "function") return btoa(str);
1631
+ if (typeof Buffer !== "undefined") return Buffer.from(str, "utf8").toString("base64");
1632
+ throw new Error("No base64 encoder available in this runtime.");
1633
+ }
1634
+ function encodeXPaymentHeader(input) {
1635
+ const payload = {
1636
+ x402Version: _nullishCoalesce(input.x402Version, () => ( 1)),
1637
+ scheme: "exact",
1638
+ network: input.network,
1639
+ payload: { signature: input.signature, authorization: input.authorization }
1640
+ };
1641
+ return base64(JSON.stringify(payload));
1642
+ }
1643
+
1644
+
1645
+
1646
+
1647
+
1648
+
1649
+
1650
+
1651
+
1652
+
1653
+
1654
+
1655
+
1656
+
1657
+
1658
+
1659
+
1660
+
1661
+
1662
+
1663
+
1664
+
1665
+
1666
+
1667
+
1668
+
1669
+
1670
+
1671
+
1672
+
1673
+
1674
+
1675
+
1676
+
1677
+
1678
+
1679
+
1680
+
1681
+ exports.CHAINS = CHAINS; exports.ConfirmationTimeoutError = _chunkWQWNPAYQcjs.ConfirmationTimeoutError; exports.EIP3009_TYPES = EIP3009_TYPES; exports.EXACT_NETWORK_SLUGS = EXACT_NETWORK_SLUGS; exports.InsufficientFundsError = _chunkWQWNPAYQcjs.InsufficientFundsError; exports.InvalidEnvelopeError = _chunkWQWNPAYQcjs.InvalidEnvelopeError; exports.MaxRetriesExceededError = _chunkWQWNPAYQcjs.MaxRetriesExceededError; exports.MissingDriverError = _chunkWQWNPAYQcjs.MissingDriverError; exports.NoCompatibleAcceptError = _chunkWQWNPAYQcjs.NoCompatibleAcceptError; exports.NonReplayableBodyError = _chunkWQWNPAYQcjs.NonReplayableBodyError; exports.PaymentDeclinedError = _chunkWQWNPAYQcjs.PaymentDeclinedError; exports.PaymentTimeoutError = _chunkWQWNPAYQcjs.PaymentTimeoutError; exports.PipRailClient = PipRailClient; exports.PipRailError = _chunkWQWNPAYQcjs.PipRailError; exports.UnknownTokenError = _chunkWQWNPAYQcjs.UnknownTokenError; exports.UnsupportedNetworkError = _chunkWQWNPAYQcjs.UnsupportedNetworkError; exports.WrongChainError = _chunkWQWNPAYQcjs.WrongChainError; exports.WrongFamilyError = _chunkWQWNPAYQcjs.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.registerDriver = registerDriver; exports.requirePayment = requirePayment; exports.resolveChain = resolveChain; exports.toInsufficientFundsError = _chunkWQWNPAYQcjs.toInsufficientFundsError; exports.toInvalidBody = toInvalidBody;