@voyage_ai/v402-web-ts 0.2.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -173,9 +173,27 @@ function getWalletDisplayName(networkType) {
173
173
  return "Unknown Wallet";
174
174
  }
175
175
  }
176
+ function getAllConnectedWalletIds() {
177
+ if (typeof window === "undefined") {
178
+ return {};
179
+ }
180
+ try {
181
+ const cached = localStorage.getItem(CONNECTED_WALLET_IDS_KEY);
182
+ return cached ? JSON.parse(cached) : {};
183
+ } catch (error) {
184
+ console.error("Failed to parse connected wallet IDs:", error);
185
+ return {};
186
+ }
187
+ }
188
+ function getConnectedWalletId(networkType) {
189
+ const walletIds = getAllConnectedWalletIds();
190
+ return walletIds[networkType] || null;
191
+ }
192
+ var CONNECTED_WALLET_IDS_KEY;
176
193
  var init_wallet = __esm({
177
194
  "src/utils/wallet.ts"() {
178
195
  "use strict";
196
+ CONNECTED_WALLET_IDS_KEY = "connected_wallet_ids";
179
197
  }
180
198
  });
181
199
 
@@ -183,16 +201,10 @@ var init_wallet = __esm({
183
201
  init_types();
184
202
 
185
203
  // src/services/svm/payment-header.ts
186
- import {
187
- ComputeBudgetProgram,
188
- Connection,
189
- PublicKey,
190
- TransactionMessage,
191
- VersionedTransaction
192
- } from "@solana/web3.js";
204
+ import { ComputeBudgetProgram, Connection, PublicKey, TransactionMessage, VersionedTransaction } from "@solana/web3.js";
193
205
  import {
194
206
  createTransferCheckedInstruction,
195
- getAssociatedTokenAddress,
207
+ getAssociatedTokenAddressSync,
196
208
  getMint,
197
209
  TOKEN_2022_PROGRAM_ID,
198
210
  TOKEN_PROGRAM_ID
@@ -201,6 +213,186 @@ import {
201
213
  // src/utils/index.ts
202
214
  init_wallet();
203
215
 
216
+ // src/utils/wallet-discovery.ts
217
+ init_wallet();
218
+ var SOLANA_WALLETS = [
219
+ {
220
+ id: "phantom",
221
+ name: "Phantom",
222
+ // Phantom official icon
223
+ icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDEyOCAxMjgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiByeD0iMjYiIGZpbGw9IiNBQjlGRjIiLz4KPHBhdGggZD0iTTExMC41IDY0QzExMC41IDg5Ljk1NjggODkuMjAxIDExMSA2My41IDExMUg0MS41QzM2LjI1MzMgMTExIDMyIDEwNi43NDcgMzIgMTAxLjVWNTQuNUMzMiAzMS4wMjggNTEuMDI4IDEyIDc0LjUgMTJDOTcuOTcyIDEyIDExNyAzMS4wMjggMTE3IDU0LjVWNTUuNUMxMTcgNTguNTM3NiAxMTQuNTM4IDYxIDExMS41IDYxSDEwOS41QzEwNi40NjIgNjEgMTA0IDYzLjQ2MjQgMTA0IDY2LjVWNjhDMTA0IDcxLjg2NiAxMDcuMTM0IDc1IDExMSA3NUgxMTEuNUMxMTQuNTM4IDc1IDExNyA3Mi41Mzc2IDExNyA2OS41VjY0SDExMC41WiIgZmlsbD0idXJsKCNwYWludDBfbGluZWFyXzEyOF8xMjgpIi8+CjxwYXRoIGQ9Ik00OC41IDY3QzUxLjUzNzYgNjcgNTQgNjQuNTM3NiA1NCA2MS41QzU0IDU4LjQ2MjQgNTEuNTM3NiA1NiA0OC41IDU2QzQ1LjQ2MjQgNTYgNDMgNTguNDYyNCA0MyA2MS41QzQzIDY0LjUzNzYgNDUuNDYyNCA2NyA0OC41IDY3WiIgZmlsbD0iIzFCMUIxQiIvPgo8cGF0aCBkPSJNNzMuNSA2N0M3Ni41Mzc2IDY3IDc5IDY0LjUzNzYgNzkgNjEuNUM3OSA1OC40NjI0IDc2LjUzNzYgNTYgNzMuNSA1NkM3MC40NjI0IDU2IDY4IDU4LjQ2MjQgNjggNjEuNUM2OCA2NC41Mzc2IDcwLjQ2MjQgNjcgNzMuNSA2N1oiIGZpbGw9IiMxQjFCMUIiLz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl8xMjhfMTI4IiB4MT0iMTE3IiB5MT0iMTIiIHgyPSIxMTciIHkyPSIxMTEiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iI0ZGRkZGRiIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNGRkZGRkYiIHN0b3Atb3BhY2l0eT0iMC44MiIvPgo8L2xpbmVhckdyYWRpZW50Pgo8L2RlZnM+Cjwvc3ZnPg==",
224
+ detect: () => window.phantom?.solana
225
+ },
226
+ {
227
+ id: "solflare",
228
+ name: "Solflare",
229
+ // Solflare icon
230
+ icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDEyOCAxMjgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiByeD0iMjYiIGZpbGw9IiNGQzZEMDEiLz4KPHBhdGggZD0iTTk2IDY0TDY0IDMyTDMyIDY0TDY0IDk2TDk2IDY0WiIgZmlsbD0id2hpdGUiLz4KPC9zdmc+",
231
+ detect: () => window.solflare
232
+ },
233
+ {
234
+ id: "backpack",
235
+ name: "Backpack",
236
+ // Backpack icon (red coral color)
237
+ icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDEyOCAxMjgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiByeD0iMjYiIGZpbGw9IiNFMzM0MzAiLz4KPHBhdGggZD0iTTQwIDQ4SDg4VjgwQzg4IDg4LjgzNjYgODAuODM2NiA5NiA3MiA5Nkg1NkM0Ny4xNjM0IDk2IDQwIDg4LjgzNjYgNDAgODBWNDhaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNNTIgMzJINzZWNDhINTJWMzJaIiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4=",
238
+ detect: () => window.backpack
239
+ },
240
+ {
241
+ id: "okx-solana",
242
+ name: "OKX Wallet",
243
+ // OKX icon
244
+ icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDEyOCAxMjgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiByeD0iMjYiIGZpbGw9ImJsYWNrIi8+CjxyZWN0IHg9IjI0IiB5PSIyNCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiByeD0iNCIgZmlsbD0id2hpdGUiLz4KPHJlY3QgeD0iNTIiIHk9IjI0IiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHJ4PSI0IiBmaWxsPSJ3aGl0ZSIvPgo8cmVjdCB4PSI4MCIgeT0iMjQiIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgcng9IjQiIGZpbGw9IndoaXRlIi8+CjxyZWN0IHg9IjI0IiB5PSI1MiIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiByeD0iNCIgZmlsbD0id2hpdGUiLz4KPHJlY3QgeD0iODAiIHk9IjUyIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHJ4PSI0IiBmaWxsPSJ3aGl0ZSIvPgo8cmVjdCB4PSIyNCIgeT0iODAiIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgcng9IjQiIGZpbGw9IndoaXRlIi8+CjxyZWN0IHg9IjUyIiB5PSI4MCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiByeD0iNCIgZmlsbD0id2hpdGUiLz4KPHJlY3QgeD0iODAiIHk9IjgwIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHJ4PSI0IiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4=",
245
+ detect: () => window.okxwallet?.solana
246
+ },
247
+ {
248
+ id: "coinbase-solana",
249
+ name: "Coinbase Wallet",
250
+ // Coinbase icon (blue)
251
+ icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDEyOCAxMjgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiByeD0iMjYiIGZpbGw9IiMwMDUyRkYiLz4KPGNpcmNsZSBjeD0iNjQiIGN5PSI2NCIgcj0iMzYiIGZpbGw9IndoaXRlIi8+CjxyZWN0IHg9IjQ4IiB5PSI1NiIgd2lkdGg9IjMyIiBoZWlnaHQ9IjE2IiByeD0iNCIgZmlsbD0iIzAwNTJGRiIvPgo8L3N2Zz4=",
252
+ detect: () => window.coinbaseSolana
253
+ },
254
+ {
255
+ id: "trust-solana",
256
+ name: "Trust Wallet",
257
+ // Trust Wallet icon
258
+ icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDEyOCAxMjgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiByeD0iMjYiIGZpbGw9IiMwNTAwRkYiLz4KPHBhdGggZD0iTTY0IDI0QzY0IDI0IDk2IDQwIDk2IDY0Qzk2IDg4IDY0IDEwNCA2NCAxMDRDNjQgMTA0IDMyIDg4IDMyIDY0QzMyIDQwIDY0IDI0IDY0IDI0WiIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSI2IiBmaWxsPSJub25lIi8+Cjwvc3ZnPg==",
259
+ detect: () => window.trustwallet?.solana
260
+ }
261
+ ];
262
+ var evmWallets = /* @__PURE__ */ new Map();
263
+ var evmDiscoveryListeners = /* @__PURE__ */ new Set();
264
+ var evmDiscoveryInitialized = false;
265
+ var currentConnectedWallet = null;
266
+ function initEVMWalletDiscovery() {
267
+ if (typeof window === "undefined" || evmDiscoveryInitialized) return;
268
+ evmDiscoveryInitialized = true;
269
+ window.addEventListener("eip6963:announceProvider", ((event) => {
270
+ const { info, provider } = event.detail;
271
+ evmWallets.set(info.uuid, { info, provider });
272
+ evmDiscoveryListeners.forEach((listener) => listener());
273
+ }));
274
+ window.dispatchEvent(new Event("eip6963:requestProvider"));
275
+ }
276
+ function getEVMWallets() {
277
+ const wallets = [];
278
+ const detectedNames = /* @__PURE__ */ new Set();
279
+ evmWallets.forEach((detail, uuid) => {
280
+ if (!detectedNames.has(detail.info.name)) {
281
+ wallets.push({
282
+ id: uuid,
283
+ name: detail.info.name,
284
+ icon: detail.info.icon,
285
+ networkType: "evm" /* EVM */,
286
+ provider: detail.provider,
287
+ installed: true
288
+ });
289
+ detectedNames.add(detail.info.name);
290
+ }
291
+ });
292
+ if (wallets.length === 0 && typeof window !== "undefined" && window.ethereum) {
293
+ const ethereum = window.ethereum;
294
+ const walletName = ethereum.isMetaMask ? "MetaMask" : ethereum.isCoinbaseWallet ? "Coinbase Wallet" : ethereum.isOkxWallet ? "OKX Wallet" : "Browser Wallet";
295
+ if (!detectedNames.has(walletName)) {
296
+ wallets.push({
297
+ id: "injected",
298
+ name: walletName,
299
+ icon: "",
300
+ // Will use first letter as avatar
301
+ networkType: "evm" /* EVM */,
302
+ provider: ethereum,
303
+ installed: true
304
+ });
305
+ }
306
+ }
307
+ return wallets;
308
+ }
309
+ function getSolanaWallets() {
310
+ if (typeof window === "undefined") return [];
311
+ const wallets = [];
312
+ const detectedProviders = /* @__PURE__ */ new Set();
313
+ const detectedNames = /* @__PURE__ */ new Set();
314
+ for (const wallet of SOLANA_WALLETS) {
315
+ const provider = wallet.detect();
316
+ if (provider && !detectedNames.has(wallet.name)) {
317
+ wallets.push({
318
+ id: wallet.id,
319
+ name: wallet.name,
320
+ icon: wallet.icon,
321
+ networkType: "solana" /* SOLANA */,
322
+ provider,
323
+ installed: true
324
+ });
325
+ detectedProviders.add(provider);
326
+ detectedNames.add(wallet.name);
327
+ }
328
+ }
329
+ const windowSolana = window.solana;
330
+ if (windowSolana && !detectedProviders.has(windowSolana)) {
331
+ const walletName = windowSolana.isPhantom ? "Phantom" : windowSolana.isSolflare ? "Solflare" : windowSolana.isBackpack ? "Backpack" : windowSolana.walletName || "Solana Wallet";
332
+ if (!detectedNames.has(walletName)) {
333
+ wallets.push({
334
+ id: "solana-unknown",
335
+ name: walletName,
336
+ icon: "",
337
+ // Will use first letter as avatar
338
+ networkType: "solana" /* SOLANA */,
339
+ provider: windowSolana,
340
+ installed: true
341
+ });
342
+ }
343
+ }
344
+ return wallets;
345
+ }
346
+ function getWalletsForNetwork(networkType) {
347
+ switch (networkType) {
348
+ case "evm" /* EVM */:
349
+ return getEVMWallets();
350
+ case "solana" /* SOLANA */:
351
+ case "svm" /* SVM */:
352
+ return getSolanaWallets();
353
+ default:
354
+ return [];
355
+ }
356
+ }
357
+ function getWalletByName(name, networkType) {
358
+ const wallets = getWalletsForNetwork(networkType);
359
+ return wallets.find((w) => w.name === name) || null;
360
+ }
361
+ function restoreConnectedWallet(networkType) {
362
+ const savedWalletName = getConnectedWalletId(networkType);
363
+ if (!savedWalletName) return null;
364
+ const wallet = getWalletByName(savedWalletName, networkType);
365
+ if (wallet) {
366
+ currentConnectedWallet = wallet;
367
+ console.log(`\u2705 Restored wallet provider: ${wallet.name}`);
368
+ return wallet;
369
+ }
370
+ console.warn(`\u26A0\uFE0F Could not find wallet with name: ${savedWalletName}`);
371
+ return null;
372
+ }
373
+ function getWalletProviderForPayment(networkType) {
374
+ if (currentConnectedWallet && currentConnectedWallet.networkType === networkType) {
375
+ return currentConnectedWallet.provider;
376
+ }
377
+ const restoredWallet = restoreConnectedWallet(networkType);
378
+ if (restoredWallet) {
379
+ return restoredWallet.provider;
380
+ }
381
+ if (typeof window === "undefined") return null;
382
+ switch (networkType) {
383
+ case "evm" /* EVM */:
384
+ return window.ethereum;
385
+ case "solana" /* SOLANA */:
386
+ case "svm" /* SVM */:
387
+ return window.phantom?.solana || window.solana;
388
+ default:
389
+ return null;
390
+ }
391
+ }
392
+ if (typeof window !== "undefined") {
393
+ initEVMWalletDiscovery();
394
+ }
395
+
204
396
  // src/services/evm/payment-header.ts
205
397
  import { ethers } from "ethers";
206
398
  async function createEvmPaymentHeader(params) {
@@ -316,6 +508,15 @@ function getChainIdFromNetwork(network) {
316
508
 
317
509
  // src/services/evm/payment-handler.ts
318
510
  init_types();
511
+ var NETWORK_NAMES = {
512
+ 1: "Ethereum Mainnet",
513
+ 11155111: "Sepolia Testnet",
514
+ 8453: "Base Mainnet",
515
+ 84532: "Base Sepolia Testnet",
516
+ 137: "Polygon Mainnet",
517
+ 42161: "Arbitrum One",
518
+ 10: "Optimism Mainnet"
519
+ };
319
520
  async function handleEvmPayment(endpoint, config, requestInit) {
320
521
  const { wallet, network, maxPaymentAmount } = config;
321
522
  const initialResponse = await fetch(endpoint, {
@@ -326,25 +527,10 @@ async function handleEvmPayment(endpoint, config, requestInit) {
326
527
  return initialResponse;
327
528
  }
328
529
  const rawResponse = await initialResponse.json();
329
- const IGNORED_ERRORS = [
330
- "X-PAYMENT header is required",
331
- "missing X-PAYMENT header",
332
- "payment_required"
333
- ];
334
- if (rawResponse.error && !IGNORED_ERRORS.includes(rawResponse.error)) {
530
+ if (rawResponse.error && !IGNORED_402_ERRORS.includes(rawResponse.error)) {
335
531
  console.error(`\u274C Payment verification failed: ${rawResponse.error}`);
336
- const ERROR_MESSAGES = {
337
- "insufficient_funds": "Insufficient balance to complete this payment",
338
- "invalid_signature": "Invalid payment signature",
339
- "expired": "Payment authorization has expired",
340
- "already_used": "This payment has already been used",
341
- "network_mismatch": "Payment network does not match",
342
- "invalid_payment": "Invalid payment data",
343
- "verification_failed": "Payment verification failed"
344
- };
345
- const errorMessage = ERROR_MESSAGES[rawResponse.error] || `Payment failed: ${rawResponse.error}`;
346
- const error = new Error(errorMessage);
347
- throw wrapPaymentError(error);
532
+ const errorMessage = PAYMENT_ERROR_MESSAGES[rawResponse.error] || `Payment failed: ${rawResponse.error}`;
533
+ throw wrapPaymentError(new Error(errorMessage));
348
534
  }
349
535
  const x402Version = rawResponse.x402Version;
350
536
  const parsedPaymentRequirements = rawResponse.accepts || [];
@@ -376,19 +562,10 @@ async function handleEvmPayment(endpoint, config, requestInit) {
376
562
  console.warn("\u26A0\uFE0F Failed to get current chainId:", error);
377
563
  }
378
564
  }
379
- const networkNames = {
380
- 1: "Ethereum Mainnet",
381
- 11155111: "Sepolia Testnet",
382
- 8453: "Base Mainnet",
383
- 84532: "Base Sepolia Testnet",
384
- 137: "Polygon Mainnet",
385
- 42161: "Arbitrum One",
386
- 10: "Optimism Mainnet"
387
- };
388
565
  if (currentChainId && currentChainId !== targetChainId) {
389
566
  if (!wallet.switchChain) {
390
- const currentNetworkName = networkNames[currentChainId] || `Chain ${currentChainId}`;
391
- const targetNetworkName = networkNames[targetChainId] || selectedRequirements.network;
567
+ const currentNetworkName = NETWORK_NAMES[currentChainId] || `Chain ${currentChainId}`;
568
+ const targetNetworkName = NETWORK_NAMES[targetChainId] || selectedRequirements.network;
392
569
  const error = new Error(
393
570
  `Network mismatch: Your wallet is connected to ${currentNetworkName}, but payment requires ${targetNetworkName}. Please switch to ${targetNetworkName} manually in your wallet.`
394
571
  );
@@ -400,7 +577,7 @@ async function handleEvmPayment(endpoint, config, requestInit) {
400
577
  console.log(`\u2705 Successfully switched to chain ${targetChainId}`);
401
578
  } catch (error) {
402
579
  console.error("\u274C Failed to switch chain:", error);
403
- const targetNetworkName = networkNames[targetChainId] || selectedRequirements.network;
580
+ const targetNetworkName = NETWORK_NAMES[targetChainId] || selectedRequirements.network;
404
581
  const wrappedError = wrapPaymentError(error);
405
582
  let finalError;
406
583
  if (wrappedError.code === "USER_REJECTED" /* USER_REJECTED */) {
@@ -454,25 +631,10 @@ async function handleEvmPayment(endpoint, config, requestInit) {
454
631
  if (retryResponse.status === 402) {
455
632
  try {
456
633
  const retryData = await retryResponse.json();
457
- const IGNORED_ERRORS2 = [
458
- "X-PAYMENT header is required",
459
- "missing X-PAYMENT header",
460
- "payment_required"
461
- ];
462
- if (retryData.error && !IGNORED_ERRORS2.includes(retryData.error)) {
634
+ if (retryData.error && !IGNORED_402_ERRORS.includes(retryData.error)) {
463
635
  console.error(`\u274C Payment verification failed: ${retryData.error}`);
464
- const ERROR_MESSAGES = {
465
- "insufficient_funds": "Insufficient balance to complete this payment",
466
- "invalid_signature": "Invalid payment signature",
467
- "expired": "Payment authorization has expired",
468
- "already_used": "This payment has already been used",
469
- "network_mismatch": "Payment network does not match",
470
- "invalid_payment": "Invalid payment data",
471
- "verification_failed": "Payment verification failed"
472
- };
473
- const errorMessage = ERROR_MESSAGES[retryData.error] || `Payment failed: ${retryData.error}`;
474
- const error = new Error(errorMessage);
475
- throw wrapPaymentError(error);
636
+ const errorMessage = PAYMENT_ERROR_MESSAGES[retryData.error] || `Payment failed: ${retryData.error}`;
637
+ throw wrapPaymentError(new Error(errorMessage));
476
638
  }
477
639
  } catch (error) {
478
640
  if (error instanceof PaymentOperationError) {
@@ -493,7 +655,7 @@ function createEvmPaymentFetch(config) {
493
655
  // src/utils/payment-helpers.ts
494
656
  init_common();
495
657
  import { ethers as ethers2 } from "ethers";
496
- async function makePayment(networkType, merchantId, endpoint = PROD_BACK_URL, additionalParams) {
658
+ async function makePayment(networkType, merchantId, endpoint = PROD_BACK_URL, additionalParams, expectedAddress) {
497
659
  const fullEndpoint = `${endpoint}/${merchantId}`;
498
660
  let response;
499
661
  const requestInit = additionalParams && Object.keys(additionalParams).length > 0 ? {
@@ -503,26 +665,41 @@ async function makePayment(networkType, merchantId, endpoint = PROD_BACK_URL, ad
503
665
  }
504
666
  } : {};
505
667
  if (networkType === "solana" /* SOLANA */ || networkType === "svm" /* SVM */) {
506
- const solana = window.solana;
668
+ const solana = getWalletProviderForPayment(networkType);
507
669
  if (!solana) {
508
- throw new Error("\u8BF7\u5B89\u88C5 Phantom \u94B1\u5305");
670
+ throw new Error("Please connect your Solana wallet first.");
509
671
  }
510
672
  if (!solana.isConnected) {
511
673
  await solana.connect();
512
674
  }
675
+ if (expectedAddress && solana.publicKey) {
676
+ const currentAddress = solana.publicKey.toString();
677
+ if (currentAddress !== expectedAddress) {
678
+ throw new Error(
679
+ `Wallet account mismatch: the current wallet account is ${currentAddress.slice(0, 8)}...\uFF0CBut the desired account is ${expectedAddress.slice(0, 8)}.... Please switch to the correct account in your wallet.`
680
+ );
681
+ }
682
+ }
513
683
  response = await handleSvmPayment(fullEndpoint, {
514
684
  wallet: solana,
515
685
  network: "solana"
516
686
  // Will use backend's network configuration
517
687
  }, requestInit);
518
688
  } else if (networkType === "evm" /* EVM */) {
519
- if (!window.ethereum) {
520
- throw new Error("\u8BF7\u5B89\u88C5 MetaMask \u94B1\u5305");
689
+ const ethereum = getWalletProviderForPayment(networkType);
690
+ if (!ethereum) {
691
+ throw new Error("Please connect the EVM wallet first");
521
692
  }
522
- const provider = new ethers2.BrowserProvider(window.ethereum);
693
+ const provider = new ethers2.BrowserProvider(ethereum);
523
694
  const signer = await provider.getSigner();
695
+ const currentAddress = await signer.getAddress();
696
+ if (expectedAddress && currentAddress.toLowerCase() !== expectedAddress.toLowerCase()) {
697
+ throw new Error(
698
+ `Wallet account mismatch: the current wallet account is ${currentAddress.slice(0, 8)}...\uFF0CBut the desired account is ${expectedAddress.slice(0, 8)}.... Please switch to the correct account in your wallet.`
699
+ );
700
+ }
524
701
  const wallet = {
525
- address: await signer.getAddress(),
702
+ address: currentAddress,
526
703
  signTypedData: async (domain, types, message) => {
527
704
  return await signer.signTypedData(domain, types, message);
528
705
  },
@@ -533,7 +710,7 @@ async function makePayment(networkType, merchantId, endpoint = PROD_BACK_URL, ad
533
710
  },
534
711
  // Switch to a different chain
535
712
  switchChain: async (chainId) => {
536
- await window.ethereum.request({
713
+ await ethereum.request({
537
714
  method: "wallet_switchEthereumChain",
538
715
  params: [{ chainId }]
539
716
  });
@@ -545,7 +722,7 @@ async function makePayment(networkType, merchantId, endpoint = PROD_BACK_URL, ad
545
722
  // Will use backend's network configuration
546
723
  }, requestInit);
547
724
  } else {
548
- throw new Error(`\u4E0D\u652F\u6301\u7684\u7F51\u7EDC\u7C7B\u578B: ${networkType}`);
725
+ throw new Error(`Unsupported network types: ${networkType}`);
549
726
  }
550
727
  return response;
551
728
  }
@@ -620,6 +797,21 @@ function is402Response(response) {
620
797
  }
621
798
 
622
799
  // src/utils/payment-error-handler.ts
800
+ var IGNORED_402_ERRORS = [
801
+ "X-PAYMENT header is required",
802
+ "missing X-PAYMENT header",
803
+ "payment_required"
804
+ ];
805
+ var PAYMENT_ERROR_MESSAGES = {
806
+ "insufficient_funds": "Insufficient balance to complete this payment",
807
+ "invalid_signature": "Invalid payment signature",
808
+ "expired": "Payment authorization has expired",
809
+ "already_used": "This payment has already been used",
810
+ "network_mismatch": "Payment network does not match",
811
+ "invalid_payment": "Invalid payment data",
812
+ "verification_failed": "Payment verification failed",
813
+ "invalid_exact_svm_payload_transaction_simulation_failed": "Transaction simulation failed due to insufficient balance. Please check your wallet balance carefully and ensure you have enough funds to cover the payment and transaction fees."
814
+ };
623
815
  function parsePaymentError(error) {
624
816
  if (!error) {
625
817
  return {
@@ -754,7 +946,7 @@ function wrapPaymentError(error) {
754
946
  // src/services/svm/payment-header.ts
755
947
  async function createSvmPaymentHeader(params) {
756
948
  const { wallet, paymentRequirements, x402Version, rpcUrl } = params;
757
- const connection = new Connection(rpcUrl, "confirmed");
949
+ const connection = new Connection(rpcUrl);
758
950
  const feePayer = paymentRequirements?.extra?.feePayer;
759
951
  if (typeof feePayer !== "string" || !feePayer) {
760
952
  throw new Error("Missing facilitator feePayer in payment requirements (extra.feePayer).");
@@ -768,83 +960,85 @@ async function createSvmPaymentHeader(params) {
768
960
  if (!paymentRequirements?.payTo) {
769
961
  throw new Error("Missing payTo in payment requirements");
770
962
  }
771
- const destination = new PublicKey(paymentRequirements.payTo);
772
- const instructions = [];
773
- instructions.push(
774
- ComputeBudgetProgram.setComputeUnitLimit({
775
- units: 7e3
776
- // Sufficient for SPL token transfer
777
- })
778
- );
779
- instructions.push(
780
- ComputeBudgetProgram.setComputeUnitPrice({
781
- microLamports: 1
782
- // Minimal price
783
- })
784
- );
963
+ const destinationPubkey = new PublicKey(paymentRequirements.payTo);
785
964
  if (!paymentRequirements.asset) {
786
965
  throw new Error("Missing token mint for SPL transfer");
787
966
  }
788
967
  const mintPubkey = new PublicKey(paymentRequirements.asset);
789
- const mintInfo = await connection.getAccountInfo(mintPubkey, "confirmed");
790
- const programId = mintInfo?.owner?.toBase58() === TOKEN_2022_PROGRAM_ID.toBase58() ? TOKEN_2022_PROGRAM_ID : TOKEN_PROGRAM_ID;
791
- const mint = await getMint(connection, mintPubkey, void 0, programId);
792
- const sourceAta = await getAssociatedTokenAddress(
968
+ const mintAccountInfo = await connection.getAccountInfo(mintPubkey);
969
+ if (!mintAccountInfo) {
970
+ throw new Error(`Mint account ${mintPubkey.toBase58()} not found`);
971
+ }
972
+ const tokenProgramId = mintAccountInfo.owner.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : TOKEN_PROGRAM_ID;
973
+ const mint = await getMint(connection, mintPubkey, void 0, tokenProgramId);
974
+ const sourceAta = getAssociatedTokenAddressSync(
793
975
  mintPubkey,
794
976
  userPubkey,
795
977
  false,
796
- programId
978
+ tokenProgramId
797
979
  );
798
- const destinationAta = await getAssociatedTokenAddress(
980
+ const destinationAta = getAssociatedTokenAddressSync(
799
981
  mintPubkey,
800
- destination,
982
+ destinationPubkey,
801
983
  false,
802
- programId
984
+ tokenProgramId
803
985
  );
804
- const sourceAtaInfo = await connection.getAccountInfo(sourceAta, "confirmed");
986
+ const sourceAtaInfo = await connection.getAccountInfo(sourceAta);
805
987
  if (!sourceAtaInfo) {
806
988
  throw new Error(
807
989
  `User does not have an Associated Token Account for ${paymentRequirements.asset}. Please create one first or ensure you have the required token.`
808
990
  );
809
991
  }
810
- const destAtaInfo = await connection.getAccountInfo(destinationAta, "confirmed");
992
+ const destAtaInfo = await connection.getAccountInfo(destinationAta);
811
993
  if (!destAtaInfo) {
812
994
  throw new Error(
813
995
  `Destination does not have an Associated Token Account for ${paymentRequirements.asset}. The receiver must create their token account before receiving payments.`
814
996
  );
815
997
  }
816
- const amount = BigInt(paymentRequirements.maxAmountRequired);
817
- instructions.push(
998
+ const instructions = [
999
+ ComputeBudgetProgram.setComputeUnitLimit({
1000
+ units: 7e3
1001
+ // Sufficient for SPL token transfer
1002
+ }),
1003
+ ComputeBudgetProgram.setComputeUnitPrice({
1004
+ microLamports: 1
1005
+ // Minimal price
1006
+ }),
818
1007
  createTransferCheckedInstruction(
819
1008
  sourceAta,
820
1009
  mintPubkey,
821
1010
  destinationAta,
822
1011
  userPubkey,
823
- amount,
1012
+ BigInt(paymentRequirements.maxAmountRequired),
824
1013
  mint.decimals,
825
1014
  [],
826
- programId
1015
+ tokenProgramId
827
1016
  )
828
- );
829
- const { blockhash } = await connection.getLatestBlockhash("confirmed");
830
- const message = new TransactionMessage({
1017
+ ];
1018
+ const { blockhash } = await connection.getLatestBlockhash();
1019
+ const messageV0 = new TransactionMessage({
831
1020
  payerKey: feePayerPubkey,
832
1021
  recentBlockhash: blockhash,
833
1022
  instructions
834
1023
  }).compileToV0Message();
835
- const transaction = new VersionedTransaction(message);
1024
+ const transaction = new VersionedTransaction(messageV0);
836
1025
  if (typeof wallet?.signTransaction !== "function") {
837
1026
  throw new Error("Connected wallet does not support signTransaction");
838
1027
  }
839
- let userSignedTx;
1028
+ let signedTransaction;
840
1029
  try {
841
- userSignedTx = await wallet.signTransaction(transaction);
1030
+ signedTransaction = await wallet.signTransaction(transaction);
842
1031
  console.log("\u2705 Transaction signed successfully");
843
1032
  } catch (error) {
844
1033
  console.error("\u274C Failed to sign transaction:", error);
845
1034
  throw wrapPaymentError(error);
846
1035
  }
847
- const serializedTransaction = Buffer.from(userSignedTx.serialize()).toString("base64");
1036
+ const serializedBytes = signedTransaction.serialize();
1037
+ let binary = "";
1038
+ for (let i = 0; i < serializedBytes.length; i++) {
1039
+ binary += String.fromCharCode(serializedBytes[i]);
1040
+ }
1041
+ const serializedTransaction = btoa(binary);
848
1042
  const paymentPayload = {
849
1043
  x402Version,
850
1044
  scheme: paymentRequirements.scheme,
@@ -853,7 +1047,7 @@ async function createSvmPaymentHeader(params) {
853
1047
  transaction: serializedTransaction
854
1048
  }
855
1049
  };
856
- const paymentHeader = Buffer.from(JSON.stringify(paymentPayload)).toString("base64");
1050
+ const paymentHeader = btoa(JSON.stringify(paymentPayload));
857
1051
  return paymentHeader;
858
1052
  }
859
1053
  function getDefaultSolanaRpcUrl(network) {
@@ -869,7 +1063,7 @@ function getDefaultSolanaRpcUrl(network) {
869
1063
  // src/services/svm/payment-handler.ts
870
1064
  init_types();
871
1065
  async function handleSvmPayment(endpoint, config, requestInit) {
872
- const { wallet, network, rpcUrl, maxPaymentAmount } = config;
1066
+ const { wallet, rpcUrl, maxPaymentAmount } = config;
873
1067
  const initialResponse = await fetch(endpoint, {
874
1068
  ...requestInit,
875
1069
  method: requestInit?.method || "POST"
@@ -878,26 +1072,10 @@ async function handleSvmPayment(endpoint, config, requestInit) {
878
1072
  return initialResponse;
879
1073
  }
880
1074
  const rawResponse = await initialResponse.json();
881
- const IGNORED_ERRORS = [
882
- "X-PAYMENT header is required",
883
- "missing X-PAYMENT header",
884
- "payment_required"
885
- ];
886
- if (rawResponse.error && !IGNORED_ERRORS.includes(rawResponse.error)) {
1075
+ if (rawResponse.error && !IGNORED_402_ERRORS.includes(rawResponse.error)) {
887
1076
  console.error(`\u274C Payment verification failed: ${rawResponse.error}`);
888
- const ERROR_MESSAGES = {
889
- "insufficient_funds": "Insufficient balance to complete this payment",
890
- "invalid_signature": "Invalid payment signature",
891
- "expired": "Payment authorization has expired",
892
- "already_used": "This payment has already been used",
893
- "network_mismatch": "Payment network does not match",
894
- "invalid_payment": "Invalid payment data",
895
- "verification_failed": "Payment verification failed",
896
- "invalid_exact_svm_payload_transaction_simulation_failed": "Transaction simulation failed due to insufficient balance. Please check your wallet balance carefully and ensure you have enough funds to cover the payment and transaction fees."
897
- };
898
- const errorMessage = ERROR_MESSAGES[rawResponse.error] || `Payment failed: ${rawResponse.error}`;
899
- const error = new Error(errorMessage);
900
- throw wrapPaymentError(error);
1077
+ const errorMessage = PAYMENT_ERROR_MESSAGES[rawResponse.error] || `Payment failed: ${rawResponse.error}`;
1078
+ throw wrapPaymentError(new Error(errorMessage));
901
1079
  }
902
1080
  const x402Version = rawResponse.x402Version;
903
1081
  const parsedPaymentRequirements = rawResponse.accepts || [];
@@ -947,26 +1125,10 @@ async function handleSvmPayment(endpoint, config, requestInit) {
947
1125
  if (retryResponse.status === 402) {
948
1126
  try {
949
1127
  const retryData = await retryResponse.json();
950
- const IGNORED_ERRORS2 = [
951
- "X-PAYMENT header is required",
952
- "missing X-PAYMENT header",
953
- "payment_required"
954
- ];
955
- if (retryData.error && !IGNORED_ERRORS2.includes(retryData.error)) {
1128
+ if (retryData.error && !IGNORED_402_ERRORS.includes(retryData.error)) {
956
1129
  console.error(`\u274C Payment verification failed: ${retryData.error}`);
957
- const ERROR_MESSAGES = {
958
- "insufficient_funds": "Insufficient balance to complete this payment",
959
- "invalid_signature": "Invalid payment signature",
960
- "expired": "Payment authorization has expired",
961
- "already_used": "This payment has already been used",
962
- "network_mismatch": "Payment network does not match",
963
- "invalid_payment": "Invalid payment data",
964
- "verification_failed": "Payment verification failed",
965
- "invalid_exact_svm_payload_transaction_simulation_failed": "Transaction simulation failed due to insufficient balance. Please check your wallet balance carefully and ensure you have enough funds to cover the payment and transaction fees."
966
- };
967
- const errorMessage = ERROR_MESSAGES[retryData.error] || `Payment failed: ${retryData.error}`;
968
- const error = new Error(errorMessage);
969
- throw wrapPaymentError(error);
1130
+ const errorMessage = PAYMENT_ERROR_MESSAGES[retryData.error] || `Payment failed: ${retryData.error}`;
1131
+ throw wrapPaymentError(new Error(errorMessage));
970
1132
  }
971
1133
  } catch (error) {
972
1134
  if (error instanceof PaymentOperationError) {