@voyage_ai/v402-web-ts 0.1.2 → 0.1.4
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.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +139 -98
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +122 -80
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +50 -1
- package/dist/react/index.d.ts +50 -1
- package/dist/react/index.js +1559 -136
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +1541 -112
- package/dist/react/index.mjs.map +1 -1
- package/dist/react/styles.css +1 -168
- package/package.json +33 -10
- package/dist/react/components/WalletConnect.tsx +0 -152
- package/dist/react/hooks/usePayment.ts +0 -109
- package/dist/react/hooks/usePaymentInfo.ts +0 -128
- package/dist/react/hooks/useWallet.ts +0 -174
- package/dist/react/hooks/useWalletStore.ts +0 -61
- package/dist/react/index.ts +0 -38
- package/dist/react/store/walletStore.ts +0 -181
- package/dist/react/styles/inline-styles.ts +0 -238
package/dist/react/index.js
CHANGED
|
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
8
11
|
var __export = (target, all) => {
|
|
9
12
|
for (var name in all)
|
|
10
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -27,63 +30,75 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
30
|
));
|
|
28
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
32
|
|
|
30
|
-
// src/react/index.ts
|
|
31
|
-
var index_exports = {};
|
|
32
|
-
__export(index_exports, {
|
|
33
|
-
WalletConnect: () => WalletConnect,
|
|
34
|
-
usePayment: () => usePayment,
|
|
35
|
-
usePaymentInfo: () => usePaymentInfo,
|
|
36
|
-
useWallet: () => useWallet
|
|
37
|
-
});
|
|
38
|
-
module.exports = __toCommonJS(index_exports);
|
|
39
|
-
|
|
40
|
-
// src/react/hooks/useWalletStore.ts
|
|
41
|
-
var import_react = require("react");
|
|
42
|
-
|
|
43
|
-
// src/types/index.ts
|
|
44
|
-
var import_types3 = require("x402/types");
|
|
45
|
-
|
|
46
33
|
// src/types/common.ts
|
|
47
|
-
var PROD_BACK_URL
|
|
34
|
+
var PROD_BACK_URL, DEV_BACK_URL;
|
|
35
|
+
var init_common = __esm({
|
|
36
|
+
"src/types/common.ts"() {
|
|
37
|
+
"use strict";
|
|
38
|
+
PROD_BACK_URL = "https://v402.onvoyage.ai/api/pay";
|
|
39
|
+
DEV_BACK_URL = "http://localhost:3000/api/pay";
|
|
40
|
+
}
|
|
41
|
+
});
|
|
48
42
|
|
|
49
43
|
// src/types/svm.ts
|
|
50
|
-
var import_zod
|
|
51
|
-
var
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
44
|
+
var import_zod, import_types, SolanaNetworkSchema, SolanaPaymentPayloadSchema;
|
|
45
|
+
var init_svm = __esm({
|
|
46
|
+
"src/types/svm.ts"() {
|
|
47
|
+
"use strict";
|
|
48
|
+
import_zod = require("zod");
|
|
49
|
+
import_types = require("x402/types");
|
|
50
|
+
SolanaNetworkSchema = import_zod.z.enum([
|
|
51
|
+
"solana-devnet",
|
|
52
|
+
"solana",
|
|
53
|
+
"solana-mainnet"
|
|
54
|
+
// Alias for mainnet
|
|
55
|
+
]);
|
|
56
|
+
SolanaPaymentPayloadSchema = import_zod.z.object({
|
|
57
|
+
x402Version: import_zod.z.literal(1),
|
|
58
|
+
scheme: import_zod.z.literal("exact"),
|
|
59
|
+
network: SolanaNetworkSchema,
|
|
60
|
+
payload: import_types.ExactSvmPayloadSchema
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
63
|
});
|
|
64
64
|
|
|
65
65
|
// src/types/evm.ts
|
|
66
|
-
var import_zod2
|
|
67
|
-
var
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
66
|
+
var import_zod2, import_types2, EvmNetworkSchema, EvmPaymentPayloadSchema;
|
|
67
|
+
var init_evm = __esm({
|
|
68
|
+
"src/types/evm.ts"() {
|
|
69
|
+
"use strict";
|
|
70
|
+
import_zod2 = require("zod");
|
|
71
|
+
import_types2 = require("x402/types");
|
|
72
|
+
EvmNetworkSchema = import_zod2.z.enum([
|
|
73
|
+
"ethereum",
|
|
74
|
+
"sepolia",
|
|
75
|
+
"base",
|
|
76
|
+
"base-sepolia",
|
|
77
|
+
"polygon",
|
|
78
|
+
"arbitrum",
|
|
79
|
+
"optimism"
|
|
80
|
+
]);
|
|
81
|
+
EvmPaymentPayloadSchema = import_zod2.z.object({
|
|
82
|
+
x402Version: import_zod2.z.literal(1),
|
|
83
|
+
scheme: import_zod2.z.literal("exact"),
|
|
84
|
+
network: EvmNetworkSchema,
|
|
85
|
+
payload: import_types2.ExactEvmPayloadSchema
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// src/types/index.ts
|
|
91
|
+
var import_types3;
|
|
92
|
+
var init_types = __esm({
|
|
93
|
+
"src/types/index.ts"() {
|
|
94
|
+
"use strict";
|
|
95
|
+
import_types3 = require("x402/types");
|
|
96
|
+
init_svm();
|
|
97
|
+
init_evm();
|
|
98
|
+
}
|
|
82
99
|
});
|
|
83
100
|
|
|
84
101
|
// src/utils/wallet.ts
|
|
85
|
-
var WALLET_DISCONNECTED_KEY = "wallet_manually_disconnected";
|
|
86
|
-
var CONNECTED_NETWORK_TYPE_KEY = "connected_network_type";
|
|
87
102
|
function isWalletInstalled(networkType) {
|
|
88
103
|
if (typeof window === "undefined") {
|
|
89
104
|
return false;
|
|
@@ -104,22 +119,50 @@ function formatAddress(address) {
|
|
|
104
119
|
}
|
|
105
120
|
return `${address.slice(0, 6)}...${address.slice(-4)}`;
|
|
106
121
|
}
|
|
107
|
-
function
|
|
122
|
+
function getDisconnectedNetworks() {
|
|
123
|
+
if (typeof window === "undefined") {
|
|
124
|
+
return {};
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
const cached = localStorage.getItem(WALLET_DISCONNECTED_NETWORKS_KEY);
|
|
128
|
+
return cached ? JSON.parse(cached) : {};
|
|
129
|
+
} catch (error) {
|
|
130
|
+
return {};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function markWalletDisconnected(networkType) {
|
|
108
134
|
if (typeof window !== "undefined") {
|
|
109
|
-
|
|
110
|
-
|
|
135
|
+
if (networkType) {
|
|
136
|
+
const disconnected = getDisconnectedNetworks();
|
|
137
|
+
disconnected[networkType] = true;
|
|
138
|
+
localStorage.setItem(WALLET_DISCONNECTED_NETWORKS_KEY, JSON.stringify(disconnected));
|
|
139
|
+
} else {
|
|
140
|
+
localStorage.setItem(WALLET_DISCONNECTED_KEY, "true");
|
|
141
|
+
localStorage.removeItem(CONNECTED_NETWORK_TYPE_KEY);
|
|
142
|
+
}
|
|
111
143
|
}
|
|
112
144
|
}
|
|
113
|
-
function clearWalletDisconnection() {
|
|
145
|
+
function clearWalletDisconnection(networkType) {
|
|
114
146
|
if (typeof window !== "undefined") {
|
|
115
|
-
|
|
147
|
+
if (networkType) {
|
|
148
|
+
const disconnected = getDisconnectedNetworks();
|
|
149
|
+
delete disconnected[networkType];
|
|
150
|
+
localStorage.setItem(WALLET_DISCONNECTED_NETWORKS_KEY, JSON.stringify(disconnected));
|
|
151
|
+
} else {
|
|
152
|
+
localStorage.removeItem(WALLET_DISCONNECTED_KEY);
|
|
153
|
+
}
|
|
116
154
|
}
|
|
117
155
|
}
|
|
118
|
-
function isWalletManuallyDisconnected() {
|
|
156
|
+
function isWalletManuallyDisconnected(networkType) {
|
|
119
157
|
if (typeof window === "undefined") {
|
|
120
158
|
return false;
|
|
121
159
|
}
|
|
122
|
-
|
|
160
|
+
if (networkType) {
|
|
161
|
+
const disconnected = getDisconnectedNetworks();
|
|
162
|
+
return disconnected[networkType] === true;
|
|
163
|
+
} else {
|
|
164
|
+
return localStorage.getItem(WALLET_DISCONNECTED_KEY) === "true";
|
|
165
|
+
}
|
|
123
166
|
}
|
|
124
167
|
function saveConnectedNetworkType(networkType) {
|
|
125
168
|
if (typeof window !== "undefined") {
|
|
@@ -144,8 +187,70 @@ function getWalletInstallUrl(networkType) {
|
|
|
144
187
|
return "#";
|
|
145
188
|
}
|
|
146
189
|
}
|
|
190
|
+
function getAllWalletAddresses() {
|
|
191
|
+
if (typeof window === "undefined") {
|
|
192
|
+
return {};
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
const cached = localStorage.getItem(WALLET_ADDRESSES_KEY);
|
|
196
|
+
return cached ? JSON.parse(cached) : {};
|
|
197
|
+
} catch (error) {
|
|
198
|
+
console.error("Failed to parse wallet addresses cache:", error);
|
|
199
|
+
return {};
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function saveWalletAddress(networkType, address) {
|
|
203
|
+
if (typeof window === "undefined") {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const addresses = getAllWalletAddresses();
|
|
207
|
+
addresses[networkType] = address;
|
|
208
|
+
localStorage.setItem(WALLET_ADDRESSES_KEY, JSON.stringify(addresses));
|
|
209
|
+
}
|
|
210
|
+
function getCachedWalletAddress(networkType) {
|
|
211
|
+
const addresses = getAllWalletAddresses();
|
|
212
|
+
return addresses[networkType] || null;
|
|
213
|
+
}
|
|
214
|
+
function removeWalletAddress(networkType) {
|
|
215
|
+
if (typeof window === "undefined") {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
const addresses = getAllWalletAddresses();
|
|
219
|
+
delete addresses[networkType];
|
|
220
|
+
localStorage.setItem(WALLET_ADDRESSES_KEY, JSON.stringify(addresses));
|
|
221
|
+
}
|
|
222
|
+
var WALLET_DISCONNECTED_KEY, WALLET_DISCONNECTED_NETWORKS_KEY, CONNECTED_NETWORK_TYPE_KEY, WALLET_ADDRESSES_KEY;
|
|
223
|
+
var init_wallet = __esm({
|
|
224
|
+
"src/utils/wallet.ts"() {
|
|
225
|
+
"use strict";
|
|
226
|
+
WALLET_DISCONNECTED_KEY = "wallet_manually_disconnected";
|
|
227
|
+
WALLET_DISCONNECTED_NETWORKS_KEY = "wallet_disconnected_networks";
|
|
228
|
+
CONNECTED_NETWORK_TYPE_KEY = "connected_network_type";
|
|
229
|
+
WALLET_ADDRESSES_KEY = "wallet_addresses_cache";
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// src/react/index.ts
|
|
234
|
+
var index_exports = {};
|
|
235
|
+
__export(index_exports, {
|
|
236
|
+
V402Checkout: () => V402Checkout,
|
|
237
|
+
WalletConnect: () => WalletConnect,
|
|
238
|
+
usePageNetwork: () => usePageNetwork,
|
|
239
|
+
usePayment: () => usePayment,
|
|
240
|
+
usePaymentInfo: () => usePaymentInfo,
|
|
241
|
+
useWallet: () => useWallet
|
|
242
|
+
});
|
|
243
|
+
module.exports = __toCommonJS(index_exports);
|
|
244
|
+
var import_styles = require("./styles.css");
|
|
245
|
+
|
|
246
|
+
// src/react/hooks/useWalletStore.ts
|
|
247
|
+
var import_react = require("react");
|
|
248
|
+
|
|
249
|
+
// src/utils/index.ts
|
|
250
|
+
init_wallet();
|
|
147
251
|
|
|
148
252
|
// src/utils/wallet-connect.ts
|
|
253
|
+
init_wallet();
|
|
149
254
|
async function connectWallet(networkType) {
|
|
150
255
|
if (typeof window === "undefined") {
|
|
151
256
|
throw new Error("\u8BF7\u5728\u6D4F\u89C8\u5668\u73AF\u5883\u4E2D\u4F7F\u7528");
|
|
@@ -180,13 +285,11 @@ async function connectWallet(networkType) {
|
|
|
180
285
|
default:
|
|
181
286
|
throw new Error("\u4E0D\u652F\u6301\u7684\u7F51\u7EDC\u7C7B\u578B");
|
|
182
287
|
}
|
|
183
|
-
clearWalletDisconnection();
|
|
288
|
+
clearWalletDisconnection(networkType);
|
|
184
289
|
saveConnectedNetworkType(networkType);
|
|
290
|
+
saveWalletAddress(networkType, address);
|
|
185
291
|
return address;
|
|
186
292
|
}
|
|
187
|
-
function disconnectWallet() {
|
|
188
|
-
markWalletDisconnected();
|
|
189
|
-
}
|
|
190
293
|
async function getCurrentWallet(networkType) {
|
|
191
294
|
if (typeof window === "undefined") {
|
|
192
295
|
return null;
|
|
@@ -195,28 +298,36 @@ async function getCurrentWallet(networkType) {
|
|
|
195
298
|
if (!type) {
|
|
196
299
|
return null;
|
|
197
300
|
}
|
|
301
|
+
const cachedAddress = getCachedWalletAddress(type);
|
|
198
302
|
try {
|
|
303
|
+
let currentAddress = null;
|
|
199
304
|
switch (type) {
|
|
200
305
|
case "evm" /* EVM */: {
|
|
201
|
-
if (!window.ethereum) return
|
|
306
|
+
if (!window.ethereum) return cachedAddress;
|
|
202
307
|
const accounts = await window.ethereum.request({
|
|
203
308
|
method: "eth_accounts",
|
|
204
309
|
params: []
|
|
205
310
|
});
|
|
206
|
-
|
|
311
|
+
currentAddress = accounts && accounts.length > 0 ? accounts[0] : null;
|
|
312
|
+
break;
|
|
207
313
|
}
|
|
208
314
|
case "solana" /* SOLANA */:
|
|
209
315
|
case "svm" /* SVM */: {
|
|
210
316
|
const solana = window.solana;
|
|
211
|
-
if (!solana || !solana.isConnected) return
|
|
212
|
-
|
|
317
|
+
if (!solana || !solana.isConnected) return cachedAddress;
|
|
318
|
+
currentAddress = solana.publicKey?.toString() || null;
|
|
319
|
+
break;
|
|
213
320
|
}
|
|
214
321
|
default:
|
|
215
|
-
return
|
|
322
|
+
return cachedAddress;
|
|
323
|
+
}
|
|
324
|
+
if (currentAddress && currentAddress !== cachedAddress) {
|
|
325
|
+
saveWalletAddress(type, currentAddress);
|
|
216
326
|
}
|
|
327
|
+
return currentAddress || cachedAddress;
|
|
217
328
|
} catch (error) {
|
|
218
329
|
console.error("Failed to get current wallet:", error);
|
|
219
|
-
return
|
|
330
|
+
return cachedAddress;
|
|
220
331
|
}
|
|
221
332
|
}
|
|
222
333
|
function onAccountsChanged(callback) {
|
|
@@ -267,16 +378,534 @@ function onWalletDisconnect(callback) {
|
|
|
267
378
|
solana.removeListener?.("disconnect", handler);
|
|
268
379
|
};
|
|
269
380
|
}
|
|
381
|
+
async function switchNetwork(networkType) {
|
|
382
|
+
const cachedAddress = getCachedWalletAddress(networkType);
|
|
383
|
+
if (cachedAddress) {
|
|
384
|
+
saveConnectedNetworkType(networkType);
|
|
385
|
+
clearWalletDisconnection(networkType);
|
|
386
|
+
const currentAddress = await getCurrentWallet(networkType);
|
|
387
|
+
if (currentAddress) {
|
|
388
|
+
return currentAddress;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
270
393
|
|
|
271
394
|
// src/services/svm/payment-header.ts
|
|
272
395
|
var import_web3 = require("@solana/web3.js");
|
|
273
396
|
var import_spl_token = require("@solana/spl-token");
|
|
397
|
+
async function createSvmPaymentHeader(params) {
|
|
398
|
+
const { wallet, paymentRequirements, x402Version, rpcUrl } = params;
|
|
399
|
+
const connection = new import_web3.Connection(rpcUrl, "confirmed");
|
|
400
|
+
const feePayer = paymentRequirements?.extra?.feePayer;
|
|
401
|
+
if (typeof feePayer !== "string" || !feePayer) {
|
|
402
|
+
throw new Error("Missing facilitator feePayer in payment requirements (extra.feePayer).");
|
|
403
|
+
}
|
|
404
|
+
const feePayerPubkey = new import_web3.PublicKey(feePayer);
|
|
405
|
+
const walletAddress = wallet?.publicKey?.toString() || wallet?.address;
|
|
406
|
+
if (!walletAddress) {
|
|
407
|
+
throw new Error("Missing connected Solana wallet address or publicKey");
|
|
408
|
+
}
|
|
409
|
+
const userPubkey = new import_web3.PublicKey(walletAddress);
|
|
410
|
+
if (!paymentRequirements?.payTo) {
|
|
411
|
+
throw new Error("Missing payTo in payment requirements");
|
|
412
|
+
}
|
|
413
|
+
const destination = new import_web3.PublicKey(paymentRequirements.payTo);
|
|
414
|
+
const instructions = [];
|
|
415
|
+
instructions.push(
|
|
416
|
+
import_web3.ComputeBudgetProgram.setComputeUnitLimit({
|
|
417
|
+
units: 7e3
|
|
418
|
+
// Sufficient for SPL token transfer
|
|
419
|
+
})
|
|
420
|
+
);
|
|
421
|
+
instructions.push(
|
|
422
|
+
import_web3.ComputeBudgetProgram.setComputeUnitPrice({
|
|
423
|
+
microLamports: 1
|
|
424
|
+
// Minimal price
|
|
425
|
+
})
|
|
426
|
+
);
|
|
427
|
+
if (!paymentRequirements.asset) {
|
|
428
|
+
throw new Error("Missing token mint for SPL transfer");
|
|
429
|
+
}
|
|
430
|
+
const mintPubkey = new import_web3.PublicKey(paymentRequirements.asset);
|
|
431
|
+
const mintInfo = await connection.getAccountInfo(mintPubkey, "confirmed");
|
|
432
|
+
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;
|
|
433
|
+
const mint = await (0, import_spl_token.getMint)(connection, mintPubkey, void 0, programId);
|
|
434
|
+
const sourceAta = await (0, import_spl_token.getAssociatedTokenAddress)(
|
|
435
|
+
mintPubkey,
|
|
436
|
+
userPubkey,
|
|
437
|
+
false,
|
|
438
|
+
programId
|
|
439
|
+
);
|
|
440
|
+
const destinationAta = await (0, import_spl_token.getAssociatedTokenAddress)(
|
|
441
|
+
mintPubkey,
|
|
442
|
+
destination,
|
|
443
|
+
false,
|
|
444
|
+
programId
|
|
445
|
+
);
|
|
446
|
+
const sourceAtaInfo = await connection.getAccountInfo(sourceAta, "confirmed");
|
|
447
|
+
if (!sourceAtaInfo) {
|
|
448
|
+
throw new Error(
|
|
449
|
+
`User does not have an Associated Token Account for ${paymentRequirements.asset}. Please create one first or ensure you have the required token.`
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
const destAtaInfo = await connection.getAccountInfo(destinationAta, "confirmed");
|
|
453
|
+
if (!destAtaInfo) {
|
|
454
|
+
throw new Error(
|
|
455
|
+
`Destination does not have an Associated Token Account for ${paymentRequirements.asset}. The receiver must create their token account before receiving payments.`
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
const amount = BigInt(paymentRequirements.maxAmountRequired);
|
|
459
|
+
instructions.push(
|
|
460
|
+
(0, import_spl_token.createTransferCheckedInstruction)(
|
|
461
|
+
sourceAta,
|
|
462
|
+
mintPubkey,
|
|
463
|
+
destinationAta,
|
|
464
|
+
userPubkey,
|
|
465
|
+
amount,
|
|
466
|
+
mint.decimals,
|
|
467
|
+
[],
|
|
468
|
+
programId
|
|
469
|
+
)
|
|
470
|
+
);
|
|
471
|
+
const { blockhash } = await connection.getLatestBlockhash("confirmed");
|
|
472
|
+
const message2 = new import_web3.TransactionMessage({
|
|
473
|
+
payerKey: feePayerPubkey,
|
|
474
|
+
recentBlockhash: blockhash,
|
|
475
|
+
instructions
|
|
476
|
+
}).compileToV0Message();
|
|
477
|
+
const transaction = new import_web3.VersionedTransaction(message2);
|
|
478
|
+
if (typeof wallet?.signTransaction !== "function") {
|
|
479
|
+
throw new Error("Connected wallet does not support signTransaction");
|
|
480
|
+
}
|
|
481
|
+
let userSignedTx;
|
|
482
|
+
try {
|
|
483
|
+
userSignedTx = await wallet.signTransaction(transaction);
|
|
484
|
+
console.log("\u2705 Transaction signed successfully");
|
|
485
|
+
} catch (error) {
|
|
486
|
+
console.error("\u274C Failed to sign transaction:", error);
|
|
487
|
+
throw wrapPaymentError(error);
|
|
488
|
+
}
|
|
489
|
+
const serializedTransaction = Buffer.from(userSignedTx.serialize()).toString("base64");
|
|
490
|
+
const paymentPayload = {
|
|
491
|
+
x402Version,
|
|
492
|
+
scheme: paymentRequirements.scheme,
|
|
493
|
+
network: paymentRequirements.network,
|
|
494
|
+
payload: {
|
|
495
|
+
transaction: serializedTransaction
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
const paymentHeader = Buffer.from(JSON.stringify(paymentPayload)).toString("base64");
|
|
499
|
+
return paymentHeader;
|
|
500
|
+
}
|
|
501
|
+
function getDefaultSolanaRpcUrl(network) {
|
|
502
|
+
const normalized = network.toLowerCase();
|
|
503
|
+
if (normalized === "solana" || normalized === "solana-mainnet") {
|
|
504
|
+
return "https://cathee-fu8ezd-fast-mainnet.helius-rpc.com";
|
|
505
|
+
} else if (normalized === "solana-devnet") {
|
|
506
|
+
return "https://api.devnet.solana.com";
|
|
507
|
+
}
|
|
508
|
+
throw new Error(`Unsupported Solana network: ${network}`);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// src/services/svm/payment-handler.ts
|
|
512
|
+
init_types();
|
|
513
|
+
async function handleSvmPayment(endpoint, config, requestInit) {
|
|
514
|
+
const { wallet, network, rpcUrl, maxPaymentAmount } = config;
|
|
515
|
+
const initialResponse = await fetch(endpoint, {
|
|
516
|
+
...requestInit,
|
|
517
|
+
method: requestInit?.method || "POST"
|
|
518
|
+
});
|
|
519
|
+
if (initialResponse.status !== 402) {
|
|
520
|
+
return initialResponse;
|
|
521
|
+
}
|
|
522
|
+
const rawResponse = await initialResponse.json();
|
|
523
|
+
const IGNORED_ERRORS = [
|
|
524
|
+
"X-PAYMENT header is required",
|
|
525
|
+
"missing X-PAYMENT header",
|
|
526
|
+
"payment_required"
|
|
527
|
+
];
|
|
528
|
+
if (rawResponse.error && !IGNORED_ERRORS.includes(rawResponse.error)) {
|
|
529
|
+
console.error(`\u274C Payment verification failed: ${rawResponse.error}`);
|
|
530
|
+
const ERROR_MESSAGES = {
|
|
531
|
+
"insufficient_funds": "Insufficient balance to complete this payment",
|
|
532
|
+
"invalid_signature": "Invalid payment signature",
|
|
533
|
+
"expired": "Payment authorization has expired",
|
|
534
|
+
"already_used": "This payment has already been used",
|
|
535
|
+
"network_mismatch": "Payment network does not match",
|
|
536
|
+
"invalid_payment": "Invalid payment data",
|
|
537
|
+
"verification_failed": "Payment verification failed",
|
|
538
|
+
"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."
|
|
539
|
+
};
|
|
540
|
+
const errorMessage = ERROR_MESSAGES[rawResponse.error] || `Payment failed: ${rawResponse.error}`;
|
|
541
|
+
const error = new Error(errorMessage);
|
|
542
|
+
throw wrapPaymentError(error);
|
|
543
|
+
}
|
|
544
|
+
const x402Version = rawResponse.x402Version;
|
|
545
|
+
const parsedPaymentRequirements = rawResponse.accepts || [];
|
|
546
|
+
const selectedRequirements = parsedPaymentRequirements.find(
|
|
547
|
+
(req) => req.scheme === "exact" && SolanaNetworkSchema.safeParse(req.network.toLowerCase()).success
|
|
548
|
+
);
|
|
549
|
+
if (!selectedRequirements) {
|
|
550
|
+
console.error(
|
|
551
|
+
"\u274C No suitable Solana payment requirements found. Available networks:",
|
|
552
|
+
parsedPaymentRequirements.map((req) => req.network)
|
|
553
|
+
);
|
|
554
|
+
throw new Error("No suitable Solana payment requirements found");
|
|
555
|
+
}
|
|
556
|
+
if (maxPaymentAmount && maxPaymentAmount > BigInt(0)) {
|
|
557
|
+
if (BigInt(selectedRequirements.maxAmountRequired) > maxPaymentAmount) {
|
|
558
|
+
throw new Error(
|
|
559
|
+
`Payment amount ${selectedRequirements.maxAmountRequired} exceeds maximum allowed ${maxPaymentAmount}`
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
const effectiveRpcUrl = rpcUrl || getDefaultSolanaRpcUrl(selectedRequirements.network);
|
|
564
|
+
console.log(`\u{1F4CD} Using Solana RPC: ${effectiveRpcUrl.substring(0, 40)}...`);
|
|
565
|
+
console.log(`\u{1F4CD} Network from backend: ${selectedRequirements.network}`);
|
|
566
|
+
let paymentHeader;
|
|
567
|
+
try {
|
|
568
|
+
paymentHeader = await createSvmPaymentHeader({
|
|
569
|
+
wallet,
|
|
570
|
+
paymentRequirements: selectedRequirements,
|
|
571
|
+
x402Version,
|
|
572
|
+
rpcUrl: effectiveRpcUrl
|
|
573
|
+
});
|
|
574
|
+
console.log("\u2705 Payment header created successfully");
|
|
575
|
+
} catch (error) {
|
|
576
|
+
console.error("\u274C Failed to create payment header:", error);
|
|
577
|
+
throw wrapPaymentError(error);
|
|
578
|
+
}
|
|
579
|
+
const newInit = {
|
|
580
|
+
...requestInit,
|
|
581
|
+
method: requestInit?.method || "POST",
|
|
582
|
+
headers: {
|
|
583
|
+
...requestInit?.headers || {},
|
|
584
|
+
"X-PAYMENT": paymentHeader,
|
|
585
|
+
"Access-Control-Expose-Headers": "X-PAYMENT-RESPONSE"
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
const retryResponse = await fetch(endpoint, newInit);
|
|
589
|
+
if (retryResponse.status === 402) {
|
|
590
|
+
try {
|
|
591
|
+
const retryData = await retryResponse.json();
|
|
592
|
+
const IGNORED_ERRORS2 = [
|
|
593
|
+
"X-PAYMENT header is required",
|
|
594
|
+
"missing X-PAYMENT header",
|
|
595
|
+
"payment_required"
|
|
596
|
+
];
|
|
597
|
+
if (retryData.error && !IGNORED_ERRORS2.includes(retryData.error)) {
|
|
598
|
+
console.error(`\u274C Payment verification failed: ${retryData.error}`);
|
|
599
|
+
const ERROR_MESSAGES = {
|
|
600
|
+
"insufficient_funds": "Insufficient balance to complete this payment",
|
|
601
|
+
"invalid_signature": "Invalid payment signature",
|
|
602
|
+
"expired": "Payment authorization has expired",
|
|
603
|
+
"already_used": "This payment has already been used",
|
|
604
|
+
"network_mismatch": "Payment network does not match",
|
|
605
|
+
"invalid_payment": "Invalid payment data",
|
|
606
|
+
"verification_failed": "Payment verification failed",
|
|
607
|
+
"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."
|
|
608
|
+
};
|
|
609
|
+
const errorMessage = ERROR_MESSAGES[retryData.error] || `Payment failed: ${retryData.error}`;
|
|
610
|
+
const error = new Error(errorMessage);
|
|
611
|
+
throw wrapPaymentError(error);
|
|
612
|
+
}
|
|
613
|
+
} catch (error) {
|
|
614
|
+
if (error instanceof PaymentOperationError) {
|
|
615
|
+
throw error;
|
|
616
|
+
}
|
|
617
|
+
console.warn("\u26A0\uFE0F Could not parse retry 402 response:", error);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
return retryResponse;
|
|
621
|
+
}
|
|
274
622
|
|
|
275
623
|
// src/services/evm/payment-header.ts
|
|
276
624
|
var import_ethers = require("ethers");
|
|
625
|
+
async function createEvmPaymentHeader(params) {
|
|
626
|
+
const { wallet, paymentRequirements, x402Version, chainId } = params;
|
|
627
|
+
if (!paymentRequirements?.payTo) {
|
|
628
|
+
throw new Error("Missing payTo in payment requirements");
|
|
629
|
+
}
|
|
630
|
+
if (!paymentRequirements?.asset) {
|
|
631
|
+
throw new Error("Missing asset (token contract) in payment requirements");
|
|
632
|
+
}
|
|
633
|
+
if (wallet.getChainId) {
|
|
634
|
+
try {
|
|
635
|
+
const currentChainIdHex = await wallet.getChainId();
|
|
636
|
+
const currentChainId = parseInt(currentChainIdHex, 16);
|
|
637
|
+
if (currentChainId !== chainId) {
|
|
638
|
+
const networkNames = {
|
|
639
|
+
1: "Ethereum Mainnet",
|
|
640
|
+
11155111: "Sepolia Testnet",
|
|
641
|
+
8453: "Base Mainnet",
|
|
642
|
+
84532: "Base Sepolia Testnet",
|
|
643
|
+
137: "Polygon Mainnet",
|
|
644
|
+
42161: "Arbitrum One",
|
|
645
|
+
10: "Optimism Mainnet"
|
|
646
|
+
};
|
|
647
|
+
const currentNetworkName = networkNames[currentChainId] || `Chain ${currentChainId}`;
|
|
648
|
+
const targetNetworkName = networkNames[chainId] || `Chain ${chainId}`;
|
|
649
|
+
throw new Error(
|
|
650
|
+
`Network mismatch: Your wallet is connected to ${currentNetworkName}, but payment requires ${targetNetworkName}. Please switch your wallet to the correct network.`
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
console.log(`\u2705 Chain ID verified: ${chainId}`);
|
|
654
|
+
} catch (error) {
|
|
655
|
+
if (error.message.includes("Network mismatch")) {
|
|
656
|
+
throw wrapPaymentError(error);
|
|
657
|
+
}
|
|
658
|
+
console.warn("Could not verify chainId:", error);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
662
|
+
const nonceBytes = import_ethers.ethers.randomBytes(32);
|
|
663
|
+
const nonceBytes32 = import_ethers.ethers.hexlify(nonceBytes);
|
|
664
|
+
const domain = {
|
|
665
|
+
name: paymentRequirements.extra?.name || "USDC",
|
|
666
|
+
version: paymentRequirements.extra?.version || "2",
|
|
667
|
+
chainId,
|
|
668
|
+
verifyingContract: paymentRequirements.asset
|
|
669
|
+
};
|
|
670
|
+
const types = {
|
|
671
|
+
TransferWithAuthorization: [
|
|
672
|
+
{ name: "from", type: "address" },
|
|
673
|
+
{ name: "to", type: "address" },
|
|
674
|
+
{ name: "value", type: "uint256" },
|
|
675
|
+
{ name: "validAfter", type: "uint256" },
|
|
676
|
+
{ name: "validBefore", type: "uint256" },
|
|
677
|
+
{ name: "nonce", type: "bytes32" }
|
|
678
|
+
]
|
|
679
|
+
};
|
|
680
|
+
const authorization = {
|
|
681
|
+
from: wallet.address,
|
|
682
|
+
to: paymentRequirements.payTo,
|
|
683
|
+
value: paymentRequirements.maxAmountRequired,
|
|
684
|
+
validAfter: "0",
|
|
685
|
+
// Effective immediately
|
|
686
|
+
validBefore: String(now + (paymentRequirements.maxTimeoutSeconds || 3600)),
|
|
687
|
+
nonce: nonceBytes32
|
|
688
|
+
};
|
|
689
|
+
let signature;
|
|
690
|
+
try {
|
|
691
|
+
signature = await wallet.signTypedData(domain, types, authorization);
|
|
692
|
+
console.log("\u2705 Signature created successfully");
|
|
693
|
+
} catch (error) {
|
|
694
|
+
console.error("\u274C Failed to create signature:", error);
|
|
695
|
+
throw wrapPaymentError(error);
|
|
696
|
+
}
|
|
697
|
+
const headerPayload = {
|
|
698
|
+
x402_version: x402Version,
|
|
699
|
+
x402Version,
|
|
700
|
+
scheme: paymentRequirements.scheme,
|
|
701
|
+
network: paymentRequirements.network,
|
|
702
|
+
payload: {
|
|
703
|
+
signature,
|
|
704
|
+
authorization: {
|
|
705
|
+
from: authorization.from,
|
|
706
|
+
to: authorization.to,
|
|
707
|
+
value: String(authorization.value),
|
|
708
|
+
valid_after: authorization.validAfter,
|
|
709
|
+
validAfter: authorization.validAfter,
|
|
710
|
+
valid_before: authorization.validBefore,
|
|
711
|
+
validBefore: authorization.validBefore,
|
|
712
|
+
nonce: authorization.nonce
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
};
|
|
716
|
+
const paymentHeader = btoa(JSON.stringify(headerPayload));
|
|
717
|
+
return paymentHeader;
|
|
718
|
+
}
|
|
719
|
+
function getChainIdFromNetwork(network) {
|
|
720
|
+
const chainIdMap = {
|
|
721
|
+
"ethereum": 1,
|
|
722
|
+
"sepolia": 11155111,
|
|
723
|
+
"base": 8453,
|
|
724
|
+
"base-sepolia": 84532,
|
|
725
|
+
"polygon": 137,
|
|
726
|
+
"arbitrum": 42161,
|
|
727
|
+
"optimism": 10
|
|
728
|
+
};
|
|
729
|
+
const chainId = chainIdMap[network.toLowerCase()];
|
|
730
|
+
if (!chainId) {
|
|
731
|
+
throw new Error(`Unknown network: ${network}`);
|
|
732
|
+
}
|
|
733
|
+
return chainId;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
// src/services/evm/payment-handler.ts
|
|
737
|
+
init_types();
|
|
738
|
+
async function handleEvmPayment(endpoint, config, requestInit) {
|
|
739
|
+
const { wallet, network, maxPaymentAmount } = config;
|
|
740
|
+
const initialResponse = await fetch(endpoint, {
|
|
741
|
+
...requestInit,
|
|
742
|
+
method: requestInit?.method || "POST"
|
|
743
|
+
});
|
|
744
|
+
if (initialResponse.status !== 402) {
|
|
745
|
+
return initialResponse;
|
|
746
|
+
}
|
|
747
|
+
const rawResponse = await initialResponse.json();
|
|
748
|
+
const IGNORED_ERRORS = [
|
|
749
|
+
"X-PAYMENT header is required",
|
|
750
|
+
"missing X-PAYMENT header",
|
|
751
|
+
"payment_required"
|
|
752
|
+
];
|
|
753
|
+
if (rawResponse.error && !IGNORED_ERRORS.includes(rawResponse.error)) {
|
|
754
|
+
console.error(`\u274C Payment verification failed: ${rawResponse.error}`);
|
|
755
|
+
const ERROR_MESSAGES = {
|
|
756
|
+
"insufficient_funds": "Insufficient balance to complete this payment",
|
|
757
|
+
"invalid_signature": "Invalid payment signature",
|
|
758
|
+
"expired": "Payment authorization has expired",
|
|
759
|
+
"already_used": "This payment has already been used",
|
|
760
|
+
"network_mismatch": "Payment network does not match",
|
|
761
|
+
"invalid_payment": "Invalid payment data",
|
|
762
|
+
"verification_failed": "Payment verification failed"
|
|
763
|
+
};
|
|
764
|
+
const errorMessage = ERROR_MESSAGES[rawResponse.error] || `Payment failed: ${rawResponse.error}`;
|
|
765
|
+
const error = new Error(errorMessage);
|
|
766
|
+
throw wrapPaymentError(error);
|
|
767
|
+
}
|
|
768
|
+
const x402Version = rawResponse.x402Version;
|
|
769
|
+
const parsedPaymentRequirements = rawResponse.accepts || [];
|
|
770
|
+
const selectedRequirements = parsedPaymentRequirements.find(
|
|
771
|
+
(req) => req.scheme === "exact" && EvmNetworkSchema.safeParse(req.network.toLowerCase()).success
|
|
772
|
+
);
|
|
773
|
+
if (!selectedRequirements) {
|
|
774
|
+
console.error(
|
|
775
|
+
"\u274C No suitable EVM payment requirements found. Available networks:",
|
|
776
|
+
parsedPaymentRequirements.map((req) => req.network)
|
|
777
|
+
);
|
|
778
|
+
throw new Error("No suitable EVM payment requirements found");
|
|
779
|
+
}
|
|
780
|
+
if (maxPaymentAmount && maxPaymentAmount > BigInt(0)) {
|
|
781
|
+
if (BigInt(selectedRequirements.maxAmountRequired) > maxPaymentAmount) {
|
|
782
|
+
throw new Error(
|
|
783
|
+
`Payment amount ${selectedRequirements.maxAmountRequired} exceeds maximum allowed ${maxPaymentAmount}`
|
|
784
|
+
);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
const targetChainId = getChainIdFromNetwork(selectedRequirements.network);
|
|
788
|
+
let currentChainId;
|
|
789
|
+
if (wallet.getChainId) {
|
|
790
|
+
try {
|
|
791
|
+
const chainIdHex = await wallet.getChainId();
|
|
792
|
+
currentChainId = parseInt(chainIdHex, 16);
|
|
793
|
+
console.log(`\u{1F4CD} Current wallet chain: ${currentChainId}`);
|
|
794
|
+
} catch (error) {
|
|
795
|
+
console.warn("\u26A0\uFE0F Failed to get current chainId:", error);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
const networkNames = {
|
|
799
|
+
1: "Ethereum Mainnet",
|
|
800
|
+
11155111: "Sepolia Testnet",
|
|
801
|
+
8453: "Base Mainnet",
|
|
802
|
+
84532: "Base Sepolia Testnet",
|
|
803
|
+
137: "Polygon Mainnet",
|
|
804
|
+
42161: "Arbitrum One",
|
|
805
|
+
10: "Optimism Mainnet"
|
|
806
|
+
};
|
|
807
|
+
if (currentChainId && currentChainId !== targetChainId) {
|
|
808
|
+
if (!wallet.switchChain) {
|
|
809
|
+
const currentNetworkName = networkNames[currentChainId] || `Chain ${currentChainId}`;
|
|
810
|
+
const targetNetworkName = networkNames[targetChainId] || selectedRequirements.network;
|
|
811
|
+
const error = new Error(
|
|
812
|
+
`Network mismatch: Your wallet is connected to ${currentNetworkName}, but payment requires ${targetNetworkName}. Please switch to ${targetNetworkName} manually in your wallet.`
|
|
813
|
+
);
|
|
814
|
+
throw wrapPaymentError(error);
|
|
815
|
+
}
|
|
816
|
+
try {
|
|
817
|
+
console.log(`\u{1F504} Switching to chain ${targetChainId}...`);
|
|
818
|
+
await wallet.switchChain(`0x${targetChainId.toString(16)}`);
|
|
819
|
+
console.log(`\u2705 Successfully switched to chain ${targetChainId}`);
|
|
820
|
+
} catch (error) {
|
|
821
|
+
console.error("\u274C Failed to switch chain:", error);
|
|
822
|
+
const targetNetworkName = networkNames[targetChainId] || selectedRequirements.network;
|
|
823
|
+
const wrappedError = wrapPaymentError(error);
|
|
824
|
+
let finalError;
|
|
825
|
+
if (wrappedError.code === "USER_REJECTED" /* USER_REJECTED */) {
|
|
826
|
+
finalError = new PaymentOperationError({
|
|
827
|
+
code: wrappedError.code,
|
|
828
|
+
message: wrappedError.message,
|
|
829
|
+
userMessage: `You rejected the network switch request. Please switch to ${targetNetworkName} manually.`,
|
|
830
|
+
originalError: wrappedError.originalError
|
|
831
|
+
});
|
|
832
|
+
} else {
|
|
833
|
+
finalError = new PaymentOperationError({
|
|
834
|
+
code: "NETWORK_SWITCH_FAILED" /* NETWORK_SWITCH_FAILED */,
|
|
835
|
+
message: wrappedError.message,
|
|
836
|
+
userMessage: `Failed to switch to ${targetNetworkName}. Please switch manually in your wallet.`,
|
|
837
|
+
originalError: wrappedError.originalError
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
throw finalError;
|
|
841
|
+
}
|
|
842
|
+
} else if (wallet.switchChain && !currentChainId) {
|
|
843
|
+
try {
|
|
844
|
+
console.log(`\u{1F504} Attempting to switch to chain ${targetChainId}...`);
|
|
845
|
+
await wallet.switchChain(`0x${targetChainId.toString(16)}`);
|
|
846
|
+
console.log(`\u2705 Switch attempted successfully`);
|
|
847
|
+
} catch (error) {
|
|
848
|
+
console.warn("\u26A0\uFE0F Failed to switch chain (best effort):", error);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
let paymentHeader;
|
|
852
|
+
try {
|
|
853
|
+
paymentHeader = await createEvmPaymentHeader({
|
|
854
|
+
wallet,
|
|
855
|
+
paymentRequirements: selectedRequirements,
|
|
856
|
+
x402Version,
|
|
857
|
+
chainId: targetChainId
|
|
858
|
+
});
|
|
859
|
+
} catch (error) {
|
|
860
|
+
console.error("\u274C Failed to create payment header:", error);
|
|
861
|
+
throw wrapPaymentError(error);
|
|
862
|
+
}
|
|
863
|
+
const newInit = {
|
|
864
|
+
...requestInit,
|
|
865
|
+
method: requestInit?.method || "POST",
|
|
866
|
+
headers: {
|
|
867
|
+
...requestInit?.headers || {},
|
|
868
|
+
"X-PAYMENT": paymentHeader,
|
|
869
|
+
"Access-Control-Expose-Headers": "X-PAYMENT-RESPONSE"
|
|
870
|
+
}
|
|
871
|
+
};
|
|
872
|
+
const retryResponse = await fetch(endpoint, newInit);
|
|
873
|
+
if (retryResponse.status === 402) {
|
|
874
|
+
try {
|
|
875
|
+
const retryData = await retryResponse.json();
|
|
876
|
+
const IGNORED_ERRORS2 = [
|
|
877
|
+
"X-PAYMENT header is required",
|
|
878
|
+
"missing X-PAYMENT header",
|
|
879
|
+
"payment_required"
|
|
880
|
+
];
|
|
881
|
+
if (retryData.error && !IGNORED_ERRORS2.includes(retryData.error)) {
|
|
882
|
+
console.error(`\u274C Payment verification failed: ${retryData.error}`);
|
|
883
|
+
const ERROR_MESSAGES = {
|
|
884
|
+
"insufficient_funds": "Insufficient balance to complete this payment",
|
|
885
|
+
"invalid_signature": "Invalid payment signature",
|
|
886
|
+
"expired": "Payment authorization has expired",
|
|
887
|
+
"already_used": "This payment has already been used",
|
|
888
|
+
"network_mismatch": "Payment network does not match",
|
|
889
|
+
"invalid_payment": "Invalid payment data",
|
|
890
|
+
"verification_failed": "Payment verification failed"
|
|
891
|
+
};
|
|
892
|
+
const errorMessage = ERROR_MESSAGES[retryData.error] || `Payment failed: ${retryData.error}`;
|
|
893
|
+
const error = new Error(errorMessage);
|
|
894
|
+
throw wrapPaymentError(error);
|
|
895
|
+
}
|
|
896
|
+
} catch (error) {
|
|
897
|
+
if (error instanceof PaymentOperationError) {
|
|
898
|
+
throw error;
|
|
899
|
+
}
|
|
900
|
+
console.warn("\u26A0\uFE0F Could not parse retry 402 response:", error);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
return retryResponse;
|
|
904
|
+
}
|
|
277
905
|
|
|
278
906
|
// src/utils/payment-helpers.ts
|
|
279
907
|
var import_ethers2 = require("ethers");
|
|
908
|
+
init_common();
|
|
280
909
|
function parsePaymentRequired(response) {
|
|
281
910
|
if (response && typeof response === "object") {
|
|
282
911
|
if ("x402Version" in response && "accepts" in response) {
|
|
@@ -300,6 +929,62 @@ function getSupportedNetworkTypes(paymentRequirements) {
|
|
|
300
929
|
});
|
|
301
930
|
return Array.from(networkTypes);
|
|
302
931
|
}
|
|
932
|
+
async function makePayment(networkType, merchantId, endpoint = PROD_BACK_URL, additionalParams) {
|
|
933
|
+
const fullEndpoint = `${endpoint}/${merchantId}`;
|
|
934
|
+
let response;
|
|
935
|
+
const requestInit = additionalParams && Object.keys(additionalParams).length > 0 ? {
|
|
936
|
+
body: JSON.stringify(additionalParams),
|
|
937
|
+
headers: {
|
|
938
|
+
"Content-Type": "application/json"
|
|
939
|
+
}
|
|
940
|
+
} : {};
|
|
941
|
+
if (networkType === "solana" /* SOLANA */ || networkType === "svm" /* SVM */) {
|
|
942
|
+
const solana = window.solana;
|
|
943
|
+
if (!solana) {
|
|
944
|
+
throw new Error("\u8BF7\u5B89\u88C5 Phantom \u94B1\u5305");
|
|
945
|
+
}
|
|
946
|
+
if (!solana.isConnected) {
|
|
947
|
+
await solana.connect();
|
|
948
|
+
}
|
|
949
|
+
response = await handleSvmPayment(fullEndpoint, {
|
|
950
|
+
wallet: solana,
|
|
951
|
+
network: "solana"
|
|
952
|
+
// Will use backend's network configuration
|
|
953
|
+
}, requestInit);
|
|
954
|
+
} else if (networkType === "evm" /* EVM */) {
|
|
955
|
+
if (!window.ethereum) {
|
|
956
|
+
throw new Error("\u8BF7\u5B89\u88C5 MetaMask \u94B1\u5305");
|
|
957
|
+
}
|
|
958
|
+
const provider = new import_ethers2.ethers.BrowserProvider(window.ethereum);
|
|
959
|
+
const signer = await provider.getSigner();
|
|
960
|
+
const wallet = {
|
|
961
|
+
address: await signer.getAddress(),
|
|
962
|
+
signTypedData: async (domain, types, message2) => {
|
|
963
|
+
return await signer.signTypedData(domain, types, message2);
|
|
964
|
+
},
|
|
965
|
+
// Get current chain ID from wallet
|
|
966
|
+
getChainId: async () => {
|
|
967
|
+
const network = await provider.getNetwork();
|
|
968
|
+
return `0x${network.chainId.toString(16)}`;
|
|
969
|
+
},
|
|
970
|
+
// Switch to a different chain
|
|
971
|
+
switchChain: async (chainId) => {
|
|
972
|
+
await window.ethereum.request({
|
|
973
|
+
method: "wallet_switchEthereumChain",
|
|
974
|
+
params: [{ chainId }]
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
response = await handleEvmPayment(fullEndpoint, {
|
|
979
|
+
wallet,
|
|
980
|
+
network: "base"
|
|
981
|
+
// Will use backend's network configuration
|
|
982
|
+
}, requestInit);
|
|
983
|
+
} else {
|
|
984
|
+
throw new Error(`\u4E0D\u652F\u6301\u7684\u7F51\u7EDC\u7C7B\u578B: ${networkType}`);
|
|
985
|
+
}
|
|
986
|
+
return response;
|
|
987
|
+
}
|
|
303
988
|
|
|
304
989
|
// src/utils/network.ts
|
|
305
990
|
var NETWORK_TYPE_MAP = {
|
|
@@ -338,6 +1023,138 @@ function getNetworkDisplayName(network) {
|
|
|
338
1023
|
return displayNames[network.toLowerCase()] || network;
|
|
339
1024
|
}
|
|
340
1025
|
|
|
1026
|
+
// src/utils/payment-error-handler.ts
|
|
1027
|
+
function parsePaymentError(error) {
|
|
1028
|
+
if (!error) {
|
|
1029
|
+
return {
|
|
1030
|
+
code: "UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
1031
|
+
message: "Unknown error occurred",
|
|
1032
|
+
userMessage: "An unknown error occurred. Please try again.",
|
|
1033
|
+
originalError: error
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
const errorMessage = error.message || error.toString();
|
|
1037
|
+
const errorCode = error.code;
|
|
1038
|
+
if (errorCode === 4001 || errorCode === "ACTION_REJECTED" || errorMessage.includes("User rejected") || errorMessage.includes("user rejected") || errorMessage.includes("User denied") || errorMessage.includes("user denied") || errorMessage.includes("ethers-user-denied")) {
|
|
1039
|
+
return {
|
|
1040
|
+
code: "USER_REJECTED" /* USER_REJECTED */,
|
|
1041
|
+
message: "User rejected the transaction",
|
|
1042
|
+
userMessage: "You rejected the signature request. Please try again if you want to proceed.",
|
|
1043
|
+
originalError: error
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
if (errorMessage.includes("chainId") && (errorMessage.includes("must match") || errorMessage.includes("does not match"))) {
|
|
1047
|
+
const match = errorMessage.match(/chainId.*?"(\d+)".*?active.*?"(\d+)"/i) || errorMessage.match(/chain (\d+).*?chain (\d+)/i);
|
|
1048
|
+
if (match) {
|
|
1049
|
+
const [, requestedChain, activeChain] = match;
|
|
1050
|
+
return {
|
|
1051
|
+
code: "CHAIN_ID_MISMATCH" /* CHAIN_ID_MISMATCH */,
|
|
1052
|
+
message: `Network mismatch (wallet is on different chain): Requested ${requestedChain}, but wallet is on ${activeChain}`,
|
|
1053
|
+
userMessage: `Your wallet is on the wrong network. Please switch to the correct network and try again.`,
|
|
1054
|
+
originalError: error
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
1057
|
+
return {
|
|
1058
|
+
code: "CHAIN_ID_MISMATCH" /* CHAIN_ID_MISMATCH */,
|
|
1059
|
+
message: "Network mismatch (wallet selected network does not match)",
|
|
1060
|
+
userMessage: "Your wallet is on the wrong network. Please switch to the correct network.",
|
|
1061
|
+
originalError: error
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
if (errorMessage.includes("Network mismatch") || errorMessage.includes("Wrong network") || errorMessage.includes("Incorrect network")) {
|
|
1065
|
+
return {
|
|
1066
|
+
code: "NETWORK_MISMATCH" /* NETWORK_MISMATCH */,
|
|
1067
|
+
message: errorMessage,
|
|
1068
|
+
userMessage: "Please switch your wallet to the correct network.",
|
|
1069
|
+
originalError: error
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
if (errorMessage.includes("locked") || errorMessage.includes("Wallet is locked")) {
|
|
1073
|
+
return {
|
|
1074
|
+
code: "WALLET_LOCKED" /* WALLET_LOCKED */,
|
|
1075
|
+
message: "Wallet is locked",
|
|
1076
|
+
userMessage: "Please unlock your wallet and try again.",
|
|
1077
|
+
originalError: error
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1080
|
+
if (errorMessage.includes("insufficient") && (errorMessage.includes("balance") || errorMessage.includes("funds"))) {
|
|
1081
|
+
return {
|
|
1082
|
+
code: "INSUFFICIENT_BALANCE" /* INSUFFICIENT_BALANCE */,
|
|
1083
|
+
message: "Insufficient balance",
|
|
1084
|
+
userMessage: "You don't have enough balance to complete this payment.",
|
|
1085
|
+
originalError: error
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
if (errorMessage.includes("Failed to switch") || errorMessage.includes("switch chain")) {
|
|
1089
|
+
return {
|
|
1090
|
+
code: "NETWORK_SWITCH_FAILED" /* NETWORK_SWITCH_FAILED */,
|
|
1091
|
+
message: errorMessage,
|
|
1092
|
+
userMessage: "Failed to switch network. Please switch manually in your wallet.",
|
|
1093
|
+
originalError: error
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
if (errorMessage.includes("not connected") || errorMessage.includes("No wallet") || errorMessage.includes("Connect wallet")) {
|
|
1097
|
+
return {
|
|
1098
|
+
code: "WALLET_NOT_CONNECTED" /* WALLET_NOT_CONNECTED */,
|
|
1099
|
+
message: "Wallet not connected",
|
|
1100
|
+
userMessage: "Please connect your wallet first.",
|
|
1101
|
+
originalError: error
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
if (errorMessage.includes("No suitable") || errorMessage.includes("payment requirements") || errorMessage.includes("Missing payTo") || errorMessage.includes("Missing asset")) {
|
|
1105
|
+
return {
|
|
1106
|
+
code: "INVALID_PAYMENT_REQUIREMENTS" /* INVALID_PAYMENT_REQUIREMENTS */,
|
|
1107
|
+
message: errorMessage,
|
|
1108
|
+
userMessage: "Invalid payment configuration. Please contact support.",
|
|
1109
|
+
originalError: error
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
if (errorMessage.includes("exceeds maximum")) {
|
|
1113
|
+
return {
|
|
1114
|
+
code: "AMOUNT_EXCEEDED" /* AMOUNT_EXCEEDED */,
|
|
1115
|
+
message: errorMessage,
|
|
1116
|
+
userMessage: "Payment amount exceeds the maximum allowed.",
|
|
1117
|
+
originalError: error
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1120
|
+
if (errorMessage.includes("signature") || errorMessage.includes("sign") || errorCode === "UNKNOWN_ERROR") {
|
|
1121
|
+
return {
|
|
1122
|
+
code: "SIGNATURE_FAILED" /* SIGNATURE_FAILED */,
|
|
1123
|
+
message: errorMessage,
|
|
1124
|
+
userMessage: "Failed to sign the transaction. Please try again.",
|
|
1125
|
+
originalError: error
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
return {
|
|
1129
|
+
code: "UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
1130
|
+
message: errorMessage,
|
|
1131
|
+
userMessage: "An unexpected error occurred. Please try again or contact support.",
|
|
1132
|
+
originalError: error
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
1135
|
+
var PaymentOperationError = class _PaymentOperationError extends Error {
|
|
1136
|
+
constructor(paymentError) {
|
|
1137
|
+
super(paymentError.message);
|
|
1138
|
+
this.name = "PaymentOperationError";
|
|
1139
|
+
this.code = paymentError.code;
|
|
1140
|
+
this.userMessage = paymentError.userMessage;
|
|
1141
|
+
this.originalError = paymentError.originalError;
|
|
1142
|
+
if (Error.captureStackTrace) {
|
|
1143
|
+
Error.captureStackTrace(this, _PaymentOperationError);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
/**
|
|
1147
|
+
* Get a formatted error message for logging
|
|
1148
|
+
*/
|
|
1149
|
+
toLogString() {
|
|
1150
|
+
return `[${this.code}] ${this.message} | User Message: ${this.userMessage}`;
|
|
1151
|
+
}
|
|
1152
|
+
};
|
|
1153
|
+
function wrapPaymentError(error) {
|
|
1154
|
+
const parsedError = parsePaymentError(error);
|
|
1155
|
+
return new PaymentOperationError(parsedError);
|
|
1156
|
+
}
|
|
1157
|
+
|
|
341
1158
|
// src/react/store/walletStore.ts
|
|
342
1159
|
var WalletStore = class {
|
|
343
1160
|
constructor() {
|
|
@@ -354,60 +1171,28 @@ var WalletStore = class {
|
|
|
354
1171
|
init() {
|
|
355
1172
|
if (this.initialized) return;
|
|
356
1173
|
this.initialized = true;
|
|
357
|
-
this.autoReconnect();
|
|
358
1174
|
onAccountsChanged((accounts) => {
|
|
359
|
-
|
|
360
|
-
if (connectedType === "evm" /* EVM */) {
|
|
1175
|
+
if (this.state.networkType === "evm" /* EVM */) {
|
|
361
1176
|
if (accounts.length === 0) {
|
|
362
1177
|
this.setState({ address: null });
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
this.setState({ address: accounts[0] });
|
|
367
|
-
console.log("\u{1F504} Account changed:", accounts[0]);
|
|
368
|
-
}
|
|
1178
|
+
} else if (!isWalletManuallyDisconnected("evm" /* EVM */)) {
|
|
1179
|
+
this.setState({ address: accounts[0] });
|
|
1180
|
+
saveWalletAddress("evm" /* EVM */, accounts[0]);
|
|
369
1181
|
}
|
|
370
1182
|
}
|
|
371
1183
|
});
|
|
372
1184
|
onChainChanged(() => {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
console.log("\u26A0\uFE0F Network changed detected - disconnecting wallet");
|
|
376
|
-
disconnectWallet();
|
|
377
|
-
this.setState({
|
|
378
|
-
address: null,
|
|
379
|
-
networkType: null,
|
|
380
|
-
error: "Network changed. Please reconnect your wallet."
|
|
381
|
-
});
|
|
1185
|
+
if (this.state.networkType === "evm" /* EVM */) {
|
|
1186
|
+
this.handleDisconnect("evm" /* EVM */, "Chain changed. Please reconnect your wallet.");
|
|
382
1187
|
}
|
|
383
1188
|
});
|
|
384
1189
|
onWalletDisconnect(() => {
|
|
385
|
-
const
|
|
386
|
-
if (
|
|
387
|
-
|
|
388
|
-
disconnectWallet();
|
|
389
|
-
this.setState({
|
|
390
|
-
address: null,
|
|
391
|
-
networkType: null
|
|
392
|
-
});
|
|
1190
|
+
const svmTypes = ["solana" /* SOLANA */, "svm" /* SVM */];
|
|
1191
|
+
if (this.state.networkType && svmTypes.includes(this.state.networkType)) {
|
|
1192
|
+
this.handleDisconnect(this.state.networkType);
|
|
393
1193
|
}
|
|
394
1194
|
});
|
|
395
1195
|
}
|
|
396
|
-
async autoReconnect() {
|
|
397
|
-
if (!isWalletManuallyDisconnected()) {
|
|
398
|
-
const connectedType = getConnectedNetworkType();
|
|
399
|
-
if (connectedType) {
|
|
400
|
-
const currentAddress = await getCurrentWallet(connectedType);
|
|
401
|
-
if (currentAddress) {
|
|
402
|
-
this.setState({
|
|
403
|
-
address: currentAddress,
|
|
404
|
-
networkType: connectedType
|
|
405
|
-
});
|
|
406
|
-
console.log("\u{1F504} Auto-reconnected wallet:", currentAddress);
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
1196
|
// Get current state
|
|
412
1197
|
getState() {
|
|
413
1198
|
return this.state;
|
|
@@ -428,18 +1213,32 @@ var WalletStore = class {
|
|
|
428
1213
|
notifyListeners() {
|
|
429
1214
|
this.listeners.forEach((listener) => listener());
|
|
430
1215
|
}
|
|
1216
|
+
// Handle wallet disconnect (internal helper)
|
|
1217
|
+
handleDisconnect(networkType, error) {
|
|
1218
|
+
removeWalletAddress(networkType);
|
|
1219
|
+
markWalletDisconnected(networkType);
|
|
1220
|
+
if (typeof window !== "undefined") {
|
|
1221
|
+
localStorage.removeItem("connected_network_type");
|
|
1222
|
+
}
|
|
1223
|
+
this.setState({
|
|
1224
|
+
address: null,
|
|
1225
|
+
networkType: null,
|
|
1226
|
+
error: error || null
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
431
1229
|
// Connect wallet
|
|
432
1230
|
async connect(type) {
|
|
1231
|
+
if (this.state.address && this.state.networkType && this.state.networkType !== type) {
|
|
1232
|
+
saveWalletAddress(this.state.networkType, this.state.address);
|
|
1233
|
+
}
|
|
433
1234
|
this.setState({ isConnecting: true, error: null });
|
|
434
1235
|
try {
|
|
435
1236
|
const walletAddress = await connectWallet(type);
|
|
436
|
-
console.log("\u2705 Wallet connected:", walletAddress, "Network:", type);
|
|
437
1237
|
this.setState({
|
|
438
1238
|
address: walletAddress,
|
|
439
1239
|
networkType: type,
|
|
440
1240
|
isConnecting: false
|
|
441
1241
|
});
|
|
442
|
-
console.log("\u{1F4DD} Store state updated");
|
|
443
1242
|
} catch (err) {
|
|
444
1243
|
this.setState({
|
|
445
1244
|
error: err.message || "Failed to connect wallet",
|
|
@@ -448,20 +1247,67 @@ var WalletStore = class {
|
|
|
448
1247
|
throw err;
|
|
449
1248
|
}
|
|
450
1249
|
}
|
|
1250
|
+
// Switch network (use cached wallet if available)
|
|
1251
|
+
async switchNetwork(type) {
|
|
1252
|
+
if (this.state.address && this.state.networkType) {
|
|
1253
|
+
saveWalletAddress(this.state.networkType, this.state.address);
|
|
1254
|
+
}
|
|
1255
|
+
this.setState({ isConnecting: true, error: null });
|
|
1256
|
+
try {
|
|
1257
|
+
const address = await switchNetwork(type);
|
|
1258
|
+
if (address) {
|
|
1259
|
+
this.setState({
|
|
1260
|
+
address,
|
|
1261
|
+
networkType: type,
|
|
1262
|
+
isConnecting: false
|
|
1263
|
+
});
|
|
1264
|
+
} else {
|
|
1265
|
+
this.setState({
|
|
1266
|
+
address: null,
|
|
1267
|
+
networkType: type,
|
|
1268
|
+
isConnecting: true
|
|
1269
|
+
});
|
|
1270
|
+
await this.connect(type);
|
|
1271
|
+
}
|
|
1272
|
+
} catch (err) {
|
|
1273
|
+
this.setState({
|
|
1274
|
+
error: err.message || "Failed to switch network",
|
|
1275
|
+
isConnecting: false
|
|
1276
|
+
});
|
|
1277
|
+
throw err;
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
451
1280
|
// Disconnect wallet
|
|
452
1281
|
disconnect() {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
1282
|
+
const currentNetwork = this.state.networkType;
|
|
1283
|
+
if (currentNetwork) {
|
|
1284
|
+
this.handleDisconnect(currentNetwork);
|
|
1285
|
+
} else {
|
|
1286
|
+
this.setState({
|
|
1287
|
+
address: null,
|
|
1288
|
+
networkType: null,
|
|
1289
|
+
error: null
|
|
1290
|
+
});
|
|
1291
|
+
}
|
|
460
1292
|
}
|
|
461
1293
|
// Clear error
|
|
462
1294
|
clearError() {
|
|
463
1295
|
this.setState({ error: null });
|
|
464
1296
|
}
|
|
1297
|
+
// Ensure network matches expected type (for page-specific network requirements)
|
|
1298
|
+
async ensureNetwork(expectedNetwork) {
|
|
1299
|
+
if (isWalletManuallyDisconnected(expectedNetwork)) {
|
|
1300
|
+
return;
|
|
1301
|
+
}
|
|
1302
|
+
if (this.state.networkType === expectedNetwork && this.state.address) {
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
if (this.state.networkType !== expectedNetwork) {
|
|
1306
|
+
await this.switchNetwork(expectedNetwork);
|
|
1307
|
+
} else if (!this.state.address) {
|
|
1308
|
+
await this.connect(expectedNetwork);
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
465
1311
|
};
|
|
466
1312
|
var walletStore = new WalletStore();
|
|
467
1313
|
if (typeof window !== "undefined") {
|
|
@@ -479,24 +1325,43 @@ function useWallet() {
|
|
|
479
1325
|
return {
|
|
480
1326
|
...state,
|
|
481
1327
|
connect: (type) => walletStore.connect(type),
|
|
1328
|
+
switchNetwork: (type) => walletStore.switchNetwork(type),
|
|
1329
|
+
ensureNetwork: (type) => walletStore.ensureNetwork(type),
|
|
482
1330
|
disconnect: () => walletStore.disconnect(),
|
|
483
1331
|
clearError: () => walletStore.clearError()
|
|
484
1332
|
};
|
|
485
1333
|
}
|
|
486
1334
|
|
|
487
|
-
// src/react/hooks/
|
|
1335
|
+
// src/react/hooks/usePageNetwork.ts
|
|
488
1336
|
var import_react2 = require("react");
|
|
1337
|
+
function usePageNetwork(expectedNetwork, options = {}) {
|
|
1338
|
+
const {
|
|
1339
|
+
autoSwitch = true,
|
|
1340
|
+
switchOnMount = true
|
|
1341
|
+
} = options;
|
|
1342
|
+
const wallet = useWallet();
|
|
1343
|
+
(0, import_react2.useEffect)(() => {
|
|
1344
|
+
if (!autoSwitch || !switchOnMount) return;
|
|
1345
|
+
wallet.ensureNetwork(expectedNetwork).catch((err) => {
|
|
1346
|
+
console.error("Failed to ensure network:", err);
|
|
1347
|
+
});
|
|
1348
|
+
}, [expectedNetwork]);
|
|
1349
|
+
return wallet;
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
// src/react/hooks/usePayment.ts
|
|
1353
|
+
var import_react3 = require("react");
|
|
489
1354
|
function usePayment() {
|
|
490
|
-
const [isProcessing, setIsProcessing] = (0,
|
|
491
|
-
const [result, setResult] = (0,
|
|
492
|
-
const [error, setError] = (0,
|
|
493
|
-
const clearResult = (0,
|
|
1355
|
+
const [isProcessing, setIsProcessing] = (0, import_react3.useState)(false);
|
|
1356
|
+
const [result, setResult] = (0, import_react3.useState)(null);
|
|
1357
|
+
const [error, setError] = (0, import_react3.useState)(null);
|
|
1358
|
+
const clearResult = (0, import_react3.useCallback)(() => {
|
|
494
1359
|
setResult(null);
|
|
495
1360
|
}, []);
|
|
496
|
-
const clearError = (0,
|
|
1361
|
+
const clearError = (0, import_react3.useCallback)(() => {
|
|
497
1362
|
setError(null);
|
|
498
1363
|
}, []);
|
|
499
|
-
const reset = (0,
|
|
1364
|
+
const reset = (0, import_react3.useCallback)(() => {
|
|
500
1365
|
setIsProcessing(false);
|
|
501
1366
|
setResult(null);
|
|
502
1367
|
setError(null);
|
|
@@ -515,12 +1380,13 @@ function usePayment() {
|
|
|
515
1380
|
}
|
|
516
1381
|
|
|
517
1382
|
// src/react/hooks/usePaymentInfo.ts
|
|
518
|
-
var
|
|
1383
|
+
var import_react4 = require("react");
|
|
1384
|
+
init_common();
|
|
519
1385
|
function usePaymentInfo(merchantId, endpoint = PROD_BACK_URL, additionalParams) {
|
|
520
|
-
const [paymentInfo, setPaymentInfo] = (0,
|
|
521
|
-
const [supportedNetworks, setSupportedNetworks] = (0,
|
|
522
|
-
const [isLoading, setIsLoading] = (0,
|
|
523
|
-
const [error, setError] = (0,
|
|
1386
|
+
const [paymentInfo, setPaymentInfo] = (0, import_react4.useState)(null);
|
|
1387
|
+
const [supportedNetworks, setSupportedNetworks] = (0, import_react4.useState)([]);
|
|
1388
|
+
const [isLoading, setIsLoading] = (0, import_react4.useState)(true);
|
|
1389
|
+
const [error, setError] = (0, import_react4.useState)(null);
|
|
524
1390
|
const fetchPaymentInfo = async () => {
|
|
525
1391
|
setIsLoading(true);
|
|
526
1392
|
setError(null);
|
|
@@ -554,7 +1420,7 @@ function usePaymentInfo(merchantId, endpoint = PROD_BACK_URL, additionalParams)
|
|
|
554
1420
|
setIsLoading(false);
|
|
555
1421
|
}
|
|
556
1422
|
};
|
|
557
|
-
(0,
|
|
1423
|
+
(0, import_react4.useEffect)(() => {
|
|
558
1424
|
fetchPaymentInfo();
|
|
559
1425
|
}, [endpoint, merchantId]);
|
|
560
1426
|
return {
|
|
@@ -567,7 +1433,7 @@ function usePaymentInfo(merchantId, endpoint = PROD_BACK_URL, additionalParams)
|
|
|
567
1433
|
}
|
|
568
1434
|
|
|
569
1435
|
// src/react/components/WalletConnect.tsx
|
|
570
|
-
var
|
|
1436
|
+
var import_react5 = __toESM(require("react"));
|
|
571
1437
|
|
|
572
1438
|
// src/react/styles/inline-styles.ts
|
|
573
1439
|
var isDarkMode = () => {
|
|
@@ -756,8 +1622,8 @@ function WalletConnect({
|
|
|
756
1622
|
onDisconnect
|
|
757
1623
|
}) {
|
|
758
1624
|
const { address, networkType, isConnecting, error, connect, disconnect } = useWallet();
|
|
759
|
-
const [hoveredButton, setHoveredButton] = (0,
|
|
760
|
-
const [hoveredLink, setHoveredLink] = (0,
|
|
1625
|
+
const [hoveredButton, setHoveredButton] = (0, import_react5.useState)(null);
|
|
1626
|
+
const [hoveredLink, setHoveredLink] = (0, import_react5.useState)(null);
|
|
761
1627
|
const handleConnect = async (network) => {
|
|
762
1628
|
try {
|
|
763
1629
|
await connect(network);
|
|
@@ -768,9 +1634,9 @@ function WalletConnect({
|
|
|
768
1634
|
disconnect();
|
|
769
1635
|
onDisconnect?.();
|
|
770
1636
|
};
|
|
771
|
-
return /* @__PURE__ */
|
|
1637
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { style: { ...containerStyle, ...className ? {} : {} }, className }, !address ? /* @__PURE__ */ import_react5.default.createElement("div", { style: getSectionStyle() }, /* @__PURE__ */ import_react5.default.createElement("h3", { style: getTitleStyle() }, "Connect Wallet"), supportedNetworks.length === 0 ? /* @__PURE__ */ import_react5.default.createElement("p", { style: getHintStyle() }, "Please install a supported wallet extension") : /* @__PURE__ */ import_react5.default.createElement("div", { style: buttonsContainerStyle }, supportedNetworks.map((network) => {
|
|
772
1638
|
const installed = isWalletInstalled(network);
|
|
773
|
-
return /* @__PURE__ */
|
|
1639
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { key: network, style: walletOptionStyle }, /* @__PURE__ */ import_react5.default.createElement(
|
|
774
1640
|
"button",
|
|
775
1641
|
{
|
|
776
1642
|
style: getConnectButtonStyle(isConnecting || !installed, hoveredButton === network),
|
|
@@ -780,7 +1646,7 @@ function WalletConnect({
|
|
|
780
1646
|
onMouseLeave: () => setHoveredButton(null)
|
|
781
1647
|
},
|
|
782
1648
|
isConnecting ? "Connecting..." : getNetworkDisplayName(network)
|
|
783
|
-
), !installed && /* @__PURE__ */
|
|
1649
|
+
), !installed && /* @__PURE__ */ import_react5.default.createElement(
|
|
784
1650
|
"a",
|
|
785
1651
|
{
|
|
786
1652
|
href: getWalletInstallUrl(network),
|
|
@@ -792,7 +1658,7 @@ function WalletConnect({
|
|
|
792
1658
|
},
|
|
793
1659
|
"Install Wallet"
|
|
794
1660
|
));
|
|
795
|
-
})), error && /* @__PURE__ */
|
|
1661
|
+
})), error && /* @__PURE__ */ import_react5.default.createElement("p", { style: getErrorStyle() }, error), /* @__PURE__ */ import_react5.default.createElement("p", { style: getHintStyle() }, "To switch accounts, please change it in your wallet extension")) : /* @__PURE__ */ import_react5.default.createElement("div", { style: getSectionStyle() }, /* @__PURE__ */ import_react5.default.createElement("div", { style: walletAddressStyle }, /* @__PURE__ */ import_react5.default.createElement("span", { style: getLabelStyle() }, "Connected ", networkType && `(${getNetworkDisplayName(networkType)})`), /* @__PURE__ */ import_react5.default.createElement("span", { style: getAddressStyle() }, formatAddress(address))), /* @__PURE__ */ import_react5.default.createElement("div", { style: walletActionsStyle }, /* @__PURE__ */ import_react5.default.createElement(
|
|
796
1662
|
"button",
|
|
797
1663
|
{
|
|
798
1664
|
style: getDisconnectButtonStyle(hoveredButton === "disconnect"),
|
|
@@ -801,11 +1667,568 @@ function WalletConnect({
|
|
|
801
1667
|
onMouseLeave: () => setHoveredButton(null)
|
|
802
1668
|
},
|
|
803
1669
|
"Disconnect"
|
|
804
|
-
)), /* @__PURE__ */
|
|
1670
|
+
)), /* @__PURE__ */ import_react5.default.createElement("p", { style: getHintStyle() }, "Switch account in your wallet to change address")));
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
// src/react/components/V402Checkout.tsx
|
|
1674
|
+
var import_react7 = __toESM(require("react"));
|
|
1675
|
+
var import_antd = require("antd");
|
|
1676
|
+
var import_icons = require("@ant-design/icons");
|
|
1677
|
+
init_common();
|
|
1678
|
+
|
|
1679
|
+
// src/react/utils/CryptoIcons.tsx
|
|
1680
|
+
var import_react6 = __toESM(require("react"));
|
|
1681
|
+
var SolanaIcon = ({ width = 16, height = 16, className, style }) => {
|
|
1682
|
+
return /* @__PURE__ */ import_react6.default.createElement(
|
|
1683
|
+
"svg",
|
|
1684
|
+
{
|
|
1685
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1686
|
+
viewBox: "0 0 16 16",
|
|
1687
|
+
width,
|
|
1688
|
+
height,
|
|
1689
|
+
className,
|
|
1690
|
+
style
|
|
1691
|
+
},
|
|
1692
|
+
/* @__PURE__ */ import_react6.default.createElement("desc", null, "Solana SOL Fill Streamline Icon: https://streamlinehq.com"),
|
|
1693
|
+
/* @__PURE__ */ import_react6.default.createElement("g", { fill: "none", fillRule: "evenodd" }, /* @__PURE__ */ import_react6.default.createElement(
|
|
1694
|
+
"path",
|
|
1695
|
+
{
|
|
1696
|
+
d: "M16 0v16H0V0h16ZM8.395333333333333 15.505333333333333l-0.007333333333333332 0.0013333333333333333 -0.047333333333333324 0.023333333333333334 -0.013333333333333332 0.0026666666666666666 -0.009333333333333332 -0.0026666666666666666 -0.047333333333333324 -0.023333333333333334c-0.006666666666666666 -0.0026666666666666666 -0.012666666666666666 -0.0006666666666666666 -0.016 0.003333333333333333l-0.0026666666666666666 0.006666666666666666 -0.011333333333333334 0.2853333333333333 0.003333333333333333 0.013333333333333332 0.006666666666666666 0.008666666666666666 0.06933333333333333 0.049333333333333326 0.009999999999999998 0.0026666666666666666 0.008 -0.0026666666666666666 0.06933333333333333 -0.049333333333333326 0.008 -0.010666666666666666 0.0026666666666666666 -0.011333333333333334 -0.011333333333333334 -0.2846666666666666c-0.0013333333333333333 -0.006666666666666666 -0.005999999999999999 -0.011333333333333334 -0.011333333333333334 -0.011999999999999999Zm0.17666666666666667 -0.07533333333333334 -0.008666666666666666 0.0013333333333333333 -0.12333333333333332 0.062 -0.006666666666666666 0.006666666666666666 -0.002 0.007333333333333332 0.011999999999999999 0.2866666666666666 0.003333333333333333 0.008 0.005333333333333333 0.004666666666666666 0.134 0.062c0.008 0.0026666666666666666 0.015333333333333332 0 0.019333333333333334 -0.005333333333333333l0.0026666666666666666 -0.009333333333333332 -0.02266666666666667 -0.4093333333333333c-0.002 -0.008 -0.006666666666666666 -0.013333333333333332 -0.013333333333333332 -0.014666666666666665Zm-0.4766666666666666 0.0013333333333333333a0.015333333333333332 0.015333333333333332 0 0 0 -0.018 0.004l-0.004 0.009333333333333332 -0.02266666666666667 0.4093333333333333c0 0.008 0.004666666666666666 0.013333333333333332 0.011333333333333334 0.016l0.009999999999999998 -0.0013333333333333333 0.134 -0.062 0.006666666666666666 -0.005333333333333333 0.0026666666666666666 -0.007333333333333332 0.011333333333333334 -0.2866666666666666 -0.002 -0.008 -0.006666666666666666 -0.006666666666666666 -0.12266666666666666 -0.06133333333333333Z",
|
|
1697
|
+
strokeWidth: "0.6667"
|
|
1698
|
+
}
|
|
1699
|
+
), /* @__PURE__ */ import_react6.default.createElement(
|
|
1700
|
+
"path",
|
|
1701
|
+
{
|
|
1702
|
+
fill: "#000000",
|
|
1703
|
+
d: "M4.862 2.862A0.6666666666666666 0.6666666666666666 0 0 1 5.333333333333333 2.6666666666666665h8.666666666666666a0.6666666666666666 0.6666666666666666 0 0 1 0.47133333333333327 1.138l-2 2A0.6666666666666666 0.6666666666666666 0 0 1 12 6H3.333333333333333a0.6666666666666666 0.6666666666666666 0 0 1 -0.47133333333333327 -1.138l2 -2Zm-2.1166666666666663 4.156666666666666A0.6666666666666666 0.6666666666666666 0 0 1 3.333333333333333 6.666666666666666h8.666666666666666a0.6666666666666666 0.6666666666666666 0 0 1 0.5546666666666666 0.29666666666666663l1.3333333333333333 2A0.6666666666666666 0.6666666666666666 0 0 1 13.333333333333332 10H4.666666666666666a0.6666666666666666 0.6666666666666666 0 0 1 -0.5546666666666666 -0.29666666666666663l-1.3333333333333333 -2a0.6666666666666666 0.6666666666666666 0 0 1 -0.03333333333333333 -0.6846666666666665Zm1.4499999999999997 3.843333333333333A0.6666666666666666 0.6666666666666666 0 0 1 4.666666666666666 10.666666666666666h8.666666666666666a0.6666666666666666 0.6666666666666666 0 0 1 0.47133333333333327 1.138l-2 2A0.6666666666666666 0.6666666666666666 0 0 1 11.333333333333332 14H2.6666666666666665a0.6666666666666666 0.6666666666666666 0 0 1 -0.47133333333333327 -1.138l2 -2Z",
|
|
1704
|
+
strokeWidth: "0.6667"
|
|
1705
|
+
}
|
|
1706
|
+
))
|
|
1707
|
+
);
|
|
1708
|
+
};
|
|
1709
|
+
var BaseIcon = ({ width = 24, height = 24, className, style }) => {
|
|
1710
|
+
return /* @__PURE__ */ import_react6.default.createElement(
|
|
1711
|
+
"svg",
|
|
1712
|
+
{
|
|
1713
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1714
|
+
viewBox: "0 0 24 24",
|
|
1715
|
+
fill: "none",
|
|
1716
|
+
stroke: "#000000",
|
|
1717
|
+
strokeLinecap: "round",
|
|
1718
|
+
strokeLinejoin: "round",
|
|
1719
|
+
width,
|
|
1720
|
+
height,
|
|
1721
|
+
className,
|
|
1722
|
+
style
|
|
1723
|
+
},
|
|
1724
|
+
/* @__PURE__ */ import_react6.default.createElement("desc", null, "Brand Coinbase Streamline Icon: https://streamlinehq.com"),
|
|
1725
|
+
/* @__PURE__ */ import_react6.default.createElement(
|
|
1726
|
+
"path",
|
|
1727
|
+
{
|
|
1728
|
+
d: "M12.95 22c-4.503 0 -8.445 -3.04 -9.61 -7.413 -1.165 -4.373 0.737 -8.988 4.638 -11.25a9.906 9.906 0 0 1 12.008 1.598l-3.335 3.367a5.185 5.185 0 0 0 -7.354 0.013 5.252 5.252 0 0 0 0 7.393 5.185 5.185 0 0 0 7.354 0.013L20 19.088A9.887 9.887 0 0 1 12.95 22z",
|
|
1729
|
+
strokeWidth: "2"
|
|
1730
|
+
}
|
|
1731
|
+
)
|
|
1732
|
+
);
|
|
1733
|
+
};
|
|
1734
|
+
var getNetworkIcon = (network) => {
|
|
1735
|
+
const networkLower = network.toLowerCase();
|
|
1736
|
+
if (networkLower.includes("solana")) {
|
|
1737
|
+
return SolanaIcon;
|
|
1738
|
+
}
|
|
1739
|
+
if (networkLower.includes("base")) {
|
|
1740
|
+
return BaseIcon;
|
|
1741
|
+
}
|
|
1742
|
+
return BaseIcon;
|
|
1743
|
+
};
|
|
1744
|
+
|
|
1745
|
+
// src/react/components/V402Checkout.tsx
|
|
1746
|
+
var { Title, Text } = import_antd.Typography;
|
|
1747
|
+
var notify = {
|
|
1748
|
+
success: (title, msg) => {
|
|
1749
|
+
import_antd.message.success(`${title}: ${msg}`);
|
|
1750
|
+
},
|
|
1751
|
+
error: (title, msg) => {
|
|
1752
|
+
import_antd.message.error(`${title}: ${msg}`);
|
|
1753
|
+
},
|
|
1754
|
+
info: (title, msg) => {
|
|
1755
|
+
import_antd.message.info(`${title}: ${msg}`);
|
|
1756
|
+
}
|
|
1757
|
+
};
|
|
1758
|
+
function V402Checkout({
|
|
1759
|
+
checkoutId,
|
|
1760
|
+
headerInfo = {},
|
|
1761
|
+
isModal = false,
|
|
1762
|
+
onPaymentComplete,
|
|
1763
|
+
additionalParams = {},
|
|
1764
|
+
expectedNetwork
|
|
1765
|
+
}) {
|
|
1766
|
+
const {
|
|
1767
|
+
title = "V402Pay - Make x402Pay Easier",
|
|
1768
|
+
subtitle = "onvoyage.ai",
|
|
1769
|
+
tooltipText = "V402Pay - Accept Crypto Payments Easier"
|
|
1770
|
+
} = headerInfo;
|
|
1771
|
+
let endpoint = DEV_BACK_URL;
|
|
1772
|
+
const {
|
|
1773
|
+
supportedNetworks,
|
|
1774
|
+
isLoading: fetchingPaymentInfo,
|
|
1775
|
+
paymentInfo
|
|
1776
|
+
} = usePaymentInfo(checkoutId, endpoint, additionalParams);
|
|
1777
|
+
const targetNetwork = expectedNetwork || supportedNetworks[0];
|
|
1778
|
+
const { address, networkType, disconnect, ensureNetwork } = usePageNetwork(
|
|
1779
|
+
targetNetwork,
|
|
1780
|
+
{ autoSwitch: !!targetNetwork, switchOnMount: true }
|
|
1781
|
+
);
|
|
1782
|
+
const { isProcessing, setIsProcessing, result, setResult, error, setError } = usePayment();
|
|
1783
|
+
const [paymentDetails, setPaymentDetails] = (0, import_react7.useState)(null);
|
|
1784
|
+
const handleDisconnect = () => {
|
|
1785
|
+
disconnect();
|
|
1786
|
+
setResult(null);
|
|
1787
|
+
setError(null);
|
|
1788
|
+
notify.info("Wallet Disconnected", "Your wallet has been disconnected successfully.");
|
|
1789
|
+
};
|
|
1790
|
+
(0, import_react7.useEffect)(() => {
|
|
1791
|
+
if (paymentInfo && paymentInfo.length > 0) {
|
|
1792
|
+
const firstPayment = paymentInfo[0];
|
|
1793
|
+
const rawAmount = firstPayment.maxAmountRequired?.toString() || "0";
|
|
1794
|
+
const decimals = 6;
|
|
1795
|
+
const humanReadableAmount = (Number(rawAmount) / Math.pow(10, decimals)).toFixed(2);
|
|
1796
|
+
const network = firstPayment.network || "Unknown";
|
|
1797
|
+
const currency = "USDC";
|
|
1798
|
+
setPaymentDetails({
|
|
1799
|
+
amount: humanReadableAmount,
|
|
1800
|
+
currency,
|
|
1801
|
+
network
|
|
1802
|
+
});
|
|
1803
|
+
}
|
|
1804
|
+
}, [paymentInfo]);
|
|
1805
|
+
(0, import_react7.useEffect)(() => {
|
|
1806
|
+
if (targetNetwork && !fetchingPaymentInfo && ensureNetwork) {
|
|
1807
|
+
ensureNetwork(targetNetwork).catch((err) => {
|
|
1808
|
+
console.error("Failed to ensure network:", err);
|
|
1809
|
+
});
|
|
1810
|
+
}
|
|
1811
|
+
}, [targetNetwork, fetchingPaymentInfo]);
|
|
1812
|
+
const handlePayment = async () => {
|
|
1813
|
+
if (!networkType) {
|
|
1814
|
+
notify.error("Wallet Not Connected", "Please connect your wallet first.");
|
|
1815
|
+
return;
|
|
1816
|
+
}
|
|
1817
|
+
setResult(null);
|
|
1818
|
+
setError(null);
|
|
1819
|
+
setIsProcessing(true);
|
|
1820
|
+
try {
|
|
1821
|
+
const response = await makePayment(networkType, checkoutId, endpoint, additionalParams);
|
|
1822
|
+
const data = await response.json();
|
|
1823
|
+
setResult(data);
|
|
1824
|
+
notify.success("Payment Successful!", "Your payment has been processed successfully.");
|
|
1825
|
+
if (onPaymentComplete) {
|
|
1826
|
+
onPaymentComplete(data);
|
|
1827
|
+
}
|
|
1828
|
+
} catch (err) {
|
|
1829
|
+
const errorMessage = err.message || "Payment failed";
|
|
1830
|
+
setError(errorMessage);
|
|
1831
|
+
notify.error("Payment Failed", errorMessage);
|
|
1832
|
+
} finally {
|
|
1833
|
+
setIsProcessing(false);
|
|
1834
|
+
}
|
|
1835
|
+
};
|
|
1836
|
+
const getNetworkColor = (network) => {
|
|
1837
|
+
if (network.toLowerCase().includes("solana")) return "#14F195";
|
|
1838
|
+
if (network.toLowerCase().includes("evm") || network.toLowerCase().includes("base")) return "#0052FF";
|
|
1839
|
+
return "#8c8c8c";
|
|
1840
|
+
};
|
|
1841
|
+
const NetworkIcon = paymentDetails ? getNetworkIcon(paymentDetails.network) : null;
|
|
1842
|
+
const networkColor = paymentDetails ? getNetworkColor(paymentDetails.network) : "#8c8c8c";
|
|
1843
|
+
const loadingColor = "#8c8c8c";
|
|
1844
|
+
const hasInvalidCheckoutId = !fetchingPaymentInfo && (!paymentInfo || paymentInfo.length === 0);
|
|
1845
|
+
return /* @__PURE__ */ import_react7.default.createElement(
|
|
1846
|
+
"div",
|
|
1847
|
+
{
|
|
1848
|
+
className: isModal ? "bg-white" : "h-screen bg-white flex items-center justify-center p-4 overflow-hidden"
|
|
1849
|
+
},
|
|
1850
|
+
/* @__PURE__ */ import_react7.default.createElement(
|
|
1851
|
+
"div",
|
|
1852
|
+
{
|
|
1853
|
+
className: "flex gap-4 items-center justify-center",
|
|
1854
|
+
style: {
|
|
1855
|
+
maxWidth: isProcessing || result || error ? "1200px" : "480px",
|
|
1856
|
+
transition: "max-width 0.4s ease-in-out",
|
|
1857
|
+
width: "100%"
|
|
1858
|
+
}
|
|
1859
|
+
},
|
|
1860
|
+
/* @__PURE__ */ import_react7.default.createElement(
|
|
1861
|
+
import_antd.Card,
|
|
1862
|
+
{
|
|
1863
|
+
className: "flex-shrink-0",
|
|
1864
|
+
style: {
|
|
1865
|
+
border: isModal ? "none" : "1px solid #e8e8e8",
|
|
1866
|
+
borderRadius: isModal ? "0" : "16px",
|
|
1867
|
+
boxShadow: isModal ? "none" : "0 4px 24px rgba(0, 0, 0, 0.06)",
|
|
1868
|
+
maxHeight: isModal ? "calc(100vh - 100px)" : "calc(100vh - 32px)",
|
|
1869
|
+
overflow: "auto",
|
|
1870
|
+
width: isModal ? "100%" : "480px",
|
|
1871
|
+
transition: "all 0.4s ease-in-out",
|
|
1872
|
+
transform: result || error ? "translateX(0)" : "translateX(0)"
|
|
1873
|
+
},
|
|
1874
|
+
styles: { body: { padding: isModal ? "0px" : "32px 24px" } }
|
|
1875
|
+
},
|
|
1876
|
+
/* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-center gap-3 mb-4" }, /* @__PURE__ */ import_react7.default.createElement(
|
|
1877
|
+
"div",
|
|
1878
|
+
{
|
|
1879
|
+
className: "w-12 h-12 rounded-xl flex items-center justify-center",
|
|
1880
|
+
style: {
|
|
1881
|
+
background: hasInvalidCheckoutId ? "#ff4d4f" : paymentDetails ? networkColor : loadingColor,
|
|
1882
|
+
transition: "background 0.3s ease"
|
|
1883
|
+
}
|
|
1884
|
+
},
|
|
1885
|
+
hasInvalidCheckoutId ? /* @__PURE__ */ import_react7.default.createElement("span", { style: { fontSize: "20px", color: "white", fontWeight: "bold" } }, "\u2717") : paymentDetails && NetworkIcon ? /* @__PURE__ */ import_react7.default.createElement(NetworkIcon, { width: 24, height: 24 }) : /* @__PURE__ */ import_react7.default.createElement(import_icons.LoadingOutlined, { style: { fontSize: "20px", color: "white" }, spin: true })
|
|
1886
|
+
), /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex-1" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react7.default.createElement(Title, { level: 4, style: { margin: 0, fontSize: "18px", fontWeight: 600 } }, title || "Echo Payment OnVoyage"), !hasInvalidCheckoutId && /* @__PURE__ */ import_react7.default.createElement(
|
|
1887
|
+
import_antd.Tooltip,
|
|
1888
|
+
{
|
|
1889
|
+
title: tooltipText,
|
|
1890
|
+
placement: "top"
|
|
1891
|
+
},
|
|
1892
|
+
/* @__PURE__ */ import_react7.default.createElement(
|
|
1893
|
+
import_icons.InfoCircleOutlined,
|
|
1894
|
+
{
|
|
1895
|
+
style: { fontSize: "14px", color: "#8c8c8c", cursor: "help" }
|
|
1896
|
+
}
|
|
1897
|
+
)
|
|
1898
|
+
)), /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, subtitle))),
|
|
1899
|
+
/* @__PURE__ */ import_react7.default.createElement("div", { className: "text-center mb-5" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "inline-flex items-center justify-center w-12 h-12 rounded-full bg-gray-50 mb-3" }, /* @__PURE__ */ import_react7.default.createElement(import_icons.LockOutlined, { style: { fontSize: "20px", color: "#595959" } })), /* @__PURE__ */ import_react7.default.createElement(Title, { level: 3, style: { margin: "0 0 6px 0", fontSize: "20px", fontWeight: 600 } }, "Payment Required"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, "Pay ", paymentDetails ? `$${paymentDetails.amount} ${paymentDetails.currency}` : "the required amount", " to access")),
|
|
1900
|
+
hasInvalidCheckoutId && /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-center py-6" }, /* @__PURE__ */ import_react7.default.createElement(
|
|
1901
|
+
"div",
|
|
1902
|
+
{
|
|
1903
|
+
className: "inline-flex items-center justify-center w-16 h-16 rounded-full mb-4",
|
|
1904
|
+
style: {
|
|
1905
|
+
background: "linear-gradient(135deg, #ef4444 0%, #f87171 100%)",
|
|
1906
|
+
boxShadow: "0 4px 20px rgba(239, 68, 68, 0.3)"
|
|
1907
|
+
}
|
|
1908
|
+
},
|
|
1909
|
+
/* @__PURE__ */ import_react7.default.createElement("span", { style: { fontSize: "32px", color: "white" } }, "!")
|
|
1910
|
+
), /* @__PURE__ */ import_react7.default.createElement(
|
|
1911
|
+
Title,
|
|
1912
|
+
{
|
|
1913
|
+
level: 4,
|
|
1914
|
+
style: { margin: "0 0 12px 0", fontSize: "18px", fontWeight: 600, color: "#262626" }
|
|
1915
|
+
},
|
|
1916
|
+
"Invalid Checkout ID"
|
|
1917
|
+
), /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "14px", color: "#8c8c8c", display: "block", marginBottom: "16px" } }, "The checkout ID you provided is invalid or has expired."), /* @__PURE__ */ import_react7.default.createElement(
|
|
1918
|
+
"div",
|
|
1919
|
+
{
|
|
1920
|
+
style: {
|
|
1921
|
+
background: "#fef2f2",
|
|
1922
|
+
padding: "16px",
|
|
1923
|
+
borderRadius: "12px",
|
|
1924
|
+
border: "1px solid #fee2e2",
|
|
1925
|
+
marginTop: "16px"
|
|
1926
|
+
}
|
|
1927
|
+
},
|
|
1928
|
+
/* @__PURE__ */ import_react7.default.createElement(Text, { style: {
|
|
1929
|
+
fontSize: "13px",
|
|
1930
|
+
color: "#dc2626",
|
|
1931
|
+
lineHeight: "1.6",
|
|
1932
|
+
fontWeight: 500
|
|
1933
|
+
} }, "Failed to load payment information. Please check your checkout ID.")
|
|
1934
|
+
)),
|
|
1935
|
+
!hasInvalidCheckoutId && fetchingPaymentInfo && /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-center py-6" }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: { color: "#8c8c8c" } }, "Loading payment information...")),
|
|
1936
|
+
!hasInvalidCheckoutId && !fetchingPaymentInfo && !address && /* @__PURE__ */ import_react7.default.createElement("div", null, /* @__PURE__ */ import_react7.default.createElement(WalletConnect, { supportedNetworks })),
|
|
1937
|
+
!hasInvalidCheckoutId && address && /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, /* @__PURE__ */ import_react7.default.createElement(
|
|
1938
|
+
"div",
|
|
1939
|
+
{
|
|
1940
|
+
className: "bg-gray-50 rounded-lg p-3 mb-4",
|
|
1941
|
+
style: { border: "1px solid #f0f0f0" }
|
|
1942
|
+
},
|
|
1943
|
+
/* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-center gap-3 flex-1" }, /* @__PURE__ */ import_react7.default.createElement(
|
|
1944
|
+
"div",
|
|
1945
|
+
{
|
|
1946
|
+
className: "w-10 h-10 rounded-full bg-black flex items-center justify-center text-white text-sm font-semibold"
|
|
1947
|
+
},
|
|
1948
|
+
address.slice(0, 2).toUpperCase()
|
|
1949
|
+
), /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: {
|
|
1950
|
+
display: "block",
|
|
1951
|
+
fontSize: "12px",
|
|
1952
|
+
color: "#8c8c8c",
|
|
1953
|
+
marginBottom: "2px"
|
|
1954
|
+
} }, "Connected Wallet"), /* @__PURE__ */ import_react7.default.createElement(
|
|
1955
|
+
Text,
|
|
1956
|
+
{
|
|
1957
|
+
style: {
|
|
1958
|
+
fontSize: "13px",
|
|
1959
|
+
fontWeight: 600,
|
|
1960
|
+
fontFamily: "Monaco, monospace"
|
|
1961
|
+
}
|
|
1962
|
+
},
|
|
1963
|
+
formatAddress(address)
|
|
1964
|
+
))), /* @__PURE__ */ import_react7.default.createElement(
|
|
1965
|
+
import_antd.Button,
|
|
1966
|
+
{
|
|
1967
|
+
type: "text",
|
|
1968
|
+
size: "small",
|
|
1969
|
+
icon: /* @__PURE__ */ import_react7.default.createElement(import_icons.DisconnectOutlined, null),
|
|
1970
|
+
onClick: handleDisconnect,
|
|
1971
|
+
style: { color: "#ff4d4f" }
|
|
1972
|
+
}
|
|
1973
|
+
))
|
|
1974
|
+
), paymentDetails && /* @__PURE__ */ import_react7.default.createElement("div", { className: "bg-gray-50 rounded-lg p-3 mb-4", style: { border: "1px solid #f0f0f0" } }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex justify-between items-center mb-2" }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, "Payment Amount"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "18px", fontWeight: 600 } }, "$", paymentDetails.amount)), /* @__PURE__ */ import_react7.default.createElement(import_antd.Divider, { style: { margin: "6px 0" } }), /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex justify-between items-center mb-2" }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, "Currency"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "14px", fontWeight: 500 } }, paymentDetails.currency)), /* @__PURE__ */ import_react7.default.createElement(import_antd.Divider, { style: { margin: "6px 0" } }), /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex justify-between items-center mb-2" }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, "Network"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "14px", fontWeight: 500 } }, paymentDetails.network)), /* @__PURE__ */ import_react7.default.createElement(import_antd.Divider, { style: { margin: "6px 0" } }), /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex justify-between items-start" }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, "Wallet Address"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: {
|
|
1975
|
+
fontSize: "11px",
|
|
1976
|
+
fontWeight: 500,
|
|
1977
|
+
fontFamily: "Monaco, monospace",
|
|
1978
|
+
wordBreak: "break-all",
|
|
1979
|
+
textAlign: "right",
|
|
1980
|
+
maxWidth: "60%",
|
|
1981
|
+
lineHeight: 1.4
|
|
1982
|
+
} }, address))), /* @__PURE__ */ import_react7.default.createElement(
|
|
1983
|
+
"div",
|
|
1984
|
+
{
|
|
1985
|
+
className: "flex items-center justify-center gap-2 mb-3 p-2 rounded-lg",
|
|
1986
|
+
style: { background: "#f6ffed", border: "1px solid #d9f7be" }
|
|
1987
|
+
},
|
|
1988
|
+
/* @__PURE__ */ import_react7.default.createElement(import_icons.SafetyOutlined, { style: { color: "#52c41a", fontSize: "13px" } }),
|
|
1989
|
+
/* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "12px", color: "#52c41a", fontWeight: 500 } }, "Secure payment powered by v402pay")
|
|
1990
|
+
), /* @__PURE__ */ import_react7.default.createElement(
|
|
1991
|
+
import_antd.Button,
|
|
1992
|
+
{
|
|
1993
|
+
type: "primary",
|
|
1994
|
+
size: "large",
|
|
1995
|
+
onClick: handlePayment,
|
|
1996
|
+
disabled: isProcessing || !paymentDetails,
|
|
1997
|
+
loading: isProcessing,
|
|
1998
|
+
block: true,
|
|
1999
|
+
style: {
|
|
2000
|
+
height: "44px",
|
|
2001
|
+
fontSize: "14px",
|
|
2002
|
+
fontWeight: 600,
|
|
2003
|
+
borderRadius: "8px",
|
|
2004
|
+
...!isProcessing && paymentDetails && {
|
|
2005
|
+
background: "#1a1a1a",
|
|
2006
|
+
borderColor: "#1a1a1a"
|
|
2007
|
+
},
|
|
2008
|
+
marginBottom: "10px"
|
|
2009
|
+
}
|
|
2010
|
+
},
|
|
2011
|
+
isProcessing ? "Processing..." : !paymentDetails ? "Loading..." : `Pay $${paymentDetails.amount} ${paymentDetails.currency}`
|
|
2012
|
+
), /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-center" }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, "Don't have USDC?", " "), /* @__PURE__ */ import_react7.default.createElement(
|
|
2013
|
+
"a",
|
|
2014
|
+
{
|
|
2015
|
+
href: "https://faucet.circle.com/",
|
|
2016
|
+
target: "_blank",
|
|
2017
|
+
rel: "noopener noreferrer",
|
|
2018
|
+
className: "text-blue-600 hover:text-blue-700 text-sm font-medium inline-flex items-center gap-1"
|
|
2019
|
+
},
|
|
2020
|
+
"Get it here ",
|
|
2021
|
+
/* @__PURE__ */ import_react7.default.createElement(import_icons.LinkOutlined, { style: { fontSize: "12px" } })
|
|
2022
|
+
)), isModal && result && /* @__PURE__ */ import_react7.default.createElement(
|
|
2023
|
+
"div",
|
|
2024
|
+
{
|
|
2025
|
+
className: "mt-4 p-4 rounded-lg",
|
|
2026
|
+
style: { background: "#f6ffed", border: "1px solid #b7eb8f" }
|
|
2027
|
+
},
|
|
2028
|
+
/* @__PURE__ */ import_react7.default.createElement("div", { className: "text-center" }, /* @__PURE__ */ import_react7.default.createElement("span", { style: { fontSize: "20px" } }, "\u2713"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: {
|
|
2029
|
+
fontSize: "14px",
|
|
2030
|
+
color: "#52c41a",
|
|
2031
|
+
fontWeight: 600,
|
|
2032
|
+
marginLeft: "8px"
|
|
2033
|
+
} }, "Payment Successful!"))
|
|
2034
|
+
), isModal && error && /* @__PURE__ */ import_react7.default.createElement(
|
|
2035
|
+
"div",
|
|
2036
|
+
{
|
|
2037
|
+
className: "mt-4 p-4 rounded-lg",
|
|
2038
|
+
style: { background: "#fff2f0", border: "1px solid #ffccc7" }
|
|
2039
|
+
},
|
|
2040
|
+
/* @__PURE__ */ import_react7.default.createElement("div", { className: "text-center mb-3" }, /* @__PURE__ */ import_react7.default.createElement("span", { style: { fontSize: "20px" } }, "\u2717"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: {
|
|
2041
|
+
fontSize: "14px",
|
|
2042
|
+
color: "#ff4d4f",
|
|
2043
|
+
fontWeight: 600,
|
|
2044
|
+
marginLeft: "8px",
|
|
2045
|
+
display: "block",
|
|
2046
|
+
marginTop: "4px"
|
|
2047
|
+
} }, "Payment Failed")),
|
|
2048
|
+
/* @__PURE__ */ import_react7.default.createElement(Text, { style: {
|
|
2049
|
+
fontSize: "13px",
|
|
2050
|
+
color: "#ff4d4f",
|
|
2051
|
+
display: "block",
|
|
2052
|
+
textAlign: "center"
|
|
2053
|
+
} }, error)
|
|
2054
|
+
))
|
|
2055
|
+
),
|
|
2056
|
+
!isModal && (isProcessing || result || error) && /* @__PURE__ */ import_react7.default.createElement(
|
|
2057
|
+
import_antd.Card,
|
|
2058
|
+
{
|
|
2059
|
+
title: /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-center gap-2" }, isProcessing && !result && !error ? /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, /* @__PURE__ */ import_react7.default.createElement(import_icons.LoadingOutlined, { style: { color: "#14b8a6", fontSize: "16px" } }), /* @__PURE__ */ import_react7.default.createElement(Text, { strong: true, style: { fontSize: "16px", color: "#262626" } }, "Processing Payment")) : result ? /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, /* @__PURE__ */ import_react7.default.createElement("span", { style: { color: "#52c41a", fontSize: "18px" } }, "\u2713"), /* @__PURE__ */ import_react7.default.createElement(Text, { strong: true, style: { fontSize: "16px", color: "#262626" } }, "Payment Successful")) : /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, /* @__PURE__ */ import_react7.default.createElement("span", { style: { color: "#ff4d4f", fontSize: "18px" } }, "\u2717"), /* @__PURE__ */ import_react7.default.createElement(Text, { strong: true, style: { fontSize: "16px", color: "#262626" } }, "Payment Failed"))),
|
|
2060
|
+
extra: !isProcessing && /* @__PURE__ */ import_react7.default.createElement(
|
|
2061
|
+
import_antd.Button,
|
|
2062
|
+
{
|
|
2063
|
+
type: "text",
|
|
2064
|
+
size: "small",
|
|
2065
|
+
onClick: () => {
|
|
2066
|
+
setResult(null);
|
|
2067
|
+
setError(null);
|
|
2068
|
+
}
|
|
2069
|
+
},
|
|
2070
|
+
"Close"
|
|
2071
|
+
),
|
|
2072
|
+
style: {
|
|
2073
|
+
border: "1px solid #e8e8e8",
|
|
2074
|
+
borderRadius: "16px",
|
|
2075
|
+
boxShadow: "0 4px 24px rgba(0, 0, 0, 0.06)",
|
|
2076
|
+
maxHeight: "calc(100vh - 32px)",
|
|
2077
|
+
width: "480px",
|
|
2078
|
+
animation: "slideInRight 0.4s ease-out"
|
|
2079
|
+
},
|
|
2080
|
+
styles: {
|
|
2081
|
+
body: {
|
|
2082
|
+
padding: "24px",
|
|
2083
|
+
maxHeight: "calc(100vh - 120px)",
|
|
2084
|
+
overflow: "auto"
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
},
|
|
2088
|
+
isProcessing && !result && !error && /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-center py-10" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "relative inline-block" }, /* @__PURE__ */ import_react7.default.createElement(
|
|
2089
|
+
"div",
|
|
2090
|
+
{
|
|
2091
|
+
className: "absolute inset-0 rounded-full blur-xl opacity-40",
|
|
2092
|
+
style: {
|
|
2093
|
+
background: "linear-gradient(135deg, #14b8a6 0%, #06b6d4 100%)",
|
|
2094
|
+
animation: "pulse 2s ease-in-out infinite"
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
), /* @__PURE__ */ import_react7.default.createElement(
|
|
2098
|
+
import_antd.Spin,
|
|
2099
|
+
{
|
|
2100
|
+
indicator: /* @__PURE__ */ import_react7.default.createElement(import_icons.LoadingOutlined, { style: { fontSize: 56, color: "#14b8a6" } })
|
|
2101
|
+
}
|
|
2102
|
+
)), /* @__PURE__ */ import_react7.default.createElement("div", { className: "mt-6" }, /* @__PURE__ */ import_react7.default.createElement(Text, { strong: true, style: { fontSize: "18px", color: "#262626", letterSpacing: "-0.02em" } }, "Verifying Payment")), /* @__PURE__ */ import_react7.default.createElement("div", { className: "mt-2 mb-6" }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "14px", color: "#8c8c8c", lineHeight: "1.6" } }, "Please wait while we confirm your transaction")), /* @__PURE__ */ import_react7.default.createElement(
|
|
2103
|
+
"div",
|
|
2104
|
+
{
|
|
2105
|
+
className: "mt-4 p-4 rounded-xl",
|
|
2106
|
+
style: {
|
|
2107
|
+
background: "linear-gradient(135deg, #f0fdfa 0%, #ecfeff 100%)",
|
|
2108
|
+
border: "1px solid #ccfbf1"
|
|
2109
|
+
}
|
|
2110
|
+
},
|
|
2111
|
+
/* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-center justify-center gap-2" }, /* @__PURE__ */ import_react7.default.createElement("span", { style: { fontSize: "16px" } }, "\u23F1\uFE0F"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "13px", color: "#0f766e", fontWeight: 500 } }, "This may take a few moments"))
|
|
2112
|
+
)),
|
|
2113
|
+
result && /* @__PURE__ */ import_react7.default.createElement("div", null, /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-center mb-6" }, /* @__PURE__ */ import_react7.default.createElement(
|
|
2114
|
+
"div",
|
|
2115
|
+
{
|
|
2116
|
+
className: "inline-flex items-center justify-center w-16 h-16 rounded-full mb-4",
|
|
2117
|
+
style: {
|
|
2118
|
+
background: "linear-gradient(135deg, #10b981 0%, #34d399 100%)",
|
|
2119
|
+
boxShadow: "0 4px 20px rgba(16, 185, 129, 0.3)"
|
|
2120
|
+
}
|
|
2121
|
+
},
|
|
2122
|
+
/* @__PURE__ */ import_react7.default.createElement("span", { style: { fontSize: "32px", color: "white" } }, "\u2713")
|
|
2123
|
+
), /* @__PURE__ */ import_react7.default.createElement("div", null, /* @__PURE__ */ import_react7.default.createElement(Text, { strong: true, style: {
|
|
2124
|
+
fontSize: "20px",
|
|
2125
|
+
color: "#262626",
|
|
2126
|
+
display: "block",
|
|
2127
|
+
marginBottom: "8px"
|
|
2128
|
+
} }, "Payment Successful!"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "14px", color: "#8c8c8c" } }, "Your transaction has been confirmed"))), /* @__PURE__ */ import_react7.default.createElement(import_antd.Divider, { style: { margin: "20px 0", borderColor: "#f0f0f0" } }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "12px", color: "#8c8c8c", fontWeight: 500 } }, "RESPONSE DATA")), /* @__PURE__ */ import_react7.default.createElement(
|
|
2129
|
+
"pre",
|
|
2130
|
+
{
|
|
2131
|
+
style: {
|
|
2132
|
+
background: "#fafafa",
|
|
2133
|
+
padding: "20px",
|
|
2134
|
+
borderRadius: "12px",
|
|
2135
|
+
fontSize: "12px",
|
|
2136
|
+
lineHeight: "1.8",
|
|
2137
|
+
overflow: "auto",
|
|
2138
|
+
margin: 0,
|
|
2139
|
+
fontFamily: "Monaco, Courier New, monospace",
|
|
2140
|
+
whiteSpace: "pre-wrap",
|
|
2141
|
+
wordBreak: "break-word",
|
|
2142
|
+
border: "1px solid #e8e8e8",
|
|
2143
|
+
color: "#262626"
|
|
2144
|
+
}
|
|
2145
|
+
},
|
|
2146
|
+
JSON.stringify(result, null, 2)
|
|
2147
|
+
)),
|
|
2148
|
+
error && /* @__PURE__ */ import_react7.default.createElement("div", null, /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-center mb-6" }, /* @__PURE__ */ import_react7.default.createElement(
|
|
2149
|
+
"div",
|
|
2150
|
+
{
|
|
2151
|
+
className: "inline-flex items-center justify-center w-16 h-16 rounded-full mb-4",
|
|
2152
|
+
style: {
|
|
2153
|
+
background: "linear-gradient(135deg, #ef4444 0%, #f87171 100%)",
|
|
2154
|
+
boxShadow: "0 4px 20px rgba(239, 68, 68, 0.3)"
|
|
2155
|
+
}
|
|
2156
|
+
},
|
|
2157
|
+
/* @__PURE__ */ import_react7.default.createElement("span", { style: { fontSize: "32px", color: "white" } }, "\u2717")
|
|
2158
|
+
), /* @__PURE__ */ import_react7.default.createElement("div", null, /* @__PURE__ */ import_react7.default.createElement(Text, { strong: true, style: {
|
|
2159
|
+
fontSize: "20px",
|
|
2160
|
+
color: "#262626",
|
|
2161
|
+
display: "block",
|
|
2162
|
+
marginBottom: "8px"
|
|
2163
|
+
} }, "Payment Failed"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "14px", color: "#8c8c8c" } }, "Something went wrong with your transaction"))), /* @__PURE__ */ import_react7.default.createElement(import_antd.Divider, { style: { margin: "20px 0", borderColor: "#f0f0f0" } }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "12px", color: "#8c8c8c", fontWeight: 500 } }, "ERROR DETAILS")), /* @__PURE__ */ import_react7.default.createElement(
|
|
2164
|
+
"div",
|
|
2165
|
+
{
|
|
2166
|
+
style: {
|
|
2167
|
+
background: "#fef2f2",
|
|
2168
|
+
padding: "20px",
|
|
2169
|
+
borderRadius: "12px",
|
|
2170
|
+
border: "1px solid #fee2e2"
|
|
2171
|
+
}
|
|
2172
|
+
},
|
|
2173
|
+
/* @__PURE__ */ import_react7.default.createElement(Text, { style: {
|
|
2174
|
+
fontSize: "14px",
|
|
2175
|
+
color: "#dc2626",
|
|
2176
|
+
lineHeight: "1.6",
|
|
2177
|
+
fontWeight: 500
|
|
2178
|
+
} }, error)
|
|
2179
|
+
), /* @__PURE__ */ import_react7.default.createElement("div", { className: "mt-4 text-center" }, /* @__PURE__ */ import_react7.default.createElement(
|
|
2180
|
+
import_antd.Button,
|
|
2181
|
+
{
|
|
2182
|
+
size: "large",
|
|
2183
|
+
onClick: handlePayment,
|
|
2184
|
+
style: {
|
|
2185
|
+
height: "44px",
|
|
2186
|
+
fontSize: "14px",
|
|
2187
|
+
fontWeight: 600,
|
|
2188
|
+
borderRadius: "8px",
|
|
2189
|
+
background: "#1a1a1a",
|
|
2190
|
+
borderColor: "#1a1a1a",
|
|
2191
|
+
color: "white",
|
|
2192
|
+
paddingLeft: "32px",
|
|
2193
|
+
paddingRight: "32px"
|
|
2194
|
+
}
|
|
2195
|
+
},
|
|
2196
|
+
"Try Again"
|
|
2197
|
+
)))
|
|
2198
|
+
)
|
|
2199
|
+
),
|
|
2200
|
+
/* @__PURE__ */ import_react7.default.createElement("style", { dangerouslySetInnerHTML: {
|
|
2201
|
+
__html: `
|
|
2202
|
+
@keyframes slideInRight {
|
|
2203
|
+
from {
|
|
2204
|
+
opacity: 0;
|
|
2205
|
+
transform: translateX(100px);
|
|
2206
|
+
}
|
|
2207
|
+
to {
|
|
2208
|
+
opacity: 1;
|
|
2209
|
+
transform: translateX(0);
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
@keyframes pulse {
|
|
2214
|
+
0%, 100% {
|
|
2215
|
+
transform: scale(1);
|
|
2216
|
+
opacity: 0.4;
|
|
2217
|
+
}
|
|
2218
|
+
50% {
|
|
2219
|
+
transform: scale(1.1);
|
|
2220
|
+
opacity: 0.6;
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
`
|
|
2224
|
+
} })
|
|
2225
|
+
);
|
|
805
2226
|
}
|
|
806
2227
|
// Annotate the CommonJS export names for ESM import in node:
|
|
807
2228
|
0 && (module.exports = {
|
|
2229
|
+
V402Checkout,
|
|
808
2230
|
WalletConnect,
|
|
2231
|
+
usePageNetwork,
|
|
809
2232
|
usePayment,
|
|
810
2233
|
usePaymentInfo,
|
|
811
2234
|
useWallet
|