@voyage_ai/v402-web-ts 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/index.d.mts +523 -0
- package/dist/index.d.ts +523 -0
- package/dist/index.js +636 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +604 -0
- package/dist/index.mjs.map +1 -0
- package/dist/react/components/PaymentButton.tsx +112 -0
- package/dist/react/components/WalletConnect.tsx +125 -0
- package/dist/react/hooks/usePayment.ts +109 -0
- package/dist/react/hooks/usePaymentInfo.ts +94 -0
- package/dist/react/hooks/useWallet.ts +147 -0
- package/dist/react/hooks/useWalletStore.ts +61 -0
- package/dist/react/index.d.mts +248 -0
- package/dist/react/index.d.ts +248 -0
- package/dist/react/index.js +942 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/index.mjs +924 -0
- package/dist/react/index.mjs.map +1 -0
- package/dist/react/index.ts +42 -0
- package/dist/react/store/walletStore.ts +152 -0
- package/dist/react/styles.css +161 -0
- package/package.json +65 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,636 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
EVM_NETWORK_CONFIGS: () => EVM_NETWORK_CONFIGS,
|
|
24
|
+
EvmNetworkSchema: () => EvmNetworkSchema,
|
|
25
|
+
EvmPaymentPayloadSchema: () => EvmPaymentPayloadSchema,
|
|
26
|
+
SolanaNetworkSchema: () => SolanaNetworkSchema,
|
|
27
|
+
SolanaPaymentPayloadSchema: () => SolanaPaymentPayloadSchema,
|
|
28
|
+
createEvmPaymentFetch: () => createEvmPaymentFetch,
|
|
29
|
+
createEvmPaymentHeader: () => createEvmPaymentHeader,
|
|
30
|
+
createSvmPaymentFetch: () => createSvmPaymentFetch,
|
|
31
|
+
createSvmPaymentHeader: () => createSvmPaymentHeader,
|
|
32
|
+
formatAddress: () => formatAddress,
|
|
33
|
+
fromAtomicUnits: () => fromAtomicUnits,
|
|
34
|
+
getChainId: () => getChainId,
|
|
35
|
+
getChainIdFromNetwork: () => getChainIdFromNetwork,
|
|
36
|
+
getDefaultSolanaRpcUrl: () => getDefaultSolanaRpcUrl,
|
|
37
|
+
getNetworkDisplayName: () => getNetworkDisplayName,
|
|
38
|
+
getNetworkType: () => getNetworkType,
|
|
39
|
+
getWalletDisplayName: () => getWalletDisplayName,
|
|
40
|
+
getWalletInstallUrl: () => getWalletInstallUrl,
|
|
41
|
+
getWalletProvider: () => getWalletProvider,
|
|
42
|
+
handleEvmPayment: () => handleEvmPayment,
|
|
43
|
+
handleSvmPayment: () => handleSvmPayment,
|
|
44
|
+
is402Response: () => is402Response,
|
|
45
|
+
isEvmAddress: () => isEvmAddress,
|
|
46
|
+
isEvmNetwork: () => isEvmNetwork,
|
|
47
|
+
isSolanaAddress: () => isSolanaAddress,
|
|
48
|
+
isSolanaNetwork: () => isSolanaNetwork,
|
|
49
|
+
isWalletInstalled: () => isWalletInstalled,
|
|
50
|
+
makePayment: () => makePayment,
|
|
51
|
+
toAtomicUnits: () => toAtomicUnits
|
|
52
|
+
});
|
|
53
|
+
module.exports = __toCommonJS(index_exports);
|
|
54
|
+
|
|
55
|
+
// src/types/index.ts
|
|
56
|
+
var import_types3 = require("x402/types");
|
|
57
|
+
|
|
58
|
+
// src/types/common.ts
|
|
59
|
+
var PROD_BACK_URL = "https://v402.onvoyage.ai/api";
|
|
60
|
+
|
|
61
|
+
// src/types/svm.ts
|
|
62
|
+
var import_zod = require("zod");
|
|
63
|
+
var import_types = require("x402/types");
|
|
64
|
+
var SolanaNetworkSchema = import_zod.z.enum([
|
|
65
|
+
"solana-devnet",
|
|
66
|
+
"solana",
|
|
67
|
+
"solana-mainnet"
|
|
68
|
+
// Alias for mainnet
|
|
69
|
+
]);
|
|
70
|
+
var SolanaPaymentPayloadSchema = import_zod.z.object({
|
|
71
|
+
x402Version: import_zod.z.literal(1),
|
|
72
|
+
scheme: import_zod.z.literal("exact"),
|
|
73
|
+
network: SolanaNetworkSchema,
|
|
74
|
+
payload: import_types.ExactSvmPayloadSchema
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// src/types/evm.ts
|
|
78
|
+
var import_zod2 = require("zod");
|
|
79
|
+
var import_types2 = require("x402/types");
|
|
80
|
+
var EvmNetworkSchema = import_zod2.z.enum([
|
|
81
|
+
"ethereum",
|
|
82
|
+
"sepolia",
|
|
83
|
+
"base",
|
|
84
|
+
"base-sepolia",
|
|
85
|
+
"polygon",
|
|
86
|
+
"arbitrum",
|
|
87
|
+
"optimism"
|
|
88
|
+
]);
|
|
89
|
+
var EvmPaymentPayloadSchema = import_zod2.z.object({
|
|
90
|
+
x402Version: import_zod2.z.literal(1),
|
|
91
|
+
scheme: import_zod2.z.literal("exact"),
|
|
92
|
+
network: EvmNetworkSchema,
|
|
93
|
+
payload: import_types2.ExactEvmPayloadSchema
|
|
94
|
+
});
|
|
95
|
+
var EVM_NETWORK_CONFIGS = {
|
|
96
|
+
"ethereum": {
|
|
97
|
+
chainId: "0x1",
|
|
98
|
+
chainName: "Ethereum Mainnet",
|
|
99
|
+
rpcUrls: ["https://eth.llamarpc.com"],
|
|
100
|
+
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }
|
|
101
|
+
},
|
|
102
|
+
"sepolia": {
|
|
103
|
+
chainId: "0xaa36a7",
|
|
104
|
+
chainName: "Sepolia",
|
|
105
|
+
rpcUrls: ["https://sepolia.infura.io/v3/"],
|
|
106
|
+
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }
|
|
107
|
+
},
|
|
108
|
+
"base": {
|
|
109
|
+
chainId: "0x2105",
|
|
110
|
+
chainName: "Base",
|
|
111
|
+
rpcUrls: ["https://mainnet.base.org"],
|
|
112
|
+
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }
|
|
113
|
+
},
|
|
114
|
+
"base-sepolia": {
|
|
115
|
+
chainId: "0x14a34",
|
|
116
|
+
chainName: "Base Sepolia",
|
|
117
|
+
rpcUrls: ["https://sepolia.base.org"],
|
|
118
|
+
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
function getChainId(network) {
|
|
122
|
+
const chainIdMap = {
|
|
123
|
+
"ethereum": 1,
|
|
124
|
+
"sepolia": 11155111,
|
|
125
|
+
"base": 8453,
|
|
126
|
+
"base-sepolia": 84532,
|
|
127
|
+
"polygon": 137,
|
|
128
|
+
"arbitrum": 42161,
|
|
129
|
+
"optimism": 10
|
|
130
|
+
};
|
|
131
|
+
return chainIdMap[network.toLowerCase()] || 1;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// src/services/svm/payment-header.ts
|
|
135
|
+
var import_web3 = require("@solana/web3.js");
|
|
136
|
+
var import_spl_token = require("@solana/spl-token");
|
|
137
|
+
async function createSvmPaymentHeader(params) {
|
|
138
|
+
const { wallet, paymentRequirements, x402Version, rpcUrl } = params;
|
|
139
|
+
const connection = new import_web3.Connection(rpcUrl, "confirmed");
|
|
140
|
+
const feePayer = paymentRequirements?.extra?.feePayer;
|
|
141
|
+
if (typeof feePayer !== "string" || !feePayer) {
|
|
142
|
+
throw new Error("Missing facilitator feePayer in payment requirements (extra.feePayer).");
|
|
143
|
+
}
|
|
144
|
+
const feePayerPubkey = new import_web3.PublicKey(feePayer);
|
|
145
|
+
const walletAddress = wallet?.publicKey?.toString() || wallet?.address;
|
|
146
|
+
if (!walletAddress) {
|
|
147
|
+
throw new Error("Missing connected Solana wallet address or publicKey");
|
|
148
|
+
}
|
|
149
|
+
const userPubkey = new import_web3.PublicKey(walletAddress);
|
|
150
|
+
if (!paymentRequirements?.payTo) {
|
|
151
|
+
throw new Error("Missing payTo in payment requirements");
|
|
152
|
+
}
|
|
153
|
+
const destination = new import_web3.PublicKey(paymentRequirements.payTo);
|
|
154
|
+
const instructions = [];
|
|
155
|
+
instructions.push(
|
|
156
|
+
import_web3.ComputeBudgetProgram.setComputeUnitLimit({
|
|
157
|
+
units: 7e3
|
|
158
|
+
// Sufficient for SPL token transfer
|
|
159
|
+
})
|
|
160
|
+
);
|
|
161
|
+
instructions.push(
|
|
162
|
+
import_web3.ComputeBudgetProgram.setComputeUnitPrice({
|
|
163
|
+
microLamports: 1
|
|
164
|
+
// Minimal price
|
|
165
|
+
})
|
|
166
|
+
);
|
|
167
|
+
if (!paymentRequirements.asset) {
|
|
168
|
+
throw new Error("Missing token mint for SPL transfer");
|
|
169
|
+
}
|
|
170
|
+
const mintPubkey = new import_web3.PublicKey(paymentRequirements.asset);
|
|
171
|
+
const mintInfo = await connection.getAccountInfo(mintPubkey, "confirmed");
|
|
172
|
+
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;
|
|
173
|
+
const mint = await (0, import_spl_token.getMint)(connection, mintPubkey, void 0, programId);
|
|
174
|
+
const sourceAta = await (0, import_spl_token.getAssociatedTokenAddress)(
|
|
175
|
+
mintPubkey,
|
|
176
|
+
userPubkey,
|
|
177
|
+
false,
|
|
178
|
+
programId
|
|
179
|
+
);
|
|
180
|
+
const destinationAta = await (0, import_spl_token.getAssociatedTokenAddress)(
|
|
181
|
+
mintPubkey,
|
|
182
|
+
destination,
|
|
183
|
+
false,
|
|
184
|
+
programId
|
|
185
|
+
);
|
|
186
|
+
const sourceAtaInfo = await connection.getAccountInfo(sourceAta, "confirmed");
|
|
187
|
+
if (!sourceAtaInfo) {
|
|
188
|
+
throw new Error(
|
|
189
|
+
`User does not have an Associated Token Account for ${paymentRequirements.asset}. Please create one first or ensure you have the required token.`
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
const destAtaInfo = await connection.getAccountInfo(destinationAta, "confirmed");
|
|
193
|
+
if (!destAtaInfo) {
|
|
194
|
+
throw new Error(
|
|
195
|
+
`Destination does not have an Associated Token Account for ${paymentRequirements.asset}. The receiver must create their token account before receiving payments.`
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
const amount = BigInt(paymentRequirements.maxAmountRequired);
|
|
199
|
+
instructions.push(
|
|
200
|
+
(0, import_spl_token.createTransferCheckedInstruction)(
|
|
201
|
+
sourceAta,
|
|
202
|
+
mintPubkey,
|
|
203
|
+
destinationAta,
|
|
204
|
+
userPubkey,
|
|
205
|
+
amount,
|
|
206
|
+
mint.decimals,
|
|
207
|
+
[],
|
|
208
|
+
programId
|
|
209
|
+
)
|
|
210
|
+
);
|
|
211
|
+
const { blockhash } = await connection.getLatestBlockhash("confirmed");
|
|
212
|
+
const message = new import_web3.TransactionMessage({
|
|
213
|
+
payerKey: feePayerPubkey,
|
|
214
|
+
recentBlockhash: blockhash,
|
|
215
|
+
instructions
|
|
216
|
+
}).compileToV0Message();
|
|
217
|
+
const transaction = new import_web3.VersionedTransaction(message);
|
|
218
|
+
if (typeof wallet?.signTransaction !== "function") {
|
|
219
|
+
throw new Error("Connected wallet does not support signTransaction");
|
|
220
|
+
}
|
|
221
|
+
const userSignedTx = await wallet.signTransaction(transaction);
|
|
222
|
+
const serializedTransaction = Buffer.from(userSignedTx.serialize()).toString("base64");
|
|
223
|
+
const paymentPayload = {
|
|
224
|
+
x402Version,
|
|
225
|
+
scheme: paymentRequirements.scheme,
|
|
226
|
+
network: paymentRequirements.network,
|
|
227
|
+
payload: {
|
|
228
|
+
transaction: serializedTransaction
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
const paymentHeader = Buffer.from(JSON.stringify(paymentPayload)).toString("base64");
|
|
232
|
+
return paymentHeader;
|
|
233
|
+
}
|
|
234
|
+
function getDefaultSolanaRpcUrl(network) {
|
|
235
|
+
const normalized = network.toLowerCase();
|
|
236
|
+
if (normalized === "solana" || normalized === "solana-mainnet") {
|
|
237
|
+
return "https://api.mainnet-beta.solana.com";
|
|
238
|
+
} else if (normalized === "solana-devnet") {
|
|
239
|
+
return "https://api.devnet.solana.com";
|
|
240
|
+
}
|
|
241
|
+
throw new Error(`Unsupported Solana network: ${network}`);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// src/services/svm/payment-handler.ts
|
|
245
|
+
async function handleSvmPayment(endpoint, config, requestInit) {
|
|
246
|
+
const { wallet, network, rpcUrl, maxPaymentAmount } = config;
|
|
247
|
+
const initialResponse = await fetch(endpoint, {
|
|
248
|
+
...requestInit,
|
|
249
|
+
method: requestInit?.method || "POST"
|
|
250
|
+
});
|
|
251
|
+
if (initialResponse.status !== 402) {
|
|
252
|
+
return initialResponse;
|
|
253
|
+
}
|
|
254
|
+
const rawResponse = await initialResponse.json();
|
|
255
|
+
const x402Version = rawResponse.x402Version;
|
|
256
|
+
const parsedPaymentRequirements = rawResponse.accepts || [];
|
|
257
|
+
const selectedRequirements = parsedPaymentRequirements.find(
|
|
258
|
+
(req) => req.scheme === "exact" && SolanaNetworkSchema.safeParse(req.network.toLowerCase()).success
|
|
259
|
+
);
|
|
260
|
+
if (!selectedRequirements) {
|
|
261
|
+
console.error(
|
|
262
|
+
"\u274C No suitable Solana payment requirements found. Available networks:",
|
|
263
|
+
parsedPaymentRequirements.map((req) => req.network)
|
|
264
|
+
);
|
|
265
|
+
throw new Error("No suitable Solana payment requirements found");
|
|
266
|
+
}
|
|
267
|
+
if (maxPaymentAmount && maxPaymentAmount > BigInt(0)) {
|
|
268
|
+
if (BigInt(selectedRequirements.maxAmountRequired) > maxPaymentAmount) {
|
|
269
|
+
throw new Error(
|
|
270
|
+
`Payment amount ${selectedRequirements.maxAmountRequired} exceeds maximum allowed ${maxPaymentAmount}`
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
const effectiveRpcUrl = rpcUrl || getDefaultSolanaRpcUrl(network);
|
|
275
|
+
const paymentHeader = await createSvmPaymentHeader({
|
|
276
|
+
wallet,
|
|
277
|
+
paymentRequirements: selectedRequirements,
|
|
278
|
+
x402Version,
|
|
279
|
+
rpcUrl: effectiveRpcUrl
|
|
280
|
+
});
|
|
281
|
+
const newInit = {
|
|
282
|
+
...requestInit,
|
|
283
|
+
method: requestInit?.method || "POST",
|
|
284
|
+
headers: {
|
|
285
|
+
...requestInit?.headers || {},
|
|
286
|
+
"X-PAYMENT": paymentHeader,
|
|
287
|
+
"Access-Control-Expose-Headers": "X-PAYMENT-RESPONSE"
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
return await fetch(endpoint, newInit);
|
|
291
|
+
}
|
|
292
|
+
function createSvmPaymentFetch(config) {
|
|
293
|
+
return async (input, init) => {
|
|
294
|
+
const endpoint = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
295
|
+
return handleSvmPayment(endpoint, config, init);
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// src/services/evm/payment-header.ts
|
|
300
|
+
var import_ethers = require("ethers");
|
|
301
|
+
async function createEvmPaymentHeader(params) {
|
|
302
|
+
const { wallet, paymentRequirements, x402Version, chainId } = params;
|
|
303
|
+
if (!paymentRequirements?.payTo) {
|
|
304
|
+
throw new Error("Missing payTo in payment requirements");
|
|
305
|
+
}
|
|
306
|
+
if (!paymentRequirements?.asset) {
|
|
307
|
+
throw new Error("Missing asset (token contract) in payment requirements");
|
|
308
|
+
}
|
|
309
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
310
|
+
const nonceBytes = import_ethers.ethers.randomBytes(32);
|
|
311
|
+
const nonceBytes32 = import_ethers.ethers.hexlify(nonceBytes);
|
|
312
|
+
const domain = {
|
|
313
|
+
name: paymentRequirements.extra?.name || "USDC",
|
|
314
|
+
version: paymentRequirements.extra?.version || "2",
|
|
315
|
+
chainId,
|
|
316
|
+
verifyingContract: paymentRequirements.asset
|
|
317
|
+
};
|
|
318
|
+
const types = {
|
|
319
|
+
TransferWithAuthorization: [
|
|
320
|
+
{ name: "from", type: "address" },
|
|
321
|
+
{ name: "to", type: "address" },
|
|
322
|
+
{ name: "value", type: "uint256" },
|
|
323
|
+
{ name: "validAfter", type: "uint256" },
|
|
324
|
+
{ name: "validBefore", type: "uint256" },
|
|
325
|
+
{ name: "nonce", type: "bytes32" }
|
|
326
|
+
]
|
|
327
|
+
};
|
|
328
|
+
const authorization = {
|
|
329
|
+
from: wallet.address,
|
|
330
|
+
to: paymentRequirements.payTo,
|
|
331
|
+
value: paymentRequirements.maxAmountRequired,
|
|
332
|
+
validAfter: "0",
|
|
333
|
+
// Effective immediately
|
|
334
|
+
validBefore: String(now + (paymentRequirements.maxTimeoutSeconds || 3600)),
|
|
335
|
+
nonce: nonceBytes32
|
|
336
|
+
};
|
|
337
|
+
const signature = await wallet.signTypedData(domain, types, authorization);
|
|
338
|
+
const headerPayload = {
|
|
339
|
+
x402_version: x402Version,
|
|
340
|
+
x402Version,
|
|
341
|
+
scheme: paymentRequirements.scheme,
|
|
342
|
+
network: paymentRequirements.network,
|
|
343
|
+
payload: {
|
|
344
|
+
signature,
|
|
345
|
+
authorization: {
|
|
346
|
+
from: authorization.from,
|
|
347
|
+
to: authorization.to,
|
|
348
|
+
value: String(authorization.value),
|
|
349
|
+
valid_after: authorization.validAfter,
|
|
350
|
+
validAfter: authorization.validAfter,
|
|
351
|
+
valid_before: authorization.validBefore,
|
|
352
|
+
validBefore: authorization.validBefore,
|
|
353
|
+
nonce: authorization.nonce
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
const paymentHeader = btoa(JSON.stringify(headerPayload));
|
|
358
|
+
return paymentHeader;
|
|
359
|
+
}
|
|
360
|
+
function getChainIdFromNetwork(network) {
|
|
361
|
+
const chainIdMap = {
|
|
362
|
+
"ethereum": 1,
|
|
363
|
+
"sepolia": 11155111,
|
|
364
|
+
"base": 8453,
|
|
365
|
+
"base-sepolia": 84532,
|
|
366
|
+
"polygon": 137,
|
|
367
|
+
"arbitrum": 42161,
|
|
368
|
+
"optimism": 10
|
|
369
|
+
};
|
|
370
|
+
const chainId = chainIdMap[network.toLowerCase()];
|
|
371
|
+
if (!chainId) {
|
|
372
|
+
throw new Error(`Unknown network: ${network}`);
|
|
373
|
+
}
|
|
374
|
+
return chainId;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// src/services/evm/payment-handler.ts
|
|
378
|
+
async function handleEvmPayment(endpoint, config, requestInit) {
|
|
379
|
+
const { wallet, network, maxPaymentAmount } = config;
|
|
380
|
+
const initialResponse = await fetch(endpoint, {
|
|
381
|
+
...requestInit,
|
|
382
|
+
method: requestInit?.method || "POST"
|
|
383
|
+
});
|
|
384
|
+
if (initialResponse.status !== 402) {
|
|
385
|
+
return initialResponse;
|
|
386
|
+
}
|
|
387
|
+
const rawResponse = await initialResponse.json();
|
|
388
|
+
const x402Version = rawResponse.x402Version;
|
|
389
|
+
const parsedPaymentRequirements = rawResponse.accepts || [];
|
|
390
|
+
const selectedRequirements = parsedPaymentRequirements.find(
|
|
391
|
+
(req) => req.scheme === "exact" && EvmNetworkSchema.safeParse(req.network.toLowerCase()).success
|
|
392
|
+
);
|
|
393
|
+
if (!selectedRequirements) {
|
|
394
|
+
console.error(
|
|
395
|
+
"\u274C No suitable EVM payment requirements found. Available networks:",
|
|
396
|
+
parsedPaymentRequirements.map((req) => req.network)
|
|
397
|
+
);
|
|
398
|
+
throw new Error("No suitable EVM payment requirements found");
|
|
399
|
+
}
|
|
400
|
+
if (maxPaymentAmount && maxPaymentAmount > BigInt(0)) {
|
|
401
|
+
if (BigInt(selectedRequirements.maxAmountRequired) > maxPaymentAmount) {
|
|
402
|
+
throw new Error(
|
|
403
|
+
`Payment amount ${selectedRequirements.maxAmountRequired} exceeds maximum allowed ${maxPaymentAmount}`
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
const targetChainId = getChainIdFromNetwork(selectedRequirements.network);
|
|
408
|
+
if (wallet.switchChain) {
|
|
409
|
+
try {
|
|
410
|
+
await wallet.switchChain(`0x${targetChainId.toString(16)}`);
|
|
411
|
+
} catch (error) {
|
|
412
|
+
console.warn("Failed to switch chain:", error);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
const paymentHeader = await createEvmPaymentHeader({
|
|
416
|
+
wallet,
|
|
417
|
+
paymentRequirements: selectedRequirements,
|
|
418
|
+
x402Version,
|
|
419
|
+
chainId: targetChainId
|
|
420
|
+
});
|
|
421
|
+
const newInit = {
|
|
422
|
+
...requestInit,
|
|
423
|
+
method: requestInit?.method || "POST",
|
|
424
|
+
headers: {
|
|
425
|
+
...requestInit?.headers || {},
|
|
426
|
+
"X-PAYMENT": paymentHeader,
|
|
427
|
+
"Access-Control-Expose-Headers": "X-PAYMENT-RESPONSE"
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
return await fetch(endpoint, newInit);
|
|
431
|
+
}
|
|
432
|
+
function createEvmPaymentFetch(config) {
|
|
433
|
+
return async (input, init) => {
|
|
434
|
+
const endpoint = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
435
|
+
return handleEvmPayment(endpoint, config, init);
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// src/utils/wallet.ts
|
|
440
|
+
function isWalletInstalled(networkType) {
|
|
441
|
+
if (typeof window === "undefined") {
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
switch (networkType) {
|
|
445
|
+
case "evm" /* EVM */:
|
|
446
|
+
return !!window.ethereum;
|
|
447
|
+
case "solana" /* SOLANA */:
|
|
448
|
+
case "svm" /* SVM */:
|
|
449
|
+
return !!window.solana || !!window.phantom;
|
|
450
|
+
default:
|
|
451
|
+
return false;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
function getWalletProvider(networkType) {
|
|
455
|
+
if (typeof window === "undefined") {
|
|
456
|
+
return null;
|
|
457
|
+
}
|
|
458
|
+
switch (networkType) {
|
|
459
|
+
case "evm" /* EVM */:
|
|
460
|
+
return window.ethereum;
|
|
461
|
+
case "solana" /* SOLANA */:
|
|
462
|
+
case "svm" /* SVM */:
|
|
463
|
+
return window.solana || window.phantom;
|
|
464
|
+
default:
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
function formatAddress(address) {
|
|
469
|
+
if (!address || address.length < 10) {
|
|
470
|
+
return address;
|
|
471
|
+
}
|
|
472
|
+
return `${address.slice(0, 6)}...${address.slice(-4)}`;
|
|
473
|
+
}
|
|
474
|
+
function getWalletInstallUrl(networkType) {
|
|
475
|
+
switch (networkType) {
|
|
476
|
+
case "evm" /* EVM */:
|
|
477
|
+
return "https://metamask.io/download/";
|
|
478
|
+
case "solana" /* SOLANA */:
|
|
479
|
+
case "svm" /* SVM */:
|
|
480
|
+
return "https://phantom.app/download";
|
|
481
|
+
default:
|
|
482
|
+
return "#";
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
function getWalletDisplayName(networkType) {
|
|
486
|
+
switch (networkType) {
|
|
487
|
+
case "evm" /* EVM */:
|
|
488
|
+
return "MetaMask";
|
|
489
|
+
case "solana" /* SOLANA */:
|
|
490
|
+
case "svm" /* SVM */:
|
|
491
|
+
return "Phantom";
|
|
492
|
+
default:
|
|
493
|
+
return "Unknown Wallet";
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// src/utils/payment-helpers.ts
|
|
498
|
+
var import_ethers2 = require("ethers");
|
|
499
|
+
async function makePayment(networkType, merchantId, endpoint = PROD_BACK_URL) {
|
|
500
|
+
endpoint = `${endpoint}/${merchantId}`;
|
|
501
|
+
let response;
|
|
502
|
+
if (networkType === "solana" /* SOLANA */ || networkType === "svm" /* SVM */) {
|
|
503
|
+
const solana = window.solana;
|
|
504
|
+
if (!solana) {
|
|
505
|
+
throw new Error("\u8BF7\u5B89\u88C5 Phantom \u94B1\u5305");
|
|
506
|
+
}
|
|
507
|
+
if (!solana.isConnected) {
|
|
508
|
+
await solana.connect();
|
|
509
|
+
}
|
|
510
|
+
response = await handleSvmPayment(endpoint, {
|
|
511
|
+
wallet: solana,
|
|
512
|
+
network: "solana-devnet"
|
|
513
|
+
});
|
|
514
|
+
} else if (networkType === "evm" /* EVM */) {
|
|
515
|
+
if (!window.ethereum) {
|
|
516
|
+
throw new Error("\u8BF7\u5B89\u88C5 MetaMask \u94B1\u5305");
|
|
517
|
+
}
|
|
518
|
+
const provider = new import_ethers2.ethers.BrowserProvider(window.ethereum);
|
|
519
|
+
const signer = await provider.getSigner();
|
|
520
|
+
const wallet = {
|
|
521
|
+
address: await signer.getAddress(),
|
|
522
|
+
signTypedData: async (domain, types, message) => {
|
|
523
|
+
return await signer.signTypedData(domain, types, message);
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
const network = endpoint.includes("sepolia") ? "base-sepolia" : "base";
|
|
527
|
+
response = await handleEvmPayment(endpoint, {
|
|
528
|
+
wallet,
|
|
529
|
+
network
|
|
530
|
+
});
|
|
531
|
+
} else {
|
|
532
|
+
throw new Error(`\u4E0D\u652F\u6301\u7684\u7F51\u7EDC\u7C7B\u578B: ${networkType}`);
|
|
533
|
+
}
|
|
534
|
+
return response;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// src/utils/network.ts
|
|
538
|
+
var NETWORK_TYPE_MAP = {
|
|
539
|
+
// EVM chains
|
|
540
|
+
"ethereum": "evm" /* EVM */,
|
|
541
|
+
"eth": "evm" /* EVM */,
|
|
542
|
+
"base": "evm" /* EVM */,
|
|
543
|
+
"base-sepolia": "evm" /* EVM */,
|
|
544
|
+
"polygon": "evm" /* EVM */,
|
|
545
|
+
"arbitrum": "evm" /* EVM */,
|
|
546
|
+
"optimism": "evm" /* EVM */,
|
|
547
|
+
"bsc": "evm" /* EVM */,
|
|
548
|
+
"sepolia": "evm" /* EVM */,
|
|
549
|
+
"goerli": "evm" /* EVM */,
|
|
550
|
+
// Solana/SVM
|
|
551
|
+
"solana": "solana" /* SOLANA */,
|
|
552
|
+
"solana-devnet": "solana" /* SOLANA */,
|
|
553
|
+
"solana-testnet": "solana" /* SOLANA */,
|
|
554
|
+
"solana-mainnet": "solana" /* SOLANA */,
|
|
555
|
+
"svm": "svm" /* SVM */
|
|
556
|
+
};
|
|
557
|
+
function getNetworkType(network) {
|
|
558
|
+
const normalizedNetwork = network.toLowerCase().trim();
|
|
559
|
+
return NETWORK_TYPE_MAP[normalizedNetwork] || "unknown" /* UNKNOWN */;
|
|
560
|
+
}
|
|
561
|
+
function isEvmNetwork(network) {
|
|
562
|
+
return getNetworkType(network) === "evm" /* EVM */;
|
|
563
|
+
}
|
|
564
|
+
function isSolanaNetwork(network) {
|
|
565
|
+
const type = getNetworkType(network);
|
|
566
|
+
return type === "solana" /* SOLANA */ || type === "svm" /* SVM */;
|
|
567
|
+
}
|
|
568
|
+
function isSolanaAddress(address) {
|
|
569
|
+
if (address.startsWith("0x")) {
|
|
570
|
+
return false;
|
|
571
|
+
}
|
|
572
|
+
const base58Regex = /^[1-9A-HJ-NP-Za-km-z]+$/;
|
|
573
|
+
return base58Regex.test(address) && address.length >= 32 && address.length <= 44;
|
|
574
|
+
}
|
|
575
|
+
function isEvmAddress(address) {
|
|
576
|
+
return /^0x[a-fA-F0-9]{40}$/.test(address);
|
|
577
|
+
}
|
|
578
|
+
function getNetworkDisplayName(network) {
|
|
579
|
+
const displayNames = {
|
|
580
|
+
"ethereum": "Ethereum",
|
|
581
|
+
"sepolia": "Sepolia Testnet",
|
|
582
|
+
"base": "Base",
|
|
583
|
+
"base-sepolia": "Base Sepolia",
|
|
584
|
+
"polygon": "Polygon",
|
|
585
|
+
"arbitrum": "Arbitrum",
|
|
586
|
+
"optimism": "Optimism",
|
|
587
|
+
"solana": "Solana",
|
|
588
|
+
"solana-devnet": "Solana Devnet",
|
|
589
|
+
"solana-mainnet": "Solana Mainnet"
|
|
590
|
+
};
|
|
591
|
+
return displayNames[network.toLowerCase()] || network;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// src/utils/helpers.ts
|
|
595
|
+
function toAtomicUnits(amount, decimals) {
|
|
596
|
+
return BigInt(Math.floor(amount * Math.pow(10, decimals)));
|
|
597
|
+
}
|
|
598
|
+
function fromAtomicUnits(atomicUnits, decimals) {
|
|
599
|
+
return Number(atomicUnits) / Math.pow(10, decimals);
|
|
600
|
+
}
|
|
601
|
+
function is402Response(response) {
|
|
602
|
+
return response && typeof response === "object" && "x402Version" in response && "accepts" in response && Array.isArray(response.accepts);
|
|
603
|
+
}
|
|
604
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
605
|
+
0 && (module.exports = {
|
|
606
|
+
EVM_NETWORK_CONFIGS,
|
|
607
|
+
EvmNetworkSchema,
|
|
608
|
+
EvmPaymentPayloadSchema,
|
|
609
|
+
SolanaNetworkSchema,
|
|
610
|
+
SolanaPaymentPayloadSchema,
|
|
611
|
+
createEvmPaymentFetch,
|
|
612
|
+
createEvmPaymentHeader,
|
|
613
|
+
createSvmPaymentFetch,
|
|
614
|
+
createSvmPaymentHeader,
|
|
615
|
+
formatAddress,
|
|
616
|
+
fromAtomicUnits,
|
|
617
|
+
getChainId,
|
|
618
|
+
getChainIdFromNetwork,
|
|
619
|
+
getDefaultSolanaRpcUrl,
|
|
620
|
+
getNetworkDisplayName,
|
|
621
|
+
getNetworkType,
|
|
622
|
+
getWalletDisplayName,
|
|
623
|
+
getWalletInstallUrl,
|
|
624
|
+
getWalletProvider,
|
|
625
|
+
handleEvmPayment,
|
|
626
|
+
handleSvmPayment,
|
|
627
|
+
is402Response,
|
|
628
|
+
isEvmAddress,
|
|
629
|
+
isEvmNetwork,
|
|
630
|
+
isSolanaAddress,
|
|
631
|
+
isSolanaNetwork,
|
|
632
|
+
isWalletInstalled,
|
|
633
|
+
makePayment,
|
|
634
|
+
toAtomicUnits
|
|
635
|
+
});
|
|
636
|
+
//# sourceMappingURL=index.js.map
|