thirdweb 5.108.4-nightly-2c84ac408999dbff007733f76c8f0f13818258b5-20250928000351 → 5.108.5-nightly-ce9220ea00e5a58bf3f6997733b4b69df981cba8-20250930000345

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 (56) hide show
  1. package/dist/cjs/auth/verify-typed-data.js +18 -0
  2. package/dist/cjs/auth/verify-typed-data.js.map +1 -1
  3. package/dist/cjs/react/web/ui/Bridge/swap-widget/select-token-ui.js +9 -5
  4. package/dist/cjs/react/web/ui/Bridge/swap-widget/select-token-ui.js.map +1 -1
  5. package/dist/cjs/react/web/ui/Bridge/swap-widget/use-tokens.js +4 -2
  6. package/dist/cjs/react/web/ui/Bridge/swap-widget/use-tokens.js.map +1 -1
  7. package/dist/cjs/version.js +1 -1
  8. package/dist/cjs/x402/common.js +60 -4
  9. package/dist/cjs/x402/common.js.map +1 -1
  10. package/dist/cjs/x402/facilitator.js +12 -4
  11. package/dist/cjs/x402/facilitator.js.map +1 -1
  12. package/dist/cjs/x402/fetchWithPayment.js +4 -4
  13. package/dist/cjs/x402/fetchWithPayment.js.map +1 -1
  14. package/dist/cjs/x402/schemas.js +29 -1
  15. package/dist/cjs/x402/schemas.js.map +1 -1
  16. package/dist/cjs/x402/types.js.map +1 -1
  17. package/dist/esm/auth/verify-typed-data.js +18 -0
  18. package/dist/esm/auth/verify-typed-data.js.map +1 -1
  19. package/dist/esm/react/web/ui/Bridge/swap-widget/select-token-ui.js +9 -5
  20. package/dist/esm/react/web/ui/Bridge/swap-widget/select-token-ui.js.map +1 -1
  21. package/dist/esm/react/web/ui/Bridge/swap-widget/use-tokens.js +4 -2
  22. package/dist/esm/react/web/ui/Bridge/swap-widget/use-tokens.js.map +1 -1
  23. package/dist/esm/version.js +1 -1
  24. package/dist/esm/x402/common.js +60 -4
  25. package/dist/esm/x402/common.js.map +1 -1
  26. package/dist/esm/x402/facilitator.js +12 -4
  27. package/dist/esm/x402/facilitator.js.map +1 -1
  28. package/dist/esm/x402/fetchWithPayment.js +4 -4
  29. package/dist/esm/x402/fetchWithPayment.js.map +1 -1
  30. package/dist/esm/x402/schemas.js +29 -1
  31. package/dist/esm/x402/schemas.js.map +1 -1
  32. package/dist/esm/x402/types.js.map +1 -1
  33. package/dist/scripts/bridge-widget.js +84 -84
  34. package/dist/types/auth/verify-typed-data.d.ts +2 -2
  35. package/dist/types/auth/verify-typed-data.d.ts.map +1 -1
  36. package/dist/types/react/web/ui/Bridge/swap-widget/select-token-ui.d.ts.map +1 -1
  37. package/dist/types/react/web/ui/Bridge/swap-widget/use-tokens.d.ts.map +1 -1
  38. package/dist/types/version.d.ts +1 -1
  39. package/dist/types/x402/common.d.ts.map +1 -1
  40. package/dist/types/x402/facilitator.d.ts +7 -3
  41. package/dist/types/x402/facilitator.d.ts.map +1 -1
  42. package/dist/types/x402/fetchWithPayment.d.ts.map +1 -1
  43. package/dist/types/x402/schemas.d.ts +248 -0
  44. package/dist/types/x402/schemas.d.ts.map +1 -1
  45. package/dist/types/x402/types.d.ts +6 -4
  46. package/dist/types/x402/types.d.ts.map +1 -1
  47. package/package.json +1 -1
  48. package/src/auth/verify-typed-data.ts +20 -2
  49. package/src/react/web/ui/Bridge/swap-widget/select-token-ui.tsx +9 -5
  50. package/src/react/web/ui/Bridge/swap-widget/use-tokens.ts +5 -2
  51. package/src/version.ts +1 -1
  52. package/src/x402/common.ts +87 -8
  53. package/src/x402/facilitator.ts +26 -7
  54. package/src/x402/fetchWithPayment.ts +8 -4
  55. package/src/x402/schemas.ts +39 -0
  56. package/src/x402/types.ts +10 -3
@@ -8,6 +8,7 @@ import { getContract } from "../contract/contract.js";
8
8
  import { isPermitSupported } from "../extensions/erc20/__generated__/IERC20Permit/write/permit.js";
9
9
  import { isTransferWithAuthorizationSupported } from "../extensions/erc20/__generated__/USDC/write/transferWithAuthorization.js";
10
10
  import { getAddress } from "../utils/address.js";
11
+ import { toUnits } from "../utils/units.js";
11
12
  import { decodePayment } from "./encode.js";
12
13
  import type { ThirdwebX402Facilitator } from "./facilitator.js";
13
14
  import {
@@ -16,6 +17,7 @@ import {
16
17
  type RequestedPaymentRequirements,
17
18
  } from "./schemas.js";
18
19
  import {
20
+ type DefaultAsset,
19
21
  type ERC20TokenAmount,
20
22
  type PaymentArgs,
21
23
  type PaymentRequiredResult,
@@ -199,12 +201,11 @@ async function processPriceToAtomicAmount(
199
201
  chainId: number,
200
202
  facilitator: ThirdwebX402Facilitator,
201
203
  ): Promise<
202
- | { maxAmountRequired: string; asset: ERC20TokenAmount["asset"] }
203
- | { error: string }
204
+ { maxAmountRequired: string; asset: DefaultAsset } | { error: string }
204
205
  > {
205
206
  // Handle USDC amount (string) or token amount (ERC20TokenAmount)
206
207
  let maxAmountRequired: string;
207
- let asset: ERC20TokenAmount["asset"];
208
+ let asset: DefaultAsset;
208
209
 
209
210
  if (typeof price === "string" || typeof price === "number") {
210
211
  // USDC amount in dollars
@@ -222,11 +223,32 @@ async function processPriceToAtomicAmount(
222
223
  };
223
224
  }
224
225
  asset = defaultAsset;
225
- maxAmountRequired = (parsedUsdAmount * 10 ** asset.decimals).toString();
226
+ maxAmountRequired = toUnits(
227
+ parsedUsdAmount.toString(),
228
+ defaultAsset.decimals,
229
+ ).toString();
226
230
  } else {
227
231
  // Token amount in atomic units
228
232
  maxAmountRequired = price.amount;
229
- asset = price.asset;
233
+ const tokenExtras = await getOrDetectTokenExtras({
234
+ facilitator,
235
+ partialAsset: price.asset,
236
+ chainId,
237
+ });
238
+ if (!tokenExtras) {
239
+ return {
240
+ error: `Unable to find token information for ${price.asset.address} on chain ${chainId}. Please specify the asset decimals and eip712 information in the asset options.`,
241
+ };
242
+ }
243
+ asset = {
244
+ address: price.asset.address,
245
+ decimals: tokenExtras.decimals,
246
+ eip712: {
247
+ name: tokenExtras.name,
248
+ version: tokenExtras.version,
249
+ primaryType: tokenExtras.primaryType,
250
+ },
251
+ };
230
252
  }
231
253
 
232
254
  return {
@@ -238,13 +260,12 @@ async function processPriceToAtomicAmount(
238
260
  async function getDefaultAsset(
239
261
  chainId: number,
240
262
  facilitator: ThirdwebX402Facilitator,
241
- ): Promise<ERC20TokenAmount["asset"] | undefined> {
263
+ ): Promise<DefaultAsset | undefined> {
242
264
  const supportedAssets = await facilitator.supported();
243
265
  const matchingAsset = supportedAssets.kinds.find(
244
266
  (supported) => supported.network === `eip155:${chainId}`,
245
267
  );
246
- const assetConfig = matchingAsset?.extra
247
- ?.defaultAsset as ERC20TokenAmount["asset"];
268
+ const assetConfig = matchingAsset?.extra?.defaultAsset as DefaultAsset;
248
269
  return assetConfig;
249
270
  }
250
271
 
@@ -287,3 +308,61 @@ export async function getSupportedSignatureType(args: {
287
308
  }
288
309
  return undefined;
289
310
  }
311
+
312
+ async function getOrDetectTokenExtras(args: {
313
+ facilitator: ThirdwebX402Facilitator;
314
+ partialAsset: ERC20TokenAmount["asset"];
315
+ chainId: number;
316
+ }): Promise<
317
+ | {
318
+ name: string;
319
+ version: string;
320
+ decimals: number;
321
+ primaryType: SupportedSignatureType;
322
+ }
323
+ | undefined
324
+ > {
325
+ const { facilitator, partialAsset, chainId } = args;
326
+ if (
327
+ partialAsset.eip712?.name &&
328
+ partialAsset.eip712?.version &&
329
+ partialAsset.decimals !== undefined
330
+ ) {
331
+ return {
332
+ name: partialAsset.eip712.name,
333
+ version: partialAsset.eip712.version,
334
+ decimals: partialAsset.decimals,
335
+ primaryType: partialAsset.eip712.primaryType,
336
+ };
337
+ }
338
+ // read from facilitator
339
+ const response = await facilitator
340
+ .supported({
341
+ chainId,
342
+ tokenAddress: partialAsset.address,
343
+ })
344
+ .catch(() => {
345
+ return {
346
+ kinds: [],
347
+ };
348
+ });
349
+
350
+ const exactScheme = response.kinds?.find((kind) => kind.scheme === "exact");
351
+ if (!exactScheme) {
352
+ return undefined;
353
+ }
354
+ const supportedAsset = exactScheme.extra?.supportedAssets?.find(
355
+ (asset) =>
356
+ asset.address.toLowerCase() === partialAsset.address.toLowerCase(),
357
+ );
358
+ if (!supportedAsset) {
359
+ return undefined;
360
+ }
361
+
362
+ return {
363
+ name: supportedAsset.eip712.name,
364
+ version: supportedAsset.eip712.version,
365
+ decimals: supportedAsset.decimals,
366
+ primaryType: supportedAsset.eip712.primaryType as SupportedSignatureType,
367
+ };
368
+ }
@@ -1,9 +1,10 @@
1
- import type { SupportedPaymentKindsResponse, VerifyResponse } from "x402/types";
1
+ import type { VerifyResponse } from "x402/types";
2
2
  import type { ThirdwebClient } from "../client/client.js";
3
3
  import { stringify } from "../utils/json.js";
4
4
  import { withCache } from "../utils/promise/withCache.js";
5
5
  import type {
6
6
  FacilitatorSettleResponse,
7
+ FacilitatorSupportedResponse,
7
8
  RequestedPaymentPayload,
8
9
  RequestedPaymentRequirements,
9
10
  } from "./schemas.js";
@@ -11,6 +12,7 @@ import type {
11
12
  export type ThirdwebX402FacilitatorConfig = {
12
13
  client: ThirdwebClient;
13
14
  serverWalletAddress: string;
15
+ waitUtil?: "simulated" | "submitted" | "confirmed";
14
16
  vaultAccessToken?: string;
15
17
  baseUrl?: string;
16
18
  };
@@ -36,7 +38,10 @@ export type ThirdwebX402Facilitator = {
36
38
  payload: RequestedPaymentPayload,
37
39
  paymentRequirements: RequestedPaymentRequirements,
38
40
  ) => Promise<FacilitatorSettleResponse>;
39
- supported: () => Promise<SupportedPaymentKindsResponse>;
41
+ supported: (filters?: {
42
+ chainId: number;
43
+ tokenAddress?: string;
44
+ }) => Promise<FacilitatorSupportedResponse>;
40
45
  };
41
46
 
42
47
  const DEFAULT_BASE_URL = "https://api.thirdweb.com/v1/payments/x402";
@@ -176,6 +181,7 @@ export function facilitator(
176
181
  x402Version: payload.x402Version,
177
182
  paymentPayload: payload,
178
183
  paymentRequirements: paymentRequirements,
184
+ ...(config.waitUtil ? { waitUtil: config.waitUtil } : {}),
179
185
  }),
180
186
  });
181
187
 
@@ -193,14 +199,27 @@ export function facilitator(
193
199
  *
194
200
  * @returns A promise that resolves to the supported payment kinds
195
201
  */
196
- async supported(): Promise<SupportedPaymentKindsResponse> {
202
+ async supported(filters?: {
203
+ chainId: number;
204
+ tokenAddress?: string;
205
+ }): Promise<FacilitatorSupportedResponse> {
197
206
  const url = config.baseUrl ?? DEFAULT_BASE_URL;
198
207
  return withCache(
199
208
  async () => {
200
209
  let headers = { "Content-Type": "application/json" };
201
210
  const authHeaders = await facilitator.createAuthHeaders();
202
211
  headers = { ...headers, ...authHeaders.supported };
203
- const res = await fetch(`${url}/supported`, { headers });
212
+ const supportedUrl = new URL(`${url}/supported`);
213
+ if (filters?.chainId) {
214
+ supportedUrl.searchParams.set(
215
+ "chainId",
216
+ filters.chainId.toString(),
217
+ );
218
+ }
219
+ if (filters?.tokenAddress) {
220
+ supportedUrl.searchParams.set("tokenAddress", filters.tokenAddress);
221
+ }
222
+ const res = await fetch(supportedUrl.toString(), { headers });
204
223
 
205
224
  if (res.status !== 200) {
206
225
  throw new Error(
@@ -209,11 +228,11 @@ export function facilitator(
209
228
  }
210
229
 
211
230
  const data = await res.json();
212
- return data as SupportedPaymentKindsResponse;
231
+ return data as FacilitatorSupportedResponse;
213
232
  },
214
233
  {
215
- cacheKey: `supported-payment-kinds-${url}`,
216
- cacheTime: 1000 * 60 * 60 * 24, // 24 hours
234
+ cacheKey: `supported-payment-kinds-${url}-${filters?.chainId}-${filters?.tokenAddress}2`,
235
+ cacheTime: 1000 * 60 * 60 * 1, // 1 hour
217
236
  },
218
237
  );
219
238
  },
@@ -61,9 +61,10 @@ export function wrapFetchWithPayment(
61
61
  return response;
62
62
  }
63
63
 
64
- const { x402Version, accepts } = (await response.json()) as {
64
+ const { x402Version, accepts, error } = (await response.json()) as {
65
65
  x402Version: number;
66
66
  accepts: unknown[];
67
+ error?: string;
67
68
  };
68
69
  const parsedPaymentRequirements = accepts
69
70
  .map((x) => RequestedPaymentRequirementsSchema.parse(x))
@@ -83,6 +84,12 @@ export function wrapFetchWithPayment(
83
84
  "exact",
84
85
  );
85
86
 
87
+ if (!selectedPaymentRequirements) {
88
+ throw new Error(
89
+ `No suitable payment requirements found for chain ${chain.id}. ${error}`,
90
+ );
91
+ }
92
+
86
93
  if (BigInt(selectedPaymentRequirements.maxAmountRequired) > maxValue) {
87
94
  throw new Error(
88
95
  `Payment amount exceeds maximum allowed (currently set to ${maxValue} in base units)`,
@@ -154,9 +161,6 @@ function defaultPaymentRequirementsSelector(
154
161
  const firstPaymentRequirement = paymentRequirements.find(
155
162
  (x) => x.scheme === scheme,
156
163
  );
157
- if (!firstPaymentRequirement) {
158
- throw new Error("No suitable payment requirements found");
159
- }
160
164
  return firstPaymentRequirement;
161
165
  }
162
166
  }
@@ -5,6 +5,7 @@ import {
5
5
  PaymentPayloadSchema,
6
6
  PaymentRequirementsSchema,
7
7
  SettleResponseSchema,
8
+ SupportedPaymentKindsResponseSchema,
8
9
  } from "x402/types";
9
10
  import { z } from "zod";
10
11
  import type { Chain } from "../chains/types.js";
@@ -56,6 +57,44 @@ export type FacilitatorSettleResponse = z.infer<
56
57
  typeof FacilitatorSettleResponseSchema
57
58
  >;
58
59
 
60
+ export const SupportedSignatureTypeSchema = z.enum([
61
+ "TransferWithAuthorization",
62
+ "Permit",
63
+ ]);
64
+
65
+ export const FacilitatorSupportedAssetSchema = z.object({
66
+ address: z.string(),
67
+ decimals: z.number(),
68
+ eip712: z.object({
69
+ name: z.string(),
70
+ version: z.string(),
71
+ primaryType: SupportedSignatureTypeSchema,
72
+ }),
73
+ });
74
+
75
+ const FacilitatorSupportedResponseSchema =
76
+ SupportedPaymentKindsResponseSchema.extend({
77
+ kinds: z.array(
78
+ z.object({
79
+ x402Version: z.literal(1),
80
+ scheme: z.literal("exact"),
81
+ network: FacilitatorNetworkSchema,
82
+ extra: z
83
+ .object({
84
+ defaultAsset: FacilitatorSupportedAssetSchema.optional(),
85
+ supportedAssets: z
86
+ .array(FacilitatorSupportedAssetSchema)
87
+ .optional(),
88
+ })
89
+ .optional(),
90
+ }),
91
+ ),
92
+ }).describe("Supported payment kinds for this facilitator");
93
+
94
+ export type FacilitatorSupportedResponse = z.infer<
95
+ typeof FacilitatorSupportedResponseSchema
96
+ >;
97
+
59
98
  export function networkToChainId(network: string | Chain): number {
60
99
  if (typeof network === "object") {
61
100
  return network.id;
package/src/x402/types.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { Money, PaymentMiddlewareConfig } from "x402/types";
2
+ import type z from "zod";
2
3
  import type { Chain } from "../chains/types.js";
3
4
  import type { Address } from "../utils/address.js";
4
5
  import type { Prettify } from "../utils/type-utils.js";
@@ -6,8 +7,10 @@ import type { ThirdwebX402Facilitator } from "./facilitator.js";
6
7
  import type {
7
8
  FacilitatorNetwork,
8
9
  FacilitatorSettleResponse,
10
+ FacilitatorSupportedAssetSchema,
9
11
  RequestedPaymentPayload,
10
12
  RequestedPaymentRequirements,
13
+ SupportedSignatureTypeSchema,
11
14
  } from "./schemas.js";
12
15
 
13
16
  export const x402Version = 1;
@@ -86,17 +89,21 @@ export type VerifyPaymentResult = Prettify<
86
89
  | PaymentRequiredResult
87
90
  >;
88
91
 
89
- export type SupportedSignatureType = "TransferWithAuthorization" | "Permit";
92
+ export type SupportedSignatureType = z.infer<
93
+ typeof SupportedSignatureTypeSchema
94
+ >;
90
95
 
91
96
  export type ERC20TokenAmount = {
92
97
  amount: string;
93
98
  asset: {
94
99
  address: `0x${string}`;
95
- decimals: number;
96
- eip712: {
100
+ decimals?: number;
101
+ eip712?: {
97
102
  name: string;
98
103
  version: string;
99
104
  primaryType: SupportedSignatureType;
100
105
  };
101
106
  };
102
107
  };
108
+
109
+ export type DefaultAsset = z.infer<typeof FacilitatorSupportedAssetSchema>;