From 665ef96bd416e0e43e8859b3a22792e95c156491 Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Mon, 24 Nov 2025 09:04:59 -0500 Subject: [PATCH 1/4] /api/image/generate - prod uses Base mainnet --- .env.example | 5 ++++- lib/consts.ts | 1 + lib/x402/paymentMiddleware.ts | 15 ++++++++------- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.env.example b/.env.example index 3909e5f0..2fa39b87 100644 --- a/.env.example +++ b/.env.example @@ -29,4 +29,7 @@ TRIGGER_SECRET_KEY=tr_dev_xxxxxxxxxx # Coinbase CDP_APP_KEY_ID=your_coinbase_developer_platform_app_key_id CDP_SECRET=your_coinbase_developer_platform_secret -CDP_PAYMASTER_KEY=your_coinbase_paymaster_key \ No newline at end of file +CDP_PAYMASTER_KEY=your_coinbase_paymaster_key + +# Environment +NODE_ENV=production \ No newline at end of file diff --git a/lib/consts.ts b/lib/consts.ts index 72f71495..6bf2f773 100644 --- a/lib/consts.ts +++ b/lib/consts.ts @@ -20,6 +20,7 @@ export const CHAT_POINT_SYSTEM_ID = 4172; export const AGENT_RUN = "agent_run"; export const MESSAGE_SENT_POINT = 1; export const MESSAGE_SENT_EVENT = "message_sent"; +export const IS_PROD = process.env.NODE_ENV === "production"; export const ENTERPRISE_DOMAINS: ReadonlySet = new Set([ "recoupable.com", diff --git a/lib/x402/paymentMiddleware.ts b/lib/x402/paymentMiddleware.ts index 9097f3e3..9cbebdc9 100644 --- a/lib/x402/paymentMiddleware.ts +++ b/lib/x402/paymentMiddleware.ts @@ -1,5 +1,6 @@ import { paymentMiddleware } from "x402-express"; import type { RequestHandler } from "express"; +import { IS_PROD } from "../consts"; const RECEIVING_WALLET_ADDRESS = "0x749B7b7A6944d72266Be9500FC8C221B6A7554Ce"; const FACILITATOR_URL = "https://x402.org/facilitator"; @@ -8,21 +9,21 @@ type RoutesConfig = Parameters[1]; const routeConfig = { "GET /api/image/generate": { - price: "$0.001", - network: "base-sepolia" as const, + price: IS_PROD ? "$0.01" : "$0.0001", + network: IS_PROD ? "base" : "base-sepolia", config: { description: "Generate images using AI", inputSchema: { - type: "object" as const, + type: "object", properties: { - location: { type: "string" as const, description: "City name" }, + location: { type: "string", description: "City name" }, }, }, outputSchema: { - type: "object" as const, + type: "object", properties: { - weather: { type: "string" as const }, - temperature: { type: "number" as const }, + weather: { type: "string" }, + temperature: { type: "number" }, }, }, }, From 7aa05b583b63a53c788a6f272fa10516934f1f93 Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Mon, 24 Nov 2025 09:26:22 -0500 Subject: [PATCH 2/4] fix facilitator to work on base mainnet --- .env.example | 4 ++-- lib/coinbase/client.ts | 6 +++--- lib/x402/paymentMiddleware.ts | 17 +++++++++++++---- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/.env.example b/.env.example index 2fa39b87..d88c9b30 100644 --- a/.env.example +++ b/.env.example @@ -27,8 +27,8 @@ REDIS_URL=your_vercel_redis_url TRIGGER_SECRET_KEY=tr_dev_xxxxxxxxxx # Coinbase -CDP_APP_KEY_ID=your_coinbase_developer_platform_app_key_id -CDP_SECRET=your_coinbase_developer_platform_secret +CDP_API_KEY_ID=your_coinbase_developer_platform_app_key_id +CDP_API_KEY_SECRET=your_coinbase_developer_platform_secret CDP_PAYMASTER_KEY=your_coinbase_paymaster_key # Environment diff --git a/lib/coinbase/client.ts b/lib/coinbase/client.ts index f83a27df..440628d4 100644 --- a/lib/coinbase/client.ts +++ b/lib/coinbase/client.ts @@ -1,10 +1,10 @@ import { Coinbase } from "@coinbase/coinbase-sdk"; -const apiKeyName = process.env.CDP_APP_KEY_ID; -const privateKey = process.env.CDP_SECRET; +const apiKeyName = process.env.CDP_API_KEY_ID; +const privateKey = process.env.CDP_API_KEY_SECRET; if (!apiKeyName || !privateKey) { - throw new Error("CDP_APP_KEY_ID and CDP_SECRET must be set"); + throw new Error("CDP_API_KEY_ID and CDP_API_KEY_SECRET must be set"); } /** diff --git a/lib/x402/paymentMiddleware.ts b/lib/x402/paymentMiddleware.ts index 9cbebdc9..f1c0070f 100644 --- a/lib/x402/paymentMiddleware.ts +++ b/lib/x402/paymentMiddleware.ts @@ -1,6 +1,7 @@ -import { paymentMiddleware } from "x402-express"; +import { paymentMiddleware, Resource } from "x402-express"; import type { RequestHandler } from "express"; import { IS_PROD } from "../consts"; +import { facilitator } from "@coinbase/x402"; const RECEIVING_WALLET_ADDRESS = "0x749B7b7A6944d72266Be9500FC8C221B6A7554Ce"; const FACILITATOR_URL = "https://x402.org/facilitator"; @@ -30,8 +31,16 @@ const routeConfig = { }, } as RoutesConfig; +const facilitatorConfig = IS_PROD + ? facilitator + : ({ + url: FACILITATOR_URL, + } as { url: Resource }); + export const createPaymentMiddleware = (): RequestHandler => { - return paymentMiddleware(RECEIVING_WALLET_ADDRESS, routeConfig, { - url: FACILITATOR_URL, - }); + return paymentMiddleware( + RECEIVING_WALLET_ADDRESS, + routeConfig, + facilitatorConfig + ); }; From 086224f7178080fa5690f5f79cae96a0f6742c76 Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Mon, 24 Nov 2025 09:28:46 -0500 Subject: [PATCH 3/4] SRP - variables to make code easier to read --- lib/x402/paymentMiddleware.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/x402/paymentMiddleware.ts b/lib/x402/paymentMiddleware.ts index f1c0070f..a6ec97c4 100644 --- a/lib/x402/paymentMiddleware.ts +++ b/lib/x402/paymentMiddleware.ts @@ -8,10 +8,13 @@ const FACILITATOR_URL = "https://x402.org/facilitator"; type RoutesConfig = Parameters[1]; +const price = IS_PROD ? "$0.01" : "$0.0001"; +const network = IS_PROD ? "base" : "base-sepolia"; + const routeConfig = { "GET /api/image/generate": { - price: IS_PROD ? "$0.01" : "$0.0001", - network: IS_PROD ? "base" : "base-sepolia", + price, + network, config: { description: "Generate images using AI", inputSchema: { From 73eb3ae42e058d49cf7d93b3c17d7298eb9df8b4 Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Mon, 24 Nov 2025 09:33:18 -0500 Subject: [PATCH 4/4] SRP - getFacilitator --- lib/x402/getFacilitator.ts | 12 ++++++++++++ lib/x402/paymentMiddleware.ts | 18 ++++-------------- package.json | 1 + pnpm-lock.yaml | 9 ++++++--- 4 files changed, 23 insertions(+), 17 deletions(-) create mode 100644 lib/x402/getFacilitator.ts diff --git a/lib/x402/getFacilitator.ts b/lib/x402/getFacilitator.ts new file mode 100644 index 00000000..b41bbeff --- /dev/null +++ b/lib/x402/getFacilitator.ts @@ -0,0 +1,12 @@ +import { facilitator as coinbaseHostedFacilitator } from "@coinbase/x402"; +import type { FacilitatorConfig, Resource } from "x402/types"; +import { IS_PROD } from "../consts"; + +const FACILITATOR_URL: Resource = "https://x402.org/facilitator"; + +export const getFacilitator = (): FacilitatorConfig => + IS_PROD + ? coinbaseHostedFacilitator + : { + url: FACILITATOR_URL, + }; diff --git a/lib/x402/paymentMiddleware.ts b/lib/x402/paymentMiddleware.ts index a6ec97c4..c1d89521 100644 --- a/lib/x402/paymentMiddleware.ts +++ b/lib/x402/paymentMiddleware.ts @@ -1,15 +1,15 @@ -import { paymentMiddleware, Resource } from "x402-express"; +import { paymentMiddleware } from "x402-express"; import type { RequestHandler } from "express"; import { IS_PROD } from "../consts"; -import { facilitator } from "@coinbase/x402"; +import { getFacilitator } from "./getFacilitator"; const RECEIVING_WALLET_ADDRESS = "0x749B7b7A6944d72266Be9500FC8C221B6A7554Ce"; -const FACILITATOR_URL = "https://x402.org/facilitator"; type RoutesConfig = Parameters[1]; const price = IS_PROD ? "$0.01" : "$0.0001"; const network = IS_PROD ? "base" : "base-sepolia"; +const facilitator = getFacilitator(); const routeConfig = { "GET /api/image/generate": { @@ -34,16 +34,6 @@ const routeConfig = { }, } as RoutesConfig; -const facilitatorConfig = IS_PROD - ? facilitator - : ({ - url: FACILITATOR_URL, - } as { url: Resource }); - export const createPaymentMiddleware = (): RequestHandler => { - return paymentMiddleware( - RECEIVING_WALLET_ADDRESS, - routeConfig, - facilitatorConfig - ); + return paymentMiddleware(RECEIVING_WALLET_ADDRESS, routeConfig, facilitator); }; diff --git a/package.json b/package.json index e6f6cdf8..be64a98e 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "tsconfig-paths": "^4.2.0", "uuid": "^11.0.5", "viem": "^2.37.5", + "x402": "^0.7.3", "x402-express": "^0.7.3", "zod": "^4.1.12" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 58eace8c..a78a1427 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -113,6 +113,9 @@ importers: viem: specifier: ^2.37.5 version: 2.37.5(bufferutil@4.0.9)(typescript@5.7.3)(utf-8-validate@5.0.10)(zod@4.1.12) + x402: + specifier: ^0.7.3 + version: 0.7.3(@solana/sysvars@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.3))(@tanstack/query-core@5.90.10)(@tanstack/react-query@5.90.10(react@18.3.1))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(ioredis@5.8.2)(react@18.3.1)(typescript@5.7.3)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) x402-express: specifier: ^0.7.3 version: 0.7.3(@solana/sysvars@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.3))(@tanstack/query-core@5.90.10)(@tanstack/react-query@5.90.10(react@18.3.1))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(ioredis@5.8.2)(react@18.3.1)(typescript@5.7.3)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) @@ -9359,7 +9362,7 @@ snapshots: is-arguments@1.2.0: dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 has-tostringtag: 1.0.2 is-arrayish@0.2.1: {} @@ -10172,7 +10175,7 @@ snapshots: ox@0.6.7(typescript@5.7.3)(zod@3.25.76): dependencies: '@adraffy/ens-normalize': 1.11.0 - '@noble/curves': 1.9.1 + '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 @@ -10186,7 +10189,7 @@ snapshots: ox@0.6.9(typescript@5.7.3)(zod@3.25.76): dependencies: '@adraffy/ens-normalize': 1.11.0 - '@noble/curves': 1.9.1 + '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0