@x402x/client 0.2.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -44,7 +44,7 @@ Client → Facilitator → Smart Contract (Hook)
44
44
  ### After (@x402x/client)
45
45
 
46
46
  ```typescript
47
- import { parseDefaultAssetAmount } from "@x402x/core";
47
+ import { parseDefaultAssetAmount } from "@x402x/extensions";
48
48
 
49
49
  const atomicAmount = parseDefaultAssetAmount("1", network); // '1000000'
50
50
  const client = new X402Client({ wallet, network, facilitatorUrl });
@@ -64,18 +64,18 @@ const result = await client.execute({
64
64
  ### Installation
65
65
 
66
66
  ```bash
67
- npm install @x402x/client @x402x/core
67
+ npm install @x402x/client @x402x/extensions
68
68
  # or
69
- pnpm add @x402x/client @x402x/core
69
+ pnpm add @x402x/client @x402x/extensions
70
70
  # or
71
- yarn add @x402x/client @x402x/core
71
+ yarn add @x402x/client @x402x/extensions
72
72
  ```
73
73
 
74
74
  ### Basic Usage (React + wagmi)
75
75
 
76
76
  ```typescript
77
77
  import { X402Client } from '@x402x/client';
78
- import { TransferHook, parseDefaultAssetAmount } from '@x402x/core';
78
+ import { TransferHook, parseDefaultAssetAmount } from '@x402x/extensions';
79
79
  import { useWalletClient } from 'wagmi';
80
80
  import { publicActions } from 'viem';
81
81
 
@@ -119,10 +119,10 @@ The `amount` parameter in `client.execute()` and `prepareSettlement()` **must be
119
119
 
120
120
  ### Converting USD Amounts to Atomic Units
121
121
 
122
- Use `parseDefaultAssetAmount()` from `@x402x/core` to convert USD amounts:
122
+ Use `parseDefaultAssetAmount()` from `@x402x/extensions` to convert USD amounts:
123
123
 
124
124
  ```typescript
125
- import { parseDefaultAssetAmount, formatDefaultAssetAmount } from "@x402x/core";
125
+ import { parseDefaultAssetAmount, formatDefaultAssetAmount } from "@x402x/extensions";
126
126
 
127
127
  // Convert USD to atomic units
128
128
  const atomicAmount = parseDefaultAssetAmount("1", "base-sepolia"); // '1000000' (1 USDC)
@@ -143,7 +143,7 @@ const displayAmount = formatDefaultAssetAmount("1000000", "base-sepolia"); // '1
143
143
 
144
144
  ```typescript
145
145
  import { X402Client } from "@x402x/client";
146
- import { parseDefaultAssetAmount } from "@x402x/core";
146
+ import { parseDefaultAssetAmount } from "@x402x/extensions";
147
147
 
148
148
  const client = new X402Client({ wallet, network: "base-sepolia" });
149
149
 
@@ -195,7 +195,7 @@ const client = new X402Client({
195
195
  });
196
196
 
197
197
  // Convert USD amount to atomic units
198
- import { parseDefaultAssetAmount } from "@x402x/core";
198
+ import { parseDefaultAssetAmount } from "@x402x/extensions";
199
199
  const atomicAmount = parseDefaultAssetAmount("1", "base-sepolia"); // '1000000'
200
200
 
201
201
  const result = await client.execute({
@@ -240,7 +240,7 @@ Provides automatic state management for settlements.
240
240
 
241
241
  ```typescript
242
242
  import { useExecute } from '@x402x/client';
243
- import { parseDefaultAssetAmount } from '@x402x/core';
243
+ import { parseDefaultAssetAmount } from '@x402x/extensions';
244
244
 
245
245
  function PayButton() {
246
246
  // Uses default facilitator at https://facilitator.x402x.dev/
@@ -285,7 +285,7 @@ Understanding the x402 protocol terminology used in this SDK:
285
285
  **Verify** (from x402 protocol) - Validate a payment payload without executing it on-chain. This is useful for pre-validation before actual settlement.
286
286
 
287
287
  - In x402 protocol: `POST /verify` endpoint
288
- - In @x402x/core: `verify()` function
288
+ - In @x402x/extensions: `verify()` function
289
289
  - Use case: Check if payment is valid before committing resources
290
290
 
291
291
  ### settle
@@ -293,7 +293,7 @@ Understanding the x402 protocol terminology used in this SDK:
293
293
  **Settle** (from x402 protocol) - Execute a payment on-chain by submitting it to the blockchain. This is the actual payment execution step.
294
294
 
295
295
  - In x402 protocol: `POST /settle` endpoint
296
- - In @x402x/core: `settle()` function
296
+ - In @x402x/extensions: `settle()` function
297
297
  - In @x402x/client: `settle()` function (convenience wrapper)
298
298
  - Use case: Submit signed payment for blockchain execution
299
299
 
@@ -333,7 +333,7 @@ Prepares settlement data for signing.
333
333
 
334
334
  ```typescript
335
335
  import { prepareSettlement } from "@x402x/client";
336
- import { parseDefaultAssetAmount } from "@x402x/core";
336
+ import { parseDefaultAssetAmount } from "@x402x/extensions";
337
337
 
338
338
  // Convert USD amount to atomic units
339
339
  const atomicAmount = parseDefaultAssetAmount("1", "base-sepolia"); // '1000000'
@@ -377,7 +377,7 @@ const result = await settle("https://facilitator.x402x.dev", signed);
377
377
 
378
378
  ```typescript
379
379
  import { X402Client } from "@x402x/client";
380
- import { TransferHook, parseDefaultAssetAmount } from "@x402x/core";
380
+ import { TransferHook, parseDefaultAssetAmount } from "@x402x/extensions";
381
381
 
382
382
  // Uses default facilitator at https://facilitator.x402x.dev/
383
383
  const client = new X402Client({
@@ -404,7 +404,7 @@ TransferHook supports distributing funds to multiple recipients by percentage:
404
404
 
405
405
  ```typescript
406
406
  import { X402Client } from "@x402x/client";
407
- import { TransferHook, parseDefaultAssetAmount, type Split } from "@x402x/core";
407
+ import { TransferHook, parseDefaultAssetAmount, type Split } from "@x402x/extensions";
408
408
 
409
409
  const client = new X402Client({
410
410
  wallet: walletClient,
@@ -449,7 +449,7 @@ console.log("Distributed transfer:", result.txHash);
449
449
 
450
450
  ```typescript
451
451
  import { useExecute } from '@x402x/client';
452
- import { NFTMintHook, parseDefaultAssetAmount } from '@x402x/core';
452
+ import { NFTMintHook, parseDefaultAssetAmount } from '@x402x/extensions';
453
453
 
454
454
  function MintNFT() {
455
455
  // Uses default facilitator
@@ -484,7 +484,7 @@ function MintNFT() {
484
484
 
485
485
  ```typescript
486
486
  import { prepareSettlement, signAuthorization, settle } from "@x402x/client";
487
- import { calculateFacilitatorFee, TransferHook, parseDefaultAssetAmount } from "@x402x/core";
487
+ import { calculateFacilitatorFee, TransferHook, parseDefaultAssetAmount } from "@x402x/extensions";
488
488
 
489
489
  // 1. Query minimum fee
490
490
  const hookData = TransferHook.encode([
@@ -527,7 +527,7 @@ console.log("Transaction:", result.transaction);
527
527
  ```typescript
528
528
  import { ref } from "vue";
529
529
  import { X402Client } from "@x402x/client";
530
- import { TransferHook, parseDefaultAssetAmount } from "@x402x/core";
530
+ import { TransferHook, parseDefaultAssetAmount } from "@x402x/extensions";
531
531
 
532
532
  export function usePayment() {
533
533
  const status = ref("idle");
@@ -660,7 +660,7 @@ function Component() {
660
660
  ```typescript
661
661
  // 10 lines with @x402x/client (no facilitatorUrl needed!)
662
662
  import { useExecute } from "@x402x/client";
663
- import { TransferHook, parseDefaultAssetAmount } from "@x402x/core";
663
+ import { TransferHook, parseDefaultAssetAmount } from "@x402x/extensions";
664
664
 
665
665
  function Component() {
666
666
  // Uses default facilitator automatically
@@ -683,7 +683,7 @@ function Component() {
683
683
 
684
684
  ## Related Packages
685
685
 
686
- - [@x402x/core](../core) - Core utilities and commitment calculation
686
+ - [@x402x/extensions](../extensions) - Core utilities and network configuration
687
687
  - [@x402x/facilitator](../../facilitator) - Facilitator server implementation
688
688
  - [x402](https://github.com/coinbase/x402) - Base x402 protocol
689
689
 
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var core = require('@x402x/core');
3
+ var extensions = require('@x402x/extensions');
4
4
  var viem = require('viem');
5
5
  var actions = require('viem/actions');
6
6
  var react = require('react');
@@ -56,7 +56,11 @@ var ValidationError = class _ValidationError extends X402ClientError {
56
56
  }
57
57
  };
58
58
  function generateSalt() {
59
- const randomBytes = crypto.getRandomValues(new Uint8Array(32));
59
+ const cryptoObj = globalThis.crypto;
60
+ if (!cryptoObj || !cryptoObj.getRandomValues) {
61
+ throw new Error("crypto.getRandomValues is not available");
62
+ }
63
+ const randomBytes = cryptoObj.getRandomValues(new Uint8Array(32));
60
64
  return `0x${Array.from(randomBytes).map((b) => b.toString(16).padStart(2, "0")).join("")}`;
61
65
  }
62
66
  function normalizeAddress(address, name = "address") {
@@ -141,9 +145,10 @@ function calculateTimeWindow(maxTimeoutSeconds = 300) {
141
145
  }
142
146
 
143
147
  // src/core/prepare.ts
148
+ var DEFAULT_FACILITATOR_URL = "https://facilitator.x402x.dev";
144
149
  async function queryFacilitatorFee(facilitatorUrl, network, hook, hookData = "0x") {
145
150
  try {
146
- return await core.calculateFacilitatorFee(facilitatorUrl, network, hook, hookData);
151
+ return await extensions.calculateFacilitatorFee(facilitatorUrl, network, hook, hookData);
147
152
  } catch (error) {
148
153
  if (error instanceof Error) {
149
154
  throw new FacilitatorError(
@@ -167,7 +172,7 @@ async function prepareSettlement(params) {
167
172
  if (!from) {
168
173
  throw new ValidationError("Wallet client must have an account");
169
174
  }
170
- const networkConfig = params.networkConfig || core.getNetworkConfig(params.network);
175
+ const networkConfig = params.networkConfig || extensions.getNetworkConfig(params.network);
171
176
  if (!networkConfig) {
172
177
  throw new NetworkError(
173
178
  `Network '${params.network}' is not supported. Please provide custom networkConfig.`
@@ -177,10 +182,11 @@ async function prepareSettlement(params) {
177
182
  validateAddress(asset, "asset");
178
183
  const salt = params.customSalt || generateSalt();
179
184
  let facilitatorFee = params.facilitatorFee || "0";
180
- if (!params.facilitatorFee && params.facilitatorUrl) {
185
+ if (!params.facilitatorFee) {
186
+ const facilitatorUrl = params.facilitatorUrl || DEFAULT_FACILITATOR_URL;
181
187
  try {
182
188
  const feeEstimate = await queryFacilitatorFee(
183
- params.facilitatorUrl,
189
+ facilitatorUrl,
184
190
  params.network,
185
191
  params.hook,
186
192
  params.hookData
@@ -201,7 +207,7 @@ async function prepareSettlement(params) {
201
207
  }
202
208
  const timeWindow = params.validAfter && params.validBefore ? { validAfter: params.validAfter, validBefore: params.validBefore } : calculateTimeWindow(300);
203
209
  const totalAmount = (BigInt(atomicAmount) + BigInt(facilitatorFee)).toString();
204
- const commitment = core.calculateCommitment({
210
+ const commitment = extensions.calculateCommitment({
205
211
  chainId: networkConfig.chainId,
206
212
  hub: networkConfig.settlementRouter,
207
213
  asset,
@@ -309,39 +315,52 @@ async function signAuthorization(wallet, settlement) {
309
315
  }
310
316
  async function settle(facilitatorUrl, signed, timeout = 3e4) {
311
317
  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
- }
318
+ const canonicalNetwork = extensions.toCanonicalNetworkKey(signed.settlement.network);
319
+ const totalAmount = (BigInt(signed.settlement.amount) + BigInt(signed.settlement.facilitatorFee)).toString();
320
+ const exactEvmPayload = {
321
+ signature: signed.signature,
322
+ authorization: {
323
+ from: signed.authorization.from,
324
+ to: signed.authorization.to,
325
+ value: signed.authorization.value,
326
+ validAfter: signed.authorization.validAfter,
327
+ validBefore: signed.authorization.validBefore,
328
+ nonce: signed.authorization.nonce
327
329
  }
328
330
  };
331
+ const paymentPayload = {
332
+ x402Version: 2,
333
+ // Use v2 protocol
334
+ resource: {
335
+ url: "https://x402x.dev/serverless",
336
+ description: "x402x Serverless Settlement",
337
+ mimeType: "application/json"
338
+ },
339
+ accepted: {
340
+ scheme: "exact",
341
+ network: canonicalNetwork,
342
+ // Type cast required: core_v2 Network type accepts both CAIP-2 and legacy formats
343
+ asset: signed.settlement.asset,
344
+ amount: totalAmount,
345
+ // Use totalAmount to match commitment calculation
346
+ payTo: signed.settlement.networkConfig.settlementRouter,
347
+ maxTimeoutSeconds: 300,
348
+ extra: {}
349
+ },
350
+ // Standard EVM exact scheme payload
351
+ payload: exactEvmPayload
352
+ // Type cast required: ExactEvmPayload structure matches v2 protocol
353
+ };
329
354
  const paymentRequirements = {
330
355
  scheme: "exact",
331
- network: signed.settlement.network,
332
- // Network type compatibility
333
- maxAmountRequired: signed.settlement.amount,
356
+ network: canonicalNetwork,
357
+ // Type cast required: core_v2 Network type accepts CAIP-2 format
358
+ amount: totalAmount,
359
+ // Total amount including facilitator fee
334
360
  asset: signed.settlement.asset,
335
361
  payTo: signed.settlement.networkConfig.settlementRouter,
336
362
  maxTimeoutSeconds: 300,
337
363
  // 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
364
  extra: {
346
365
  name: signed.settlement.networkConfig.defaultAsset.eip712.name,
347
366
  version: signed.settlement.networkConfig.defaultAsset.eip712.version,
@@ -353,8 +372,7 @@ async function settle(facilitatorUrl, signed, timeout = 3e4) {
353
372
  hookData: signed.settlement.hookData
354
373
  }
355
374
  };
356
- paymentPayload.paymentRequirements = paymentRequirements;
357
- const result = await core.settle(facilitatorUrl, paymentPayload, paymentRequirements, timeout);
375
+ const result = await extensions.settle(facilitatorUrl, paymentPayload, paymentRequirements, timeout);
358
376
  return {
359
377
  success: result.success,
360
378
  transaction: result.transaction,
@@ -374,7 +392,6 @@ async function settle(facilitatorUrl, signed, timeout = 3e4) {
374
392
  }
375
393
 
376
394
  // src/client.ts
377
- var DEFAULT_FACILITATOR_URL = "https://facilitator.x402x.dev";
378
395
  var X402Client = class {
379
396
  /**
380
397
  * Create a new X402Client instance
@@ -446,7 +463,7 @@ var X402Client = class {
446
463
  * ```
447
464
  */
448
465
  async execute(params, waitForConfirmation = false) {
449
- const hook = params.hook ? normalizeAddress(params.hook, "hook") : core.TransferHook.getAddress(this.config.network);
466
+ const hook = params.hook ? normalizeAddress(params.hook, "hook") : extensions.TransferHook.getAddress(this.config.network);
450
467
  const payTo = normalizeAddress(params.payTo, "payTo");
451
468
  const hookData = params.hookData || "0x";
452
469
  if (params.hookData) {
@@ -507,7 +524,7 @@ var X402Client = class {
507
524
  const normalizedHook = normalizeAddress(hook, "hook");
508
525
  validateHex(hookData, "hookData");
509
526
  try {
510
- return await core.calculateFacilitatorFee(
527
+ return await extensions.calculateFacilitatorFee(
511
528
  this.config.facilitatorUrl,
512
529
  this.config.network,
513
530
  normalizedHook,
@@ -586,12 +603,28 @@ var CHAIN_ID_TO_NETWORK = {
586
603
  84532: "base-sepolia",
587
604
  8453: "base",
588
605
  196: "x-layer",
589
- 1952: "x-layer-testnet"
606
+ 1952: "x-layer-testnet",
607
+ 97: "bsc-testnet",
608
+ 56: "bsc"
590
609
  };
591
610
  function useX402Client(config) {
592
- const { data: walletClient } = wagmi.useWalletClient();
593
- const { isConnected } = wagmi.useAccount();
594
- const chainId = wagmi.useChainId();
611
+ let walletClient;
612
+ let isConnected;
613
+ let chainId;
614
+ try {
615
+ const walletClientResult = wagmi.useWalletClient();
616
+ const accountResult = wagmi.useAccount();
617
+ const chainIdResult = wagmi.useChainId();
618
+ walletClient = walletClientResult.data;
619
+ isConnected = accountResult.isConnected;
620
+ chainId = chainIdResult;
621
+ } catch (error) {
622
+ if (error instanceof wagmi.WagmiProviderNotFoundError || error?.name === "WagmiProviderNotFoundError" || error instanceof Error && error.message.includes("useConfig") && error.message.includes("WagmiProvider")) {
623
+ return null;
624
+ }
625
+ console.warn("[x402x] Unable to access wagmi provider:", error);
626
+ return null;
627
+ }
595
628
  return react.useMemo(() => {
596
629
  if (!isConnected || !walletClient) {
597
630
  return null;
@@ -674,15 +707,15 @@ function useExecute(config) {
674
707
 
675
708
  Object.defineProperty(exports, "AmountError", {
676
709
  enumerable: true,
677
- get: function () { return core.AmountError; }
710
+ get: function () { return extensions.AmountError; }
678
711
  });
679
712
  Object.defineProperty(exports, "formatDefaultAssetAmount", {
680
713
  enumerable: true,
681
- get: function () { return core.formatDefaultAssetAmount; }
714
+ get: function () { return extensions.formatDefaultAssetAmount; }
682
715
  });
683
716
  Object.defineProperty(exports, "parseDefaultAssetAmount", {
684
717
  enumerable: true,
685
- get: function () { return core.parseDefaultAssetAmount; }
718
+ get: function () { return extensions.parseDefaultAssetAmount; }
686
719
  });
687
720
  exports.DEFAULT_FACILITATOR_URL = DEFAULT_FACILITATOR_URL;
688
721
  exports.FacilitatorError = FacilitatorError;