@dexterai/x402 3.0.1 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,954 +1 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/adapters/index.ts
31
- var adapters_exports = {};
32
- __export(adapters_exports, {
33
- ARBITRUM_ONE: () => ARBITRUM_ONE,
34
- AVALANCHE: () => AVALANCHE,
35
- BASE_MAINNET: () => BASE_MAINNET,
36
- BASE_SEPOLIA: () => BASE_SEPOLIA,
37
- BSC_MAINNET: () => BSC_MAINNET,
38
- BSC_STABLECOIN_ADDRESSES: () => BSC_STABLECOIN_ADDRESSES,
39
- BSC_USDC: () => BSC_USDC,
40
- BSC_USDT: () => BSC_USDT,
41
- ETHEREUM_MAINNET: () => ETHEREUM_MAINNET,
42
- EvmAdapter: () => EvmAdapter,
43
- OPTIMISM: () => OPTIMISM,
44
- PERMIT2_ADDRESS: () => PERMIT2_ADDRESS,
45
- POLYGON: () => POLYGON,
46
- SKALE_BASE: () => SKALE_BASE,
47
- SKALE_BASE_SEPOLIA: () => SKALE_BASE_SEPOLIA,
48
- SOLANA_DEVNET: () => SOLANA_DEVNET,
49
- SOLANA_MAINNET: () => SOLANA_MAINNET,
50
- SOLANA_TESTNET: () => SOLANA_TESTNET,
51
- SolanaAdapter: () => SolanaAdapter,
52
- USDC_ADDRESSES: () => USDC_ADDRESSES,
53
- X402_EXACT_PERMIT2_PROXY: () => X402_EXACT_PERMIT2_PROXY,
54
- createDefaultAdapters: () => createDefaultAdapters,
55
- createEvmAdapter: () => createEvmAdapter,
56
- createSolanaAdapter: () => createSolanaAdapter,
57
- findAdapter: () => findAdapter,
58
- isEvmWallet: () => isEvmWallet,
59
- isKnownUSDC: () => isKnownUSDC,
60
- isSolanaWallet: () => isSolanaWallet
61
- });
62
- module.exports = __toCommonJS(adapters_exports);
63
-
64
- // src/adapters/solana.ts
65
- var import_web3 = require("@solana/web3.js");
66
- var import_spl_token = require("@solana/spl-token");
67
- var SOLANA_MAINNET = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
68
- var SOLANA_DEVNET = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1";
69
- var SOLANA_TESTNET = "solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z";
70
- var DEFAULT_RPC_URLS = {
71
- [SOLANA_MAINNET]: "https://api.dexter.cash/api/solana/rpc",
72
- [SOLANA_DEVNET]: "https://api.devnet.solana.com",
73
- [SOLANA_TESTNET]: "https://api.testnet.solana.com"
74
- };
75
- var DEFAULT_COMPUTE_UNIT_LIMIT = 12e3;
76
- var DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS = 1;
77
- function isSolanaWallet(wallet) {
78
- if (!wallet || typeof wallet !== "object") return false;
79
- const w = wallet;
80
- return "publicKey" in w && "signTransaction" in w && typeof w.signTransaction === "function";
81
- }
82
- var SolanaAdapter = class {
83
- name = "Solana";
84
- networks = [SOLANA_MAINNET, SOLANA_DEVNET, SOLANA_TESTNET];
85
- config;
86
- log;
87
- constructor(config = {}) {
88
- this.config = config;
89
- this.log = config.verbose ? console.log.bind(console, "[x402:solana]") : () => {
90
- };
91
- }
92
- canHandle(network) {
93
- if (this.networks.includes(network)) return true;
94
- if (network === "solana") return true;
95
- if (network === "solana-devnet") return true;
96
- if (network === "solana-testnet") return true;
97
- if (network.startsWith("solana:")) return true;
98
- return false;
99
- }
100
- getDefaultRpcUrl(network) {
101
- if (this.config.rpcUrls?.[network]) {
102
- return this.config.rpcUrls[network];
103
- }
104
- if (DEFAULT_RPC_URLS[network]) {
105
- return DEFAULT_RPC_URLS[network];
106
- }
107
- if (network === "solana") return DEFAULT_RPC_URLS[SOLANA_MAINNET];
108
- if (network === "solana-devnet") return DEFAULT_RPC_URLS[SOLANA_DEVNET];
109
- if (network === "solana-testnet") return DEFAULT_RPC_URLS[SOLANA_TESTNET];
110
- return DEFAULT_RPC_URLS[SOLANA_MAINNET];
111
- }
112
- getAddress(wallet) {
113
- if (!isSolanaWallet(wallet)) return null;
114
- return wallet.publicKey?.toBase58() ?? null;
115
- }
116
- isConnected(wallet) {
117
- if (!isSolanaWallet(wallet)) return false;
118
- return wallet.publicKey !== null;
119
- }
120
- async getBalance(accept, wallet, rpcUrl) {
121
- if (!isSolanaWallet(wallet) || !wallet.publicKey) {
122
- return 0;
123
- }
124
- const url = rpcUrl || this.getDefaultRpcUrl(accept.network);
125
- const connection = new import_web3.Connection(url, "confirmed");
126
- const userPubkey = new import_web3.PublicKey(wallet.publicKey.toBase58());
127
- const mintPubkey = new import_web3.PublicKey(accept.asset);
128
- try {
129
- const mintInfo = await connection.getAccountInfo(mintPubkey, "confirmed");
130
- const programId = mintInfo?.owner.toBase58() === import_spl_token.TOKEN_2022_PROGRAM_ID.toBase58() ? import_spl_token.TOKEN_2022_PROGRAM_ID : import_spl_token.TOKEN_PROGRAM_ID;
131
- const ata = await (0, import_spl_token.getAssociatedTokenAddress)(
132
- mintPubkey,
133
- userPubkey,
134
- false,
135
- programId
136
- );
137
- const account = await (0, import_spl_token.getAccount)(connection, ata, void 0, programId);
138
- const decimals = accept.extra?.decimals ?? 6;
139
- return Number(account.amount) / Math.pow(10, decimals);
140
- } catch (err) {
141
- if (err && typeof err === "object" && "name" in err && (err.name === "TokenAccountNotFoundError" || err.name === "TokenInvalidAccountOwnerError")) {
142
- return 0;
143
- }
144
- throw err;
145
- }
146
- }
147
- async buildTransaction(accept, wallet, rpcUrl) {
148
- if (!isSolanaWallet(wallet)) {
149
- throw new Error("Invalid Solana wallet");
150
- }
151
- if (!wallet.publicKey) {
152
- throw new Error("Wallet not connected");
153
- }
154
- const url = rpcUrl || this.getDefaultRpcUrl(accept.network);
155
- const connection = new import_web3.Connection(url, "confirmed");
156
- const userPubkey = new import_web3.PublicKey(wallet.publicKey.toBase58());
157
- const { payTo, asset, extra } = accept;
158
- const amount = accept.amount ?? accept.maxAmountRequired;
159
- if (!amount) {
160
- throw new Error("Missing amount in payment requirements");
161
- }
162
- if (!extra?.feePayer) {
163
- throw new Error("Missing feePayer in payment requirements");
164
- }
165
- const feePayerPubkey = new import_web3.PublicKey(extra.feePayer);
166
- const mintPubkey = new import_web3.PublicKey(asset);
167
- const destinationPubkey = new import_web3.PublicKey(payTo);
168
- this.log("Building transaction:", {
169
- from: userPubkey.toBase58(),
170
- to: payTo,
171
- amount,
172
- asset,
173
- feePayer: extra.feePayer
174
- });
175
- const instructions = [];
176
- instructions.push(
177
- import_web3.ComputeBudgetProgram.setComputeUnitLimit({
178
- units: DEFAULT_COMPUTE_UNIT_LIMIT
179
- })
180
- );
181
- instructions.push(
182
- import_web3.ComputeBudgetProgram.setComputeUnitPrice({
183
- microLamports: DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS
184
- })
185
- );
186
- const mintInfo = await connection.getAccountInfo(mintPubkey, "confirmed");
187
- if (!mintInfo) {
188
- throw new Error(`Token mint ${asset} not found`);
189
- }
190
- const programId = mintInfo.owner.toBase58() === import_spl_token.TOKEN_2022_PROGRAM_ID.toBase58() ? import_spl_token.TOKEN_2022_PROGRAM_ID : import_spl_token.TOKEN_PROGRAM_ID;
191
- const mint = await (0, import_spl_token.getMint)(connection, mintPubkey, void 0, programId);
192
- if (typeof extra?.decimals === "number" && mint.decimals !== extra.decimals) {
193
- this.log(
194
- `Decimals mismatch: requirements say ${extra.decimals}, mint says ${mint.decimals}`
195
- );
196
- }
197
- const sourceAta = await (0, import_spl_token.getAssociatedTokenAddress)(
198
- mintPubkey,
199
- userPubkey,
200
- false,
201
- programId
202
- );
203
- const destinationAta = await (0, import_spl_token.getAssociatedTokenAddress)(
204
- mintPubkey,
205
- destinationPubkey,
206
- false,
207
- programId
208
- );
209
- const sourceAtaInfo = await connection.getAccountInfo(sourceAta, "confirmed");
210
- if (!sourceAtaInfo) {
211
- throw new Error(
212
- `No token account found for ${asset}. Please ensure you have USDC in your wallet.`
213
- );
214
- }
215
- const destAtaInfo = await connection.getAccountInfo(destinationAta, "confirmed");
216
- if (!destAtaInfo) {
217
- throw new Error(
218
- `Seller token account not found. The seller (${payTo}) must have a USDC account.`
219
- );
220
- }
221
- const amountBigInt = BigInt(amount);
222
- instructions.push(
223
- (0, import_spl_token.createTransferCheckedInstruction)(
224
- sourceAta,
225
- mintPubkey,
226
- destinationAta,
227
- userPubkey,
228
- amountBigInt,
229
- mint.decimals,
230
- [],
231
- programId
232
- )
233
- );
234
- const { blockhash } = await connection.getLatestBlockhash("confirmed");
235
- const message = new import_web3.TransactionMessage({
236
- payerKey: feePayerPubkey,
237
- recentBlockhash: blockhash,
238
- instructions
239
- }).compileToV0Message();
240
- const transaction = new import_web3.VersionedTransaction(message);
241
- const signedTx = await wallet.signTransaction(transaction);
242
- this.log("Transaction signed successfully");
243
- return {
244
- serialized: Buffer.from(signedTx.serialize()).toString("base64")
245
- };
246
- }
247
- };
248
- function createSolanaAdapter(config) {
249
- return new SolanaAdapter(config);
250
- }
251
-
252
- // src/adapters/evm.ts
253
- var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
254
- var X402_EXACT_PERMIT2_PROXY = "0x402085c248EeA27D92E8b30b2C58ed07f9E20001";
255
- var PERMIT2_WITNESS_TYPES = {
256
- PermitWitnessTransferFrom: [
257
- { name: "permitted", type: "TokenPermissions" },
258
- { name: "spender", type: "address" },
259
- { name: "nonce", type: "uint256" },
260
- { name: "deadline", type: "uint256" },
261
- { name: "witness", type: "Witness" }
262
- ],
263
- TokenPermissions: [
264
- { name: "token", type: "address" },
265
- { name: "amount", type: "uint256" }
266
- ],
267
- Witness: [
268
- { name: "to", type: "address" },
269
- { name: "validAfter", type: "uint256" }
270
- ]
271
- };
272
- var MAX_UINT256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
273
- var BASE_MAINNET = "eip155:8453";
274
- var BASE_SEPOLIA = "eip155:84532";
275
- var ARBITRUM_ONE = "eip155:42161";
276
- var POLYGON = "eip155:137";
277
- var OPTIMISM = "eip155:10";
278
- var AVALANCHE = "eip155:43114";
279
- var BSC_MAINNET = "eip155:56";
280
- var SKALE_BASE = "eip155:1187947933";
281
- var SKALE_BASE_SEPOLIA = "eip155:324705682";
282
- var ETHEREUM_MAINNET = "eip155:1";
283
- var BSC_USDT = "0x55d398326f99059fF775485246999027B3197955";
284
- var BSC_USDC = "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d";
285
- var CHAIN_IDS = {
286
- [BSC_MAINNET]: 56,
287
- [BASE_MAINNET]: 8453,
288
- [BASE_SEPOLIA]: 84532,
289
- [ARBITRUM_ONE]: 42161,
290
- [POLYGON]: 137,
291
- [OPTIMISM]: 10,
292
- [AVALANCHE]: 43114,
293
- [SKALE_BASE]: 1187947933,
294
- [SKALE_BASE_SEPOLIA]: 324705682,
295
- [ETHEREUM_MAINNET]: 1
296
- };
297
- var DEFAULT_RPC_URLS2 = {
298
- [BSC_MAINNET]: "https://bsc-dataseed1.binance.org",
299
- [BASE_MAINNET]: "https://api.dexter.cash/api/base/rpc",
300
- [BASE_SEPOLIA]: "https://sepolia.base.org",
301
- [ARBITRUM_ONE]: "https://arb1.arbitrum.io/rpc",
302
- [POLYGON]: "https://polygon-rpc.com",
303
- [OPTIMISM]: "https://mainnet.optimism.io",
304
- [AVALANCHE]: "https://api.avax.network/ext/bc/C/rpc",
305
- [SKALE_BASE]: "https://skale-base.skalenodes.com/v1/base",
306
- [SKALE_BASE_SEPOLIA]: "https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",
307
- [ETHEREUM_MAINNET]: "https://eth.llamarpc.com"
308
- };
309
- var USDC_ADDRESSES = {
310
- [BSC_MAINNET]: BSC_USDC,
311
- [BASE_MAINNET]: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
312
- [BASE_SEPOLIA]: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
313
- [ARBITRUM_ONE]: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
314
- [POLYGON]: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
315
- [OPTIMISM]: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
316
- [AVALANCHE]: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
317
- [SKALE_BASE]: "0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",
318
- [SKALE_BASE_SEPOLIA]: "0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",
319
- [ETHEREUM_MAINNET]: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
320
- };
321
- var BSC_STABLECOIN_ADDRESSES = {
322
- [BSC_USDT]: { symbol: "USDT", decimals: 18 },
323
- [BSC_USDC]: { symbol: "USDC", decimals: 18 }
324
- };
325
- function isEvmWallet(wallet) {
326
- if (!wallet || typeof wallet !== "object") return false;
327
- const w = wallet;
328
- return "address" in w && typeof w.address === "string" && w.address.startsWith("0x");
329
- }
330
- var EvmAdapter = class {
331
- name = "EVM";
332
- networks = [BSC_MAINNET, BASE_MAINNET, BASE_SEPOLIA, ETHEREUM_MAINNET, ARBITRUM_ONE];
333
- config;
334
- log;
335
- constructor(config = {}) {
336
- this.config = config;
337
- this.log = config.verbose ? console.log.bind(console, "[x402:evm]") : () => {
338
- };
339
- }
340
- canHandle(network) {
341
- if (this.networks.includes(network)) return true;
342
- if (network === "base") return true;
343
- if (network === "bsc") return true;
344
- if (network === "ethereum") return true;
345
- if (network === "arbitrum") return true;
346
- if (network.startsWith("eip155:")) return true;
347
- return false;
348
- }
349
- getDefaultRpcUrl(network) {
350
- if (this.config.rpcUrls?.[network]) {
351
- return this.config.rpcUrls[network];
352
- }
353
- if (DEFAULT_RPC_URLS2[network]) {
354
- return DEFAULT_RPC_URLS2[network];
355
- }
356
- if (network === "base") return DEFAULT_RPC_URLS2[BASE_MAINNET];
357
- if (network === "bsc") return DEFAULT_RPC_URLS2[BSC_MAINNET];
358
- if (network === "ethereum") return DEFAULT_RPC_URLS2[ETHEREUM_MAINNET];
359
- if (network === "arbitrum") return DEFAULT_RPC_URLS2[ARBITRUM_ONE];
360
- return DEFAULT_RPC_URLS2[BASE_MAINNET];
361
- }
362
- getAddress(wallet) {
363
- if (!isEvmWallet(wallet)) return null;
364
- return wallet.address;
365
- }
366
- isConnected(wallet) {
367
- if (!isEvmWallet(wallet)) return false;
368
- return !!wallet.address;
369
- }
370
- getChainId(network) {
371
- if (CHAIN_IDS[network]) return CHAIN_IDS[network];
372
- if (network.startsWith("eip155:")) {
373
- const chainIdStr = network.split(":")[1];
374
- return parseInt(chainIdStr, 10);
375
- }
376
- if (network === "base") return 8453;
377
- if (network === "bsc") return 56;
378
- if (network === "ethereum") return 1;
379
- if (network === "arbitrum") return 42161;
380
- return 8453;
381
- }
382
- async getBalance(accept, wallet, rpcUrl) {
383
- if (!isEvmWallet(wallet) || !wallet.address) {
384
- return 0;
385
- }
386
- const url = rpcUrl || this.getDefaultRpcUrl(accept.network);
387
- try {
388
- const data = this.encodeBalanceOf(wallet.address);
389
- const response = await fetch(url, {
390
- method: "POST",
391
- headers: { "Content-Type": "application/json" },
392
- body: JSON.stringify({
393
- jsonrpc: "2.0",
394
- id: 1,
395
- method: "eth_call",
396
- params: [
397
- {
398
- to: accept.asset,
399
- data
400
- },
401
- "latest"
402
- ]
403
- })
404
- });
405
- if (!response.ok) {
406
- throw new Error(`RPC request failed: ${response.status}`);
407
- }
408
- const result = await response.json();
409
- if (result.error) {
410
- throw new Error(`RPC error: ${JSON.stringify(result.error)}`);
411
- }
412
- if (!result.result || result.result === "0x") {
413
- return 0;
414
- }
415
- const balance = BigInt(result.result);
416
- const decimals = accept.extra?.decimals ?? 6;
417
- return Number(balance) / Math.pow(10, decimals);
418
- } catch (err) {
419
- throw err;
420
- }
421
- }
422
- encodeBalanceOf(address) {
423
- const selector = "0x70a08231";
424
- const paddedAddress = address.slice(2).toLowerCase().padStart(64, "0");
425
- return selector + paddedAddress;
426
- }
427
- async buildTransaction(accept, wallet, rpcUrl) {
428
- if (!isEvmWallet(wallet)) {
429
- throw new Error("Invalid EVM wallet");
430
- }
431
- if (!wallet.address) {
432
- throw new Error("Wallet not connected");
433
- }
434
- if (accept.scheme === "exact-approval") {
435
- return this.buildApprovalTransaction(accept, wallet, rpcUrl);
436
- }
437
- if (accept.extra?.assetTransferMethod === "permit2") {
438
- return this.buildPermit2Transaction(accept, wallet, rpcUrl);
439
- }
440
- const { payTo, asset, extra } = accept;
441
- const amount = accept.amount ?? accept.maxAmountRequired;
442
- if (!amount) {
443
- throw new Error("Missing amount in payment requirements");
444
- }
445
- this.log("Building EVM transaction:", {
446
- from: wallet.address,
447
- to: payTo,
448
- amount,
449
- asset,
450
- network: accept.network
451
- });
452
- const chainId = this.getChainId(accept.network);
453
- const domain = {
454
- name: extra?.name ?? "USD Coin",
455
- version: extra?.version ?? "2",
456
- chainId: BigInt(chainId),
457
- verifyingContract: asset
458
- };
459
- const types = {
460
- TransferWithAuthorization: [
461
- { name: "from", type: "address" },
462
- { name: "to", type: "address" },
463
- { name: "value", type: "uint256" },
464
- { name: "validAfter", type: "uint256" },
465
- { name: "validBefore", type: "uint256" },
466
- { name: "nonce", type: "bytes32" }
467
- ]
468
- };
469
- const nonceBytes = new Uint8Array(32);
470
- (globalThis.crypto ?? (await import("crypto")).webcrypto).getRandomValues(nonceBytes);
471
- const nonce = "0x" + [...nonceBytes].map((b) => b.toString(16).padStart(2, "0")).join("");
472
- const now = Math.floor(Date.now() / 1e3);
473
- const authorization = {
474
- from: wallet.address,
475
- to: payTo,
476
- value: amount,
477
- // string
478
- validAfter: String(now - 600),
479
- // 10 minutes before (matching upstream)
480
- validBefore: String(now + (accept.maxTimeoutSeconds || 60)),
481
- nonce
482
- };
483
- const message = {
484
- from: wallet.address,
485
- to: payTo,
486
- value: BigInt(amount),
487
- validAfter: BigInt(now - 600),
488
- validBefore: BigInt(now + (accept.maxTimeoutSeconds || 60)),
489
- nonce
490
- };
491
- if (!wallet.signTypedData) {
492
- throw new Error("Wallet does not support signTypedData (EIP-712)");
493
- }
494
- const signature = await wallet.signTypedData({
495
- domain,
496
- types,
497
- primaryType: "TransferWithAuthorization",
498
- message
499
- });
500
- this.log("EIP-712 signature obtained");
501
- const payload = {
502
- authorization,
503
- signature
504
- };
505
- return {
506
- serialized: JSON.stringify(payload),
507
- signature
508
- };
509
- }
510
- // ===========================================================================
511
- // exact-approval: BSC and other chains without EIP-3009
512
- // ===========================================================================
513
- /**
514
- * Build a payment transaction for chains that use the approval-based scheme.
515
- * The facilitator's /supported response provides the EIP-712 domain and types
516
- * in accept.extra, so the client doesn't hardcode any contract addresses.
517
- */
518
- async buildApprovalTransaction(accept, wallet, rpcUrl) {
519
- const { payTo, asset, extra } = accept;
520
- const amount = accept.amount ?? accept.maxAmountRequired;
521
- if (!amount) {
522
- throw new Error("Missing amount in payment requirements");
523
- }
524
- const facilitatorContract = extra?.facilitatorContract;
525
- if (!facilitatorContract) {
526
- throw new Error(
527
- "exact-approval scheme requires extra.facilitatorContract from the facilitator. The /supported endpoint should provide this."
528
- );
529
- }
530
- if (!wallet.signTypedData) {
531
- throw new Error("Wallet does not support signTypedData (EIP-712)");
532
- }
533
- this.log("Building approval-based transaction:", {
534
- from: wallet.address,
535
- to: payTo,
536
- amount,
537
- asset,
538
- network: accept.network,
539
- facilitatorContract
540
- });
541
- const url = rpcUrl || this.getDefaultRpcUrl(accept.network);
542
- const fee = extra?.fee ?? "0";
543
- const totalNeeded = BigInt(amount) + BigInt(fee);
544
- const currentAllowance = await this.readAllowance(url, asset, wallet.address, facilitatorContract);
545
- if (currentAllowance < totalNeeded) {
546
- if (!wallet.sendTransaction) {
547
- throw new Error(
548
- "BSC payments require a wallet that supports sendTransaction for the one-time token approval. Use createEvmKeypairWallet() or a browser wallet with transaction support."
549
- );
550
- }
551
- const approvalAmount = this.calculateApprovalAmount(amount, fee, extra?.approvalStrategy);
552
- this.log(`Approving ${approvalAmount} for ${facilitatorContract} (current allowance: ${currentAllowance})`);
553
- const approveTxHash = await wallet.sendTransaction({
554
- to: asset,
555
- data: this.encodeApprove(facilitatorContract, approvalAmount),
556
- value: 0n
557
- });
558
- this.log(`Approval tx sent: ${approveTxHash}`);
559
- await this.waitForReceipt(url, approveTxHash);
560
- this.log("Approval confirmed");
561
- } else {
562
- this.log("Sufficient allowance, skipping approval");
563
- }
564
- const nonceBytes = new Uint8Array(16);
565
- (globalThis.crypto ?? (await import("crypto")).webcrypto).getRandomValues(nonceBytes);
566
- const nonce = [...nonceBytes].reduce((acc, b) => acc * 256n + BigInt(b), 0n).toString();
567
- const paymentIdBytes = new Uint8Array(32);
568
- (globalThis.crypto ?? (await import("crypto")).webcrypto).getRandomValues(paymentIdBytes);
569
- const paymentId = "0x" + [...paymentIdBytes].map((b) => b.toString(16).padStart(2, "0")).join("");
570
- const now = Math.floor(Date.now() / 1e3);
571
- const deadline = now + (accept.maxTimeoutSeconds || 300);
572
- const eip712Domain = extra?.eip712Domain;
573
- const domain = eip712Domain ? {
574
- name: eip712Domain.name,
575
- version: eip712Domain.version,
576
- chainId: BigInt(eip712Domain.chainId),
577
- verifyingContract: eip712Domain.verifyingContract
578
- } : {
579
- name: "DexterBSCFacilitator",
580
- version: "1",
581
- chainId: BigInt(this.getChainId(accept.network)),
582
- verifyingContract: facilitatorContract
583
- };
584
- const types = extra?.eip712Types ?? {
585
- Payment: [
586
- { name: "from", type: "address" },
587
- { name: "to", type: "address" },
588
- { name: "token", type: "address" },
589
- { name: "amount", type: "uint256" },
590
- { name: "fee", type: "uint256" },
591
- { name: "nonce", type: "uint256" },
592
- { name: "deadline", type: "uint256" },
593
- { name: "paymentId", type: "bytes32" }
594
- ]
595
- };
596
- const message = {
597
- from: wallet.address,
598
- to: payTo,
599
- token: asset,
600
- amount: BigInt(amount),
601
- fee: BigInt(fee),
602
- nonce: BigInt(nonce),
603
- deadline: BigInt(deadline),
604
- paymentId
605
- };
606
- const signature = await wallet.signTypedData({
607
- domain,
608
- types,
609
- primaryType: "Payment",
610
- message
611
- });
612
- this.log("EIP-712 Payment signature obtained");
613
- const payload = {
614
- from: wallet.address,
615
- to: payTo,
616
- token: asset,
617
- amount,
618
- fee,
619
- nonce,
620
- deadline,
621
- paymentId,
622
- signature
623
- };
624
- return {
625
- serialized: JSON.stringify(payload),
626
- signature
627
- };
628
- }
629
- // ===========================================================================
630
- // Permit2: Universal ERC-20 payments via Uniswap's Permit2 contract
631
- // ===========================================================================
632
- /**
633
- * Build a Permit2 payment transaction. Used when the facilitator signals
634
- * assetTransferMethod: "permit2" in extra (e.g., BSC where EIP-3009 is unavailable).
635
- *
636
- * Flow:
637
- * 1. Check if token has approved the Permit2 contract. If not, approve(Permit2, maxUint256).
638
- * 2. Sign EIP-712 PermitWitnessTransferFrom against the Permit2 contract.
639
- * 3. Return { permit2Authorization, signature } payload for the facilitator.
640
- */
641
- async buildPermit2Transaction(accept, wallet, rpcUrl) {
642
- const { payTo, asset } = accept;
643
- const amount = accept.amount ?? accept.maxAmountRequired;
644
- if (!amount) {
645
- throw new Error("Missing amount in payment requirements");
646
- }
647
- if (!wallet.signTypedData) {
648
- throw new Error("Wallet does not support signTypedData (EIP-712)");
649
- }
650
- this.log("Building Permit2 transaction:", {
651
- from: wallet.address,
652
- to: payTo,
653
- amount,
654
- asset,
655
- network: accept.network
656
- });
657
- const url = rpcUrl || this.getDefaultRpcUrl(accept.network);
658
- const currentAllowance = await this.readAllowance(url, asset, wallet.address, PERMIT2_ADDRESS);
659
- let approvalExtension;
660
- if (currentAllowance < BigInt(amount)) {
661
- const approveData = this.encodeApprove(PERMIT2_ADDRESS, MAX_UINT256);
662
- if (wallet.signTransaction) {
663
- this.log(`Signing Permit2 approval for relay (current allowance: ${currentAllowance})`);
664
- const chainId2 = this.getChainId(accept.network);
665
- const gasPrice = await this.readGasPrice(url);
666
- const nonce2 = await this.readNonce(url, wallet.address);
667
- const signedTx = await wallet.signTransaction({
668
- to: asset,
669
- data: approveData,
670
- chainId: chainId2,
671
- gas: 50000n,
672
- // standard ERC-20 approve
673
- gasPrice,
674
- nonce: nonce2
675
- });
676
- approvalExtension = {
677
- erc20ApprovalGasSponsoring: {
678
- info: {
679
- from: wallet.address,
680
- asset,
681
- spender: PERMIT2_ADDRESS,
682
- amount: MAX_UINT256.toString(),
683
- signedTransaction: signedTx,
684
- version: "1"
685
- }
686
- }
687
- };
688
- this.log("Permit2 approval signed for facilitator relay");
689
- } else if (wallet.sendTransaction) {
690
- this.log(`Approving Permit2 directly (current allowance: ${currentAllowance})`);
691
- const approveTxHash = await wallet.sendTransaction({
692
- to: asset,
693
- data: approveData,
694
- value: 0n
695
- });
696
- this.log(`Permit2 approval tx sent: ${approveTxHash}`);
697
- await this.waitForReceipt(url, approveTxHash);
698
- this.log("Permit2 approval confirmed");
699
- } else {
700
- throw new Error(
701
- "Permit2 payments require a wallet that supports signTransaction or sendTransaction for the one-time Permit2 approval. Use createEvmKeypairWallet() or a browser wallet with transaction support."
702
- );
703
- }
704
- } else {
705
- this.log("Sufficient Permit2 allowance, skipping approval");
706
- }
707
- const nonceBytes = new Uint8Array(32);
708
- (globalThis.crypto ?? (await import("crypto")).webcrypto).getRandomValues(nonceBytes);
709
- const nonce = [...nonceBytes].reduce((acc, b) => acc * 256n + BigInt(b), 0n);
710
- const now = Math.floor(Date.now() / 1e3);
711
- const validAfter = now - 600;
712
- const deadline = now + (accept.maxTimeoutSeconds || 300);
713
- const chainId = this.getChainId(accept.network);
714
- const domain = {
715
- name: "Permit2",
716
- chainId: BigInt(chainId),
717
- verifyingContract: PERMIT2_ADDRESS
718
- };
719
- const message = {
720
- permitted: {
721
- token: asset,
722
- amount: BigInt(amount)
723
- },
724
- spender: X402_EXACT_PERMIT2_PROXY,
725
- nonce,
726
- deadline: BigInt(deadline),
727
- witness: {
728
- to: payTo,
729
- validAfter: BigInt(validAfter)
730
- }
731
- };
732
- const signature = await wallet.signTypedData({
733
- domain,
734
- types: PERMIT2_WITNESS_TYPES,
735
- primaryType: "PermitWitnessTransferFrom",
736
- message
737
- });
738
- this.log("Permit2 PermitWitnessTransferFrom signature obtained");
739
- const payload = {
740
- signature,
741
- permit2Authorization: {
742
- from: wallet.address,
743
- permitted: {
744
- token: asset,
745
- amount
746
- },
747
- spender: X402_EXACT_PERMIT2_PROXY,
748
- nonce: nonce.toString(),
749
- deadline: String(deadline),
750
- witness: {
751
- to: payTo,
752
- validAfter: String(validAfter)
753
- }
754
- }
755
- };
756
- return {
757
- serialized: JSON.stringify(payload),
758
- signature,
759
- extensions: approvalExtension
760
- };
761
- }
762
- /**
763
- * Read ERC-20 allowance via raw eth_call (no viem dependency needed).
764
- */
765
- async readAllowance(rpcUrl, token, owner, spender) {
766
- const selector = "0xdd62ed3e";
767
- const paddedOwner = owner.slice(2).toLowerCase().padStart(64, "0");
768
- const paddedSpender = spender.slice(2).toLowerCase().padStart(64, "0");
769
- const data = selector + paddedOwner + paddedSpender;
770
- try {
771
- const response = await fetch(rpcUrl, {
772
- method: "POST",
773
- headers: { "Content-Type": "application/json" },
774
- body: JSON.stringify({
775
- jsonrpc: "2.0",
776
- id: 1,
777
- method: "eth_call",
778
- params: [{ to: token, data }, "latest"]
779
- })
780
- });
781
- const result = await response.json();
782
- if (result.error || !result.result || result.result === "0x") return 0n;
783
- return BigInt(result.result);
784
- } catch {
785
- return 0n;
786
- }
787
- }
788
- /**
789
- * Encode ERC-20 approve(address,uint256) calldata.
790
- */
791
- encodeApprove(spender, amount) {
792
- const selector = "0x095ea7b3";
793
- const paddedSpender = spender.slice(2).toLowerCase().padStart(64, "0");
794
- const paddedAmount = amount.toString(16).padStart(64, "0");
795
- return selector + paddedSpender + paddedAmount;
796
- }
797
- /**
798
- * Wait for a transaction receipt by polling eth_getTransactionReceipt.
799
- */
800
- async waitForReceipt(rpcUrl, txHash, timeoutMs = 3e4) {
801
- const start = Date.now();
802
- while (Date.now() - start < timeoutMs) {
803
- try {
804
- const response = await fetch(rpcUrl, {
805
- method: "POST",
806
- headers: { "Content-Type": "application/json" },
807
- body: JSON.stringify({
808
- jsonrpc: "2.0",
809
- id: 1,
810
- method: "eth_getTransactionReceipt",
811
- params: [txHash]
812
- })
813
- });
814
- const result = await response.json();
815
- if (result.result) {
816
- if (result.result.status === "0x0") {
817
- throw new Error(`Approval transaction reverted: ${txHash}`);
818
- }
819
- return;
820
- }
821
- } catch (err) {
822
- if (err instanceof Error && err.message.includes("reverted")) throw err;
823
- }
824
- await new Promise((r) => setTimeout(r, 2e3));
825
- }
826
- throw new Error(`Approval transaction receipt timeout after ${timeoutMs}ms: ${txHash}`);
827
- }
828
- /**
829
- * Read gas price via eth_gasPrice RPC call.
830
- */
831
- async readGasPrice(rpcUrl) {
832
- try {
833
- const response = await fetch(rpcUrl, {
834
- method: "POST",
835
- headers: { "Content-Type": "application/json" },
836
- body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_gasPrice", params: [] })
837
- });
838
- const result = await response.json();
839
- return result.result ? BigInt(result.result) : 50000000n;
840
- } catch {
841
- return 50000000n;
842
- }
843
- }
844
- /**
845
- * Read transaction count (nonce) via eth_getTransactionCount RPC call.
846
- */
847
- async readNonce(rpcUrl, address) {
848
- try {
849
- const response = await fetch(rpcUrl, {
850
- method: "POST",
851
- headers: { "Content-Type": "application/json" },
852
- body: JSON.stringify({
853
- jsonrpc: "2.0",
854
- id: 1,
855
- method: "eth_getTransactionCount",
856
- params: [address, "latest"]
857
- })
858
- });
859
- const result = await response.json();
860
- return result.result ? parseInt(result.result, 16) : 0;
861
- } catch {
862
- return 0;
863
- }
864
- }
865
- /**
866
- * Calculate how much to approve based on the facilitator's approval strategy.
867
- * Buffered approvals reduce the number of on-chain approval txs for micropayments.
868
- */
869
- calculateApprovalAmount(paymentAmount, fee, strategy) {
870
- const total = BigInt(paymentAmount) + BigInt(fee);
871
- if (!strategy || strategy.mode === "exact") {
872
- return total;
873
- }
874
- const multiple = BigInt(strategy.defaultMultiple ?? 10);
875
- const buffered = total * multiple;
876
- if (strategy.maxCapUsd) {
877
- const decimals = this.inferDecimals(paymentAmount);
878
- const maxCap = BigInt(Math.floor(strategy.maxCapUsd * Math.pow(10, decimals)));
879
- if (buffered > maxCap) return maxCap;
880
- }
881
- if (strategy.exactAboveUsd) {
882
- const decimals = this.inferDecimals(paymentAmount);
883
- const threshold = BigInt(Math.floor(strategy.exactAboveUsd * Math.pow(10, decimals)));
884
- if (BigInt(paymentAmount) > threshold) return total;
885
- }
886
- return buffered;
887
- }
888
- /**
889
- * Infer token decimals from payment amount magnitude.
890
- * BSC stablecoins use 18 decimals, all others use 6.
891
- * A $1 payment is 1000000 (6 dec) or 1000000000000000000 (18 dec).
892
- * If the amount has > 12 digits, it's almost certainly 18 decimals.
893
- */
894
- inferDecimals(amount) {
895
- return amount.length > 12 ? 18 : 6;
896
- }
897
- };
898
- function createEvmAdapter(config) {
899
- return new EvmAdapter(config);
900
- }
901
-
902
- // src/adapters/index.ts
903
- function isKnownUSDC(asset) {
904
- if (asset === "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") return true;
905
- if (asset === "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU") return true;
906
- const lc = asset.toLowerCase();
907
- for (const addr of Object.values(USDC_ADDRESSES)) {
908
- if (addr.toLowerCase() === lc) return true;
909
- }
910
- for (const addr of Object.keys(BSC_STABLECOIN_ADDRESSES)) {
911
- if (addr.toLowerCase() === lc) return true;
912
- }
913
- return false;
914
- }
915
- function createDefaultAdapters(verbose = false) {
916
- return [
917
- createSolanaAdapter({ verbose }),
918
- createEvmAdapter({ verbose })
919
- ];
920
- }
921
- function findAdapter(adapters, network) {
922
- return adapters.find((adapter) => adapter.canHandle(network));
923
- }
924
- // Annotate the CommonJS export names for ESM import in node:
925
- 0 && (module.exports = {
926
- ARBITRUM_ONE,
927
- AVALANCHE,
928
- BASE_MAINNET,
929
- BASE_SEPOLIA,
930
- BSC_MAINNET,
931
- BSC_STABLECOIN_ADDRESSES,
932
- BSC_USDC,
933
- BSC_USDT,
934
- ETHEREUM_MAINNET,
935
- EvmAdapter,
936
- OPTIMISM,
937
- PERMIT2_ADDRESS,
938
- POLYGON,
939
- SKALE_BASE,
940
- SKALE_BASE_SEPOLIA,
941
- SOLANA_DEVNET,
942
- SOLANA_MAINNET,
943
- SOLANA_TESTNET,
944
- SolanaAdapter,
945
- USDC_ADDRESSES,
946
- X402_EXACT_PERMIT2_PROXY,
947
- createDefaultAdapters,
948
- createEvmAdapter,
949
- createSolanaAdapter,
950
- findAdapter,
951
- isEvmWallet,
952
- isKnownUSDC,
953
- isSolanaWallet
954
- });
1
+ "use strict";var it=Object.create;var H=Object.defineProperty;var ct=Object.getOwnPropertyDescriptor;var dt=Object.getOwnPropertyNames;var pt=Object.getPrototypeOf,ut=Object.prototype.hasOwnProperty;var ft=(r,t)=>{for(var e in t)H(r,e,{get:t[e],enumerable:!0})},ot=(r,t,e,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of dt(t))!ut.call(r,a)&&a!==e&&H(r,a,{get:()=>t[a],enumerable:!(o=ct(t,a))||o.enumerable});return r};var X=(r,t,e)=>(e=r!=null?it(pt(r)):{},ot(t||!r||!r.__esModule?H(e,"default",{value:r,enumerable:!0}):e,r)),lt=r=>ot(H({},"__esModule",{value:!0}),r);var Et={};ft(Et,{ARBITRUM_ONE:()=>P,AVALANCHE:()=>J,BASE_MAINNET:()=>b,BASE_SEPOLIA:()=>O,BSC_MAINNET:()=>x,BSC_STABLECOIN_ADDRESSES:()=>et,BSC_USDC:()=>Q,BSC_USDT:()=>rt,ETHEREUM_MAINNET:()=>B,EvmAdapter:()=>q,OPTIMISM:()=>V,PERMIT2_ADDRESS:()=>U,POLYGON:()=>$,SKALE_BASE:()=>z,SKALE_BASE_SEPOLIA:()=>G,SOLANA_DEVNET:()=>F,SOLANA_MAINNET:()=>k,SOLANA_TESTNET:()=>j,SolanaAdapter:()=>K,USDC_ADDRESSES:()=>tt,X402_EXACT_PERMIT2_PROXY:()=>Z,createDefaultAdapters:()=>At,createEvmAdapter:()=>nt,createSolanaAdapter:()=>Y,findAdapter:()=>St,isEvmWallet:()=>M,isKnownUSDC:()=>yt,isSolanaWallet:()=>N});module.exports=lt(Et);var f=require("@solana/web3.js"),u=require("@solana/spl-token"),k="solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",F="solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",j="solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z",_={[k]:"https://api.dexter.cash/api/solana/rpc",[F]:"https://api.devnet.solana.com",[j]:"https://api.testnet.solana.com"},mt=12e3,gt=1;function N(r){if(!r||typeof r!="object")return!1;let t=r;return"publicKey"in t&&"signTransaction"in t&&typeof t.signTransaction=="function"}var K=class{name="Solana";networks=[k,F,j];config;log;constructor(t={}){this.config=t,this.log=t.verbose?console.log.bind(console,"[x402:solana]"):()=>{}}canHandle(t){return!!(this.networks.includes(t)||t==="solana"||t==="solana-devnet"||t==="solana-testnet"||t.startsWith("solana:"))}getDefaultRpcUrl(t){return this.config.rpcUrls?.[t]?this.config.rpcUrls[t]:_[t]?_[t]:t==="solana"?_[k]:t==="solana-devnet"?_[F]:t==="solana-testnet"?_[j]:_[k]}getAddress(t){return N(t)?t.publicKey?.toBase58()??null:null}isConnected(t){return N(t)?t.publicKey!==null:!1}async getBalance(t,e,o){if(!N(e)||!e.publicKey)return 0;let a=o||this.getDefaultRpcUrl(t.network),n=new f.Connection(a,"confirmed"),c=new f.PublicKey(e.publicKey.toBase58()),s=new f.PublicKey(t.asset);try{let d=(await n.getAccountInfo(s,"confirmed"))?.owner.toBase58()===u.TOKEN_2022_PROGRAM_ID.toBase58()?u.TOKEN_2022_PROGRAM_ID:u.TOKEN_PROGRAM_ID,p=await(0,u.getAssociatedTokenAddress)(s,c,!1,d),y=await(0,u.getAccount)(n,p,void 0,d),l=t.extra?.decimals??6;return Number(y.amount)/Math.pow(10,l)}catch(i){if(i&&typeof i=="object"&&"name"in i&&(i.name==="TokenAccountNotFoundError"||i.name==="TokenInvalidAccountOwnerError"))return 0;throw i}}async buildTransaction(t,e,o){if(!N(e))throw new Error("Invalid Solana wallet");if(!e.publicKey)throw new Error("Wallet not connected");let a=o||this.getDefaultRpcUrl(t.network),n=new f.Connection(a,"confirmed"),c=new f.PublicKey(e.publicKey.toBase58()),{payTo:s,asset:i,extra:d}=t,p=t.amount??t.maxAmountRequired;if(!p)throw new Error("Missing amount in payment requirements");if(!d?.feePayer)throw new Error("Missing feePayer in payment requirements");let y=new f.PublicKey(d.feePayer),l=new f.PublicKey(i),m=new f.PublicKey(s);this.log("Building transaction:",{from:c.toBase58(),to:s,amount:p,asset:i,feePayer:d.feePayer});let g=[];g.push(f.ComputeBudgetProgram.setComputeUnitLimit({units:mt})),g.push(f.ComputeBudgetProgram.setComputeUnitPrice({microLamports:gt}));let E=await n.getAccountInfo(l,"confirmed");if(!E)throw new Error(`Token mint ${i} not found`);let h=E.owner.toBase58()===u.TOKEN_2022_PROGRAM_ID.toBase58()?u.TOKEN_2022_PROGRAM_ID:u.TOKEN_PROGRAM_ID,v=await(0,u.getMint)(n,l,void 0,h);typeof d?.decimals=="number"&&v.decimals!==d.decimals&&this.log(`Decimals mismatch: requirements say ${d.decimals}, mint says ${v.decimals}`);let A=await(0,u.getAssociatedTokenAddress)(l,c,!1,h),S=await(0,u.getAssociatedTokenAddress)(l,m,!1,h);if(!await n.getAccountInfo(A,"confirmed"))throw new Error(`No token account found for ${i}. Please ensure you have USDC in your wallet.`);if(!await n.getAccountInfo(S,"confirmed"))throw new Error(`Seller token account not found. The seller (${s}) must have a USDC account.`);let L=BigInt(p);g.push((0,u.createTransferCheckedInstruction)(A,l,S,c,L,v.decimals,[],h));let{blockhash:D}=await n.getLatestBlockhash("confirmed"),W=new f.TransactionMessage({payerKey:y,recentBlockhash:D,instructions:g}).compileToV0Message(),w=new f.VersionedTransaction(W),R=await e.signTransaction(w);return this.log("Transaction signed successfully"),{serialized:Buffer.from(R.serialize()).toString("base64")}}};function Y(r){return new K(r)}var U="0x000000000022D473030F116dDEE9F6B43aC78BA3",Z="0x402085c248EeA27D92E8b30b2C58ed07f9E20001",ht={PermitWitnessTransferFrom:[{name:"permitted",type:"TokenPermissions"},{name:"spender",type:"address"},{name:"nonce",type:"uint256"},{name:"deadline",type:"uint256"},{name:"witness",type:"Witness"}],TokenPermissions:[{name:"token",type:"address"},{name:"amount",type:"uint256"}],Witness:[{name:"to",type:"address"},{name:"validAfter",type:"uint256"}]},at=BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),b="eip155:8453",O="eip155:84532",P="eip155:42161",$="eip155:137",V="eip155:10",J="eip155:43114",x="eip155:56",z="eip155:1187947933",G="eip155:324705682",B="eip155:1",rt="0x55d398326f99059fF775485246999027B3197955",Q="0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",st={[x]:56,[b]:8453,[O]:84532,[P]:42161,[$]:137,[V]:10,[J]:43114,[z]:1187947933,[G]:324705682,[B]:1},C={[x]:"https://bsc-dataseed1.binance.org",[b]:"https://api.dexter.cash/api/base/rpc",[O]:"https://sepolia.base.org",[P]:"https://arb1.arbitrum.io/rpc",[$]:"https://polygon-rpc.com",[V]:"https://mainnet.optimism.io",[J]:"https://api.avax.network/ext/bc/C/rpc",[z]:"https://skale-base.skalenodes.com/v1/base",[G]:"https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",[B]:"https://eth.llamarpc.com"},tt={[x]:Q,[b]:"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",[O]:"0x036CbD53842c5426634e7929541eC2318f3dCF7e",[P]:"0xaf88d065e77c8cC2239327C5EDb3A432268e5831",[$]:"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",[V]:"0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",[J]:"0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",[z]:"0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",[G]:"0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",[B]:"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"},et={[rt]:{symbol:"USDT",decimals:18},[Q]:{symbol:"USDC",decimals:18}};function M(r){if(!r||typeof r!="object")return!1;let t=r;return"address"in t&&typeof t.address=="string"&&t.address.startsWith("0x")}var q=class{name="EVM";networks=[x,b,O,B,P];config;log;constructor(t={}){this.config=t,this.log=t.verbose?console.log.bind(console,"[x402:evm]"):()=>{}}canHandle(t){return!!(this.networks.includes(t)||t==="base"||t==="bsc"||t==="ethereum"||t==="arbitrum"||t.startsWith("eip155:"))}getDefaultRpcUrl(t){return this.config.rpcUrls?.[t]?this.config.rpcUrls[t]:C[t]?C[t]:t==="base"?C[b]:t==="bsc"?C[x]:t==="ethereum"?C[B]:t==="arbitrum"?C[P]:C[b]}getAddress(t){return M(t)?t.address:null}isConnected(t){return M(t)?!!t.address:!1}getChainId(t){if(st[t])return st[t];if(t.startsWith("eip155:")){let e=t.split(":")[1];return parseInt(e,10)}return t==="base"?8453:t==="bsc"?56:t==="ethereum"?1:t==="arbitrum"?42161:8453}async getBalance(t,e,o){if(!M(e)||!e.address)return 0;let a=o||this.getDefaultRpcUrl(t.network);try{let n=this.encodeBalanceOf(e.address),c=await fetch(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"eth_call",params:[{to:t.asset,data:n},"latest"]})});if(!c.ok)throw new Error(`RPC request failed: ${c.status}`);let s=await c.json();if(s.error)throw new Error(`RPC error: ${JSON.stringify(s.error)}`);if(!s.result||s.result==="0x")return 0;let i=BigInt(s.result),d=t.extra?.decimals??6;return Number(i)/Math.pow(10,d)}catch(n){throw n}}encodeBalanceOf(t){let e="0x70a08231",o=t.slice(2).toLowerCase().padStart(64,"0");return e+o}async buildTransaction(t,e,o){if(!M(e))throw new Error("Invalid EVM wallet");if(!e.address)throw new Error("Wallet not connected");if(t.scheme==="exact-approval")return this.buildApprovalTransaction(t,e,o);if(t.extra?.assetTransferMethod==="permit2")return this.buildPermit2Transaction(t,e,o);let{payTo:a,asset:n,extra:c}=t,s=t.amount??t.maxAmountRequired;if(!s)throw new Error("Missing amount in payment requirements");this.log("Building EVM transaction:",{from:e.address,to:a,amount:s,asset:n,network:t.network});let i=this.getChainId(t.network),d={name:c?.name??"USD Coin",version:c?.version??"2",chainId:BigInt(i),verifyingContract:n},p={TransferWithAuthorization:[{name:"from",type:"address"},{name:"to",type:"address"},{name:"value",type:"uint256"},{name:"validAfter",type:"uint256"},{name:"validBefore",type:"uint256"},{name:"nonce",type:"bytes32"}]},y=new Uint8Array(32);(globalThis.crypto??(await import("crypto")).webcrypto).getRandomValues(y);let l="0x"+[...y].map(A=>A.toString(16).padStart(2,"0")).join(""),m=Math.floor(Date.now()/1e3),g={from:e.address,to:a,value:s,validAfter:String(m-600),validBefore:String(m+(t.maxTimeoutSeconds||60)),nonce:l},E={from:e.address,to:a,value:BigInt(s),validAfter:BigInt(m-600),validBefore:BigInt(m+(t.maxTimeoutSeconds||60)),nonce:l};if(!e.signTypedData)throw new Error("Wallet does not support signTypedData (EIP-712)");let h=await e.signTypedData({domain:d,types:p,primaryType:"TransferWithAuthorization",message:E});return this.log("EIP-712 signature obtained"),{serialized:JSON.stringify({authorization:g,signature:h}),signature:h}}async buildApprovalTransaction(t,e,o){let{payTo:a,asset:n,extra:c}=t,s=t.amount??t.maxAmountRequired;if(!s)throw new Error("Missing amount in payment requirements");let i=c?.facilitatorContract;if(!i)throw new Error("exact-approval scheme requires extra.facilitatorContract from the facilitator. The /supported endpoint should provide this.");if(!e.signTypedData)throw new Error("Wallet does not support signTypedData (EIP-712)");this.log("Building approval-based transaction:",{from:e.address,to:a,amount:s,asset:n,network:t.network,facilitatorContract:i});let d=o||this.getDefaultRpcUrl(t.network),p=c?.fee??"0",y=BigInt(s)+BigInt(p),l=await this.readAllowance(d,n,e.address,i);if(l<y){if(!e.sendTransaction)throw new Error("BSC payments require a wallet that supports sendTransaction for the one-time token approval. Use createEvmKeypairWallet() or a browser wallet with transaction support.");let w=this.calculateApprovalAmount(s,p,c?.approvalStrategy);this.log(`Approving ${w} for ${i} (current allowance: ${l})`);let R=await e.sendTransaction({to:n,data:this.encodeApprove(i,w),value:0n});this.log(`Approval tx sent: ${R}`),await this.waitForReceipt(d,R),this.log("Approval confirmed")}else this.log("Sufficient allowance, skipping approval");let m=new Uint8Array(16);(globalThis.crypto??(await import("crypto")).webcrypto).getRandomValues(m);let g=[...m].reduce((w,R)=>w*256n+BigInt(R),0n).toString(),E=new Uint8Array(32);(globalThis.crypto??(await import("crypto")).webcrypto).getRandomValues(E);let h="0x"+[...E].map(w=>w.toString(16).padStart(2,"0")).join(""),A=Math.floor(Date.now()/1e3)+(t.maxTimeoutSeconds||300),S=c?.eip712Domain,I=S?{name:S.name,version:S.version,chainId:BigInt(S.chainId),verifyingContract:S.verifyingContract}:{name:"DexterBSCFacilitator",version:"1",chainId:BigInt(this.getChainId(t.network)),verifyingContract:i},T=c?.eip712Types??{Payment:[{name:"from",type:"address"},{name:"to",type:"address"},{name:"token",type:"address"},{name:"amount",type:"uint256"},{name:"fee",type:"uint256"},{name:"nonce",type:"uint256"},{name:"deadline",type:"uint256"},{name:"paymentId",type:"bytes32"}]},L={from:e.address,to:a,token:n,amount:BigInt(s),fee:BigInt(p),nonce:BigInt(g),deadline:BigInt(A),paymentId:h},D=await e.signTypedData({domain:I,types:T,primaryType:"Payment",message:L});this.log("EIP-712 Payment signature obtained");let W={from:e.address,to:a,token:n,amount:s,fee:p,nonce:g,deadline:A,paymentId:h,signature:D};return{serialized:JSON.stringify(W),signature:D}}async buildPermit2Transaction(t,e,o){let{payTo:a,asset:n}=t,c=t.amount??t.maxAmountRequired;if(!c)throw new Error("Missing amount in payment requirements");if(!e.signTypedData)throw new Error("Wallet does not support signTypedData (EIP-712)");this.log("Building Permit2 transaction:",{from:e.address,to:a,amount:c,asset:n,network:t.network});let s=o||this.getDefaultRpcUrl(t.network),i=await this.readAllowance(s,n,e.address,U),d;if(i<BigInt(c)){let I=this.encodeApprove(U,at);if(e.signTransaction){this.log(`Signing Permit2 approval for relay (current allowance: ${i})`);let T=this.getChainId(t.network),L=await this.readGasPrice(s),D=await this.readNonce(s,e.address),W=await e.signTransaction({to:n,data:I,chainId:T,gas:50000n,gasPrice:L,nonce:D});d={erc20ApprovalGasSponsoring:{info:{from:e.address,asset:n,spender:U,amount:at.toString(),signedTransaction:W,version:"1"}}},this.log("Permit2 approval signed for facilitator relay")}else if(e.sendTransaction){this.log(`Approving Permit2 directly (current allowance: ${i})`);let T=await e.sendTransaction({to:n,data:I,value:0n});this.log(`Permit2 approval tx sent: ${T}`),await this.waitForReceipt(s,T),this.log("Permit2 approval confirmed")}else throw new Error("Permit2 payments require a wallet that supports signTransaction or sendTransaction for the one-time Permit2 approval. Use createEvmKeypairWallet() or a browser wallet with transaction support.")}else this.log("Sufficient Permit2 allowance, skipping approval");let p=new Uint8Array(32);(globalThis.crypto??(await import("crypto")).webcrypto).getRandomValues(p);let y=[...p].reduce((I,T)=>I*256n+BigInt(T),0n),l=Math.floor(Date.now()/1e3),m=l-600,g=l+(t.maxTimeoutSeconds||300),E=this.getChainId(t.network),h={name:"Permit2",chainId:BigInt(E),verifyingContract:U},v={permitted:{token:n,amount:BigInt(c)},spender:Z,nonce:y,deadline:BigInt(g),witness:{to:a,validAfter:BigInt(m)}},A=await e.signTypedData({domain:h,types:ht,primaryType:"PermitWitnessTransferFrom",message:v});this.log("Permit2 PermitWitnessTransferFrom signature obtained");let S={signature:A,permit2Authorization:{from:e.address,permitted:{token:n,amount:c},spender:Z,nonce:y.toString(),deadline:String(g),witness:{to:a,validAfter:String(m)}}};return{serialized:JSON.stringify(S),signature:A,extensions:d}}async readAllowance(t,e,o,a){let n="0xdd62ed3e",c=o.slice(2).toLowerCase().padStart(64,"0"),s=a.slice(2).toLowerCase().padStart(64,"0"),i=n+c+s;try{let p=await(await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"eth_call",params:[{to:e,data:i},"latest"]})})).json();return p.error||!p.result||p.result==="0x"?0n:BigInt(p.result)}catch{return 0n}}encodeApprove(t,e){let o="0x095ea7b3",a=t.slice(2).toLowerCase().padStart(64,"0"),n=e.toString(16).padStart(64,"0");return o+a+n}async waitForReceipt(t,e,o=3e4){let a=Date.now();for(;Date.now()-a<o;){try{let c=await(await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"eth_getTransactionReceipt",params:[e]})})).json();if(c.result){if(c.result.status==="0x0")throw new Error(`Approval transaction reverted: ${e}`);return}}catch(n){if(n instanceof Error&&n.message.includes("reverted"))throw n}await new Promise(n=>setTimeout(n,2e3))}throw new Error(`Approval transaction receipt timeout after ${o}ms: ${e}`)}async readGasPrice(t){try{let o=await(await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"eth_gasPrice",params:[]})})).json();return o.result?BigInt(o.result):50000000n}catch{return 50000000n}}async readNonce(t,e){try{let a=await(await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"eth_getTransactionCount",params:[e,"latest"]})})).json();return a.result?parseInt(a.result,16):0}catch{return 0}}calculateApprovalAmount(t,e,o){let a=BigInt(t)+BigInt(e);if(!o||o.mode==="exact")return a;let n=BigInt(o.defaultMultiple??10),c=a*n;if(o.maxCapUsd){let s=this.inferDecimals(t),i=BigInt(Math.floor(o.maxCapUsd*Math.pow(10,s)));if(c>i)return i}if(o.exactAboveUsd){let s=this.inferDecimals(t),i=BigInt(Math.floor(o.exactAboveUsd*Math.pow(10,s)));if(BigInt(t)>i)return a}return c}inferDecimals(t){return t.length>12?18:6}};function nt(r){return new q(r)}function yt(r){if(r==="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"||r==="4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU")return!0;let t=r.toLowerCase();for(let e of Object.values(tt))if(e.toLowerCase()===t)return!0;for(let e of Object.keys(et))if(e.toLowerCase()===t)return!0;return!1}function At(r=!1){return[Y({verbose:r}),nt({verbose:r})]}function St(r,t){return r.find(e=>e.canHandle(t))}0&&(module.exports={ARBITRUM_ONE,AVALANCHE,BASE_MAINNET,BASE_SEPOLIA,BSC_MAINNET,BSC_STABLECOIN_ADDRESSES,BSC_USDC,BSC_USDT,ETHEREUM_MAINNET,EvmAdapter,OPTIMISM,PERMIT2_ADDRESS,POLYGON,SKALE_BASE,SKALE_BASE_SEPOLIA,SOLANA_DEVNET,SOLANA_MAINNET,SOLANA_TESTNET,SolanaAdapter,USDC_ADDRESSES,X402_EXACT_PERMIT2_PROXY,createDefaultAdapters,createEvmAdapter,createSolanaAdapter,findAdapter,isEvmWallet,isKnownUSDC,isSolanaWallet});