@agentokratia/x402-escrow 2.1.0 → 2.1.2

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.
Files changed (2) hide show
  1. package/README.md +228 -94
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,76 +1,72 @@
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
 
14
14
  ```bash
15
- npm install @agentokratia/x402-escrow
15
+ npm install @x402/core @x402/next @x402/fetch @x402/evm @agentokratia/x402-escrow viem
16
16
  ```
17
17
 
18
- ## Client Usage
18
+ ## Server Integration
19
19
 
20
- For apps and agents paying for APIs.
21
-
22
- ### Simple (recommended)
20
+ ### Next.js with paymentProxy
23
21
 
24
22
  ```typescript
25
- import { createEscrowFetch } from '@agentokratia/x402-escrow/client';
26
-
27
- const { fetch: escrowFetch, scheme, x402 } = createEscrowFetch(walletClient);
23
+ import { x402ResourceServer, HTTPFacilitatorClient } from '@x402/core/server';
24
+ import { ExactEvmScheme } from '@x402/evm/exact/server';
25
+ import { EscrowScheme } from '@agentokratia/x402-escrow/server';
26
+ import { paymentProxy } from '@x402/next';
28
27
 
29
- // Payments handled automatically
30
- const response = await escrowFetch('https://api.example.com/premium');
28
+ const facilitator = new HTTPFacilitatorClient({
29
+ url: 'https://facilitator.agentokratia.com',
30
+ createAuthHeaders: async () => ({
31
+ verify: { Authorization: `Bearer ${process.env.X402_API_KEY}` },
32
+ settle: { Authorization: `Bearer ${process.env.X402_API_KEY}` },
33
+ }),
34
+ });
31
35
 
32
- // Access sessions
33
- scheme.sessions.getAll();
34
- scheme.sessions.hasValid(receiverAddress, '10000');
35
- ```
36
+ const escrow = new EscrowScheme({ facilitator });
36
37
 
37
- ### With hooks
38
+ const USDC = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
38
39
 
39
- ```typescript
40
- const { fetch: escrowFetch, x402 } = createEscrowFetch(walletClient);
40
+ const server = new x402ResourceServer(facilitator)
41
+ .register('eip155:8453', new ExactEvmScheme())
42
+ .register('eip155:8453', escrow);
41
43
 
42
- // Add hooks for user control
43
- x402.onBeforePaymentCreation(async (ctx) => {
44
- console.log('About to pay:', ctx.paymentRequirements);
44
+ // Auto-discovers supported tokens (USDC, WETH, DAI...)
45
+ const escrowAccepts = await escrow.buildAccepts({
46
+ network: 'eip155:8453',
47
+ price: '$0.01',
48
+ payTo: '0xYourWallet...',
49
+ asset: USDC, // settlement token (default: auto-detect)
45
50
  });
46
51
 
47
- x402.onAfterPaymentCreation(async (ctx) => {
48
- console.log('Payment created:', ctx.paymentPayload);
49
- });
50
- ```
51
-
52
- ### Advanced (manual setup)
53
-
54
- ```typescript
55
- 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);
52
+ export const middleware = paymentProxy(
53
+ {
54
+ '/api/premium': {
55
+ accepts: [
56
+ { scheme: 'exact', network: 'eip155:8453', price: '$0.01', payTo: '0xYourWallet...' },
57
+ ...escrowAccepts,
58
+ ],
59
+ },
60
+ },
61
+ server
62
+ );
63
63
  ```
64
64
 
65
- ## Server Usage
66
-
67
- For APIs accepting payments. Config is auto-discovered from facilitator.
68
-
69
- ### Express
65
+ ### Express with paymentMiddleware
70
66
 
71
67
  ```typescript
72
- import { x402ResourceServer, HTTPFacilitatorClient } from '@x402/core/server';
73
68
  import { paymentMiddleware } from '@x402/express';
69
+ import { x402ResourceServer, HTTPFacilitatorClient } from '@x402/core/server';
74
70
  import { EscrowScheme } from '@agentokratia/x402-escrow/server';
75
71
 
76
72
  const facilitator = new HTTPFacilitatorClient({
@@ -78,81 +74,219 @@ const facilitator = new HTTPFacilitatorClient({
78
74
  createAuthHeaders: async () => ({
79
75
  verify: { Authorization: `Bearer ${process.env.X402_API_KEY}` },
80
76
  settle: { Authorization: `Bearer ${process.env.X402_API_KEY}` },
81
- supported: {},
82
77
  }),
83
78
  });
84
79
 
85
- const server = new x402ResourceServer(facilitator).register('eip155:84532', new EscrowScheme());
80
+ const escrow = new EscrowScheme({ facilitator });
81
+ const accepts = await escrow.buildAccepts({
82
+ network: 'eip155:8453',
83
+ price: '$0.01',
84
+ payTo: '0xYourWallet',
85
+ });
86
86
 
87
87
  app.use(
88
88
  paymentMiddleware(
89
89
  {
90
- 'GET /api/premium': {
91
- accepts: {
92
- scheme: 'escrow',
93
- price: '$0.01',
94
- network: 'eip155:84532',
95
- payTo: ownerAddress,
96
- },
97
- },
90
+ 'GET /api/analyze': { accepts },
98
91
  },
99
- server
92
+ new x402ResourceServer(facilitator)
100
93
  )
101
94
  );
102
95
  ```
103
96
 
104
- ### Next.js
97
+ ### Dynamic Pricing (Custom API Routes)
98
+
99
+ For endpoints with per-request pricing (like tip-app):
100
+
101
+ ```typescript
102
+ import { NextRequest, NextResponse } from 'next/server';
103
+ import { HTTPFacilitatorClient } from '@x402/core/server';
104
+ import { EscrowScheme, preprocessSwapPayload } from '@agentokratia/x402-escrow/server';
105
+
106
+ const facilitator = new HTTPFacilitatorClient({
107
+ /* config */
108
+ });
109
+ const escrow = new EscrowScheme({ facilitator, apiKey: process.env.X402_API_KEY });
110
+
111
+ export async function GET(request: NextRequest) {
112
+ const amount = request.nextUrl.searchParams.get('amount');
113
+ const recipient = request.nextUrl.searchParams.get('to');
114
+ const paymentSignature = request.headers.get('payment-signature');
115
+
116
+ if (!paymentSignature) {
117
+ // Fetch fresh DEX quotes with buildAcceptsResolved
118
+ const accepts = await escrow.buildAcceptsResolved({
119
+ network: 'eip155:8453',
120
+ price: `$${amount}`,
121
+ payTo: recipient,
122
+ });
123
+
124
+ const requirements = accepts.map((a) => ({
125
+ scheme: a.scheme,
126
+ network: a.network,
127
+ asset: a.price.asset,
128
+ amount: a.price.amount,
129
+ payTo: a.payTo,
130
+ maxTimeoutSeconds: 600,
131
+ extra: a.price.extra || {},
132
+ }));
133
+
134
+ const response = NextResponse.json({ message: 'Payment required' }, { status: 402 });
135
+ response.headers.set(
136
+ 'PAYMENT-REQUIRED',
137
+ Buffer.from(JSON.stringify(requirements)).toString('base64')
138
+ );
139
+ return response;
140
+ }
141
+
142
+ // Process payment
143
+ const payload = JSON.parse(Buffer.from(paymentSignature, 'base64').toString());
144
+ const processed = preprocessSwapPayload({ x402Version: 2, ...payload });
145
+
146
+ const verifyResult = await facilitator.verify(processed, processed.accepted);
147
+ if (!verifyResult.isValid) {
148
+ return NextResponse.json({ error: verifyResult.invalidReason }, { status: 402 });
149
+ }
150
+
151
+ const settleResult = await facilitator.settle(processed, processed.accepted);
152
+ return NextResponse.json({ success: true, transaction: settleResult.transaction });
153
+ }
154
+ ```
155
+
156
+ ## Client Integration
157
+
158
+ ### Balance-Aware Token Selection (Recommended)
105
159
 
106
160
  ```typescript
107
- import { paymentProxy } from '@x402/next';
108
- import { EscrowScheme } from '@agentokratia/x402-escrow/server';
161
+ import { wrapFetchWithPayment, x402Client } from '@x402/fetch';
162
+ import { ExactEvmScheme } from '@x402/evm/exact/client';
163
+ import { createWalletClient, createPublicClient, http } from 'viem';
164
+ import { privateKeyToAccount } from 'viem/accounts';
165
+ import { base } from 'viem/chains';
166
+ import {
167
+ EscrowScheme,
168
+ createBalanceSelector,
169
+ preferTokenPolicy,
170
+ } from '@agentokratia/x402-escrow/client';
171
+
172
+ const WETH = '0x4200000000000000000000000000000000000006';
173
+ const USDC = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
174
+
175
+ const account = privateKeyToAccount(process.env.PRIVATE_KEY);
176
+
177
+ const walletClient = createWalletClient({
178
+ account,
179
+ chain: base,
180
+ transport: http(),
181
+ });
109
182
 
110
- const server = new x402ResourceServer(facilitator).register('eip155:84532', new EscrowScheme());
183
+ const publicClient = createPublicClient({
184
+ chain: base,
185
+ transport: http(),
186
+ });
111
187
 
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
- );
188
+ // Balance-aware: auto-picks USDC (gasless) or WETH/DAI (swap)
189
+ const client = new x402Client(createBalanceSelector(publicClient, account.address))
190
+ .register('eip155:8453', new ExactEvmScheme(account))
191
+ .register('eip155:8453', new EscrowScheme(walletClient))
192
+ .registerPolicy(preferTokenPolicy([WETH, USDC]));
193
+
194
+ const paidFetch = wrapFetchWithPayment(fetch, client);
195
+
196
+ const res = await paidFetch('https://api.example.com/premium');
197
+ const data = await res.json();
198
+ ```
199
+
200
+ ### Simple Setup (Browser with wagmi)
201
+
202
+ ```typescript
203
+ import { wrapFetchWithPayment, x402Client } from '@x402/fetch';
204
+ import { ExactEvmScheme } from '@x402/evm/exact/client';
205
+ import { EscrowScheme } from '@agentokratia/x402-escrow/client';
206
+
207
+ // With wagmi's useWalletClient
208
+ const { data: walletClient } = useWalletClient();
209
+
210
+ const signer = {
211
+ address: walletClient.account.address,
212
+ signTypedData: (msg) => walletClient.signTypedData({ account: walletClient.account, ...msg }),
213
+ };
214
+
215
+ const client = new x402Client()
216
+ .register('eip155:8453', new ExactEvmScheme(signer))
217
+ .register('eip155:8453', new EscrowScheme(walletClient));
218
+
219
+ const paidFetch = wrapFetchWithPayment(fetch, client);
220
+ const res = await paidFetch('https://api.example.com/premium');
120
221
  ```
121
222
 
122
223
  ## How It Works
123
224
 
124
225
  ```
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
226
+ Client Server Facilitator
227
+ │ │ │
228
+ GET /api/resource │ │
229
+ │──────────────────────────────>│ │
230
+ │ │ buildAccepts() │
231
+ │ │─────────────────────────────>│
232
+ │ │ (fetches quotes for swaps) │
233
+ │ │<─────────────────────────────│
234
+ │ 402 + PAYMENT-REQUIRED │ │
235
+ │<──────────────────────────────│ │
236
+ │ │ │
237
+ │ User selects token (WETH) │ │
238
+ │ Signs EIP-712 Permit2 │ │
239
+ │ │ │
240
+ │ GET + PAYMENT-SIGNATURE │ │
241
+ │──────────────────────────────>│ │
242
+ │ │ verify() + settle() │
243
+ │ │─────────────────────────────>│
244
+ │ │ (executes swap on-chain) │
245
+ │ │<─────────────────────────────│
246
+ │ 200 + transaction hash │ │
247
+ │<──────────────────────────────│ │
130
248
  ```
131
249
 
132
250
  ## Networks
133
251
 
134
- | Network | Chain ID | Escrow Contract |
135
- | ------------ | -------- | -------------------------------------------- |
136
- | Base Mainnet | 8453 | `0xbDEa0d1BCc5966192b070fDF62ab4eF5B4420Cff` |
137
- | Base Sepolia | 84532 | `0xbDEa0d1BCc5966192b070fDF62ab4eF5B4420Cff` |
252
+ | Network | Chain ID | Facilitator |
253
+ | ------------ | -------- | -------------------------------------- |
254
+ | Base Mainnet | 8453 | `https://facilitator.agentokratia.com` |
255
+ | Base Sepolia | 84532 | `https://facilitator.agentokratia.com` |
138
256
 
139
257
  ## API
140
258
 
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 |
259
+ ### Client Exports
260
+
261
+ | Export | Description |
262
+ | ------------------------- | ------------------------------------------------- |
263
+ | `EscrowScheme` | Client scheme for x402Client (takes WalletClient) |
264
+ | `createBalanceSelector` | Async selector that checks on-chain balances |
265
+ | `preferTokenPolicy` | Sync policy that reorders by token preference |
266
+ | `checkBalance` | Utility for custom balance checks |
267
+ | `signERC3009` | Sign ERC-3009 authorization |
268
+ | `signPermit2TransferFrom` | Sign Permit2 transfer |
269
+ | `computePaymentNonce` | Derive deterministic nonce from payment params |
270
+ | `PERMIT2_ADDRESS` | Universal Permit2 contract address |
271
+ | `decompressCalldata` | Decompress gzipped aggregator calldata |
272
+
273
+ ### Server Exports
274
+
275
+ | Export | Description |
276
+ | ----------------------- | ------------------------------------------------- |
277
+ | `EscrowScheme` | Server scheme for x402ResourceServer |
278
+ | `HTTPFacilitatorClient` | Re-export from @x402/core/server |
279
+ | `preprocessSwapPayload` | Decompress swap calldata before facilitator calls |
280
+ | `compressCalldata` | Compress aggregator calldata (gzip) |
281
+
282
+ ## Supported Input Tokens (Base Mainnet)
283
+
284
+ | Token | Address |
285
+ | ----- | -------------------------------------------- |
286
+ | USDC | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` |
287
+ | WETH | `0x4200000000000000000000000000000000000006` |
288
+ | DAI | `0x50c5725949a6f0c72e6c4a641f24049a917db0cb` |
289
+ | USDT | `0xfde4c96c8593536e31f229ea8f37b2ada2699bb2` |
156
290
 
157
291
  ## License
158
292
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentokratia/x402-escrow",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
4
4
  "description": "Escrow payment scheme for x402 protocol - session-based payments for high-frequency APIs",
5
5
  "license": "MIT",
6
6
  "author": "Agentokratia",