diff --git a/.env.example b/.env.example index 3909e5f0..d88c9b30 100644 --- a/.env.example +++ b/.env.example @@ -27,6 +27,9 @@ 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_PAYMASTER_KEY=your_coinbase_paymaster_key \ No newline at end of file +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 +NODE_ENV=production \ No newline at end of file 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/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/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 9097f3e3..c1d89521 100644 --- a/lib/x402/paymentMiddleware.ts +++ b/lib/x402/paymentMiddleware.ts @@ -1,28 +1,33 @@ import { paymentMiddleware } from "x402-express"; import type { RequestHandler } from "express"; +import { IS_PROD } from "../consts"; +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": { - price: "$0.001", - network: "base-sepolia" as const, + price, + network, 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" }, }, }, }, @@ -30,7 +35,5 @@ const routeConfig = { } as RoutesConfig; export const createPaymentMiddleware = (): RequestHandler => { - return paymentMiddleware(RECEIVING_WALLET_ADDRESS, routeConfig, { - url: FACILITATOR_URL, - }); + 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