Skip to content

Commit 1c10f56

Browse files
committed
update to use nexus keys instead
1 parent dfa35f6 commit 1c10f56

File tree

12 files changed

+522
-2301
lines changed

12 files changed

+522
-2301
lines changed

packages/nexus/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
"url": "https://github.com/thirdweb-dev/js/issues"
88
},
99
"dependencies": {
10-
"thirdweb": "workspace:*",
1110
"x402": "0.7.0",
1211
"zod": "3.25.75"
1312
},

packages/nexus/src/common.ts

Lines changed: 3 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,4 @@
1-
import type { ThirdwebClient } from "thirdweb";
2-
import { type Abi, getContract, resolveContractAbi } from "thirdweb/contract";
3-
import {
4-
isPermitSupported,
5-
isTransferWithAuthorizationSupported,
6-
} from "thirdweb/extensions/erc20";
7-
import { getAddress, toFunctionSelector, toUnits } from "thirdweb/utils";
81
import { ChainIdToNetwork, type Money, moneySchema } from "x402/types";
9-
import { getCachedChain } from "../../thirdweb/dist/types/chains/utils.js";
102
import { decodePayment } from "./encode.js";
113
import type { ThirdwebX402Facilitator } from "./facilitator.js";
124
import {
@@ -22,6 +14,7 @@ import {
2214
type SupportedSignatureType,
2315
x402Version,
2416
} from "./types.js";
17+
import { toUnits } from "./utils.js";
2518

2619
type GetPaymentRequirementsResult = {
2720
status: 200;
@@ -104,9 +97,9 @@ export async function decodePaymentRequest(
10497
resource: resourceUrl,
10598
description: description ?? "",
10699
mimeType: mimeType ?? "application/json",
107-
payTo: getAddress(facilitator.address), // always pay to the facilitator address first
100+
payTo: facilitator.address as `0x${string}`, // always pay to the facilitator address first
108101
maxTimeoutSeconds: maxTimeoutSeconds ?? 86400,
109-
asset: getAddress(asset.address),
102+
asset: asset.address as `0x${string}`,
110103
outputSchema: {
111104
input: {
112105
type: "http",
@@ -268,46 +261,6 @@ async function getDefaultAsset(
268261
return assetConfig;
269262
}
270263

271-
export async function getSupportedSignatureType(args: {
272-
client: ThirdwebClient;
273-
asset: string;
274-
chainId: number;
275-
eip712Extras: ERC20TokenAmount["asset"]["eip712"] | undefined;
276-
}): Promise<SupportedSignatureType | undefined> {
277-
const primaryType = args.eip712Extras?.primaryType;
278-
279-
if (primaryType === "Permit" || primaryType === "TransferWithAuthorization") {
280-
return primaryType;
281-
}
282-
283-
// not specified, so we need to detect it
284-
const abi: Abi = await resolveContractAbi(
285-
getContract({
286-
client: args.client,
287-
address: args.asset,
288-
chain: getCachedChain(args.chainId),
289-
}),
290-
).catch((error) => {
291-
console.error("Error resolving contract ABI", error);
292-
return [];
293-
});
294-
const selectors = abi
295-
.filter((f) => f.type === "function")
296-
.map((f) => toFunctionSelector(f));
297-
const hasPermit = isPermitSupported(selectors);
298-
const hasTransferWithAuthorization =
299-
isTransferWithAuthorizationSupported(selectors);
300-
301-
// prefer transferWithAuthorization over permit
302-
if (hasTransferWithAuthorization) {
303-
return "TransferWithAuthorization";
304-
}
305-
if (hasPermit) {
306-
return "Permit";
307-
}
308-
return undefined;
309-
}
310-
311264
async function getOrDetectTokenExtras(args: {
312265
facilitator: ThirdwebX402Facilitator;
313266
partialAsset: ERC20TokenAmount["asset"];
Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
11
export type {
2-
HTTPRequestStructure,
3-
Money,
4-
PaymentMiddlewareConfig,
5-
Resource,
2+
HTTPRequestStructure,
3+
Money,
4+
PaymentMiddlewareConfig,
5+
Resource,
66
} from "x402/types";
77
export { decodePayment, encodePayment } from "../encode.js";
88
export {
9-
facilitator,
10-
type ThirdwebX402Facilitator,
11-
type ThirdwebX402FacilitatorConfig,
12-
type WaitUntil,
9+
createFacilitator,
10+
type ThirdwebX402Facilitator,
11+
type ThirdwebX402FacilitatorConfig,
12+
type WaitUntil,
1313
} from "../facilitator.js";
14-
export { wrapFetchWithPayment } from "../fetchWithPayment.js";
1514
export { settlePayment } from "../settle-payment.js";
1615
export type {
17-
ERC20TokenAmount,
18-
PaymentArgs,
19-
PaymentRequiredResult,
20-
SettlePaymentArgs,
21-
SettlePaymentResult,
22-
SupportedSignatureType,
23-
VerifyPaymentResult,
16+
ERC20TokenAmount,
17+
PaymentArgs,
18+
PaymentRequiredResult,
19+
SettlePaymentArgs,
20+
SettlePaymentResult,
21+
SupportedSignatureType,
22+
VerifyPaymentResult,
2423
} from "../types.js";
2524
export { verifyPayment } from "../verify-payment.js";

packages/nexus/src/facilitator.ts

Lines changed: 49 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import type { ThirdwebClient } from "thirdweb";
2-
import { stringify } from "thirdweb/utils";
31
import type { VerifyResponse } from "x402/types";
42
import type {
53
FacilitatorSettleResponse,
@@ -8,14 +6,14 @@ import type {
86
RequestedPaymentPayload,
97
RequestedPaymentRequirements,
108
} from "./schemas.js";
9+
import { stringify } from "./utils.js";
1110

1211
export type WaitUntil = "simulated" | "submitted" | "confirmed";
1312

1413
export type ThirdwebX402FacilitatorConfig = {
15-
client: ThirdwebClient;
16-
serverWalletAddress: string;
14+
walletSecret: string;
15+
walletAddress: string;
1716
waitUntil?: WaitUntil;
18-
vaultAccessToken?: string;
1917
baseUrl?: string;
2018
};
2119

@@ -47,7 +45,7 @@ export type ThirdwebX402Facilitator = {
4745
}) => Promise<FacilitatorSupportedResponse>;
4846
};
4947

50-
const DEFAULT_BASE_URL = "https://api.thirdweb.com/v1/payments/x402";
48+
const DEFAULT_BASE_URL = "https://nexus-api.thirdweb.com";
5149

5250
/**
5351
* Creates a facilitator for the x402 payment protocol.
@@ -58,21 +56,17 @@ const DEFAULT_BASE_URL = "https://api.thirdweb.com/v1/payments/x402";
5856
*
5957
* @example
6058
* ```ts
61-
* import { facilitator } from "thirdweb/x402";
62-
* import { createThirdwebClient } from "thirdweb";
59+
* import { createFacilitator } from "@thirdweb-dev/nexus";
6360
* import { paymentMiddleware } from 'x402-hono'
6461
*
65-
* const client = createThirdwebClient({
66-
* secretKey: "your-secret-key",
67-
* });
68-
* const thirdwebX402Facilitator = facilitator({
69-
* client: client,
70-
* serverWalletAddress: "0x1234567890123456789012345678901234567890",
62+
* const facilitator = createFacilitator({
63+
* walletSecret: <your-wallet-secret>,
64+
* walletAddress: <your-wallet-address>,
7165
* });
7266
*
7367
* // add the facilitator to any x402 payment middleware
7468
* const middleware = paymentMiddleware(
75-
* "0x1234567890123456789012345678901234567890",
69+
* facilitator.address,
7670
* {
7771
* "/api/paywall": {
7872
* price: "$0.01",
@@ -82,16 +76,16 @@ const DEFAULT_BASE_URL = "https://api.thirdweb.com/v1/payments/x402";
8276
* },
8377
* },
8478
* },
85-
* thirdwebX402Facilitator,
79+
* facilitator,
8680
* );
8781
* ```
8882
*
8983
* #### Configuration Options
9084
*
9185
* ```ts
92-
* const thirdwebX402Facilitator = facilitator({
93-
* client: client,
94-
* serverWalletAddress: "0x1234567890123456789012345678901234567890",
86+
* const thirdwebX402Facilitator = createFacilitator({
87+
* walletSecret: <your-wallet-secret>,
88+
* walletAddress: <your-wallet-address>,
9589
* // Optional: Wait behavior for settlements
9690
* // - "simulated": Only simulate the transaction (fastest)
9791
* // - "submitted": Wait until transaction is submitted
@@ -101,43 +95,39 @@ const DEFAULT_BASE_URL = "https://api.thirdweb.com/v1/payments/x402";
10195
10296
* ```
10397
*
104-
* @bridge x402
10598
*/
106-
export function facilitator(
99+
export function createFacilitator(
107100
config: ThirdwebX402FacilitatorConfig,
108101
): ThirdwebX402Facilitator {
109-
const secretKey = config.client.secretKey;
110-
if (!secretKey) {
111-
throw new Error("Client secret key is required for the x402 facilitator");
102+
if (!config.walletSecret) {
103+
throw new Error("Wallet secret is required for the x402 facilitator");
112104
}
113-
const serverWalletAddress = config.serverWalletAddress;
114-
if (!serverWalletAddress) {
115-
throw new Error(
116-
"Server wallet address is required for the x402 facilitator",
117-
);
105+
106+
if (!config.walletAddress) {
107+
throw new Error("Wallet address is required for the x402 facilitator");
118108
}
119-
const facilitator = {
120-
url: (config.baseUrl ?? DEFAULT_BASE_URL) as `${string}://${string}`,
121-
address: serverWalletAddress,
122-
createAuthHeaders: async () => {
123-
return {
124-
verify: {
125-
"x-secret-key": secretKey,
126-
},
127-
settle: {
128-
"x-secret-key": secretKey,
129-
...(config.vaultAccessToken
130-
? { "x-vault-access-token": config.vaultAccessToken }
131-
: {}),
132-
},
133-
supported: {
134-
"x-secret-key": secretKey,
135-
},
136-
list: {
137-
"x-secret-key": secretKey,
138-
},
139-
};
109+
110+
const BASE_URL = config.baseUrl ?? DEFAULT_BASE_URL;
111+
112+
const AUTH_HEADERS = {
113+
verify: {
114+
authorization: `Bearer ${config.walletSecret}`,
115+
},
116+
settle: {
117+
authorization: `Bearer ${config.walletSecret}`,
118+
},
119+
supported: {
120+
authorization: `Bearer ${config.walletSecret}`,
140121
},
122+
list: {
123+
authorization: `Bearer ${config.walletSecret}`,
124+
},
125+
} as const;
126+
127+
return {
128+
url: BASE_URL as `${string}://${string}`,
129+
address: config.walletAddress,
130+
createAuthHeaders: async () => AUTH_HEADERS,
141131
/**
142132
* Verifies a payment payload with the facilitator service
143133
*
@@ -149,13 +139,11 @@ export function facilitator(
149139
payload: RequestedPaymentPayload,
150140
paymentRequirements: RequestedPaymentRequirements,
151141
): Promise<FacilitatorVerifyResponse> {
152-
const url = config.baseUrl ?? DEFAULT_BASE_URL;
153-
154142
let headers = { "Content-Type": "application/json" };
155-
const authHeaders = await facilitator.createAuthHeaders();
156-
headers = { ...headers, ...authHeaders.verify };
157143

158-
const res = await fetch(`${url}/verify`, {
144+
headers = { ...headers, ...AUTH_HEADERS.verify };
145+
146+
const res = await fetch(new URL("/verify", BASE_URL), {
159147
method: "POST",
160148
headers,
161149
body: stringify({
@@ -186,14 +174,11 @@ export function facilitator(
186174
paymentRequirements: RequestedPaymentRequirements,
187175
waitUntil?: WaitUntil,
188176
): Promise<FacilitatorSettleResponse> {
189-
const url = config.baseUrl ?? DEFAULT_BASE_URL;
190-
191177
let headers = { "Content-Type": "application/json" };
192-
const authHeaders = await facilitator.createAuthHeaders();
193-
headers = { ...headers, ...authHeaders.settle };
178+
headers = { ...headers, ...AUTH_HEADERS.settle };
194179
const waitUntilParam = waitUntil || config.waitUntil;
195180

196-
const res = await fetch(`${url}/settle`, {
181+
const res = await fetch(new URL("/settle", BASE_URL), {
197182
method: "POST",
198183
headers,
199184
body: JSON.stringify({
@@ -222,22 +207,18 @@ export function facilitator(
222207
chainId: number;
223208
tokenAddress?: string;
224209
}): Promise<FacilitatorSupportedResponse> {
225-
const url = config.baseUrl ?? DEFAULT_BASE_URL;
226-
227-
// TODO: re-add caching? (see thirdweb/x402/facilitator.ts)
228-
const authHeaders = await facilitator.createAuthHeaders();
229210
const headers = {
230211
"Content-Type": "application/json",
231-
...authHeaders.supported,
212+
...AUTH_HEADERS.supported,
232213
};
233-
const supportedUrl = new URL(`${url}/supported`);
214+
const supportedUrl = new URL("/supported", BASE_URL);
234215
if (filters?.chainId) {
235216
supportedUrl.searchParams.set("chainId", filters.chainId.toString());
236217
}
237218
if (filters?.tokenAddress) {
238219
supportedUrl.searchParams.set("tokenAddress", filters.tokenAddress);
239220
}
240-
const res = await fetch(supportedUrl.toString(), { headers });
221+
const res = await fetch(supportedUrl, { headers });
241222

242223
if (res.status !== 200) {
243224
throw new Error(
@@ -248,7 +229,5 @@ export function facilitator(
248229
const data = await res.json();
249230
return data as FacilitatorSupportedResponse;
250231
},
251-
};
252-
253-
return facilitator;
232+
} as const satisfies ThirdwebX402Facilitator;
254233
}

0 commit comments

Comments
 (0)