@agentokratia/x402-escrow 2.0.1 → 2.1.1

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 CHANGED
@@ -1,13 +1,13 @@
1
1
  # @agentokratia/x402-escrow
2
2
 
3
- Escrow payment scheme for the x402 protocol. Session-based payments for high-frequency APIs.
3
+ Escrow payment scheme for the x402 protocol. Supports direct USDC payments and cross-token swaps.
4
4
 
5
5
  ## Features
6
6
 
7
- - **Session-based payments** - Sign once, make unlimited API calls
8
- - **Zero per-request gas** - Facilitator handles on-chain transactions
9
- - **100% reclaimable** - Withdraw unused funds anytime
10
- - **ERC-3009 gasless** - Users sign off-chain, no wallet transaction needed
7
+ - **Direct USDC payments** - Gasless via ERC-3009 ReceiveWithAuthorization
8
+ - **Multi-token support** - Pay with WETH, DAI, USDT → receiver gets USDC
9
+ - **Automatic swap quotes** - Server fetches DEX quotes, client just signs
10
+ - **Gzip compression** - Aggregator calldata compressed for smaller payloads
11
11
 
12
12
  ## Installation
13
13
 
@@ -19,140 +19,260 @@ npm install @agentokratia/x402-escrow
19
19
 
20
20
  For apps and agents paying for APIs.
21
21
 
22
- ### Simple (recommended)
22
+ ### Basic Setup
23
23
 
24
24
  ```typescript
25
- import { createEscrowFetch } from '@agentokratia/x402-escrow/client';
26
-
27
- const { fetch: escrowFetch, scheme, x402 } = createEscrowFetch(walletClient);
28
-
29
- // Payments handled automatically
30
- const response = await escrowFetch('https://api.example.com/premium');
31
-
32
- // Access sessions
33
- scheme.sessions.getAll();
34
- scheme.sessions.hasValid(receiverAddress, '10000');
35
- ```
36
-
37
- ### With hooks
38
-
39
- ```typescript
40
- const { fetch: escrowFetch, x402 } = createEscrowFetch(walletClient);
41
-
42
- // Add hooks for user control
43
- x402.onBeforePaymentCreation(async (ctx) => {
44
- console.log('About to pay:', ctx.paymentRequirements);
45
- });
25
+ import { EscrowScheme } from '@agentokratia/x402-escrow/client';
26
+ import { x402Client } from '@x402/core/client';
27
+ import { ExactEvmScheme } from '@x402/evm';
28
+ import type { WalletClient } from 'viem';
29
+
30
+ // Convert wagmi WalletClient to x402 signer
31
+ function walletClientToSigner(walletClient: WalletClient) {
32
+ return {
33
+ address: walletClient.account!.address,
34
+ signTypedData: async (message) =>
35
+ walletClient.signTypedData({
36
+ account: walletClient.account!,
37
+ domain: message.domain,
38
+ types: message.types,
39
+ primaryType: message.primaryType,
40
+ message: message.message,
41
+ }),
42
+ };
43
+ }
44
+
45
+ // Create x402 client
46
+ const client = new x402Client();
47
+
48
+ // Register exact scheme for direct USDC payments
49
+ const exactScheme = new ExactEvmScheme(walletClientToSigner(walletClient));
50
+ client.register('eip155:8453', exactScheme);
51
+
52
+ // Register escrow scheme for swap payments
53
+ const escrowScheme = new EscrowScheme(walletClient);
54
+ client.register('eip155:8453', escrowScheme);
46
55
 
47
- x402.onAfterPaymentCreation(async (ctx) => {
48
- console.log('Payment created:', ctx.paymentPayload);
49
- });
56
+ // Create payment payload from 402 response
57
+ const paymentPayload = await client.createPaymentPayload(paymentRequired);
50
58
  ```
51
59
 
52
- ### Advanced (manual setup)
60
+ ### With Policies (Token Selection)
53
61
 
54
62
  ```typescript
55
63
  import { x402Client } from '@x402/core/client';
56
- import { wrapFetchWithPayment } from '@x402/fetch';
57
- import { EscrowScheme, withSessionExtraction } from '@agentokratia/x402-escrow/client';
58
-
59
- const escrowScheme = new EscrowScheme(walletClient);
60
- const x402 = new x402Client().register('eip155:84532', escrowScheme);
61
- const paidFetch = wrapFetchWithPayment(fetch, x402);
62
- const escrowFetch = withSessionExtraction(paidFetch, escrowScheme);
64
+ import { EscrowScheme } from '@agentokratia/x402-escrow/client';
65
+
66
+ // Selector that prefers exact scheme over escrow
67
+ const preferExactSelector = (version, requirements) => {
68
+ const exact = requirements.find((r) => r.scheme === 'exact');
69
+ return exact || requirements[0];
70
+ };
71
+
72
+ // Policy that filters by input token
73
+ function createInputTokenPolicy(inputToken: string) {
74
+ return (version, requirements) => {
75
+ return requirements.filter((req) => {
76
+ if (req.scheme === 'exact') {
77
+ return req.asset?.toLowerCase() === inputToken.toLowerCase();
78
+ }
79
+ // For escrow, check swapData.inputToken
80
+ const swapData = req.extra?.swapData;
81
+ if (swapData?.inputToken) {
82
+ return swapData.inputToken.toLowerCase() === inputToken.toLowerCase();
83
+ }
84
+ return req.asset?.toLowerCase() === inputToken.toLowerCase();
85
+ });
86
+ };
87
+ }
88
+
89
+ // Create client with selector
90
+ const client = new x402Client(preferExactSelector);
91
+
92
+ // Register policy to filter by selected token
93
+ client.registerPolicy(createInputTokenPolicy('0x4200000000000000000000000000000000000006')); // WETH
94
+
95
+ // Register schemes
96
+ client.register('eip155:8453', new ExactEvmScheme(signer));
97
+ client.register('eip155:8453', new EscrowScheme(walletClient));
63
98
  ```
64
99
 
65
100
  ## Server Usage
66
101
 
67
102
  For APIs accepting payments. Config is auto-discovered from facilitator.
68
103
 
69
- ### Express
104
+ ### Basic Setup
70
105
 
71
106
  ```typescript
72
107
  import { x402ResourceServer, HTTPFacilitatorClient } from '@x402/core/server';
73
- import { paymentMiddleware } from '@x402/express';
74
108
  import { EscrowScheme } from '@agentokratia/x402-escrow/server';
109
+ import { ExactEvmScheme } from '@x402/evm/exact/server';
75
110
 
111
+ // 1. Create facilitator client
76
112
  const facilitator = new HTTPFacilitatorClient({
77
113
  url: 'https://facilitator.agentokratia.com',
78
114
  createAuthHeaders: async () => ({
79
115
  verify: { Authorization: `Bearer ${process.env.X402_API_KEY}` },
80
116
  settle: { Authorization: `Bearer ${process.env.X402_API_KEY}` },
81
- supported: {},
117
+ supported: { Authorization: `Bearer ${process.env.X402_API_KEY}` },
82
118
  }),
83
119
  });
84
120
 
85
- const server = new x402ResourceServer(facilitator).register('eip155:84532', new EscrowScheme());
86
-
87
- app.use(
88
- paymentMiddleware(
89
- {
90
- 'GET /api/premium': {
91
- accepts: {
92
- scheme: 'escrow',
93
- price: '$0.01',
94
- network: 'eip155:84532',
95
- payTo: ownerAddress,
96
- },
97
- },
98
- },
99
- server
100
- )
101
- );
121
+ // 2. Create escrow scheme (for swap payments)
122
+ const escrow = new EscrowScheme({
123
+ facilitator,
124
+ apiKey: process.env.X402_API_KEY,
125
+ });
126
+
127
+ // 3. Create x402 server with both schemes
128
+ const server = new x402ResourceServer(facilitator);
129
+ server.register('eip155:8453', new ExactEvmScheme()); // Direct USDC
130
+ server.register('eip155:8453', escrow); // Swaps
102
131
  ```
103
132
 
104
- ### Next.js
133
+ ### Building Payment Requirements (402 Response)
105
134
 
106
135
  ```typescript
107
- import { paymentProxy } from '@x402/next';
108
- import { EscrowScheme } from '@agentokratia/x402-escrow/server';
136
+ // Build accepts for both schemes in parallel
137
+ const [exactResult, escrowResult] = await Promise.allSettled([
138
+ // Exact scheme (USDC direct)
139
+ server.buildPaymentRequirements({
140
+ scheme: 'exact',
141
+ network: 'eip155:8453',
142
+ price: '$1.00',
143
+ payTo: recipientAddress,
144
+ maxTimeoutSeconds: 600,
145
+ }),
146
+ // Escrow scheme (swaps) - fetches DEX quotes
147
+ escrow.buildAcceptsResolved({
148
+ network: 'eip155:8453',
149
+ price: '$1.00',
150
+ payTo: recipientAddress,
151
+ }),
152
+ ]);
153
+
154
+ // Combine into payment requirements array
155
+ const paymentRequirements = [];
156
+
157
+ if (exactResult.status === 'fulfilled') {
158
+ paymentRequirements.push(...exactResult.value);
159
+ }
160
+
161
+ if (escrowResult.status === 'fulfilled') {
162
+ for (const accept of escrowResult.value) {
163
+ paymentRequirements.push({
164
+ scheme: accept.scheme,
165
+ network: accept.network,
166
+ asset: accept.price.asset,
167
+ amount: accept.price.amount,
168
+ payTo: accept.payTo,
169
+ maxTimeoutSeconds: accept.maxTimeoutSeconds || 600,
170
+ extra: accept.price.extra || {},
171
+ });
172
+ }
173
+ }
174
+
175
+ // Return 402 with PAYMENT-REQUIRED header
176
+ const encoded = Buffer.from(JSON.stringify(paymentRequirements)).toString('base64');
177
+ response.headers.set('PAYMENT-REQUIRED', encoded);
178
+ ```
179
+
180
+ ### Processing Payments (Verify & Settle)
109
181
 
110
- const server = new x402ResourceServer(facilitator).register('eip155:84532', new EscrowScheme());
182
+ ```typescript
183
+ import { preprocessSwapPayload } from '@agentokratia/x402-escrow/server';
184
+
185
+ // Decode payment from PAYMENT-SIGNATURE header
186
+ const paymentPayload = JSON.parse(Buffer.from(paymentSignature, 'base64').toString());
187
+
188
+ // Decompress swap calldata before forwarding to facilitator
189
+ // (Server compresses in buildAccepts, client passes through compressed)
190
+ const processedPayload = preprocessSwapPayload({
191
+ x402Version: 2,
192
+ resource: { url: '/api/endpoint', mimeType: 'application/json' },
193
+ accepted: paymentPayload.accepted,
194
+ payload: paymentPayload.payload,
195
+ });
196
+
197
+ // Verify and settle with facilitator
198
+ const verifyResult = await facilitator.verify(processedPayload, processedPayload.accepted);
199
+ if (!verifyResult.isValid) {
200
+ throw new Error(verifyResult.invalidReason);
201
+ }
202
+
203
+ const settleResult = await facilitator.settle(processedPayload, processedPayload.accepted);
204
+ if (!settleResult.success) {
205
+ throw new Error(settleResult.errorReason);
206
+ }
111
207
 
112
- export const proxy = paymentProxy(
113
- {
114
- '/api/premium': {
115
- accepts: { scheme: 'escrow', network: 'eip155:84532', payTo: ownerAddress, price: '$0.01' },
116
- },
117
- },
118
- server
119
- );
208
+ // Return success with transaction hash
209
+ return { success: true, transaction: settleResult.transaction };
120
210
  ```
121
211
 
122
212
  ## How It Works
123
213
 
124
214
  ```
125
- 1. User signs ERC-3009 authorization (gasless)
126
- 2. Facilitator deposits funds to escrow contract
127
- 3. Session created with balance
128
- 4. Each API call debits from session (no signature needed)
129
- 5. User can reclaim unused funds anytime
215
+ Client Server Facilitator
216
+ │ │ │
217
+ GET /api/resource │ │
218
+ │──────────────────────────────>│ │
219
+ │ │ buildAccepts() │
220
+ │ │─────────────────────────────>│
221
+ │ │ (fetches quotes for swaps) │
222
+ │ │<─────────────────────────────│
223
+ │ 402 + PAYMENT-REQUIRED │ │
224
+ │<──────────────────────────────│ │
225
+ │ │ │
226
+ │ User selects token (WETH) │ │
227
+ │ Signs EIP-712 Permit2 │ │
228
+ │ │ │
229
+ │ GET + PAYMENT-SIGNATURE │ │
230
+ │──────────────────────────────>│ │
231
+ │ │ verify() + settle() │
232
+ │ │─────────────────────────────>│
233
+ │ │ (executes swap on-chain) │
234
+ │ │<─────────────────────────────│
235
+ │ 200 + transaction hash │ │
236
+ │<──────────────────────────────│ │
130
237
  ```
131
238
 
132
239
  ## Networks
133
240
 
134
- | Network | Chain ID | Escrow Contract |
135
- | ------------ | -------- | -------------------------------------------- |
136
- | Base Mainnet | 8453 | `0xbDEa0d1BCc5966192b070fDF62ab4eF5B4420Cff` |
137
- | Base Sepolia | 84532 | `0xbDEa0d1BCc5966192b070fDF62ab4eF5B4420Cff` |
241
+ | Network | Chain ID | Facilitator |
242
+ | ------------ | -------- | -------------------------------------- |
243
+ | Base Mainnet | 8453 | `https://facilitator.agentokratia.com` |
244
+ | Base Sepolia | 84532 | `https://facilitator.agentokratia.com` |
138
245
 
139
246
  ## API
140
247
 
141
- ### Client
142
-
143
- | Export | Description |
144
- | ------------------------------------------- | --------------------------------------------- |
145
- | `createEscrowFetch(walletClient, options?)` | Creates fetch with automatic payment handling |
146
- | `EscrowScheme` | Core scheme class for x402Client |
147
- | `withSessionExtraction(fetch, scheme)` | Wrapper to extract sessions from responses |
148
- | `withAxiosSessionExtraction(scheme)` | Axios interceptor for session extraction |
149
-
150
- ### Server
151
-
152
- | Export | Description |
153
- | ----------------------- | ------------------------------------ |
154
- | `EscrowScheme` | Server scheme for x402ResourceServer |
155
- | `HTTPFacilitatorClient` | Re-export from @x402/core |
248
+ ### Client Exports
249
+
250
+ | Export | Description |
251
+ | ------------------------- | ------------------------------------------------- |
252
+ | `EscrowScheme` | Client scheme for x402Client (takes WalletClient) |
253
+ | `signERC3009` | Sign ERC-3009 authorization |
254
+ | `signPermit2TransferFrom` | Sign Permit2 transfer |
255
+ | `computePaymentNonce` | Derive deterministic nonce from payment params |
256
+ | `PERMIT2_ADDRESS` | Universal Permit2 contract address |
257
+ | `decompressCalldata` | Decompress gzipped aggregator calldata |
258
+
259
+ ### Server Exports
260
+
261
+ | Export | Description |
262
+ | ----------------------- | ------------------------------------------------- |
263
+ | `EscrowScheme` | Server scheme for x402ResourceServer |
264
+ | `HTTPFacilitatorClient` | Re-export from @x402/core/server |
265
+ | `preprocessSwapPayload` | Decompress swap calldata before facilitator calls |
266
+ | `compressCalldata` | Compress aggregator calldata (gzip) |
267
+
268
+ ## Supported Input Tokens (Base Mainnet)
269
+
270
+ | Token | Address |
271
+ | ----- | -------------------------------------------- |
272
+ | USDC | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` |
273
+ | WETH | `0x4200000000000000000000000000000000000006` |
274
+ | DAI | `0x50c5725949a6f0c72e6c4a641f24049a917db0cb` |
275
+ | USDT | `0xfde4c96c8593536e31f229ea8f37b2ada2699bb2` |
156
276
 
157
277
  ## License
158
278