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
@@ -1,5 +1,12 @@
1
- import type { FacilitatorConfig } from "x402/types";
1
+ import type { SupportedPaymentKindsResponse, VerifyResponse } from "x402/types";
2
2
  import type { ThirdwebClient } from "../client/client.js";
3
+ import { stringify } from "../utils/json.js";
4
+ import { withCache } from "../utils/promise/withCache.js";
5
+ import type {
6
+ FacilitatorSettleResponse,
7
+ RequestedPaymentPayload,
8
+ RequestedPaymentRequirements,
9
+ } from "./schemas.js";
3
10
 
4
11
  export type ThirdwebX402FacilitatorConfig = {
5
12
  client: ThirdwebClient;
@@ -12,7 +19,7 @@ const DEFAULT_BASE_URL = "https://api.thirdweb.com/v1/payments/x402";
12
19
 
13
20
  /**
14
21
  * Creates a facilitator for the x402 payment protocol.
15
- * Use this with any x402 middleware to enable settling transactions with your thirdweb server wallet.
22
+ * You can use this with `settlePayment` or with any x402 middleware to enable settling transactions with your thirdweb server wallet.
16
23
  *
17
24
  * @param config - The configuration for the facilitator
18
25
  * @returns a x402 compatible FacilitatorConfig
@@ -48,9 +55,7 @@ const DEFAULT_BASE_URL = "https://api.thirdweb.com/v1/payments/x402";
48
55
  *
49
56
  * @bridge x402
50
57
  */
51
- export function facilitator(
52
- config: ThirdwebX402FacilitatorConfig,
53
- ): FacilitatorConfig {
58
+ export function facilitator(config: ThirdwebX402FacilitatorConfig) {
54
59
  const secretKey = config.client.secretKey;
55
60
  if (!secretKey) {
56
61
  throw new Error("Client secret key is required for the x402 facilitator");
@@ -61,7 +66,7 @@ export function facilitator(
61
66
  "Server wallet address is required for the x402 facilitator",
62
67
  );
63
68
  }
64
- return {
69
+ const facilitator = {
65
70
  url: (config.baseUrl ?? DEFAULT_BASE_URL) as `${string}://${string}`,
66
71
  createAuthHeaders: async () => {
67
72
  return {
@@ -83,5 +88,108 @@ export function facilitator(
83
88
  },
84
89
  };
85
90
  },
91
+ /**
92
+ * Verifies a payment payload with the facilitator service
93
+ *
94
+ * @param payload - The payment payload to verify
95
+ * @param paymentRequirements - The payment requirements to verify against
96
+ * @returns A promise that resolves to the verification response
97
+ */
98
+ async verify(
99
+ payload: RequestedPaymentPayload,
100
+ paymentRequirements: RequestedPaymentRequirements,
101
+ ): Promise<VerifyResponse> {
102
+ const url = config.baseUrl ?? DEFAULT_BASE_URL;
103
+
104
+ let headers = { "Content-Type": "application/json" };
105
+ const authHeaders = await facilitator.createAuthHeaders();
106
+ headers = { ...headers, ...authHeaders.verify };
107
+
108
+ const res = await fetch(`${url}/verify`, {
109
+ method: "POST",
110
+ headers,
111
+ body: stringify({
112
+ x402Version: payload.x402Version,
113
+ paymentPayload: payload,
114
+ paymentRequirements: paymentRequirements,
115
+ }),
116
+ });
117
+
118
+ if (res.status !== 200) {
119
+ const text = `${res.statusText} ${await res.text()}`;
120
+ throw new Error(`Failed to verify payment: ${res.status} ${text}`);
121
+ }
122
+
123
+ const data = await res.json();
124
+ return data as VerifyResponse;
125
+ },
126
+
127
+ /**
128
+ * Settles a payment with the facilitator service
129
+ *
130
+ * @param payload - The payment payload to settle
131
+ * @param paymentRequirements - The payment requirements for the settlement
132
+ * @returns A promise that resolves to the settlement response
133
+ */
134
+ async settle(
135
+ payload: RequestedPaymentPayload,
136
+ paymentRequirements: RequestedPaymentRequirements,
137
+ ): Promise<FacilitatorSettleResponse> {
138
+ const url = config.baseUrl ?? DEFAULT_BASE_URL;
139
+
140
+ let headers = { "Content-Type": "application/json" };
141
+ const authHeaders = await facilitator.createAuthHeaders();
142
+ headers = { ...headers, ...authHeaders.settle };
143
+
144
+ const res = await fetch(`${url}/settle`, {
145
+ method: "POST",
146
+ headers,
147
+ body: JSON.stringify({
148
+ x402Version: payload.x402Version,
149
+ paymentPayload: payload,
150
+ paymentRequirements: paymentRequirements,
151
+ }),
152
+ });
153
+
154
+ if (res.status !== 200) {
155
+ const text = `${res.statusText} ${await res.text()}`;
156
+ throw new Error(`Failed to settle payment: ${res.status} ${text}`);
157
+ }
158
+
159
+ const data = await res.json();
160
+ return data as FacilitatorSettleResponse;
161
+ },
162
+
163
+ /**
164
+ * Gets the supported payment kinds from the facilitator service.
165
+ *
166
+ * @returns A promise that resolves to the supported payment kinds
167
+ */
168
+ async supported(): Promise<SupportedPaymentKindsResponse> {
169
+ const url = config.baseUrl ?? DEFAULT_BASE_URL;
170
+ return withCache(
171
+ async () => {
172
+ let headers = { "Content-Type": "application/json" };
173
+ const authHeaders = await facilitator.createAuthHeaders();
174
+ headers = { ...headers, ...authHeaders.supported };
175
+ const res = await fetch(`${url}/supported`, { headers });
176
+
177
+ if (res.status !== 200) {
178
+ throw new Error(
179
+ `Failed to get supported payment kinds: ${res.statusText}`,
180
+ );
181
+ }
182
+
183
+ const data = await res.json();
184
+ return data as SupportedPaymentKindsResponse;
185
+ },
186
+ {
187
+ cacheKey: `supported-payment-kinds-${url}`,
188
+ cacheTime: 1000 * 60 * 60 * 24, // 24 hours
189
+ },
190
+ );
191
+ },
86
192
  };
193
+
194
+ return facilitator;
87
195
  }
@@ -1,15 +1,13 @@
1
- import { createPaymentHeader } from "x402/client";
2
- import {
3
- ChainIdToNetwork,
4
- EvmNetworkToChainId,
5
- type PaymentRequirements,
6
- PaymentRequirementsSchema,
7
- type Signer,
8
- } from "x402/types";
9
- import { viemAdapter } from "../adapters/viem.js";
1
+ import { ChainIdToNetwork } from "x402/types";
10
2
  import { getCachedChain } from "../chains/utils.js";
11
3
  import type { ThirdwebClient } from "../client/client.js";
12
4
  import type { Wallet } from "../wallets/interfaces/wallet.js";
5
+ import {
6
+ networkToChainId,
7
+ type RequestedPaymentRequirements,
8
+ RequestedPaymentRequirementsSchema,
9
+ } from "./schemas.js";
10
+ import { createPaymentHeader } from "./sign.js";
13
11
 
14
12
  /**
15
13
  * Enables the payment of APIs using the x402 payment protocol.
@@ -52,7 +50,7 @@ import type { Wallet } from "../wallets/interfaces/wallet.js";
52
50
  */
53
51
  export function wrapFetchWithPayment(
54
52
  fetch: typeof globalThis.fetch,
55
- client: ThirdwebClient,
53
+ _client: ThirdwebClient,
56
54
  wallet: Wallet,
57
55
  maxValue: bigint = BigInt(1 * 10 ** 6), // Default to 1 USDC
58
56
  ) {
@@ -68,7 +66,7 @@ export function wrapFetchWithPayment(
68
66
  accepts: unknown[];
69
67
  };
70
68
  const parsedPaymentRequirements = accepts
71
- .map((x) => PaymentRequirementsSchema.parse(x))
69
+ .map((x) => RequestedPaymentRequirementsSchema.parse(x))
72
70
  .filter((x) => x.scheme === "exact"); // TODO (402): accept other schemes
73
71
 
74
72
  const account = wallet.getAccount();
@@ -89,16 +87,10 @@ export function wrapFetchWithPayment(
89
87
  throw new Error("Payment amount exceeds maximum allowed");
90
88
  }
91
89
 
92
- const paymentChainId = EvmNetworkToChainId.get(
90
+ const paymentChainId = networkToChainId(
93
91
  selectedPaymentRequirements.network,
94
92
  );
95
93
 
96
- if (!paymentChainId) {
97
- throw new Error(
98
- `No chain found for the selected payment requirement: ${selectedPaymentRequirements.network}`,
99
- );
100
- }
101
-
102
94
  // switch to the payment chain if it's not the current chain
103
95
  if (paymentChainId !== chain.id) {
104
96
  await wallet.switchChain(getCachedChain(paymentChainId));
@@ -108,14 +100,8 @@ export function wrapFetchWithPayment(
108
100
  }
109
101
  }
110
102
 
111
- const walletClient = viemAdapter.wallet.toViem({
112
- wallet: wallet,
113
- chain,
114
- client,
115
- }) as Signer;
116
-
117
103
  const paymentHeader = await createPaymentHeader(
118
- walletClient,
104
+ account,
119
105
  x402Version,
120
106
  selectedPaymentRequirements,
121
107
  );
@@ -142,7 +128,7 @@ export function wrapFetchWithPayment(
142
128
  }
143
129
 
144
130
  function defaultPaymentRequirementsSelector(
145
- paymentRequirements: PaymentRequirements[],
131
+ paymentRequirements: RequestedPaymentRequirements[],
146
132
  chainId: number,
147
133
  scheme: "exact",
148
134
  ) {
@@ -151,7 +137,7 @@ function defaultPaymentRequirementsSelector(
151
137
  "No valid payment requirements found in server 402 response",
152
138
  );
153
139
  }
154
- const currentWalletNetwork = ChainIdToNetwork[chainId];
140
+ const currentWalletNetwork = ChainIdToNetwork[chainId] || `eip155:${chainId}`;
155
141
  // find the payment requirements matching the connected wallet chain
156
142
  const matchingPaymentRequirements = paymentRequirements.find(
157
143
  (x) => x.network === currentWalletNetwork && x.scheme === scheme,
@@ -0,0 +1,76 @@
1
+ import {
2
+ EvmNetworkToChainId,
3
+ type ExactEvmPayload,
4
+ type Network,
5
+ PaymentPayloadSchema,
6
+ PaymentRequirementsSchema,
7
+ SettleResponseSchema,
8
+ } from "x402/types";
9
+ import { z } from "zod";
10
+
11
+ const FacilitatorNetworkSchema = z.union([
12
+ z.literal("base-sepolia"),
13
+ z.literal("base"),
14
+ z.literal("avalanche-fuji"),
15
+ z.literal("avalanche"),
16
+ z.literal("iotex"),
17
+ z.literal("solana-devnet"),
18
+ z.literal("solana"),
19
+ z.literal("sei"),
20
+ z.literal("sei-testnet"),
21
+ z.string().refine((value) => value.startsWith("eip155:"), {
22
+ message: "Invalid network",
23
+ }),
24
+ ]);
25
+
26
+ export type FacilitatorNetwork = z.infer<typeof FacilitatorNetworkSchema>;
27
+
28
+ export const RequestedPaymentPayloadSchema = PaymentPayloadSchema.extend({
29
+ network: FacilitatorNetworkSchema,
30
+ });
31
+
32
+ export type RequestedPaymentPayload = z.infer<
33
+ typeof RequestedPaymentPayloadSchema
34
+ >;
35
+ export type UnsignedPaymentPayload = Omit<
36
+ RequestedPaymentPayload,
37
+ "payload"
38
+ > & {
39
+ payload: Omit<ExactEvmPayload, "signature"> & { signature: undefined };
40
+ };
41
+
42
+ export const RequestedPaymentRequirementsSchema =
43
+ PaymentRequirementsSchema.extend({
44
+ network: FacilitatorNetworkSchema,
45
+ });
46
+
47
+ export type RequestedPaymentRequirements = z.infer<
48
+ typeof RequestedPaymentRequirementsSchema
49
+ >;
50
+
51
+ const FacilitatorSettleResponseSchema = SettleResponseSchema.extend({
52
+ network: FacilitatorNetworkSchema,
53
+ });
54
+ export type FacilitatorSettleResponse = z.infer<
55
+ typeof FacilitatorSettleResponseSchema
56
+ >;
57
+
58
+ export function networkToChainId(network: string): number {
59
+ if (network.startsWith("eip155:")) {
60
+ const chainId = parseInt(network.split(":")[1] ?? "0");
61
+ if (!Number.isNaN(chainId) && chainId > 0) {
62
+ return chainId;
63
+ } else {
64
+ throw new Error(`Invalid network: ${network}`);
65
+ }
66
+ }
67
+ const mappedChainId = EvmNetworkToChainId.get(network as Network);
68
+ if (!mappedChainId) {
69
+ throw new Error(`Invalid network: ${network}`);
70
+ }
71
+ // TODO (402): support solana networks
72
+ if (mappedChainId === 101 || mappedChainId === 103) {
73
+ throw new Error("Solana networks not supported yet.");
74
+ }
75
+ return mappedChainId;
76
+ }
@@ -0,0 +1,186 @@
1
+ import { stringify } from "../utils/json.js";
2
+ import { decodePaymentRequest } from "./common.js";
3
+ import { safeBase64Encode } from "./encode.js";
4
+ import {
5
+ type PaymentArgs,
6
+ type SettlePaymentResult,
7
+ x402Version,
8
+ } from "./types.js";
9
+
10
+ /**
11
+ * Verifies and processes X402 payments for protected resources.
12
+ *
13
+ * This function implements the X402 payment protocol, verifying payment proofs
14
+ * and settling payments through a facilitator service. It handles the complete
15
+ * payment flow from validation to settlement.
16
+ *
17
+ * @param args - Configuration object containing payment verification parameters
18
+ * @returns A promise that resolves to either a successful payment result (200) or payment required error (402)
19
+ *
20
+ * @example
21
+ *
22
+ * ### Next.js API route example
23
+ *
24
+ * ```ts
25
+ * // Usage in a Next.js API route
26
+ * import { settlePayment, facilitator } from "thirdweb/x402";
27
+ * import { createThirdwebClient } from "thirdweb";
28
+ *
29
+ * const client = createThirdwebClient({
30
+ * secretKey: process.env.THIRDWEB_SECRET_KEY,
31
+ * });
32
+ *
33
+ * const thirdwebFacilitator = facilitator({
34
+ * client,
35
+ * serverWalletAddress: "0x1234567890123456789012345678901234567890",
36
+ * });
37
+ *
38
+ * export async function GET(request: Request) {
39
+ * const paymentData = request.headers.get("x-payment");
40
+ *
41
+ * // verify and process the payment
42
+ * const result = await settlePayment({
43
+ * resourceUrl: "https://api.example.com/premium-content",
44
+ * method: "GET",
45
+ * paymentData,
46
+ * payTo: "0x1234567890123456789012345678901234567890",
47
+ * network: "eip155:84532", // CAIP2 format: "eip155:<chain_id>"
48
+ * price: "$0.10", // or { amount: "100000", asset: { address: "0x...", decimals: 6 } }
49
+ * facilitator: thirdwebFacilitator,
50
+ * routeConfig: {
51
+ * description: "Access to premium API content",
52
+ * mimeType: "application/json",
53
+ * maxTimeoutSeconds: 300,
54
+ * },
55
+ * });
56
+ *
57
+ * if (result.status === 200) {
58
+ * // Payment verified and settled successfully
59
+ * return Response.json({ data: "premium content" });
60
+ * } else {
61
+ * // Payment required
62
+ * return Response.json(result.responseBody, {
63
+ * status: result.status,
64
+ * headers: result.responseHeaders,
65
+ * });
66
+ * }
67
+ * }
68
+ * ```
69
+ *
70
+ * ### Express middleware example
71
+ *
72
+ * ```ts
73
+ * // Usage in Express middleware
74
+ * import express from "express";
75
+ * import { settlePayment, facilitator } from "thirdweb/x402";
76
+ * import { createThirdwebClient } from "thirdweb";
77
+ *
78
+ * const client = createThirdwebClient({
79
+ * secretKey: process.env.THIRDWEB_SECRET_KEY,
80
+ * });
81
+ *
82
+ * const thirdwebFacilitator = facilitator({
83
+ * client,
84
+ * serverWalletAddress: "0x1234567890123456789012345678901234567890",
85
+ * });
86
+ *
87
+ * const app = express();
88
+ *
89
+ * async function paymentMiddleware(req, res, next) {
90
+ * // verify and process the payment
91
+ * const result = await settlePayment({
92
+ * resourceUrl: `${req.protocol}://${req.get('host')}${req.originalUrl}`,
93
+ * method: req.method,
94
+ * paymentData: req.headers["x-payment"],
95
+ * payTo: "0x1234567890123456789012345678901234567890",
96
+ * network: "eip155:8453", // CAIP2 format: "eip155:<chain_id>"
97
+ * price: "$0.05",
98
+ * facilitator: thirdwebFacilitator,
99
+ * });
100
+ *
101
+ * if (result.status === 200) {
102
+ * // Set payment receipt headers and continue
103
+ * Object.entries(result.responseHeaders).forEach(([key, value]) => {
104
+ * res.setHeader(key, value);
105
+ * });
106
+ * next();
107
+ * } else {
108
+ * // Return payment required response
109
+ * res.status(result.status)
110
+ * .set(result.responseHeaders)
111
+ * .json(result.responseBody);
112
+ * }
113
+ * }
114
+ *
115
+ * app.get("/api/premium", paymentMiddleware, (req, res) => {
116
+ * res.json({ message: "This is premium content!" });
117
+ * });
118
+ * ```
119
+ *
120
+ * @public
121
+ * @beta
122
+ * @bridge x402
123
+ */
124
+ export async function settlePayment(
125
+ args: PaymentArgs,
126
+ ): Promise<SettlePaymentResult> {
127
+ const { routeConfig = {}, facilitator } = args;
128
+ const { errorMessages } = routeConfig;
129
+
130
+ const decodePaymentResult = await decodePaymentRequest(args);
131
+
132
+ if (decodePaymentResult.status !== 200) {
133
+ return decodePaymentResult;
134
+ }
135
+
136
+ const { selectedPaymentRequirements, decodedPayment, paymentRequirements } =
137
+ decodePaymentResult;
138
+
139
+ // Settle payment
140
+ try {
141
+ const settlement = await facilitator.settle(
142
+ decodedPayment,
143
+ selectedPaymentRequirements,
144
+ );
145
+
146
+ if (settlement.success) {
147
+ return {
148
+ status: 200,
149
+ paymentReceipt: settlement,
150
+ responseHeaders: {
151
+ "Access-Control-Expose-Headers": "X-PAYMENT-RESPONSE",
152
+ "X-PAYMENT-RESPONSE": safeBase64Encode(stringify(settlement)),
153
+ },
154
+ };
155
+ } else {
156
+ return {
157
+ status: 402,
158
+ responseHeaders: {
159
+ "Content-Type": "application/json",
160
+ },
161
+ responseBody: {
162
+ x402Version,
163
+ error:
164
+ errorMessages?.settlementFailed ||
165
+ settlement.errorReason ||
166
+ "Settlement failed",
167
+ accepts: paymentRequirements,
168
+ },
169
+ };
170
+ }
171
+ } catch (error) {
172
+ return {
173
+ status: 402,
174
+ responseHeaders: {
175
+ "Content-Type": "application/json",
176
+ },
177
+ responseBody: {
178
+ x402Version,
179
+ error:
180
+ errorMessages?.settlementFailed ||
181
+ (error instanceof Error ? error.message : "Settlement error"),
182
+ accepts: paymentRequirements,
183
+ },
184
+ };
185
+ }
186
+ }