@dexterai/x402 1.7.2 → 1.8.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.
@@ -3,9 +3,6 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __esm = (fn, res) => function __init() {
7
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
- };
9
6
  var __export = (target, all) => {
10
7
  for (var name in all)
11
8
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -20,398 +17,6 @@ var __copyProps = (to, from, except, desc) => {
20
17
  };
21
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
19
 
23
- // src/adapters/solana.ts
24
- function isSolanaWallet(wallet) {
25
- if (!wallet || typeof wallet !== "object") return false;
26
- const w = wallet;
27
- return "publicKey" in w && "signTransaction" in w && typeof w.signTransaction === "function";
28
- }
29
- function createSolanaAdapter(config) {
30
- return new SolanaAdapter(config);
31
- }
32
- var import_web3, import_spl_token, SOLANA_MAINNET, SOLANA_DEVNET, SOLANA_TESTNET, DEFAULT_RPC_URLS, DEFAULT_COMPUTE_UNIT_LIMIT, DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS, SolanaAdapter;
33
- var init_solana = __esm({
34
- "src/adapters/solana.ts"() {
35
- "use strict";
36
- import_web3 = require("@solana/web3.js");
37
- import_spl_token = require("@solana/spl-token");
38
- SOLANA_MAINNET = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
39
- SOLANA_DEVNET = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1";
40
- SOLANA_TESTNET = "solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z";
41
- DEFAULT_RPC_URLS = {
42
- [SOLANA_MAINNET]: "https://api.dexter.cash/api/solana/rpc",
43
- [SOLANA_DEVNET]: "https://api.devnet.solana.com",
44
- [SOLANA_TESTNET]: "https://api.testnet.solana.com"
45
- };
46
- DEFAULT_COMPUTE_UNIT_LIMIT = 12e3;
47
- DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS = 1;
48
- SolanaAdapter = class {
49
- name = "Solana";
50
- networks = [SOLANA_MAINNET, SOLANA_DEVNET, SOLANA_TESTNET];
51
- config;
52
- log;
53
- constructor(config = {}) {
54
- this.config = config;
55
- this.log = config.verbose ? console.log.bind(console, "[x402:solana]") : () => {
56
- };
57
- }
58
- canHandle(network) {
59
- if (this.networks.includes(network)) return true;
60
- if (network === "solana") return true;
61
- if (network === "solana-devnet") return true;
62
- if (network === "solana-testnet") return true;
63
- if (network.startsWith("solana:")) return true;
64
- return false;
65
- }
66
- getDefaultRpcUrl(network) {
67
- if (this.config.rpcUrls?.[network]) {
68
- return this.config.rpcUrls[network];
69
- }
70
- if (DEFAULT_RPC_URLS[network]) {
71
- return DEFAULT_RPC_URLS[network];
72
- }
73
- if (network === "solana") return DEFAULT_RPC_URLS[SOLANA_MAINNET];
74
- if (network === "solana-devnet") return DEFAULT_RPC_URLS[SOLANA_DEVNET];
75
- if (network === "solana-testnet") return DEFAULT_RPC_URLS[SOLANA_TESTNET];
76
- return DEFAULT_RPC_URLS[SOLANA_MAINNET];
77
- }
78
- getAddress(wallet) {
79
- if (!isSolanaWallet(wallet)) return null;
80
- return wallet.publicKey?.toBase58() ?? null;
81
- }
82
- isConnected(wallet) {
83
- if (!isSolanaWallet(wallet)) return false;
84
- return wallet.publicKey !== null;
85
- }
86
- async getBalance(accept, wallet, rpcUrl) {
87
- if (!isSolanaWallet(wallet) || !wallet.publicKey) {
88
- return 0;
89
- }
90
- const url = rpcUrl || this.getDefaultRpcUrl(accept.network);
91
- const connection = new import_web3.Connection(url, "confirmed");
92
- const userPubkey = new import_web3.PublicKey(wallet.publicKey.toBase58());
93
- const mintPubkey = new import_web3.PublicKey(accept.asset);
94
- try {
95
- const mintInfo = await connection.getAccountInfo(mintPubkey, "confirmed");
96
- 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;
97
- const ata = await (0, import_spl_token.getAssociatedTokenAddress)(
98
- mintPubkey,
99
- userPubkey,
100
- false,
101
- programId
102
- );
103
- const account = await (0, import_spl_token.getAccount)(connection, ata, void 0, programId);
104
- const decimals = accept.extra?.decimals ?? 6;
105
- return Number(account.amount) / Math.pow(10, decimals);
106
- } catch {
107
- return 0;
108
- }
109
- }
110
- async buildTransaction(accept, wallet, rpcUrl) {
111
- if (!isSolanaWallet(wallet)) {
112
- throw new Error("Invalid Solana wallet");
113
- }
114
- if (!wallet.publicKey) {
115
- throw new Error("Wallet not connected");
116
- }
117
- const url = rpcUrl || this.getDefaultRpcUrl(accept.network);
118
- const connection = new import_web3.Connection(url, "confirmed");
119
- const userPubkey = new import_web3.PublicKey(wallet.publicKey.toBase58());
120
- const { payTo, asset, extra } = accept;
121
- const amount = accept.amount || accept.maxAmountRequired;
122
- if (!amount) {
123
- throw new Error("Missing amount in payment requirements");
124
- }
125
- if (!extra?.feePayer) {
126
- throw new Error("Missing feePayer in payment requirements");
127
- }
128
- const feePayerPubkey = new import_web3.PublicKey(extra.feePayer);
129
- const mintPubkey = new import_web3.PublicKey(asset);
130
- const destinationPubkey = new import_web3.PublicKey(payTo);
131
- this.log("Building transaction:", {
132
- from: userPubkey.toBase58(),
133
- to: payTo,
134
- amount,
135
- asset,
136
- feePayer: extra.feePayer
137
- });
138
- const instructions = [];
139
- instructions.push(
140
- import_web3.ComputeBudgetProgram.setComputeUnitLimit({
141
- units: DEFAULT_COMPUTE_UNIT_LIMIT
142
- })
143
- );
144
- instructions.push(
145
- import_web3.ComputeBudgetProgram.setComputeUnitPrice({
146
- microLamports: DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS
147
- })
148
- );
149
- const mintInfo = await connection.getAccountInfo(mintPubkey, "confirmed");
150
- if (!mintInfo) {
151
- throw new Error(`Token mint ${asset} not found`);
152
- }
153
- 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;
154
- const mint = await (0, import_spl_token.getMint)(connection, mintPubkey, void 0, programId);
155
- if (typeof extra?.decimals === "number" && mint.decimals !== extra.decimals) {
156
- this.log(
157
- `Decimals mismatch: requirements say ${extra.decimals}, mint says ${mint.decimals}`
158
- );
159
- }
160
- const sourceAta = await (0, import_spl_token.getAssociatedTokenAddress)(
161
- mintPubkey,
162
- userPubkey,
163
- false,
164
- programId
165
- );
166
- const destinationAta = await (0, import_spl_token.getAssociatedTokenAddress)(
167
- mintPubkey,
168
- destinationPubkey,
169
- false,
170
- programId
171
- );
172
- const sourceAtaInfo = await connection.getAccountInfo(sourceAta, "confirmed");
173
- if (!sourceAtaInfo) {
174
- throw new Error(
175
- `No token account found for ${asset}. Please ensure you have USDC in your wallet.`
176
- );
177
- }
178
- const destAtaInfo = await connection.getAccountInfo(destinationAta, "confirmed");
179
- if (!destAtaInfo) {
180
- throw new Error(
181
- `Seller token account not found. The seller (${payTo}) must have a USDC account.`
182
- );
183
- }
184
- const amountBigInt = BigInt(amount);
185
- instructions.push(
186
- (0, import_spl_token.createTransferCheckedInstruction)(
187
- sourceAta,
188
- mintPubkey,
189
- destinationAta,
190
- userPubkey,
191
- amountBigInt,
192
- mint.decimals,
193
- [],
194
- programId
195
- )
196
- );
197
- const { blockhash } = await connection.getLatestBlockhash("confirmed");
198
- const message = new import_web3.TransactionMessage({
199
- payerKey: feePayerPubkey,
200
- recentBlockhash: blockhash,
201
- instructions
202
- }).compileToV0Message();
203
- const transaction = new import_web3.VersionedTransaction(message);
204
- const signedTx = await wallet.signTransaction(transaction);
205
- this.log("Transaction signed successfully");
206
- return {
207
- serialized: Buffer.from(signedTx.serialize()).toString("base64")
208
- };
209
- }
210
- };
211
- }
212
- });
213
-
214
- // src/adapters/evm.ts
215
- function isEvmWallet(wallet) {
216
- if (!wallet || typeof wallet !== "object") return false;
217
- const w = wallet;
218
- return "address" in w && typeof w.address === "string" && w.address.startsWith("0x");
219
- }
220
- function createEvmAdapter(config) {
221
- return new EvmAdapter(config);
222
- }
223
- var BASE_MAINNET, BASE_SEPOLIA, ETHEREUM_MAINNET, ARBITRUM_ONE, CHAIN_IDS, DEFAULT_RPC_URLS2, USDC_ADDRESSES, EvmAdapter;
224
- var init_evm = __esm({
225
- "src/adapters/evm.ts"() {
226
- "use strict";
227
- BASE_MAINNET = "eip155:8453";
228
- BASE_SEPOLIA = "eip155:84532";
229
- ETHEREUM_MAINNET = "eip155:1";
230
- ARBITRUM_ONE = "eip155:42161";
231
- CHAIN_IDS = {
232
- [BASE_MAINNET]: 8453,
233
- [BASE_SEPOLIA]: 84532,
234
- [ETHEREUM_MAINNET]: 1,
235
- [ARBITRUM_ONE]: 42161
236
- };
237
- DEFAULT_RPC_URLS2 = {
238
- [BASE_MAINNET]: "https://api.dexter.cash/api/base/rpc",
239
- [BASE_SEPOLIA]: "https://sepolia.base.org",
240
- [ETHEREUM_MAINNET]: "https://eth.llamarpc.com",
241
- [ARBITRUM_ONE]: "https://arb1.arbitrum.io/rpc"
242
- };
243
- USDC_ADDRESSES = {
244
- [BASE_MAINNET]: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
245
- [ETHEREUM_MAINNET]: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
246
- [ARBITRUM_ONE]: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"
247
- };
248
- EvmAdapter = class {
249
- name = "EVM";
250
- networks = [BASE_MAINNET, BASE_SEPOLIA, ETHEREUM_MAINNET, ARBITRUM_ONE];
251
- config;
252
- log;
253
- constructor(config = {}) {
254
- this.config = config;
255
- this.log = config.verbose ? console.log.bind(console, "[x402:evm]") : () => {
256
- };
257
- }
258
- canHandle(network) {
259
- if (this.networks.includes(network)) return true;
260
- if (network === "base") return true;
261
- if (network === "ethereum") return true;
262
- if (network === "arbitrum") return true;
263
- if (network.startsWith("eip155:")) return true;
264
- return false;
265
- }
266
- getDefaultRpcUrl(network) {
267
- if (this.config.rpcUrls?.[network]) {
268
- return this.config.rpcUrls[network];
269
- }
270
- if (DEFAULT_RPC_URLS2[network]) {
271
- return DEFAULT_RPC_URLS2[network];
272
- }
273
- if (network === "base") return DEFAULT_RPC_URLS2[BASE_MAINNET];
274
- if (network === "ethereum") return DEFAULT_RPC_URLS2[ETHEREUM_MAINNET];
275
- if (network === "arbitrum") return DEFAULT_RPC_URLS2[ARBITRUM_ONE];
276
- return DEFAULT_RPC_URLS2[BASE_MAINNET];
277
- }
278
- getAddress(wallet) {
279
- if (!isEvmWallet(wallet)) return null;
280
- return wallet.address;
281
- }
282
- isConnected(wallet) {
283
- if (!isEvmWallet(wallet)) return false;
284
- return !!wallet.address;
285
- }
286
- getChainId(network) {
287
- if (CHAIN_IDS[network]) return CHAIN_IDS[network];
288
- if (network.startsWith("eip155:")) {
289
- const chainIdStr = network.split(":")[1];
290
- return parseInt(chainIdStr, 10);
291
- }
292
- if (network === "base") return 8453;
293
- if (network === "ethereum") return 1;
294
- if (network === "arbitrum") return 42161;
295
- return 8453;
296
- }
297
- async getBalance(accept, wallet, rpcUrl) {
298
- if (!isEvmWallet(wallet) || !wallet.address) {
299
- return 0;
300
- }
301
- const url = rpcUrl || this.getDefaultRpcUrl(accept.network);
302
- try {
303
- const data = this.encodeBalanceOf(wallet.address);
304
- const response = await fetch(url, {
305
- method: "POST",
306
- headers: { "Content-Type": "application/json" },
307
- body: JSON.stringify({
308
- jsonrpc: "2.0",
309
- id: 1,
310
- method: "eth_call",
311
- params: [
312
- {
313
- to: accept.asset,
314
- data
315
- },
316
- "latest"
317
- ]
318
- })
319
- });
320
- const result = await response.json();
321
- if (result.error || !result.result) {
322
- return 0;
323
- }
324
- const balance = BigInt(result.result);
325
- const decimals = accept.extra?.decimals ?? 6;
326
- return Number(balance) / Math.pow(10, decimals);
327
- } catch {
328
- return 0;
329
- }
330
- }
331
- encodeBalanceOf(address) {
332
- const selector = "0x70a08231";
333
- const paddedAddress = address.slice(2).toLowerCase().padStart(64, "0");
334
- return selector + paddedAddress;
335
- }
336
- async buildTransaction(accept, wallet, _rpcUrl) {
337
- if (!isEvmWallet(wallet)) {
338
- throw new Error("Invalid EVM wallet");
339
- }
340
- if (!wallet.address) {
341
- throw new Error("Wallet not connected");
342
- }
343
- const { payTo, asset, extra } = accept;
344
- const amount = accept.amount || accept.maxAmountRequired;
345
- if (!amount) {
346
- throw new Error("Missing amount in payment requirements");
347
- }
348
- this.log("Building EVM transaction:", {
349
- from: wallet.address,
350
- to: payTo,
351
- amount,
352
- asset,
353
- network: accept.network
354
- });
355
- const chainId = this.getChainId(accept.network);
356
- const domain = {
357
- name: extra?.name ?? "USD Coin",
358
- version: extra?.version ?? "2",
359
- chainId: BigInt(chainId),
360
- verifyingContract: asset
361
- };
362
- const types = {
363
- TransferWithAuthorization: [
364
- { name: "from", type: "address" },
365
- { name: "to", type: "address" },
366
- { name: "value", type: "uint256" },
367
- { name: "validAfter", type: "uint256" },
368
- { name: "validBefore", type: "uint256" },
369
- { name: "nonce", type: "bytes32" }
370
- ]
371
- };
372
- const nonce = "0x" + [...Array(32)].map(() => Math.floor(Math.random() * 256).toString(16).padStart(2, "0")).join("");
373
- const now = Math.floor(Date.now() / 1e3);
374
- const authorization = {
375
- from: wallet.address,
376
- to: payTo,
377
- value: amount,
378
- // string
379
- validAfter: String(now - 600),
380
- // 10 minutes before (matching upstream)
381
- validBefore: String(now + (accept.maxTimeoutSeconds || 60)),
382
- nonce
383
- };
384
- const message = {
385
- from: wallet.address,
386
- to: payTo,
387
- value: BigInt(amount),
388
- validAfter: BigInt(now - 600),
389
- validBefore: BigInt(now + (accept.maxTimeoutSeconds || 60)),
390
- nonce
391
- };
392
- if (!wallet.signTypedData) {
393
- throw new Error("Wallet does not support signTypedData (EIP-712)");
394
- }
395
- const signature = await wallet.signTypedData({
396
- domain,
397
- types,
398
- primaryType: "TransferWithAuthorization",
399
- message
400
- });
401
- this.log("EIP-712 signature obtained");
402
- const payload = {
403
- authorization,
404
- signature
405
- };
406
- return {
407
- serialized: JSON.stringify(payload),
408
- signature
409
- };
410
- }
411
- };
412
- }
413
- });
414
-
415
20
  // src/react/index.ts
416
21
  var react_exports = {};
417
22
  __export(react_exports, {
@@ -443,11 +48,409 @@ var X402Error = class _X402Error extends Error {
443
48
  }
444
49
  };
445
50
 
446
- // src/adapters/index.ts
447
- init_solana();
448
- init_evm();
51
+ // src/adapters/solana.ts
52
+ var import_web3 = require("@solana/web3.js");
53
+ var import_spl_token = require("@solana/spl-token");
54
+ var SOLANA_MAINNET = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
55
+ var SOLANA_DEVNET = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1";
56
+ var SOLANA_TESTNET = "solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z";
57
+ var DEFAULT_RPC_URLS = {
58
+ [SOLANA_MAINNET]: "https://api.dexter.cash/api/solana/rpc",
59
+ [SOLANA_DEVNET]: "https://api.devnet.solana.com",
60
+ [SOLANA_TESTNET]: "https://api.testnet.solana.com"
61
+ };
62
+ var DEFAULT_COMPUTE_UNIT_LIMIT = 12e3;
63
+ var DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS = 1;
64
+ function isSolanaWallet(wallet) {
65
+ if (!wallet || typeof wallet !== "object") return false;
66
+ const w = wallet;
67
+ return "publicKey" in w && "signTransaction" in w && typeof w.signTransaction === "function";
68
+ }
69
+ var SolanaAdapter = class {
70
+ name = "Solana";
71
+ networks = [SOLANA_MAINNET, SOLANA_DEVNET, SOLANA_TESTNET];
72
+ config;
73
+ log;
74
+ constructor(config = {}) {
75
+ this.config = config;
76
+ this.log = config.verbose ? console.log.bind(console, "[x402:solana]") : () => {
77
+ };
78
+ }
79
+ canHandle(network) {
80
+ if (this.networks.includes(network)) return true;
81
+ if (network === "solana") return true;
82
+ if (network === "solana-devnet") return true;
83
+ if (network === "solana-testnet") return true;
84
+ if (network.startsWith("solana:")) return true;
85
+ return false;
86
+ }
87
+ getDefaultRpcUrl(network) {
88
+ if (this.config.rpcUrls?.[network]) {
89
+ return this.config.rpcUrls[network];
90
+ }
91
+ if (DEFAULT_RPC_URLS[network]) {
92
+ return DEFAULT_RPC_URLS[network];
93
+ }
94
+ if (network === "solana") return DEFAULT_RPC_URLS[SOLANA_MAINNET];
95
+ if (network === "solana-devnet") return DEFAULT_RPC_URLS[SOLANA_DEVNET];
96
+ if (network === "solana-testnet") return DEFAULT_RPC_URLS[SOLANA_TESTNET];
97
+ return DEFAULT_RPC_URLS[SOLANA_MAINNET];
98
+ }
99
+ getAddress(wallet) {
100
+ if (!isSolanaWallet(wallet)) return null;
101
+ return wallet.publicKey?.toBase58() ?? null;
102
+ }
103
+ isConnected(wallet) {
104
+ if (!isSolanaWallet(wallet)) return false;
105
+ return wallet.publicKey !== null;
106
+ }
107
+ async getBalance(accept, wallet, rpcUrl) {
108
+ if (!isSolanaWallet(wallet) || !wallet.publicKey) {
109
+ return 0;
110
+ }
111
+ const url = rpcUrl || this.getDefaultRpcUrl(accept.network);
112
+ const connection = new import_web3.Connection(url, "confirmed");
113
+ const userPubkey = new import_web3.PublicKey(wallet.publicKey.toBase58());
114
+ const mintPubkey = new import_web3.PublicKey(accept.asset);
115
+ try {
116
+ const mintInfo = await connection.getAccountInfo(mintPubkey, "confirmed");
117
+ 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;
118
+ const ata = await (0, import_spl_token.getAssociatedTokenAddress)(
119
+ mintPubkey,
120
+ userPubkey,
121
+ false,
122
+ programId
123
+ );
124
+ const account = await (0, import_spl_token.getAccount)(connection, ata, void 0, programId);
125
+ const decimals = accept.extra?.decimals ?? 6;
126
+ return Number(account.amount) / Math.pow(10, decimals);
127
+ } catch {
128
+ return 0;
129
+ }
130
+ }
131
+ async buildTransaction(accept, wallet, rpcUrl) {
132
+ if (!isSolanaWallet(wallet)) {
133
+ throw new Error("Invalid Solana wallet");
134
+ }
135
+ if (!wallet.publicKey) {
136
+ throw new Error("Wallet not connected");
137
+ }
138
+ const url = rpcUrl || this.getDefaultRpcUrl(accept.network);
139
+ const connection = new import_web3.Connection(url, "confirmed");
140
+ const userPubkey = new import_web3.PublicKey(wallet.publicKey.toBase58());
141
+ const { payTo, asset, extra } = accept;
142
+ const amount = accept.amount || accept.maxAmountRequired;
143
+ if (!amount) {
144
+ throw new Error("Missing amount in payment requirements");
145
+ }
146
+ if (!extra?.feePayer) {
147
+ throw new Error("Missing feePayer in payment requirements");
148
+ }
149
+ const feePayerPubkey = new import_web3.PublicKey(extra.feePayer);
150
+ const mintPubkey = new import_web3.PublicKey(asset);
151
+ const destinationPubkey = new import_web3.PublicKey(payTo);
152
+ this.log("Building transaction:", {
153
+ from: userPubkey.toBase58(),
154
+ to: payTo,
155
+ amount,
156
+ asset,
157
+ feePayer: extra.feePayer
158
+ });
159
+ const instructions = [];
160
+ instructions.push(
161
+ import_web3.ComputeBudgetProgram.setComputeUnitLimit({
162
+ units: DEFAULT_COMPUTE_UNIT_LIMIT
163
+ })
164
+ );
165
+ instructions.push(
166
+ import_web3.ComputeBudgetProgram.setComputeUnitPrice({
167
+ microLamports: DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS
168
+ })
169
+ );
170
+ const mintInfo = await connection.getAccountInfo(mintPubkey, "confirmed");
171
+ if (!mintInfo) {
172
+ throw new Error(`Token mint ${asset} not found`);
173
+ }
174
+ 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;
175
+ const mint = await (0, import_spl_token.getMint)(connection, mintPubkey, void 0, programId);
176
+ if (typeof extra?.decimals === "number" && mint.decimals !== extra.decimals) {
177
+ this.log(
178
+ `Decimals mismatch: requirements say ${extra.decimals}, mint says ${mint.decimals}`
179
+ );
180
+ }
181
+ const sourceAta = await (0, import_spl_token.getAssociatedTokenAddress)(
182
+ mintPubkey,
183
+ userPubkey,
184
+ false,
185
+ programId
186
+ );
187
+ const destinationAta = await (0, import_spl_token.getAssociatedTokenAddress)(
188
+ mintPubkey,
189
+ destinationPubkey,
190
+ false,
191
+ programId
192
+ );
193
+ const sourceAtaInfo = await connection.getAccountInfo(sourceAta, "confirmed");
194
+ if (!sourceAtaInfo) {
195
+ throw new Error(
196
+ `No token account found for ${asset}. Please ensure you have USDC in your wallet.`
197
+ );
198
+ }
199
+ const destAtaInfo = await connection.getAccountInfo(destinationAta, "confirmed");
200
+ if (!destAtaInfo) {
201
+ throw new Error(
202
+ `Seller token account not found. The seller (${payTo}) must have a USDC account.`
203
+ );
204
+ }
205
+ const amountBigInt = BigInt(amount);
206
+ instructions.push(
207
+ (0, import_spl_token.createTransferCheckedInstruction)(
208
+ sourceAta,
209
+ mintPubkey,
210
+ destinationAta,
211
+ userPubkey,
212
+ amountBigInt,
213
+ mint.decimals,
214
+ [],
215
+ programId
216
+ )
217
+ );
218
+ const { blockhash } = await connection.getLatestBlockhash("confirmed");
219
+ const message = new import_web3.TransactionMessage({
220
+ payerKey: feePayerPubkey,
221
+ recentBlockhash: blockhash,
222
+ instructions
223
+ }).compileToV0Message();
224
+ const transaction = new import_web3.VersionedTransaction(message);
225
+ const signedTx = await wallet.signTransaction(transaction);
226
+ this.log("Transaction signed successfully");
227
+ return {
228
+ serialized: Buffer.from(signedTx.serialize()).toString("base64")
229
+ };
230
+ }
231
+ };
232
+ function createSolanaAdapter(config) {
233
+ return new SolanaAdapter(config);
234
+ }
235
+
236
+ // src/adapters/evm.ts
237
+ var BASE_MAINNET = "eip155:8453";
238
+ var BASE_SEPOLIA = "eip155:84532";
239
+ var ARBITRUM_ONE = "eip155:42161";
240
+ var POLYGON = "eip155:137";
241
+ var OPTIMISM = "eip155:10";
242
+ var AVALANCHE = "eip155:43114";
243
+ var SKALE_BASE = "eip155:1187947933";
244
+ var SKALE_BASE_SEPOLIA = "eip155:324705682";
245
+ var ETHEREUM_MAINNET = "eip155:1";
246
+ var CHAIN_IDS = {
247
+ [BASE_MAINNET]: 8453,
248
+ [BASE_SEPOLIA]: 84532,
249
+ [ARBITRUM_ONE]: 42161,
250
+ [POLYGON]: 137,
251
+ [OPTIMISM]: 10,
252
+ [AVALANCHE]: 43114,
253
+ [SKALE_BASE]: 1187947933,
254
+ [SKALE_BASE_SEPOLIA]: 324705682,
255
+ [ETHEREUM_MAINNET]: 1
256
+ };
257
+ var DEFAULT_RPC_URLS2 = {
258
+ [BASE_MAINNET]: "https://api.dexter.cash/api/base/rpc",
259
+ [BASE_SEPOLIA]: "https://sepolia.base.org",
260
+ [ARBITRUM_ONE]: "https://arb1.arbitrum.io/rpc",
261
+ [POLYGON]: "https://polygon-rpc.com",
262
+ [OPTIMISM]: "https://mainnet.optimism.io",
263
+ [AVALANCHE]: "https://api.avax.network/ext/bc/C/rpc",
264
+ [SKALE_BASE]: "https://skale-base.skalenodes.com/v1/base",
265
+ [SKALE_BASE_SEPOLIA]: "https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",
266
+ [ETHEREUM_MAINNET]: "https://eth.llamarpc.com"
267
+ };
268
+ var USDC_ADDRESSES = {
269
+ [BASE_MAINNET]: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
270
+ [BASE_SEPOLIA]: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
271
+ [ARBITRUM_ONE]: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
272
+ [POLYGON]: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
273
+ [OPTIMISM]: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
274
+ [AVALANCHE]: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
275
+ [SKALE_BASE]: "0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",
276
+ [SKALE_BASE_SEPOLIA]: "0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",
277
+ [ETHEREUM_MAINNET]: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
278
+ };
279
+ function isEvmWallet(wallet) {
280
+ if (!wallet || typeof wallet !== "object") return false;
281
+ const w = wallet;
282
+ return "address" in w && typeof w.address === "string" && w.address.startsWith("0x");
283
+ }
284
+ var EvmAdapter = class {
285
+ name = "EVM";
286
+ networks = [BASE_MAINNET, BASE_SEPOLIA, ETHEREUM_MAINNET, ARBITRUM_ONE];
287
+ config;
288
+ log;
289
+ constructor(config = {}) {
290
+ this.config = config;
291
+ this.log = config.verbose ? console.log.bind(console, "[x402:evm]") : () => {
292
+ };
293
+ }
294
+ canHandle(network) {
295
+ if (this.networks.includes(network)) return true;
296
+ if (network === "base") return true;
297
+ if (network === "ethereum") return true;
298
+ if (network === "arbitrum") return true;
299
+ if (network.startsWith("eip155:")) return true;
300
+ return false;
301
+ }
302
+ getDefaultRpcUrl(network) {
303
+ if (this.config.rpcUrls?.[network]) {
304
+ return this.config.rpcUrls[network];
305
+ }
306
+ if (DEFAULT_RPC_URLS2[network]) {
307
+ return DEFAULT_RPC_URLS2[network];
308
+ }
309
+ if (network === "base") return DEFAULT_RPC_URLS2[BASE_MAINNET];
310
+ if (network === "ethereum") return DEFAULT_RPC_URLS2[ETHEREUM_MAINNET];
311
+ if (network === "arbitrum") return DEFAULT_RPC_URLS2[ARBITRUM_ONE];
312
+ return DEFAULT_RPC_URLS2[BASE_MAINNET];
313
+ }
314
+ getAddress(wallet) {
315
+ if (!isEvmWallet(wallet)) return null;
316
+ return wallet.address;
317
+ }
318
+ isConnected(wallet) {
319
+ if (!isEvmWallet(wallet)) return false;
320
+ return !!wallet.address;
321
+ }
322
+ getChainId(network) {
323
+ if (CHAIN_IDS[network]) return CHAIN_IDS[network];
324
+ if (network.startsWith("eip155:")) {
325
+ const chainIdStr = network.split(":")[1];
326
+ return parseInt(chainIdStr, 10);
327
+ }
328
+ if (network === "base") return 8453;
329
+ if (network === "ethereum") return 1;
330
+ if (network === "arbitrum") return 42161;
331
+ return 8453;
332
+ }
333
+ async getBalance(accept, wallet, rpcUrl) {
334
+ if (!isEvmWallet(wallet) || !wallet.address) {
335
+ return 0;
336
+ }
337
+ const url = rpcUrl || this.getDefaultRpcUrl(accept.network);
338
+ try {
339
+ const data = this.encodeBalanceOf(wallet.address);
340
+ const response = await fetch(url, {
341
+ method: "POST",
342
+ headers: { "Content-Type": "application/json" },
343
+ body: JSON.stringify({
344
+ jsonrpc: "2.0",
345
+ id: 1,
346
+ method: "eth_call",
347
+ params: [
348
+ {
349
+ to: accept.asset,
350
+ data
351
+ },
352
+ "latest"
353
+ ]
354
+ })
355
+ });
356
+ const result = await response.json();
357
+ if (result.error || !result.result) {
358
+ return 0;
359
+ }
360
+ const balance = BigInt(result.result);
361
+ const decimals = accept.extra?.decimals ?? 6;
362
+ return Number(balance) / Math.pow(10, decimals);
363
+ } catch {
364
+ return 0;
365
+ }
366
+ }
367
+ encodeBalanceOf(address) {
368
+ const selector = "0x70a08231";
369
+ const paddedAddress = address.slice(2).toLowerCase().padStart(64, "0");
370
+ return selector + paddedAddress;
371
+ }
372
+ async buildTransaction(accept, wallet, _rpcUrl) {
373
+ if (!isEvmWallet(wallet)) {
374
+ throw new Error("Invalid EVM wallet");
375
+ }
376
+ if (!wallet.address) {
377
+ throw new Error("Wallet not connected");
378
+ }
379
+ const { payTo, asset, extra } = accept;
380
+ const amount = accept.amount || accept.maxAmountRequired;
381
+ if (!amount) {
382
+ throw new Error("Missing amount in payment requirements");
383
+ }
384
+ this.log("Building EVM transaction:", {
385
+ from: wallet.address,
386
+ to: payTo,
387
+ amount,
388
+ asset,
389
+ network: accept.network
390
+ });
391
+ const chainId = this.getChainId(accept.network);
392
+ const domain = {
393
+ name: extra?.name ?? "USD Coin",
394
+ version: extra?.version ?? "2",
395
+ chainId: BigInt(chainId),
396
+ verifyingContract: asset
397
+ };
398
+ const types = {
399
+ TransferWithAuthorization: [
400
+ { name: "from", type: "address" },
401
+ { name: "to", type: "address" },
402
+ { name: "value", type: "uint256" },
403
+ { name: "validAfter", type: "uint256" },
404
+ { name: "validBefore", type: "uint256" },
405
+ { name: "nonce", type: "bytes32" }
406
+ ]
407
+ };
408
+ const nonce = "0x" + [...Array(32)].map(() => Math.floor(Math.random() * 256).toString(16).padStart(2, "0")).join("");
409
+ const now = Math.floor(Date.now() / 1e3);
410
+ const authorization = {
411
+ from: wallet.address,
412
+ to: payTo,
413
+ value: amount,
414
+ // string
415
+ validAfter: String(now - 600),
416
+ // 10 minutes before (matching upstream)
417
+ validBefore: String(now + (accept.maxTimeoutSeconds || 60)),
418
+ nonce
419
+ };
420
+ const message = {
421
+ from: wallet.address,
422
+ to: payTo,
423
+ value: BigInt(amount),
424
+ validAfter: BigInt(now - 600),
425
+ validBefore: BigInt(now + (accept.maxTimeoutSeconds || 60)),
426
+ nonce
427
+ };
428
+ if (!wallet.signTypedData) {
429
+ throw new Error("Wallet does not support signTypedData (EIP-712)");
430
+ }
431
+ const signature = await wallet.signTypedData({
432
+ domain,
433
+ types,
434
+ primaryType: "TransferWithAuthorization",
435
+ message
436
+ });
437
+ this.log("EIP-712 signature obtained");
438
+ const payload = {
439
+ authorization,
440
+ signature
441
+ };
442
+ return {
443
+ serialized: JSON.stringify(payload),
444
+ signature
445
+ };
446
+ }
447
+ };
448
+ function createEvmAdapter(config) {
449
+ return new EvmAdapter(config);
450
+ }
449
451
 
450
452
  // src/client/x402-client.ts
453
+ var receiptStore = /* @__PURE__ */ new WeakMap();
451
454
  function createX402Client(config) {
452
455
  const {
453
456
  adapters = [createSolanaAdapter({ verbose: config.verbose }), createEvmAdapter({ verbose: config.verbose })],
@@ -817,7 +820,8 @@ function createX402Client(config) {
817
820
  if (paymentResponseHeader) {
818
821
  try {
819
822
  const receipt = JSON.parse(atob(paymentResponseHeader));
820
- retryResponse._x402 = receipt;
823
+ receiptStore.set(retryResponse, receipt);
824
+ retryResponse["_x402"] = receipt;
821
825
  if (receipt.extensions) {
822
826
  log("Settlement extensions:", Object.keys(receipt.extensions).join(", "));
823
827
  }