@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 +20 -20
- package/dist/index.cjs +77 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -50
- package/dist/index.d.ts +50 -50
- package/dist/index.js +70 -37
- package/dist/index.js.map +1 -1
- package/package.json +15 -16
- package/LICENSE +0 -190
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/
|
|
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/
|
|
67
|
+
npm install @x402x/client @x402x/extensions
|
|
68
68
|
# or
|
|
69
|
-
pnpm add @x402x/client @x402x/
|
|
69
|
+
pnpm add @x402x/client @x402x/extensions
|
|
70
70
|
# or
|
|
71
|
-
yarn add @x402x/client @x402x/
|
|
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/
|
|
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/
|
|
122
|
+
Use `parseDefaultAssetAmount()` from `@x402x/extensions` to convert USD amounts:
|
|
123
123
|
|
|
124
124
|
```typescript
|
|
125
|
-
import { parseDefaultAssetAmount, formatDefaultAssetAmount } from "@x402x/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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
|
|
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
|
|
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
|
|
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 ||
|
|
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
|
|
185
|
+
if (!params.facilitatorFee) {
|
|
186
|
+
const facilitatorUrl = params.facilitatorUrl || DEFAULT_FACILITATOR_URL;
|
|
181
187
|
try {
|
|
182
188
|
const feeEstimate = await queryFacilitatorFee(
|
|
183
|
-
|
|
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 =
|
|
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
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
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:
|
|
332
|
-
// Network type
|
|
333
|
-
|
|
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
|
-
|
|
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") :
|
|
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
|
|
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
|
-
|
|
593
|
-
|
|
594
|
-
|
|
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
|
|
710
|
+
get: function () { return extensions.AmountError; }
|
|
678
711
|
});
|
|
679
712
|
Object.defineProperty(exports, "formatDefaultAssetAmount", {
|
|
680
713
|
enumerable: true,
|
|
681
|
-
get: function () { return
|
|
714
|
+
get: function () { return extensions.formatDefaultAssetAmount; }
|
|
682
715
|
});
|
|
683
716
|
Object.defineProperty(exports, "parseDefaultAssetAmount", {
|
|
684
717
|
enumerable: true,
|
|
685
|
-
get: function () { return
|
|
718
|
+
get: function () { return extensions.parseDefaultAssetAmount; }
|
|
686
719
|
});
|
|
687
720
|
exports.DEFAULT_FACILITATOR_URL = DEFAULT_FACILITATOR_URL;
|
|
688
721
|
exports.FacilitatorError = FacilitatorError;
|