thirdweb 5.107.1 → 5.108.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.
Files changed (96) hide show
  1. package/dist/cjs/exports/x402.js +8 -1
  2. package/dist/cjs/exports/x402.js.map +1 -1
  3. package/dist/cjs/react/core/utils/defaultTokens.js +2 -8
  4. package/dist/cjs/react/core/utils/defaultTokens.js.map +1 -1
  5. package/dist/cjs/react/web/ui/Bridge/BridgeOrchestrator.js +18 -14
  6. package/dist/cjs/react/web/ui/Bridge/BridgeOrchestrator.js.map +1 -1
  7. package/dist/cjs/react/web/ui/Bridge/BuyWidget.js +15 -6
  8. package/dist/cjs/react/web/ui/Bridge/BuyWidget.js.map +1 -1
  9. package/dist/cjs/version.js +1 -1
  10. package/dist/cjs/x402/common.js +173 -0
  11. package/dist/cjs/x402/common.js.map +1 -0
  12. package/dist/cjs/x402/encode.js +71 -0
  13. package/dist/cjs/x402/encode.js.map +1 -0
  14. package/dist/cjs/x402/facilitator.js +83 -2
  15. package/dist/cjs/x402/facilitator.js.map +1 -1
  16. package/dist/cjs/x402/fetchWithPayment.js +7 -15
  17. package/dist/cjs/x402/fetchWithPayment.js.map +1 -1
  18. package/dist/cjs/x402/schemas.js +50 -0
  19. package/dist/cjs/x402/schemas.js.map +1 -0
  20. package/dist/cjs/x402/settle-payment.js +174 -0
  21. package/dist/cjs/x402/settle-payment.js.map +1 -0
  22. package/dist/cjs/x402/sign.js +148 -0
  23. package/dist/cjs/x402/sign.js.map +1 -0
  24. package/dist/cjs/x402/types.js +5 -0
  25. package/dist/cjs/x402/types.js.map +1 -0
  26. package/dist/cjs/x402/verify-payment.js +121 -0
  27. package/dist/cjs/x402/verify-payment.js.map +1 -0
  28. package/dist/esm/exports/x402.js +3 -0
  29. package/dist/esm/exports/x402.js.map +1 -1
  30. package/dist/esm/react/core/utils/defaultTokens.js +2 -8
  31. package/dist/esm/react/core/utils/defaultTokens.js.map +1 -1
  32. package/dist/esm/react/web/ui/Bridge/BridgeOrchestrator.js +18 -14
  33. package/dist/esm/react/web/ui/Bridge/BridgeOrchestrator.js.map +1 -1
  34. package/dist/esm/react/web/ui/Bridge/BuyWidget.js +15 -6
  35. package/dist/esm/react/web/ui/Bridge/BuyWidget.js.map +1 -1
  36. package/dist/esm/version.js +1 -1
  37. package/dist/esm/x402/common.js +170 -0
  38. package/dist/esm/x402/common.js.map +1 -0
  39. package/dist/esm/x402/encode.js +66 -0
  40. package/dist/esm/x402/encode.js.map +1 -0
  41. package/dist/esm/x402/facilitator.js +83 -2
  42. package/dist/esm/x402/facilitator.js.map +1 -1
  43. package/dist/esm/x402/fetchWithPayment.js +8 -16
  44. package/dist/esm/x402/fetchWithPayment.js.map +1 -1
  45. package/dist/esm/x402/schemas.js +46 -0
  46. package/dist/esm/x402/schemas.js.map +1 -0
  47. package/dist/esm/x402/settle-payment.js +171 -0
  48. package/dist/esm/x402/settle-payment.js.map +1 -0
  49. package/dist/esm/x402/sign.js +145 -0
  50. package/dist/esm/x402/sign.js.map +1 -0
  51. package/dist/esm/x402/types.js +2 -0
  52. package/dist/esm/x402/types.js.map +1 -0
  53. package/dist/esm/x402/verify-payment.js +118 -0
  54. package/dist/esm/x402/verify-payment.js.map +1 -0
  55. package/dist/types/exports/x402.d.ts +4 -0
  56. package/dist/types/exports/x402.d.ts.map +1 -1
  57. package/dist/types/react/core/utils/defaultTokens.d.ts +2 -7
  58. package/dist/types/react/core/utils/defaultTokens.d.ts.map +1 -1
  59. package/dist/types/react/web/ui/Bridge/BridgeOrchestrator.d.ts +4 -3
  60. package/dist/types/react/web/ui/Bridge/BridgeOrchestrator.d.ts.map +1 -1
  61. package/dist/types/react/web/ui/Bridge/BuyWidget.d.ts +7 -3
  62. package/dist/types/react/web/ui/Bridge/BuyWidget.d.ts.map +1 -1
  63. package/dist/types/version.d.ts +1 -1
  64. package/dist/types/x402/common.d.ts +16 -0
  65. package/dist/types/x402/common.d.ts.map +1 -0
  66. package/dist/types/x402/encode.d.ts +23 -0
  67. package/dist/types/x402/encode.d.ts.map +1 -0
  68. package/dist/types/x402/facilitator.d.ts +44 -3
  69. package/dist/types/x402/facilitator.d.ts.map +1 -1
  70. package/dist/types/x402/fetchWithPayment.d.ts +1 -1
  71. package/dist/types/x402/fetchWithPayment.d.ts.map +1 -1
  72. package/dist/types/x402/schemas.d.ts +164 -0
  73. package/dist/types/x402/schemas.d.ts.map +1 -0
  74. package/dist/types/x402/settle-payment.d.ts +117 -0
  75. package/dist/types/x402/settle-payment.d.ts.map +1 -0
  76. package/dist/types/x402/sign.d.ts +12 -0
  77. package/dist/types/x402/sign.d.ts.map +1 -0
  78. package/dist/types/x402/types.d.ts +71 -0
  79. package/dist/types/x402/types.d.ts.map +1 -0
  80. package/dist/types/x402/verify-payment.d.ts +69 -0
  81. package/dist/types/x402/verify-payment.d.ts.map +1 -0
  82. package/package.json +1 -1
  83. package/src/exports/x402.ts +8 -0
  84. package/src/react/core/utils/defaultTokens.ts +2 -8
  85. package/src/react/web/ui/Bridge/BridgeOrchestrator.tsx +42 -31
  86. package/src/react/web/ui/Bridge/BuyWidget.tsx +24 -9
  87. package/src/version.ts +1 -1
  88. package/src/x402/common.ts +242 -0
  89. package/src/x402/encode.ts +81 -0
  90. package/src/x402/facilitator.ts +114 -6
  91. package/src/x402/fetchWithPayment.ts +13 -27
  92. package/src/x402/schemas.ts +76 -0
  93. package/src/x402/settle-payment.ts +186 -0
  94. package/src/x402/sign.ts +206 -0
  95. package/src/x402/types.ts +90 -0
  96. package/src/x402/verify-payment.ts +133 -0
@@ -0,0 +1,206 @@
1
+ import type { ExactEvmPayloadAuthorization } from "x402/types";
2
+ import { type Address, getAddress } from "../utils/address.js";
3
+ import { type Hex, toHex } from "../utils/encoding/hex.js";
4
+ import type { Account } from "../wallets/interfaces/wallet.js";
5
+ import { encodePayment } from "./encode.js";
6
+ import {
7
+ networkToChainId,
8
+ type RequestedPaymentPayload,
9
+ type RequestedPaymentRequirements,
10
+ type UnsignedPaymentPayload,
11
+ } from "./schemas.js";
12
+
13
+ /**
14
+ * Prepares an unsigned payment header with the given sender address and payment requirements.
15
+ *
16
+ * @param from - The sender's address from which the payment will be made
17
+ * @param x402Version - The version of the X402 protocol to use
18
+ * @param paymentRequirements - The payment requirements containing scheme and network information
19
+ * @returns An unsigned payment payload containing authorization details
20
+ */
21
+ function preparePaymentHeader(
22
+ from: Address,
23
+ x402Version: number,
24
+ paymentRequirements: RequestedPaymentRequirements,
25
+ ): UnsignedPaymentPayload {
26
+ const nonce = createNonce();
27
+
28
+ const validAfter = BigInt(
29
+ Math.floor(Date.now() / 1000) - 600, // 10 minutes before
30
+ ).toString();
31
+ const validBefore = BigInt(
32
+ Math.floor(Date.now() / 1000 + paymentRequirements.maxTimeoutSeconds),
33
+ ).toString();
34
+
35
+ return {
36
+ x402Version,
37
+ scheme: paymentRequirements.scheme,
38
+ network: paymentRequirements.network,
39
+ payload: {
40
+ signature: undefined,
41
+ authorization: {
42
+ from,
43
+ to: paymentRequirements.payTo as Address,
44
+ value: paymentRequirements.maxAmountRequired,
45
+ validAfter: validAfter.toString(),
46
+ validBefore: validBefore.toString(),
47
+ nonce,
48
+ },
49
+ },
50
+ };
51
+ }
52
+
53
+ /**
54
+ * Signs a payment header using the provided client and payment requirements.
55
+ *
56
+ * @param client - The signer wallet instance used to sign the payment header
57
+ * @param paymentRequirements - The payment requirements containing scheme and network information
58
+ * @param unsignedPaymentHeader - The unsigned payment payload to be signed
59
+ * @returns A promise that resolves to the signed payment payload
60
+ */
61
+ async function signPaymentHeader(
62
+ account: Account,
63
+ paymentRequirements: RequestedPaymentRequirements,
64
+ unsignedPaymentHeader: UnsignedPaymentPayload,
65
+ ): Promise<RequestedPaymentPayload> {
66
+ const { signature } = await signAuthorization(
67
+ account,
68
+ unsignedPaymentHeader.payload.authorization,
69
+ paymentRequirements,
70
+ );
71
+
72
+ return {
73
+ ...unsignedPaymentHeader,
74
+ payload: {
75
+ ...unsignedPaymentHeader.payload,
76
+ signature,
77
+ },
78
+ };
79
+ }
80
+
81
+ /**
82
+ * Creates a complete payment payload by preparing and signing a payment header.
83
+ *
84
+ * @param client - The signer wallet instance used to create and sign the payment
85
+ * @param x402Version - The version of the X402 protocol to use
86
+ * @param paymentRequirements - The payment requirements containing scheme and network information
87
+ * @returns A promise that resolves to the complete signed payment payload
88
+ */
89
+ async function createPayment(
90
+ account: Account,
91
+ x402Version: number,
92
+ paymentRequirements: RequestedPaymentRequirements,
93
+ ): Promise<RequestedPaymentPayload> {
94
+ const from = getAddress(account.address);
95
+ const unsignedPaymentHeader = preparePaymentHeader(
96
+ from,
97
+ x402Version,
98
+ paymentRequirements,
99
+ );
100
+ return signPaymentHeader(account, paymentRequirements, unsignedPaymentHeader);
101
+ }
102
+
103
+ /**
104
+ * Creates and encodes a payment header for the given client and payment requirements.
105
+ *
106
+ * @param client - The signer wallet instance used to create the payment header
107
+ * @param x402Version - The version of the X402 protocol to use
108
+ * @param paymentRequirements - The payment requirements containing scheme and network information
109
+ * @returns A promise that resolves to the encoded payment header string
110
+ */
111
+ export async function createPaymentHeader(
112
+ account: Account,
113
+ x402Version: number,
114
+ paymentRequirements: RequestedPaymentRequirements,
115
+ ): Promise<string> {
116
+ const payment = await createPayment(
117
+ account,
118
+ x402Version,
119
+ paymentRequirements,
120
+ );
121
+ return encodePayment(payment);
122
+ }
123
+
124
+ /**
125
+ * Signs an EIP-3009 authorization for USDC transfer
126
+ *
127
+ * @param walletClient - The wallet client that will sign the authorization
128
+ * @param params - The authorization parameters containing transfer details
129
+ * @param params.from - The address tokens will be transferred from
130
+ * @param params.to - The address tokens will be transferred to
131
+ * @param params.value - The amount of USDC tokens to transfer (in base units)
132
+ * @param params.validAfter - Unix timestamp after which the authorization becomes valid
133
+ * @param params.validBefore - Unix timestamp before which the authorization is valid
134
+ * @param params.nonce - Random 32-byte nonce to prevent replay attacks
135
+ * @param paymentRequirements - The payment requirements containing asset and network information
136
+ * @param paymentRequirements.asset - The address of the USDC contract
137
+ * @param paymentRequirements.network - The network where the USDC contract exists
138
+ * @param paymentRequirements.extra - The extra information containing the name and version of the ERC20 contract
139
+ * @returns The signature for the authorization
140
+ */
141
+ async function signAuthorization(
142
+ account: Account,
143
+ {
144
+ from,
145
+ to,
146
+ value,
147
+ validAfter,
148
+ validBefore,
149
+ nonce,
150
+ }: ExactEvmPayloadAuthorization,
151
+ { asset, network, extra }: RequestedPaymentRequirements,
152
+ ): Promise<{ signature: Hex }> {
153
+ const chainId = networkToChainId(network);
154
+ const name = extra?.name;
155
+ const version = extra?.version;
156
+
157
+ // TODO (402): detect permit vs transfer on asset contract
158
+ const data = {
159
+ types: {
160
+ TransferWithAuthorization: [
161
+ { name: "from", type: "address" },
162
+ { name: "to", type: "address" },
163
+ { name: "value", type: "uint256" },
164
+ { name: "validAfter", type: "uint256" },
165
+ { name: "validBefore", type: "uint256" },
166
+ { name: "nonce", type: "bytes32" },
167
+ ],
168
+ },
169
+ domain: {
170
+ name,
171
+ version,
172
+ chainId,
173
+ verifyingContract: getAddress(asset),
174
+ },
175
+ primaryType: "TransferWithAuthorization" as const,
176
+ message: {
177
+ from: getAddress(from),
178
+ to: getAddress(to),
179
+ value,
180
+ validAfter,
181
+ validBefore,
182
+ nonce: nonce,
183
+ },
184
+ };
185
+
186
+ const signature = await account.signTypedData(data);
187
+ return {
188
+ signature,
189
+ };
190
+ }
191
+
192
+ /**
193
+ * Generates a random 32-byte nonce for use in authorization signatures
194
+ *
195
+ * @returns A random 32-byte nonce as a hex string
196
+ */
197
+ function createNonce(): Hex {
198
+ const cryptoObj =
199
+ typeof globalThis.crypto !== "undefined" &&
200
+ typeof globalThis.crypto.getRandomValues === "function"
201
+ ? globalThis.crypto
202
+ : // Dynamic require is needed to support node.js
203
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
204
+ require("crypto").webcrypto;
205
+ return toHex(cryptoObj.getRandomValues(new Uint8Array(32)));
206
+ }
@@ -0,0 +1,90 @@
1
+ import type {
2
+ ERC20TokenAmount,
3
+ Money,
4
+ PaymentMiddlewareConfig,
5
+ } from "x402/types";
6
+ import type { Address } from "../utils/address.js";
7
+ import type { Prettify } from "../utils/type-utils.js";
8
+ import type { facilitator as facilitatorType } from "./facilitator.js";
9
+ import type {
10
+ FacilitatorNetwork,
11
+ FacilitatorSettleResponse,
12
+ RequestedPaymentPayload,
13
+ RequestedPaymentRequirements,
14
+ } from "./schemas.js";
15
+
16
+ export const x402Version = 1;
17
+
18
+ /**
19
+ * Configuration object for verifying or processing X402 payments.
20
+ *
21
+ * @public
22
+ */
23
+ export type PaymentArgs = {
24
+ /** The URL of the resource being protected by the payment */
25
+ resourceUrl: string;
26
+ /** The HTTP method used to access the resource */
27
+ method: "GET" | "POST" | ({} & string);
28
+ /** The payment data/proof provided by the client, typically from the X-PAYMENT header */
29
+ paymentData?: string | null;
30
+ /** The wallet address that should receive the payment */
31
+ payTo: Address;
32
+ /** The blockchain network where the payment should be processed */
33
+ network: FacilitatorNetwork;
34
+ /** The price for accessing the resource - either a USD amount (e.g., "$0.10") or a specific token amount */
35
+ price: Money | ERC20TokenAmount;
36
+ /** The payment facilitator instance used to verify and settle payments */
37
+ facilitator: ReturnType<typeof facilitatorType>;
38
+ /** Optional configuration for the payment middleware route */
39
+ routeConfig?: PaymentMiddlewareConfig;
40
+ };
41
+
42
+ export type PaymentRequiredResult = {
43
+ /** HTTP 402 - Payment Required, verification or processing failed or payment missing */
44
+ status: 402;
45
+ /** The error response body containing payment requirements */
46
+ responseBody: {
47
+ /** The X402 protocol version */
48
+ x402Version: number;
49
+ /** Human-readable error message */
50
+ error: string;
51
+ /** Array of acceptable payment methods and requirements */
52
+ accepts: RequestedPaymentRequirements[];
53
+ /** Optional payer address if verification partially succeeded */
54
+ payer?: string;
55
+ };
56
+ /** Response headers for the error response */
57
+ responseHeaders: Record<string, string>;
58
+ };
59
+
60
+ /**
61
+ * The result of a payment settlement operation.
62
+ *
63
+ * @public
64
+ */
65
+ export type SettlePaymentResult = Prettify<
66
+ | {
67
+ /** HTTP 200 - Payment was successfully processed */
68
+ status: 200;
69
+ /** Response headers including payment receipt information */
70
+ responseHeaders: Record<string, string>;
71
+ /** The payment receipt from the payment facilitator */
72
+ paymentReceipt: FacilitatorSettleResponse;
73
+ }
74
+ | PaymentRequiredResult
75
+ >;
76
+
77
+ /**
78
+ * The result of a payment verification operation.
79
+ *
80
+ * @public
81
+ */
82
+ export type VerifyPaymentResult = Prettify<
83
+ | {
84
+ /** HTTP 200 - Payment was successfully verified */
85
+ status: 200;
86
+ decodedPayment: RequestedPaymentPayload;
87
+ selectedPaymentRequirements: RequestedPaymentRequirements;
88
+ }
89
+ | PaymentRequiredResult
90
+ >;
@@ -0,0 +1,133 @@
1
+ import { decodePaymentRequest } from "./common.js";
2
+ import {
3
+ type PaymentArgs,
4
+ type VerifyPaymentResult,
5
+ x402Version,
6
+ } from "./types.js";
7
+
8
+ /**
9
+ * Verifies X402 payments for protected resources. This function only verifies the payment,
10
+ * you should use `settlePayment` to settle the payment.
11
+ *
12
+ * @param args - Configuration object containing payment verification parameters
13
+ * @returns A promise that resolves to either a successful verification result (200) or payment required error (402)
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * // Usage in a Next.js API route
18
+ * import { verifyPayment, facilitator } from "thirdweb/x402";
19
+ * import { createThirdwebClient } from "thirdweb";
20
+ *
21
+ * const client = createThirdwebClient({
22
+ * secretKey: process.env.THIRDWEB_SECRET_KEY,
23
+ * });
24
+ *
25
+ * const thirdwebFacilitator = facilitator({
26
+ * client,
27
+ * serverWalletAddress: "0x1234567890123456789012345678901234567890",
28
+ * });
29
+ *
30
+ * export async function GET(request: Request) {
31
+ * const paymentData = request.headers.get("x-payment");
32
+ *
33
+ * const paymentArgs = {
34
+ * resourceUrl: "https://api.example.com/premium-content",
35
+ * method: "GET",
36
+ * paymentData,
37
+ * payTo: "0x1234567890123456789012345678901234567890",
38
+ * network: "eip155:84532", // CAIP2 format: "eip155:<chain_id>"
39
+ * price: "$0.10", // or { amount: "100000", asset: { address: "0x...", decimals: 6 } }
40
+ * facilitator: thirdwebFacilitator,
41
+ * routeConfig: {
42
+ * description: "Access to premium API content",
43
+ * mimeType: "application/json",
44
+ * maxTimeoutSeconds: 300,
45
+ * },
46
+ * };
47
+ *
48
+ * // verify the payment
49
+ * const result = await verifyPayment(paymentArgs);
50
+ *
51
+ * if (result.status === 200) {
52
+ * // Payment verified, but not settled yet
53
+ * // you can do the work that requires payment first
54
+ * const result = await doSomething();
55
+ * // then settle the payment
56
+ * const settleResult = await settlePayment(paymentArgs);
57
+ *
58
+ * // then return the result
59
+ * return Response.json(result);
60
+ * } else {
61
+ * // verification failed, return payment required
62
+ * return Response.json(result.responseBody, {
63
+ * status: result.status,
64
+ * headers: result.responseHeaders,
65
+ * });
66
+ * }
67
+ * }
68
+ * ```
69
+ *
70
+ * @public
71
+ * @beta
72
+ * @bridge x402
73
+ */
74
+ export async function verifyPayment(
75
+ args: PaymentArgs,
76
+ ): Promise<VerifyPaymentResult> {
77
+ const { routeConfig = {}, facilitator } = args;
78
+ const { errorMessages } = routeConfig;
79
+
80
+ const decodePaymentResult = await decodePaymentRequest(args);
81
+
82
+ if (decodePaymentResult.status !== 200) {
83
+ return decodePaymentResult;
84
+ }
85
+
86
+ const { selectedPaymentRequirements, decodedPayment, paymentRequirements } =
87
+ decodePaymentResult;
88
+
89
+ // Verify payment
90
+ try {
91
+ const verification = await facilitator.verify(
92
+ decodedPayment,
93
+ selectedPaymentRequirements,
94
+ );
95
+
96
+ if (verification.isValid) {
97
+ return {
98
+ status: 200,
99
+ decodedPayment,
100
+ selectedPaymentRequirements,
101
+ };
102
+ } else {
103
+ return {
104
+ status: 402,
105
+ responseHeaders: {
106
+ "Content-Type": "application/json",
107
+ },
108
+ responseBody: {
109
+ x402Version,
110
+ error:
111
+ errorMessages?.verificationFailed ||
112
+ verification.invalidReason ||
113
+ "Verification failed",
114
+ accepts: paymentRequirements,
115
+ },
116
+ };
117
+ }
118
+ } catch (error) {
119
+ return {
120
+ status: 402,
121
+ responseHeaders: {
122
+ "Content-Type": "application/json",
123
+ },
124
+ responseBody: {
125
+ x402Version,
126
+ error:
127
+ errorMessages?.verificationFailed ||
128
+ (error instanceof Error ? error.message : "Verification error"),
129
+ accepts: paymentRequirements,
130
+ },
131
+ };
132
+ }
133
+ }