@x402x/client 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,705 @@
1
+ 'use strict';
2
+
3
+ var core = require('@x402x/core');
4
+ var viem = require('viem');
5
+ var actions = require('viem/actions');
6
+ var react = require('react');
7
+ var wagmi = require('wagmi');
8
+
9
+ // src/client.ts
10
+
11
+ // src/errors.ts
12
+ var X402ClientError = class _X402ClientError extends Error {
13
+ constructor(message, code) {
14
+ super(message);
15
+ this.code = code;
16
+ this.name = "X402ClientError";
17
+ Object.setPrototypeOf(this, _X402ClientError.prototype);
18
+ }
19
+ };
20
+ var NetworkError = class _NetworkError extends X402ClientError {
21
+ constructor(message, code) {
22
+ super(message, code);
23
+ this.name = "NetworkError";
24
+ Object.setPrototypeOf(this, _NetworkError.prototype);
25
+ }
26
+ };
27
+ var SigningError = class _SigningError extends X402ClientError {
28
+ constructor(message, code) {
29
+ super(message, code);
30
+ this.name = "SigningError";
31
+ Object.setPrototypeOf(this, _SigningError.prototype);
32
+ }
33
+ };
34
+ var FacilitatorError = class _FacilitatorError extends X402ClientError {
35
+ constructor(message, code, statusCode, response) {
36
+ super(message, code);
37
+ this.statusCode = statusCode;
38
+ this.response = response;
39
+ this.name = "FacilitatorError";
40
+ Object.setPrototypeOf(this, _FacilitatorError.prototype);
41
+ }
42
+ };
43
+ var TransactionError = class _TransactionError extends X402ClientError {
44
+ constructor(message, code, txHash) {
45
+ super(message, code);
46
+ this.txHash = txHash;
47
+ this.name = "TransactionError";
48
+ Object.setPrototypeOf(this, _TransactionError.prototype);
49
+ }
50
+ };
51
+ var ValidationError = class _ValidationError extends X402ClientError {
52
+ constructor(message, code) {
53
+ super(message, code);
54
+ this.name = "ValidationError";
55
+ Object.setPrototypeOf(this, _ValidationError.prototype);
56
+ }
57
+ };
58
+ function generateSalt() {
59
+ const randomBytes = crypto.getRandomValues(new Uint8Array(32));
60
+ return `0x${Array.from(randomBytes).map((b) => b.toString(16).padStart(2, "0")).join("")}`;
61
+ }
62
+ function normalizeAddress(address, name = "address") {
63
+ if (!address || typeof address !== "string") {
64
+ throw new ValidationError(`${name} is required`);
65
+ }
66
+ try {
67
+ return viem.getAddress(address);
68
+ } catch (error) {
69
+ throw new ValidationError(
70
+ `${name} is not a valid Ethereum address: ${error instanceof Error ? error.message : "Unknown error"}`
71
+ );
72
+ }
73
+ }
74
+ function validateAddress(address, name) {
75
+ if (!address || typeof address !== "string") {
76
+ throw new ValidationError(`${name} is required`);
77
+ }
78
+ if (!viem.isAddress(address)) {
79
+ throw new ValidationError(`${name} must be a valid Ethereum address`);
80
+ }
81
+ }
82
+ function validateHex(hex, name, expectedLength) {
83
+ if (!hex || typeof hex !== "string") {
84
+ throw new ValidationError(`${name} is required`);
85
+ }
86
+ if (!hex.startsWith("0x")) {
87
+ throw new ValidationError(`${name} must start with 0x`);
88
+ }
89
+ if (!/^0x[0-9a-fA-F]*$/.test(hex)) {
90
+ throw new ValidationError(`${name} must be a valid hex string`);
91
+ }
92
+ if (expectedLength !== void 0) {
93
+ const actualLength = (hex.length - 2) / 2;
94
+ if (actualLength !== expectedLength) {
95
+ throw new ValidationError(
96
+ `${name} must be ${expectedLength} bytes, got ${actualLength} bytes`
97
+ );
98
+ }
99
+ }
100
+ }
101
+ function validateAmount(amount, name) {
102
+ if (amount === null || amount === void 0 || amount === "") {
103
+ throw new ValidationError(`${name} is required`);
104
+ }
105
+ const amountStr = typeof amount === "number" ? amount.toString() : amount;
106
+ if (typeof amountStr !== "string" || amountStr.trim() === "") {
107
+ throw new ValidationError(`${name} must be a non-empty string`);
108
+ }
109
+ if (!/^\d+$/.test(amountStr)) {
110
+ throw new ValidationError(
111
+ `${name} must be a positive integer string (atomic units). Use parseDefaultAssetAmount() from @x402x/core to convert USD amounts.`
112
+ );
113
+ }
114
+ try {
115
+ const atomicAmount = BigInt(amountStr);
116
+ if (atomicAmount < 0n) {
117
+ throw new ValidationError(`${name} cannot be negative`);
118
+ }
119
+ if (atomicAmount === 0n) {
120
+ throw new ValidationError(`${name} cannot be zero`);
121
+ }
122
+ } catch (error) {
123
+ if (error instanceof ValidationError) {
124
+ throw error;
125
+ }
126
+ throw new ValidationError(
127
+ `${name} is not a valid amount: ${error instanceof Error ? error.message : "Invalid format"}`
128
+ );
129
+ }
130
+ }
131
+ function formatFacilitatorUrl(url) {
132
+ return url.endsWith("/") ? url.slice(0, -1) : url;
133
+ }
134
+ function calculateTimeWindow(maxTimeoutSeconds = 300) {
135
+ const now = Math.floor(Date.now() / 1e3);
136
+ return {
137
+ validAfter: (now - 600).toString(),
138
+ // 10 minutes before
139
+ validBefore: (now + maxTimeoutSeconds).toString()
140
+ };
141
+ }
142
+
143
+ // src/core/prepare.ts
144
+ async function queryFacilitatorFee(facilitatorUrl, network, hook, hookData = "0x") {
145
+ try {
146
+ return await core.calculateFacilitatorFee(facilitatorUrl, network, hook, hookData);
147
+ } catch (error) {
148
+ if (error instanceof Error) {
149
+ throw new FacilitatorError(
150
+ `Failed to query facilitator fee: ${error.message}`,
151
+ "FEE_QUERY_FAILED"
152
+ );
153
+ }
154
+ throw new FacilitatorError("Failed to query facilitator fee: Unknown error", "UNKNOWN_ERROR");
155
+ }
156
+ }
157
+ async function prepareSettlement(params) {
158
+ validateAddress(params.hook, "hook");
159
+ validateHex(params.hookData, "hookData");
160
+ validateAddress(params.payTo, "payTo");
161
+ validateAmount(params.amount, "amount");
162
+ const atomicAmount = params.amount;
163
+ if (params.customSalt) {
164
+ validateHex(params.customSalt, "customSalt", 32);
165
+ }
166
+ const from = params.wallet.account?.address;
167
+ if (!from) {
168
+ throw new ValidationError("Wallet client must have an account");
169
+ }
170
+ const networkConfig = params.networkConfig || core.getNetworkConfig(params.network);
171
+ if (!networkConfig) {
172
+ throw new NetworkError(
173
+ `Network '${params.network}' is not supported. Please provide custom networkConfig.`
174
+ );
175
+ }
176
+ const asset = params.asset || networkConfig.defaultAsset.address;
177
+ validateAddress(asset, "asset");
178
+ const salt = params.customSalt || generateSalt();
179
+ let facilitatorFee = params.facilitatorFee || "0";
180
+ if (!params.facilitatorFee && params.facilitatorUrl) {
181
+ try {
182
+ const feeEstimate = await queryFacilitatorFee(
183
+ params.facilitatorUrl,
184
+ params.network,
185
+ params.hook,
186
+ params.hookData
187
+ // Pass hookData for accurate fee calculation
188
+ );
189
+ if (!feeEstimate.hookAllowed) {
190
+ throw new ValidationError(
191
+ `Hook ${params.hook} is not allowed on network ${params.network}.`
192
+ );
193
+ }
194
+ facilitatorFee = feeEstimate.facilitatorFee;
195
+ } catch (error) {
196
+ console.warn(
197
+ `[x402x] Failed to query facilitator fee, using 0. This may cause settlement to fail. Error: ${error instanceof Error ? error.message : "Unknown"}`
198
+ );
199
+ facilitatorFee = "0";
200
+ }
201
+ }
202
+ const timeWindow = params.validAfter && params.validBefore ? { validAfter: params.validAfter, validBefore: params.validBefore } : calculateTimeWindow(300);
203
+ const totalAmount = (BigInt(atomicAmount) + BigInt(facilitatorFee)).toString();
204
+ const commitment = core.calculateCommitment({
205
+ chainId: networkConfig.chainId,
206
+ hub: networkConfig.settlementRouter,
207
+ asset,
208
+ from,
209
+ value: totalAmount,
210
+ validAfter: timeWindow.validAfter,
211
+ validBefore: timeWindow.validBefore,
212
+ salt,
213
+ payTo: params.payTo,
214
+ facilitatorFee,
215
+ hook: params.hook,
216
+ hookData: params.hookData
217
+ });
218
+ return {
219
+ network: params.network,
220
+ networkConfig,
221
+ asset,
222
+ from,
223
+ amount: atomicAmount,
224
+ validAfter: timeWindow.validAfter,
225
+ validBefore: timeWindow.validBefore,
226
+ salt,
227
+ payTo: params.payTo,
228
+ facilitatorFee,
229
+ hook: params.hook,
230
+ hookData: params.hookData,
231
+ commitment
232
+ };
233
+ }
234
+ var AUTHORIZATION_TYPES = {
235
+ TransferWithAuthorization: [
236
+ { name: "from", type: "address" },
237
+ { name: "to", type: "address" },
238
+ { name: "value", type: "uint256" },
239
+ { name: "validAfter", type: "uint256" },
240
+ { name: "validBefore", type: "uint256" },
241
+ { name: "nonce", type: "bytes32" }
242
+ ]
243
+ };
244
+ async function signAuthorization(wallet, settlement) {
245
+ try {
246
+ if (!wallet.account) {
247
+ throw new SigningError("Wallet client must have an account");
248
+ }
249
+ const domain = {
250
+ name: settlement.networkConfig.defaultAsset.eip712.name,
251
+ version: settlement.networkConfig.defaultAsset.eip712.version,
252
+ chainId: settlement.networkConfig.chainId,
253
+ verifyingContract: viem.getAddress(settlement.asset)
254
+ };
255
+ const totalAmount = BigInt(settlement.amount) + BigInt(settlement.facilitatorFee);
256
+ const message = {
257
+ from: viem.getAddress(settlement.from),
258
+ to: viem.getAddress(settlement.networkConfig.settlementRouter),
259
+ value: totalAmount,
260
+ validAfter: BigInt(settlement.validAfter),
261
+ validBefore: BigInt(settlement.validBefore),
262
+ nonce: settlement.commitment
263
+ // Use commitment as nonce
264
+ };
265
+ console.log("[x402x/client] EIP-712 Message for signing:", {
266
+ from: message.from,
267
+ to: message.to,
268
+ value: message.value.toString(),
269
+ validAfter: message.validAfter.toString(),
270
+ validBefore: message.validBefore.toString(),
271
+ nonce: message.nonce
272
+ });
273
+ const signature = await actions.signTypedData(wallet, {
274
+ account: wallet.account,
275
+ domain,
276
+ types: AUTHORIZATION_TYPES,
277
+ primaryType: "TransferWithAuthorization",
278
+ message
279
+ });
280
+ const authorization = {
281
+ from: settlement.from,
282
+ to: settlement.networkConfig.settlementRouter,
283
+ value: totalAmount.toString(),
284
+ // Use total amount (business + fee)
285
+ validAfter: settlement.validAfter,
286
+ validBefore: settlement.validBefore,
287
+ nonce: settlement.commitment
288
+ };
289
+ return {
290
+ settlement,
291
+ signature,
292
+ authorization
293
+ };
294
+ } catch (error) {
295
+ if (error instanceof SigningError) {
296
+ throw error;
297
+ }
298
+ if (error instanceof Error) {
299
+ if (error.message.includes("User rejected")) {
300
+ throw new SigningError("User rejected the signing request", "USER_REJECTED");
301
+ }
302
+ if (error.message.includes("account")) {
303
+ throw new SigningError("Wallet account not available", "NO_ACCOUNT");
304
+ }
305
+ throw new SigningError(`Failed to sign authorization: ${error.message}`, "SIGNING_FAILED");
306
+ }
307
+ throw new SigningError("Failed to sign authorization: Unknown error", "UNKNOWN_ERROR");
308
+ }
309
+ }
310
+ async function settle(facilitatorUrl, signed, timeout = 3e4) {
311
+ try {
312
+ const paymentPayload = {
313
+ x402Version: 1,
314
+ scheme: "exact",
315
+ network: signed.settlement.network,
316
+ // Network type compatibility
317
+ payload: {
318
+ signature: signed.signature,
319
+ authorization: {
320
+ from: signed.authorization.from,
321
+ to: signed.authorization.to,
322
+ value: signed.authorization.value,
323
+ validAfter: signed.authorization.validAfter,
324
+ validBefore: signed.authorization.validBefore,
325
+ nonce: signed.authorization.nonce
326
+ }
327
+ }
328
+ };
329
+ const paymentRequirements = {
330
+ scheme: "exact",
331
+ network: signed.settlement.network,
332
+ // Network type compatibility
333
+ maxAmountRequired: signed.settlement.amount,
334
+ asset: signed.settlement.asset,
335
+ payTo: signed.settlement.networkConfig.settlementRouter,
336
+ maxTimeoutSeconds: 300,
337
+ // 5 minutes
338
+ // Required by x402 protocol (even though not used in serverless mode)
339
+ // In the future, the x402 v2 will remove the resource field from the payment requirements
340
+ // (https://github.com/coinbase/x402/pull/446)
341
+ resource: "https://x402x.dev/serverless",
342
+ // Placeholder for serverless mode
343
+ description: "x402x Serverless Settlement",
344
+ mimeType: "application/json",
345
+ extra: {
346
+ name: signed.settlement.networkConfig.defaultAsset.eip712.name,
347
+ version: signed.settlement.networkConfig.defaultAsset.eip712.version,
348
+ settlementRouter: signed.settlement.networkConfig.settlementRouter,
349
+ salt: signed.settlement.salt,
350
+ payTo: signed.settlement.payTo,
351
+ facilitatorFee: signed.settlement.facilitatorFee,
352
+ hook: signed.settlement.hook,
353
+ hookData: signed.settlement.hookData
354
+ }
355
+ };
356
+ paymentPayload.paymentRequirements = paymentRequirements;
357
+ const result = await core.settle(facilitatorUrl, paymentPayload, paymentRequirements, timeout);
358
+ return {
359
+ success: result.success,
360
+ transaction: result.transaction,
361
+ network: result.network || signed.settlement.network,
362
+ payer: result.payer || signed.settlement.from,
363
+ errorReason: result.errorReason
364
+ };
365
+ } catch (error) {
366
+ if (error instanceof FacilitatorError) {
367
+ throw error;
368
+ }
369
+ if (error instanceof Error) {
370
+ throw new FacilitatorError(`Failed to settle payment: ${error.message}`, "SETTLEMENT_ERROR");
371
+ }
372
+ throw new FacilitatorError("Failed to settle payment: Unknown error", "UNKNOWN_ERROR");
373
+ }
374
+ }
375
+
376
+ // src/client.ts
377
+ var DEFAULT_FACILITATOR_URL = "https://facilitator.x402x.dev";
378
+ var X402Client = class {
379
+ /**
380
+ * Create a new X402Client instance
381
+ *
382
+ * @param config - Client configuration
383
+ * @throws NetworkError if network is unsupported
384
+ * @throws ValidationError if configuration is invalid
385
+ */
386
+ constructor(config) {
387
+ if (!config.wallet) {
388
+ throw new ValidationError("wallet is required");
389
+ }
390
+ if (!config.network) {
391
+ throw new ValidationError("network is required");
392
+ }
393
+ this.config = {
394
+ ...config,
395
+ facilitatorUrl: config.facilitatorUrl || DEFAULT_FACILITATOR_URL,
396
+ timeout: config.timeout || 3e4,
397
+ confirmationTimeout: config.confirmationTimeout || 6e4
398
+ };
399
+ }
400
+ /**
401
+ * Execute a settlement transaction
402
+ *
403
+ * This is the main method that orchestrates the entire settlement flow:
404
+ * 1. Validates parameters
405
+ * 2. Prepares settlement data (queries fee if needed)
406
+ * 3. Signs EIP-3009 authorization
407
+ * 4. Submits to facilitator
408
+ * 5. Optionally waits for transaction confirmation
409
+ *
410
+ * @param params - Execution parameters
411
+ * @param waitForConfirmation - Whether to wait for transaction confirmation (default: true)
412
+ * @returns Execution result with transaction hash and optional receipt
413
+ *
414
+ * @throws ValidationError if parameters are invalid
415
+ * @throws NetworkError if network is unsupported
416
+ * @throws SigningError if user rejects signing
417
+ * @throws FacilitatorError if facilitator request fails
418
+ * @throws TransactionError if transaction fails
419
+ *
420
+ * @example Simple transfer (uses TransferHook by default)
421
+ * ```typescript
422
+ * import { parseDefaultAssetAmount } from '@x402x/core';
423
+ *
424
+ * // Convert USD amount to atomic units
425
+ * const atomicAmount = parseDefaultAssetAmount('1', 'base-sepolia'); // '1000000'
426
+ *
427
+ * const result = await client.execute({
428
+ * amount: atomicAmount, // Must be atomic units
429
+ * payTo: '0x...'
430
+ * });
431
+ * console.log('Transaction:', result.txHash);
432
+ * ```
433
+ *
434
+ * @example Custom hook
435
+ * ```typescript
436
+ * import { parseDefaultAssetAmount } from '@x402x/core';
437
+ *
438
+ * const atomicAmount = parseDefaultAssetAmount('5', 'base-sepolia'); // '5000000'
439
+ *
440
+ * const result = await client.execute({
441
+ * hook: '0x...',
442
+ * hookData: '0x...',
443
+ * amount: atomicAmount, // Must be atomic units
444
+ * payTo: '0x...'
445
+ * });
446
+ * ```
447
+ */
448
+ async execute(params, waitForConfirmation = false) {
449
+ const hook = params.hook ? normalizeAddress(params.hook, "hook") : core.TransferHook.getAddress(this.config.network);
450
+ const payTo = normalizeAddress(params.payTo, "payTo");
451
+ const hookData = params.hookData || "0x";
452
+ if (params.hookData) {
453
+ validateHex(params.hookData, "hookData");
454
+ }
455
+ validateAmount(params.amount, "amount");
456
+ const settlement = await prepareSettlement({
457
+ wallet: this.config.wallet,
458
+ network: this.config.network,
459
+ hook,
460
+ hookData,
461
+ asset: params.asset,
462
+ amount: params.amount,
463
+ payTo,
464
+ facilitatorFee: params.facilitatorFee,
465
+ customSalt: params.customSalt,
466
+ validAfter: params.validAfter,
467
+ validBefore: params.validBefore,
468
+ networkConfig: this.config.networkConfig,
469
+ facilitatorUrl: this.config.facilitatorUrl
470
+ });
471
+ const signed = await signAuthorization(this.config.wallet, settlement);
472
+ const settleResult = await settle(this.config.facilitatorUrl, signed, this.config.timeout);
473
+ let receipt;
474
+ if (waitForConfirmation) {
475
+ receipt = await this.waitForTransaction(settleResult.transaction);
476
+ }
477
+ return {
478
+ txHash: settleResult.transaction,
479
+ network: settleResult.network,
480
+ payer: settleResult.payer,
481
+ receipt,
482
+ settlement
483
+ };
484
+ }
485
+ /**
486
+ * Calculate facilitator fee for a hook with optional hook data
487
+ *
488
+ * Queries the facilitator for the recommended fee based on current gas prices
489
+ * and hook gas usage. The returned fee includes a safety margin to ensure
490
+ * settlement will succeed.
491
+ *
492
+ * @param hook - Hook contract address
493
+ * @param hookData - Optional encoded hook parameters (default: '0x')
494
+ * @returns Fee calculation result from facilitator
495
+ *
496
+ * @throws FacilitatorError if query fails
497
+ *
498
+ * @example
499
+ * ```typescript
500
+ * const fee = await client.calculateFee('0x...', '0x');
501
+ * console.log('Facilitator fee:', fee.facilitatorFee);
502
+ * console.log('Fee in USD:', fee.facilitatorFeeUSD);
503
+ * console.log('Valid for:', fee.validitySeconds, 'seconds');
504
+ * ```
505
+ */
506
+ async calculateFee(hook, hookData = "0x") {
507
+ const normalizedHook = normalizeAddress(hook, "hook");
508
+ validateHex(hookData, "hookData");
509
+ try {
510
+ return await core.calculateFacilitatorFee(
511
+ this.config.facilitatorUrl,
512
+ this.config.network,
513
+ normalizedHook,
514
+ hookData
515
+ );
516
+ } catch (error) {
517
+ if (error instanceof Error) {
518
+ throw new FacilitatorError(
519
+ `Failed to calculate facilitator fee: ${error.message}`,
520
+ "FEE_QUERY_FAILED"
521
+ );
522
+ }
523
+ throw new FacilitatorError(
524
+ "Failed to calculate facilitator fee: Unknown error",
525
+ "UNKNOWN_ERROR"
526
+ );
527
+ }
528
+ }
529
+ /**
530
+ * Wait for transaction confirmation
531
+ *
532
+ * @param txHash - Transaction hash to wait for
533
+ * @returns Transaction receipt
534
+ *
535
+ * @throws TransactionError if transaction fails or times out
536
+ *
537
+ * @example
538
+ * ```typescript
539
+ * const receipt = await client.waitForTransaction('0x...');
540
+ * console.log('Status:', receipt.status);
541
+ * ```
542
+ */
543
+ async waitForTransaction(txHash) {
544
+ const publicClient = this.config.wallet;
545
+ if (typeof publicClient.waitForTransactionReceipt !== "function") {
546
+ throw new Error(
547
+ "Wallet client does not support waitForTransactionReceipt. Please use a viem PublicClient or WalletClient with public actions."
548
+ );
549
+ }
550
+ try {
551
+ const receipt = await publicClient.waitForTransactionReceipt({
552
+ hash: txHash,
553
+ timeout: this.config.confirmationTimeout
554
+ });
555
+ if (receipt.status !== "success") {
556
+ throw new Error(`Transaction failed with status: ${receipt.status}`);
557
+ }
558
+ return receipt;
559
+ } catch (error) {
560
+ if (error instanceof Error) {
561
+ throw new Error(`Failed to confirm transaction: ${error.message}`);
562
+ }
563
+ throw new Error("Failed to confirm transaction: Unknown error");
564
+ }
565
+ }
566
+ /**
567
+ * Get the network name
568
+ */
569
+ get network() {
570
+ return this.config.network;
571
+ }
572
+ /**
573
+ * Get the facilitator URL
574
+ */
575
+ get facilitatorUrl() {
576
+ return this.config.facilitatorUrl;
577
+ }
578
+ /**
579
+ * Get the wallet client
580
+ */
581
+ get wallet() {
582
+ return this.config.wallet;
583
+ }
584
+ };
585
+ var CHAIN_ID_TO_NETWORK = {
586
+ 84532: "base-sepolia",
587
+ 8453: "base",
588
+ 196: "x-layer",
589
+ 1952: "x-layer-testnet"
590
+ };
591
+ function useX402Client(config) {
592
+ const { data: walletClient } = wagmi.useWalletClient();
593
+ const { isConnected } = wagmi.useAccount();
594
+ const chainId = wagmi.useChainId();
595
+ return react.useMemo(() => {
596
+ if (!isConnected || !walletClient) {
597
+ return null;
598
+ }
599
+ const network = config?.network || CHAIN_ID_TO_NETWORK[chainId];
600
+ if (!network) {
601
+ console.warn(
602
+ `[x402x] Unknown chainId ${chainId}. Please provide network name explicitly in config.`
603
+ );
604
+ return null;
605
+ }
606
+ try {
607
+ const extendedWallet = walletClient.extend(viem.publicActions);
608
+ return new X402Client({
609
+ wallet: extendedWallet,
610
+ network,
611
+ facilitatorUrl: config?.facilitatorUrl,
612
+ networkConfig: config?.networkConfig,
613
+ timeout: config?.timeout,
614
+ confirmationTimeout: config?.confirmationTimeout
615
+ });
616
+ } catch (error) {
617
+ console.error("[x402x] Failed to create X402Client:", error);
618
+ return null;
619
+ }
620
+ }, [
621
+ isConnected,
622
+ walletClient,
623
+ chainId,
624
+ config?.network,
625
+ config?.facilitatorUrl,
626
+ config?.networkConfig,
627
+ config?.timeout,
628
+ config?.confirmationTimeout
629
+ ]);
630
+ }
631
+ function useExecute(config) {
632
+ const client = useX402Client(config);
633
+ const [status, setStatus] = react.useState("idle");
634
+ const [error, setError] = react.useState(null);
635
+ const [result, setResult] = react.useState(null);
636
+ const execute = react.useCallback(
637
+ async (params, waitForConfirmation = true) => {
638
+ if (!client) {
639
+ throw new Error("X402Client not available. Please connect your wallet.");
640
+ }
641
+ setStatus("preparing");
642
+ setError(null);
643
+ setResult(null);
644
+ try {
645
+ const executeResult = await client.execute(params, waitForConfirmation);
646
+ setStatus("success");
647
+ setResult(executeResult);
648
+ return executeResult;
649
+ } catch (err) {
650
+ const error2 = err instanceof Error ? err : new Error("Unknown error");
651
+ setStatus("error");
652
+ setError(error2);
653
+ throw error2;
654
+ }
655
+ },
656
+ [client]
657
+ );
658
+ const reset = react.useCallback(() => {
659
+ setStatus("idle");
660
+ setError(null);
661
+ setResult(null);
662
+ }, []);
663
+ return {
664
+ execute,
665
+ status,
666
+ error,
667
+ result,
668
+ reset,
669
+ isExecuting: ["preparing", "signing", "submitting", "confirming"].includes(status),
670
+ isSuccess: status === "success",
671
+ isError: status === "error"
672
+ };
673
+ }
674
+
675
+ Object.defineProperty(exports, "AmountError", {
676
+ enumerable: true,
677
+ get: function () { return core.AmountError; }
678
+ });
679
+ Object.defineProperty(exports, "formatDefaultAssetAmount", {
680
+ enumerable: true,
681
+ get: function () { return core.formatDefaultAssetAmount; }
682
+ });
683
+ Object.defineProperty(exports, "parseDefaultAssetAmount", {
684
+ enumerable: true,
685
+ get: function () { return core.parseDefaultAssetAmount; }
686
+ });
687
+ exports.DEFAULT_FACILITATOR_URL = DEFAULT_FACILITATOR_URL;
688
+ exports.FacilitatorError = FacilitatorError;
689
+ exports.NetworkError = NetworkError;
690
+ exports.SigningError = SigningError;
691
+ exports.TransactionError = TransactionError;
692
+ exports.ValidationError = ValidationError;
693
+ exports.X402Client = X402Client;
694
+ exports.X402ClientError = X402ClientError;
695
+ exports.calculateTimeWindow = calculateTimeWindow;
696
+ exports.formatFacilitatorUrl = formatFacilitatorUrl;
697
+ exports.generateSalt = generateSalt;
698
+ exports.normalizeAddress = normalizeAddress;
699
+ exports.prepareSettlement = prepareSettlement;
700
+ exports.settle = settle;
701
+ exports.signAuthorization = signAuthorization;
702
+ exports.useExecute = useExecute;
703
+ exports.useX402Client = useX402Client;
704
+ //# sourceMappingURL=index.cjs.map
705
+ //# sourceMappingURL=index.cjs.map