@perkos/middleware-x402 1.0.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.
package/README.md ADDED
@@ -0,0 +1,177 @@
1
+ # @perkos/middleware-x402
2
+
3
+ x402 v2 payment protocol middleware and utilities for building vendor services with micropayments.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @perkos/middleware-x402
9
+ # or
10
+ pnpm add @perkos/middleware-x402
11
+ # or
12
+ yarn add @perkos/middleware-x402
13
+ ```
14
+
15
+ ## Features
16
+
17
+ - **x402 v2 Protocol Support**: Full implementation of the x402 v2 payment specification
18
+ - **Multi-Network Support**: Avalanche, Base, Celo (mainnet and testnets)
19
+ - **Payment Middleware**: Easy integration with Next.js API routes
20
+ - **EIP-712 Signatures**: TransferWithAuthorization support for USDC
21
+ - **Type-Safe**: Full TypeScript support with comprehensive types
22
+
23
+ ## Quick Start
24
+
25
+ ### Next.js Integration
26
+
27
+ ```typescript
28
+ import { NextRequest, NextResponse } from "next/server";
29
+ import { verifyX402PaymentNext, type PaymentConfig, type PaymentRoutes } from "@perkos/middleware-x402";
30
+
31
+ // Configure your payment settings
32
+ const config: PaymentConfig = {
33
+ payTo: "0xYourWalletAddress" as `0x${string}`,
34
+ facilitatorUrl: "https://stack.perkos.xyz",
35
+ network: "avalanche",
36
+ priceUsd: "0.05",
37
+ };
38
+
39
+ // Define payment routes
40
+ const routes: PaymentRoutes = {
41
+ "/api/ai/translate": 0.03,
42
+ "/api/ai/analyze": 0.05,
43
+ "/api/ai/generate": 0.15,
44
+ };
45
+
46
+ export async function POST(request: NextRequest) {
47
+ // Verify payment
48
+ const paymentResult = await verifyX402PaymentNext(request, "/api/ai/translate", {
49
+ config,
50
+ routes,
51
+ });
52
+
53
+ if (!paymentResult.isValid) {
54
+ return paymentResult.response;
55
+ }
56
+
57
+ // Process request - payment verified!
58
+ const result = await processRequest(request);
59
+
60
+ // Return response with payment header
61
+ const headers: Record<string, string> = {};
62
+ if (paymentResult.paymentResponseHeader) {
63
+ headers["PAYMENT-RESPONSE"] = paymentResult.paymentResponseHeader;
64
+ }
65
+
66
+ return NextResponse.json({ success: true, data: result }, { headers });
67
+ }
68
+ ```
69
+
70
+ ### Utilities
71
+
72
+ ```typescript
73
+ import {
74
+ getUSDCAddress,
75
+ toCAIP2Network,
76
+ parsePriceToUSDC,
77
+ generateNonce,
78
+ createEIP712Domain,
79
+ } from "@perkos/middleware-x402";
80
+
81
+ // Get USDC address for a network
82
+ const usdcAddress = getUSDCAddress("avalanche");
83
+ // => "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E"
84
+
85
+ // Convert network to CAIP-2 format
86
+ const caip2 = toCAIP2Network("base-sepolia");
87
+ // => "eip155:84532"
88
+
89
+ // Parse USD price to USDC atomic units
90
+ const amount = parsePriceToUSDC("$0.05");
91
+ // => 50000n
92
+
93
+ // Generate payment nonce
94
+ const nonce = generateNonce();
95
+ // => "0x..."
96
+
97
+ // Create EIP-712 domain for signing
98
+ const domain = createEIP712Domain("avalanche");
99
+ // => { name: "USD Coin", version: "2", chainId: 43114, verifyingContract: "0x..." }
100
+ ```
101
+
102
+ ## API Reference
103
+
104
+ ### Types
105
+
106
+ #### `PaymentConfig`
107
+ ```typescript
108
+ interface PaymentConfig {
109
+ payTo: `0x${string}`; // Recipient wallet address
110
+ facilitatorUrl: string; // x402 facilitator URL
111
+ network: NetworkName; // Network name
112
+ priceUsd: string; // Default price in USD
113
+ }
114
+ ```
115
+
116
+ #### `PaymentRoutes`
117
+ ```typescript
118
+ type PaymentRoutes = Record<string, number>;
119
+ // Example: { "/api/endpoint": 0.05 }
120
+ ```
121
+
122
+ #### `PaymentEnvelope`
123
+ ```typescript
124
+ interface PaymentEnvelope {
125
+ network: string;
126
+ authorization: {
127
+ from: string;
128
+ to: string;
129
+ value: string;
130
+ nonce: string;
131
+ validBefore: string;
132
+ };
133
+ signature: string;
134
+ }
135
+ ```
136
+
137
+ ### Constants
138
+
139
+ - `USDC_ADDRESSES` - USDC contract addresses by network
140
+ - `CHAIN_IDS` - Chain IDs by network
141
+ - `NETWORK_TO_CAIP2` - Network to CAIP-2 mapping
142
+ - `VALID_NETWORKS` - List of supported networks
143
+
144
+ ### Functions
145
+
146
+ #### `verifyX402PaymentNext(request, route, options)`
147
+ Verify x402 payment in Next.js API route.
148
+
149
+ #### `getUSDCAddress(network)`
150
+ Get USDC contract address for a network.
151
+
152
+ #### `toCAIP2Network(network)`
153
+ Convert network name to CAIP-2 format.
154
+
155
+ #### `parsePriceToUSDC(price)`
156
+ Parse USD price string to USDC atomic units.
157
+
158
+ #### `generateNonce()`
159
+ Generate random 32-byte nonce for payment.
160
+
161
+ #### `createEIP712Domain(network, tokenAddress?, tokenName?)`
162
+ Create EIP-712 domain for TransferWithAuthorization.
163
+
164
+ ## Supported Networks
165
+
166
+ | Network | Chain ID | CAIP-2 |
167
+ |---------|----------|--------|
168
+ | Avalanche | 43114 | eip155:43114 |
169
+ | Avalanche Fuji | 43113 | eip155:43113 |
170
+ | Base | 8453 | eip155:8453 |
171
+ | Base Sepolia | 84532 | eip155:84532 |
172
+ | Celo | 42220 | eip155:42220 |
173
+ | Celo Sepolia | 11142220 | eip155:11142220 |
174
+
175
+ ## License
176
+
177
+ MIT
@@ -0,0 +1,320 @@
1
+ import { Address } from 'viem';
2
+
3
+ /**
4
+ * x402 Core Types
5
+ * Type definitions for x402 v2 payment protocol
6
+ */
7
+
8
+ /**
9
+ * Payment envelope containing authorization and signature
10
+ */
11
+ interface PaymentEnvelope {
12
+ network: string;
13
+ authorization: {
14
+ from: string;
15
+ to: string;
16
+ value: string;
17
+ nonce: string;
18
+ validAfter?: string;
19
+ validBefore: string;
20
+ };
21
+ signature: string;
22
+ }
23
+ /**
24
+ * Payment requirements for a protected resource
25
+ */
26
+ interface PaymentRequirements {
27
+ endpoint?: string;
28
+ method?: string;
29
+ price?: string;
30
+ network: string;
31
+ payTo: string;
32
+ facilitator?: string;
33
+ maxAmountRequired?: string;
34
+ resource?: string;
35
+ scheme?: string;
36
+ asset?: string;
37
+ tokenName?: string;
38
+ tokenVersion?: string;
39
+ }
40
+ /**
41
+ * Payment configuration for x402 middleware
42
+ */
43
+ interface PaymentConfig {
44
+ payTo: `0x${string}`;
45
+ facilitatorUrl: string;
46
+ network: NetworkName;
47
+ priceUsd: string;
48
+ }
49
+ /**
50
+ * Result of payment verification
51
+ */
52
+ interface PaymentVerificationResult {
53
+ isValid: boolean;
54
+ payer?: string;
55
+ invalidReason?: string;
56
+ transactionHash?: string;
57
+ }
58
+ /**
59
+ * Result of verifyX402Payment middleware
60
+ */
61
+ interface X402PaymentResult {
62
+ isValid: boolean;
63
+ response?: any;
64
+ payer?: string;
65
+ envelope?: PaymentEnvelope;
66
+ paymentResponseHeader?: string;
67
+ }
68
+ /**
69
+ * Supported network names
70
+ */
71
+ type NetworkName = "base" | "base-sepolia" | "avalanche" | "avalanche-fuji" | "celo" | "celo-sepolia";
72
+ /**
73
+ * CAIP-2 network identifier
74
+ */
75
+ type CAIP2Network = "eip155:8453" | "eip155:84532" | "eip155:43114" | "eip155:43113" | "eip155:42220" | "eip155:11142220";
76
+ /**
77
+ * Token information for EIP-712 domain
78
+ */
79
+ interface TokenInfo {
80
+ address: Address;
81
+ name: string;
82
+ symbol: string;
83
+ decimals: number;
84
+ chainId: number;
85
+ }
86
+ /**
87
+ * Settlement result from facilitator
88
+ */
89
+ interface SettlementResult {
90
+ success: boolean;
91
+ transactionHash?: string;
92
+ error?: string;
93
+ }
94
+ /**
95
+ * Payment route configuration (path → price in USD)
96
+ */
97
+ type PaymentRoutes = Record<string, number>;
98
+ /**
99
+ * Options for x402 middleware
100
+ */
101
+ interface X402MiddlewareOptions {
102
+ config: PaymentConfig;
103
+ routes: PaymentRoutes;
104
+ tokenDetector?: (address: Address, network: string) => Promise<TokenInfo | null>;
105
+ logger?: {
106
+ log: (...args: any[]) => void;
107
+ error: (...args: any[]) => void;
108
+ };
109
+ }
110
+
111
+ /**
112
+ * x402 Core Constants
113
+ * Network configurations, addresses, and mappings
114
+ */
115
+
116
+ /**
117
+ * USDC Contract Addresses by Network
118
+ */
119
+ declare const USDC_ADDRESSES: Record<NetworkName, Address>;
120
+ /**
121
+ * Chain IDs by Network
122
+ */
123
+ declare const CHAIN_IDS: Record<string, number>;
124
+ /**
125
+ * Network to CAIP-2 mapping
126
+ */
127
+ declare const NETWORK_TO_CAIP2: Record<NetworkName, CAIP2Network>;
128
+ /**
129
+ * CAIP-2 to Network mapping
130
+ */
131
+ declare const CAIP2_TO_NETWORK: Record<string, NetworkName>;
132
+ /**
133
+ * Default RPC URLs by Network
134
+ */
135
+ declare const DEFAULT_RPC_URLS: Record<NetworkName, string>;
136
+ /**
137
+ * Valid network names
138
+ */
139
+ declare const VALID_NETWORKS: NetworkName[];
140
+ /**
141
+ * EIP-712 TransferWithAuthorization types
142
+ */
143
+ declare const TRANSFER_WITH_AUTHORIZATION_TYPES: {
144
+ readonly TransferWithAuthorization: readonly [{
145
+ readonly name: "from";
146
+ readonly type: "address";
147
+ }, {
148
+ readonly name: "to";
149
+ readonly type: "address";
150
+ }, {
151
+ readonly name: "value";
152
+ readonly type: "uint256";
153
+ }, {
154
+ readonly name: "validAfter";
155
+ readonly type: "uint256";
156
+ }, {
157
+ readonly name: "validBefore";
158
+ readonly type: "uint256";
159
+ }, {
160
+ readonly name: "nonce";
161
+ readonly type: "bytes32";
162
+ }];
163
+ };
164
+
165
+ /**
166
+ * x402 Core Utilities
167
+ * Helper functions for x402 payment processing
168
+ */
169
+
170
+ /**
171
+ * Get USDC address for a network
172
+ */
173
+ declare function getUSDCAddress(network: string): Address;
174
+ /**
175
+ * Get chain ID for a network
176
+ */
177
+ declare function getChainId(network: string): number;
178
+ /**
179
+ * Get RPC URL for a network (with environment variable override support)
180
+ */
181
+ declare function getRpcUrl(network: string, envOverrides?: Record<string, string | undefined>): string;
182
+ /**
183
+ * Convert network name to CAIP-2 format for x402 V2
184
+ * e.g., "base-sepolia" → "eip155:84532"
185
+ */
186
+ declare function toCAIP2Network(network: string): string;
187
+ /**
188
+ * Convert CAIP-2 network format to legacy format
189
+ * e.g., "eip155:43114" → "avalanche"
190
+ */
191
+ declare function toLegacyNetwork(network: string): string;
192
+ /**
193
+ * Parse USD price string to USDC amount (6 decimals)
194
+ * e.g., "$0.05" → 50000n
195
+ */
196
+ declare function parsePriceToUSDC(price: string): bigint;
197
+ /**
198
+ * Format USDC amount to USD string
199
+ * e.g., 50000n → "$0.05"
200
+ */
201
+ declare function formatUSDCToPrice(amount: bigint): string;
202
+ /**
203
+ * Generate random nonce for payment (32 bytes)
204
+ */
205
+ declare function generateNonce(): `0x${string}`;
206
+ /**
207
+ * Create EIP-712 domain for token transferWithAuthorization
208
+ */
209
+ declare function createEIP712Domain(network: string, tokenAddress?: Address, tokenName?: string): {
210
+ name: string;
211
+ version: string;
212
+ chainId: number;
213
+ verifyingContract: `0x${string}`;
214
+ };
215
+ /**
216
+ * Format payment payload for x402 v2 PAYMENT-SIGNATURE header
217
+ * Per spec: https://www.x402.org/writing/x402-v2-launch
218
+ */
219
+ declare function formatPaymentSignature(envelope: PaymentEnvelope, network: string, encodeBase64?: boolean): string;
220
+ /**
221
+ * Parse payment signature from header
222
+ */
223
+ declare function parsePaymentSignature(header: string): PaymentEnvelope | null;
224
+ /**
225
+ * Validate network name
226
+ */
227
+ declare function isValidNetwork(network: string): network is NetworkName;
228
+ /**
229
+ * Get valid before timestamp (default: 30 minutes from now)
230
+ */
231
+ declare function getValidBefore(minutes?: number): string;
232
+ /**
233
+ * Get valid after timestamp (default: now)
234
+ */
235
+ declare function getValidAfter(): string;
236
+
237
+ /**
238
+ * x402 Payment Middleware
239
+ * Payment verification and settlement for API routes
240
+ */
241
+
242
+ interface MiddlewareContext {
243
+ config: PaymentConfig;
244
+ routes: PaymentRoutes;
245
+ tokenDetector?: (address: string, network: string) => Promise<TokenInfo | null>;
246
+ createResponse?: (body: any, options: {
247
+ status: number;
248
+ headers?: Record<string, string>;
249
+ }) => any;
250
+ getHeader?: (request: any, name: string) => string | null;
251
+ }
252
+ /**
253
+ * Extract payment envelope from request headers
254
+ */
255
+ declare function extractPaymentEnvelope(request: any, getHeader?: (req: any, name: string) => string | null): PaymentEnvelope | null;
256
+ /**
257
+ * Verify payment with facilitator
258
+ */
259
+ declare function verifyPayment(envelope: PaymentEnvelope, route: string, ctx: MiddlewareContext): Promise<PaymentVerificationResult>;
260
+ /**
261
+ * Settle payment with facilitator
262
+ */
263
+ declare function settlePayment(envelope: PaymentEnvelope, ctx: MiddlewareContext): Promise<SettlementResult>;
264
+ /**
265
+ * Create 402 Payment Required response
266
+ */
267
+ declare function create402Response(route: string, ctx: MiddlewareContext): {
268
+ body: any;
269
+ status: number;
270
+ headers: Record<string, string>;
271
+ };
272
+ /**
273
+ * Main middleware function to verify x402 payment
274
+ */
275
+ declare function verifyX402Payment$1(request: any, route: string, ctx: MiddlewareContext): Promise<X402PaymentResult>;
276
+
277
+ /**
278
+ * x402 Next.js Integration
279
+ * Helper functions for Next.js API routes
280
+ */
281
+
282
+ /**
283
+ * Next.js specific middleware context
284
+ */
285
+ interface NextX402Options {
286
+ config: PaymentConfig;
287
+ routes: PaymentRoutes;
288
+ tokenDetector?: (address: string, network: string) => Promise<TokenInfo | null>;
289
+ }
290
+ /**
291
+ * Verify x402 payment in Next.js API route
292
+ *
293
+ * @example
294
+ * ```typescript
295
+ * import { verifyX402Payment } from "@perkos/x402-core/next";
296
+ *
297
+ * export async function POST(request: NextRequest) {
298
+ * const result = await verifyX402Payment(request, "/api/ai/translate", {
299
+ * config: x402Config,
300
+ * routes: paymentRoutes,
301
+ * });
302
+ *
303
+ * if (!result.isValid) {
304
+ * return result.response;
305
+ * }
306
+ *
307
+ * // Process request...
308
+ * }
309
+ * ```
310
+ */
311
+ declare function verifyX402Payment(request: any, route: string, options: NextX402Options): Promise<X402PaymentResult>;
312
+ /**
313
+ * Create a configured middleware instance for Next.js
314
+ */
315
+ declare function createX402Middleware(options: NextX402Options): {
316
+ verify: (request: any, route: string) => Promise<X402PaymentResult>;
317
+ options: NextX402Options;
318
+ };
319
+
320
+ export { type CAIP2Network, CAIP2_TO_NETWORK, CHAIN_IDS, DEFAULT_RPC_URLS, type MiddlewareContext, NETWORK_TO_CAIP2, type NetworkName, type NextX402Options, type PaymentConfig, type PaymentEnvelope, type PaymentRequirements, type PaymentRoutes, type PaymentVerificationResult, type SettlementResult, TRANSFER_WITH_AUTHORIZATION_TYPES, type TokenInfo, USDC_ADDRESSES, VALID_NETWORKS, type X402MiddlewareOptions, type X402PaymentResult, create402Response, createEIP712Domain, createX402Middleware, extractPaymentEnvelope, formatPaymentSignature, formatUSDCToPrice, generateNonce, getChainId, getRpcUrl, getUSDCAddress, getValidAfter, getValidBefore, isValidNetwork, parsePaymentSignature, parsePriceToUSDC, settlePayment, toCAIP2Network, toLegacyNetwork, verifyPayment, verifyX402Payment$1 as verifyX402Payment, verifyX402Payment as verifyX402PaymentNext };