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