@infiniteezverse/monskills-ezpath 0.1.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/.well-known/agent.json +241 -0
- package/.well-known/openapi.json +310 -0
- package/ARENA.md +551 -0
- package/DEPLOYMENT.md +460 -0
- package/LAUNCH.md +345 -0
- package/LICENSE +24 -0
- package/MANIFEST.md +356 -0
- package/MONAD.md +375 -0
- package/QUICKSTART.md +378 -0
- package/README.md +88 -0
- package/X402_IMPLEMENTATION.md +468 -0
- package/dist/agents/arena-agent.d.ts +166 -0
- package/dist/agents/arena-agent.d.ts.map +1 -0
- package/dist/agents/arena-agent.js +267 -0
- package/dist/agents/arena-agent.js.map +1 -0
- package/dist/agents/bankroll-manager.d.ts +114 -0
- package/dist/agents/bankroll-manager.d.ts.map +1 -0
- package/dist/agents/bankroll-manager.js +293 -0
- package/dist/agents/bankroll-manager.js.map +1 -0
- package/dist/agents/index.d.ts +9 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +29 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/strategy.d.ts +48 -0
- package/dist/agents/strategy.d.ts.map +1 -0
- package/dist/agents/strategy.js +265 -0
- package/dist/agents/strategy.js.map +1 -0
- package/dist/agents/types.d.ts +197 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/types.js +7 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/config/monad.d.ts +175 -0
- package/dist/config/monad.d.ts.map +1 -0
- package/dist/config/monad.js +222 -0
- package/dist/config/monad.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +153 -0
- package/dist/index.js.map +1 -0
- package/dist/payments/eip3009.d.ts +210 -0
- package/dist/payments/eip3009.d.ts.map +1 -0
- package/dist/payments/eip3009.js +261 -0
- package/dist/payments/eip3009.js.map +1 -0
- package/dist/payments/index.d.ts +8 -0
- package/dist/payments/index.d.ts.map +1 -0
- package/dist/payments/index.js +25 -0
- package/dist/payments/index.js.map +1 -0
- package/dist/payments/quote-execution.d.ts +76 -0
- package/dist/payments/quote-execution.d.ts.map +1 -0
- package/dist/payments/quote-execution.js +285 -0
- package/dist/payments/quote-execution.js.map +1 -0
- package/dist/types/ezpath.d.ts +65 -0
- package/dist/types/ezpath.d.ts.map +1 -0
- package/dist/types/ezpath.js +7 -0
- package/dist/types/ezpath.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
# X402 EIP-3009 Payment Implementation
|
|
2
|
+
|
|
3
|
+
Complete implementation of X402 payment protocol for EZ-Path quote settlement using EIP-3009 TransferWithAuthorization.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
X402 is an HTTP protocol for micro-payments that enables agents to pay for on-demand services. EZ-Path uses X402 with EIP-3009 to handle payment for DEX routing quotes.
|
|
8
|
+
|
|
9
|
+
**Flow:**
|
|
10
|
+
```
|
|
11
|
+
Agent Request
|
|
12
|
+
↓
|
|
13
|
+
GET /api/v1/quote (no auth)
|
|
14
|
+
↓
|
|
15
|
+
HTTP 402 Payment Required (with fee details)
|
|
16
|
+
↓
|
|
17
|
+
Create EIP-3009 TransferWithAuthorization message
|
|
18
|
+
↓
|
|
19
|
+
Sign with agent's private key
|
|
20
|
+
↓
|
|
21
|
+
Build X-Payment header (base64 encoded)
|
|
22
|
+
↓
|
|
23
|
+
GET /api/v1/quote + X-Payment header
|
|
24
|
+
↓
|
|
25
|
+
HTTP 200 OK (with settlement_tx)
|
|
26
|
+
↓
|
|
27
|
+
Quote + settlement transaction ready
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Architecture
|
|
31
|
+
|
|
32
|
+
### Module Structure
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
src/payments/
|
|
36
|
+
├── eip3009.ts # EIP-3009 signing and USDC domain
|
|
37
|
+
├── quote-execution.ts # Quote executor with X402 retry logic
|
|
38
|
+
└── index.ts # Barrel export
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Key Components
|
|
42
|
+
|
|
43
|
+
#### 1. EIP-3009 Message Creation (`eip3009.ts`)
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// Create authorization message
|
|
47
|
+
const authMessage = createAuthorizationMessage(
|
|
48
|
+
agentAddress, // Who is paying
|
|
49
|
+
TOLL_ADDRESS, // Who receives payment
|
|
50
|
+
BigInt(30000), // Amount (atomic USDC)
|
|
51
|
+
300 // Validity (seconds)
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
// Result:
|
|
55
|
+
{
|
|
56
|
+
from: '0x...', // Agent address
|
|
57
|
+
to: '0x13dD...', // EZ-Path toll address
|
|
58
|
+
value: '30000', // 0.03 USDC
|
|
59
|
+
validAfter: 0, // Valid immediately
|
|
60
|
+
validBefore: 1234567890, // Expires in 5 minutes
|
|
61
|
+
nonce: '0x...' // Random 32 bytes
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
#### 2. EIP-712 Signing (`eip3009.ts`)
|
|
66
|
+
|
|
67
|
+
Messages are signed using EIP-712 typed data:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
const signature = await signer.signTypedData(
|
|
71
|
+
{
|
|
72
|
+
name: 'USD Coin',
|
|
73
|
+
version: '2',
|
|
74
|
+
chainId: 8453,
|
|
75
|
+
verifyingContract: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
TransferWithAuthorization: [
|
|
79
|
+
{ name: 'from', type: 'address' },
|
|
80
|
+
{ name: 'to', type: 'address' },
|
|
81
|
+
{ name: 'value', type: 'uint256' },
|
|
82
|
+
{ name: 'validAfter', type: 'uint256' },
|
|
83
|
+
{ name: 'validBefore', type: 'uint256' },
|
|
84
|
+
{ name: 'nonce', type: 'bytes32' },
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
authMessage
|
|
88
|
+
);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
#### 3. X402 Payment Header (`eip3009.ts`)
|
|
92
|
+
|
|
93
|
+
The signature and message are packaged into an HTTP header:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
const header = createX402PaymentHeader({
|
|
97
|
+
signature, // EIP-712 signature
|
|
98
|
+
authorization: authMessage,
|
|
99
|
+
quote_issued_at: now,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Header is base64-encoded JSON:
|
|
103
|
+
// X-Payment: eyJwYXlsb2FkIjp7InNpZ25hdHVyZSI6IjB4Li4uIn19
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### 4. Quote Execution (`quote-execution.ts`)
|
|
107
|
+
|
|
108
|
+
The `QuoteExecutor` class handles the complete flow:
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
const executor = new QuoteExecutor(
|
|
112
|
+
'https://ezpath.myezverse.xyz',
|
|
113
|
+
{
|
|
114
|
+
agentAddress: '0x...',
|
|
115
|
+
signingFunction: async (message) => {
|
|
116
|
+
return await signer.signTypedData(...);
|
|
117
|
+
},
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const result = await executor.executeQuote({
|
|
122
|
+
chain: 'base',
|
|
123
|
+
sellToken: USDC,
|
|
124
|
+
buyToken: WETH,
|
|
125
|
+
sellAmount: '1000000',
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
if (result.success) {
|
|
129
|
+
console.log('Bought:', result.data.buyAmount);
|
|
130
|
+
console.log('Settlement:', result.data.settlement_tx);
|
|
131
|
+
} else if (result.paymentRequired) {
|
|
132
|
+
console.log('Payment needed:', result.estimatedFee.usd, 'USDC');
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Integration Guide
|
|
137
|
+
|
|
138
|
+
### 1. Setup with ethers.js
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
import { ethers } from 'ethers';
|
|
142
|
+
import { QuoteExecutor } from '@infiniteezverse/monskills-ezpath/dist/payments';
|
|
143
|
+
|
|
144
|
+
// Create signer
|
|
145
|
+
const privateKey = process.env.AGENT_PRIVATE_KEY;
|
|
146
|
+
const signer = new ethers.Wallet(privateKey);
|
|
147
|
+
|
|
148
|
+
// Create executor
|
|
149
|
+
const executor = new QuoteExecutor('https://ezpath.myezverse.xyz', {
|
|
150
|
+
agentAddress: signer.address,
|
|
151
|
+
signingFunction: async (message) => {
|
|
152
|
+
return await signer.signTypedData(
|
|
153
|
+
USDC_BASE_DOMAIN,
|
|
154
|
+
TRANSFER_WITH_AUTHORIZATION_TYPE,
|
|
155
|
+
message
|
|
156
|
+
);
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 2. Execute Quote with Payment
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
// Get quote with automatic payment handling
|
|
165
|
+
const result = await executor.executeQuote({
|
|
166
|
+
chain: 'base',
|
|
167
|
+
sellToken: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
168
|
+
buyToken: '0x4200000000000000000000000000000000000006',
|
|
169
|
+
sellAmount: '1000000',
|
|
170
|
+
slippagePercentage: 0.5,
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Handle result
|
|
174
|
+
if (result.success) {
|
|
175
|
+
// Quote executed successfully
|
|
176
|
+
console.log(`Bought: ${result.data.buyAmount} WETH`);
|
|
177
|
+
console.log(`Best venue: ${result.data.routingEngine}`);
|
|
178
|
+
|
|
179
|
+
// Settlement transaction is available
|
|
180
|
+
if (result.data.settlement_tx) {
|
|
181
|
+
await verifySettlementOnChain(result.data.settlement_tx);
|
|
182
|
+
}
|
|
183
|
+
} else if (result.paymentRequired) {
|
|
184
|
+
// Payment was required but failed
|
|
185
|
+
console.log(`Payment failed: ${result.error}`);
|
|
186
|
+
console.log(`Fee: ${result.estimatedFee.usd} USDC`);
|
|
187
|
+
console.log(`Retries: ${result.retries}`);
|
|
188
|
+
} else {
|
|
189
|
+
// Other error
|
|
190
|
+
console.log(`Error: ${result.error}`);
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### 3. With Arena Agent
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
import { Agent } from '@infiniteezverse/monskills-ezpath/dist/agents';
|
|
198
|
+
import { QuoteExecutor } from '@infiniteezverse/monskills-ezpath/dist/payments';
|
|
199
|
+
|
|
200
|
+
// Create agent
|
|
201
|
+
const agent = new Agent({
|
|
202
|
+
// ... agent config
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// Create executor with agent's signer
|
|
206
|
+
const executor = new QuoteExecutor('https://ezpath.myezverse.xyz', {
|
|
207
|
+
agentAddress: agent.address,
|
|
208
|
+
signingFunction: agent.signer.signTypedData.bind(agent.signer),
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// Get quotes for bankroll valuation
|
|
212
|
+
const quote = await executor.executeQuote({
|
|
213
|
+
chain: 'base',
|
|
214
|
+
sellToken: agent.bankrollToken,
|
|
215
|
+
buyToken: USDC,
|
|
216
|
+
sellAmount: agent.currentBankroll.toString(),
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
if (quote.success) {
|
|
220
|
+
const bankrollValue = quote.data.buyAmount;
|
|
221
|
+
// Use for risk calculations
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Payment Tiers
|
|
226
|
+
|
|
227
|
+
### Free Tier (Basic)
|
|
228
|
+
- **Cost:** $0.03 USDC
|
|
229
|
+
- **Amount:** 30,000 atomic USDC
|
|
230
|
+
- **Features:** Direct 0x routing
|
|
231
|
+
- **Rate limit:** 120 requests/minute
|
|
232
|
+
|
|
233
|
+
### Resilient Tier
|
|
234
|
+
- **Cost:** $0.10 USDC
|
|
235
|
+
- **Amount:** 100,000 atomic USDC
|
|
236
|
+
- **Features:** 4-venue racing
|
|
237
|
+
- **Rate limit:** 500 requests/minute
|
|
238
|
+
|
|
239
|
+
### Institutional Tier
|
|
240
|
+
- **Cost:** $0.50 USDC
|
|
241
|
+
- **Amount:** 500,000 atomic USDC
|
|
242
|
+
- **Features:** Full 10-venue racing
|
|
243
|
+
- **Rate limit:** 1000 requests/minute
|
|
244
|
+
|
|
245
|
+
### Selecting Tier
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
import { getTierByAmount, PAYMENT_TIERS } from '@infiniteezverse/monskills-ezpath/dist/payments';
|
|
249
|
+
|
|
250
|
+
// Get tier by amount
|
|
251
|
+
const tier = getTierByAmount(BigInt(30000)); // 'basic'
|
|
252
|
+
const tier = getTierByAmount(BigInt(100000)); // 'resilient'
|
|
253
|
+
const tier = getTierByAmount(BigInt(500000)); // 'institutional'
|
|
254
|
+
|
|
255
|
+
// Get tier config
|
|
256
|
+
const basicTier = PAYMENT_TIERS.basic;
|
|
257
|
+
console.log(`Cost: $${basicTier.costUSDC}`);
|
|
258
|
+
console.log(`Atomic: ${basicTier.costAtomic.toString()}`);
|
|
259
|
+
console.log(`Features: ${basicTier.description}`);
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Error Handling
|
|
263
|
+
|
|
264
|
+
### HTTP 402 Payment Required
|
|
265
|
+
|
|
266
|
+
When the endpoint requires payment, it returns HTTP 402 with fee details:
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
// Handle 402 response
|
|
270
|
+
if (result.paymentRequired) {
|
|
271
|
+
console.log(`Payment required: ${result.error}`);
|
|
272
|
+
console.log(`Fee: ${result.estimatedFee.usd} USDC`);
|
|
273
|
+
console.log(`Atomic: ${result.estimatedFee.atomic}`);
|
|
274
|
+
|
|
275
|
+
// Agent can:
|
|
276
|
+
// 1. Sign and retry (automatic in QuoteExecutor)
|
|
277
|
+
// 2. Cancel the operation
|
|
278
|
+
// 3. Upgrade to paid tier
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Signing Failure
|
|
283
|
+
|
|
284
|
+
If the agent cannot sign the message:
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
// Result includes error details
|
|
288
|
+
if (!result.success && result.paymentRequired) {
|
|
289
|
+
if (result.error.includes('sign')) {
|
|
290
|
+
console.log('Signing failed - check private key');
|
|
291
|
+
console.log('Ensure signer has signing capability');
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Expired Authorization
|
|
297
|
+
|
|
298
|
+
Authorization messages have a 5-minute validity window:
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
// If message expires before broadcast:
|
|
302
|
+
const authMessage = createAuthorizationMessage(
|
|
303
|
+
agentAddress,
|
|
304
|
+
TOLL_ADDRESS,
|
|
305
|
+
amount,
|
|
306
|
+
300 // Increase validity if needed
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
// Validation will catch expired messages:
|
|
310
|
+
const validation = validateAuthorizationMessage(authMessage);
|
|
311
|
+
if (!validation.valid) {
|
|
312
|
+
console.log(`Error: ${validation.error}`);
|
|
313
|
+
// Create new message and retry
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## Security Considerations
|
|
318
|
+
|
|
319
|
+
### Private Key Management
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
// ✅ Good: Load from secure environment variable
|
|
323
|
+
const privateKey = process.env.AGENT_PRIVATE_KEY;
|
|
324
|
+
const signer = new ethers.Wallet(privateKey);
|
|
325
|
+
|
|
326
|
+
// ❌ Bad: Hardcoded private key
|
|
327
|
+
const signer = new ethers.Wallet('0x123...');
|
|
328
|
+
|
|
329
|
+
// ✅ Better: Use secrets manager
|
|
330
|
+
const privateKey = await secretsManager.getSecret('AGENT_PRIVATE_KEY');
|
|
331
|
+
const signer = new ethers.Wallet(privateKey);
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Nonce Randomness
|
|
335
|
+
|
|
336
|
+
Each authorization message must have a random nonce to prevent replay attacks:
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
// createAuthorizationMessage uses crypto.randomBytes(32)
|
|
340
|
+
// This is cryptographically secure
|
|
341
|
+
|
|
342
|
+
// Verify nonce uniqueness
|
|
343
|
+
const nonce = authMessage.nonce;
|
|
344
|
+
// Should verify nonce hasn't been used before
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Validity Window
|
|
348
|
+
|
|
349
|
+
Authorization is only valid during a specific time window:
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
// Message created at 12:00:00
|
|
353
|
+
// validAfter: 0 (immediately)
|
|
354
|
+
// validBefore: 12:05:00 (5 minutes)
|
|
355
|
+
|
|
356
|
+
// If broadcast after 12:05:00: invalid
|
|
357
|
+
// EIP-3009 validation will reject it
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### USDC Domain Verification
|
|
361
|
+
|
|
362
|
+
The domain separator must match the contract:
|
|
363
|
+
|
|
364
|
+
```typescript
|
|
365
|
+
// For USDC v2 on Base: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
|
|
366
|
+
// Different address = different domain = invalid signature
|
|
367
|
+
|
|
368
|
+
// Always verify:
|
|
369
|
+
// - Correct USDC address
|
|
370
|
+
// - Correct chain ID (8453 for Base)
|
|
371
|
+
// - Correct contract version (v2)
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## Troubleshooting
|
|
375
|
+
|
|
376
|
+
### "Payment signature is invalid"
|
|
377
|
+
|
|
378
|
+
**Cause:** Signature was computed with wrong domain or message
|
|
379
|
+
|
|
380
|
+
**Solution:**
|
|
381
|
+
```typescript
|
|
382
|
+
// Verify domain matches USDC
|
|
383
|
+
console.log(USDC_BASE_DOMAIN.verifyingContract);
|
|
384
|
+
// Should be: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
|
|
385
|
+
|
|
386
|
+
// Verify chain ID
|
|
387
|
+
console.log(USDC_BASE_DOMAIN.chainId);
|
|
388
|
+
// Should be: 8453 (Base)
|
|
389
|
+
|
|
390
|
+
// Re-sign with correct domain:
|
|
391
|
+
const signature = await signer.signTypedData(
|
|
392
|
+
USDC_BASE_DOMAIN,
|
|
393
|
+
TRANSFER_WITH_AUTHORIZATION_TYPE,
|
|
394
|
+
message
|
|
395
|
+
);
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### "Authorization expired"
|
|
399
|
+
|
|
400
|
+
**Cause:** Message validBefore has passed
|
|
401
|
+
|
|
402
|
+
**Solution:**
|
|
403
|
+
```typescript
|
|
404
|
+
// Create new message with longer validity
|
|
405
|
+
const message = createAuthorizationMessage(
|
|
406
|
+
from,
|
|
407
|
+
to,
|
|
408
|
+
amount,
|
|
409
|
+
600 // 10 minutes instead of 5
|
|
410
|
+
);
|
|
411
|
+
|
|
412
|
+
// Or check system time is correct:
|
|
413
|
+
console.log('Current time:', Date.now());
|
|
414
|
+
console.log('Valid before:', message.validBefore * 1000);
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### "Invalid nonce"
|
|
418
|
+
|
|
419
|
+
**Cause:** Nonce is not 32 random bytes
|
|
420
|
+
|
|
421
|
+
**Solution:**
|
|
422
|
+
```typescript
|
|
423
|
+
// Nonce must be exactly 66 characters: 0x + 64 hex chars
|
|
424
|
+
const nonce = message.nonce;
|
|
425
|
+
console.log(`Length: ${nonce.length}`); // Should be 66
|
|
426
|
+
console.log(`Prefix: ${nonce.substring(0, 2)}`); // Should be 0x
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## Production Checklist
|
|
430
|
+
|
|
431
|
+
- [ ] Private key loaded from secure source (not hardcoded)
|
|
432
|
+
- [ ] USDC domain verified (0x8335... on Base)
|
|
433
|
+
- [ ] Chain ID correct (8453 for Base)
|
|
434
|
+
- [ ] Signer has sufficient USDC balance for payment
|
|
435
|
+
- [ ] Error handling implemented for all failure cases
|
|
436
|
+
- [ ] Logging/monitoring for payment failures
|
|
437
|
+
- [ ] Rate limiting respected (120/minute for basic tier)
|
|
438
|
+
- [ ] Validity window set appropriately (300s minimum)
|
|
439
|
+
- [ ] Nonce is random for each message
|
|
440
|
+
- [ ] Settlement transaction verified on-chain
|
|
441
|
+
|
|
442
|
+
## Examples
|
|
443
|
+
|
|
444
|
+
Complete working examples in `/examples/`:
|
|
445
|
+
|
|
446
|
+
- **`x402-payment.ts`** — Full X402 payment flow with 8 examples
|
|
447
|
+
|
|
448
|
+
Run examples:
|
|
449
|
+
|
|
450
|
+
```bash
|
|
451
|
+
npm install
|
|
452
|
+
npx ts-node examples/x402-payment.ts
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
## References
|
|
456
|
+
|
|
457
|
+
- **EIP-3009:** https://eips.ethereum.org/EIPS/eip-3009
|
|
458
|
+
- **EIP-712:** https://eips.ethereum.org/EIPS/eip-712
|
|
459
|
+
- **X402 Spec:** https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/402
|
|
460
|
+
- **USDC Docs:** https://www.circle.com/en/usdc
|
|
461
|
+
- **Ethers.js:** https://docs.ethers.org/v6/
|
|
462
|
+
|
|
463
|
+
## Support
|
|
464
|
+
|
|
465
|
+
- 📖 Code: https://github.com/infiniteezverse/monskills-ezpath/src/payments/
|
|
466
|
+
- 💬 Discord: https://discord.gg/monad
|
|
467
|
+
- 🐦 Twitter: @infiniteezverse
|
|
468
|
+
- 🌐 EZ-Path: https://ezpath.myezverse.xyz
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Arena Agent
|
|
3
|
+
* Complete poker-style competition agent with bankroll management and strategy
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - Real-time bankroll valuation via EZ-Path
|
|
7
|
+
* - Risk of ruin calculations
|
|
8
|
+
* - Dynamic strategy selection
|
|
9
|
+
* - Tournament participation logic
|
|
10
|
+
* - Performance tracking
|
|
11
|
+
*/
|
|
12
|
+
import { ArenaAgent, AgentConfig, Tournament, DecisionContext, BankrollMetrics, StrategyRecommendation } from './types';
|
|
13
|
+
/**
|
|
14
|
+
* Arena Agent Implementation
|
|
15
|
+
*/
|
|
16
|
+
export declare class Agent implements ArenaAgent {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
address: `0x${string}`;
|
|
20
|
+
chain: 'base' | 'monad';
|
|
21
|
+
bankrollToken: `0x${string}`;
|
|
22
|
+
initialBankroll: bigint;
|
|
23
|
+
currentBankroll: bigint;
|
|
24
|
+
minimumBankroll: bigint;
|
|
25
|
+
skillLevel: 'beginner' | 'intermediate' | 'advanced' | 'expert';
|
|
26
|
+
strategy: 'aggressive' | 'balanced' | 'conservative' | 'adaptive';
|
|
27
|
+
aggressivenessLevel: number;
|
|
28
|
+
riskTolerance: number;
|
|
29
|
+
targetROI: number;
|
|
30
|
+
createdAt: number;
|
|
31
|
+
updatedAt: number;
|
|
32
|
+
metadata?: Record<string, any>;
|
|
33
|
+
private bankrollManager;
|
|
34
|
+
private tournamentEntry?;
|
|
35
|
+
constructor(config: AgentConfig);
|
|
36
|
+
/**
|
|
37
|
+
* Join a tournament
|
|
38
|
+
*/
|
|
39
|
+
joinTournament(tournament: Tournament, buyin: bigint): Promise<boolean>;
|
|
40
|
+
/**
|
|
41
|
+
* Exit tournament (busted or cashed)
|
|
42
|
+
*/
|
|
43
|
+
exitTournament(finishPosition: number, _finalStack: bigint, prize: bigint): void;
|
|
44
|
+
/**
|
|
45
|
+
* Get strategy recommendation
|
|
46
|
+
*/
|
|
47
|
+
getStrategyRecommendation(): Promise<StrategyRecommendation>;
|
|
48
|
+
/**
|
|
49
|
+
* Update strategy if recommended
|
|
50
|
+
*/
|
|
51
|
+
updateStrategyIfNeeded(): Promise<boolean>;
|
|
52
|
+
/**
|
|
53
|
+
* Make game decision given context
|
|
54
|
+
*/
|
|
55
|
+
makeDecision(context: Partial<DecisionContext>): {
|
|
56
|
+
action: "fold" | "check" | "call" | "raise" | "all-in";
|
|
57
|
+
confidence: number;
|
|
58
|
+
reasoning: string;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Get bankroll metrics
|
|
62
|
+
*/
|
|
63
|
+
getMetrics(): Promise<BankrollMetrics>;
|
|
64
|
+
/**
|
|
65
|
+
* Get agent status
|
|
66
|
+
*/
|
|
67
|
+
getStatus(): Promise<{
|
|
68
|
+
agent: {
|
|
69
|
+
id: string;
|
|
70
|
+
name: string;
|
|
71
|
+
address: `0x${string}`;
|
|
72
|
+
skillLevel: "beginner" | "intermediate" | "advanced" | "expert";
|
|
73
|
+
currentStrategy: "aggressive" | "balanced" | "conservative" | "adaptive";
|
|
74
|
+
};
|
|
75
|
+
bankroll: {
|
|
76
|
+
current: string;
|
|
77
|
+
initial: string;
|
|
78
|
+
inUSDC: string;
|
|
79
|
+
buyinsRemaining: string;
|
|
80
|
+
status: import("./types").BankrollStatus;
|
|
81
|
+
};
|
|
82
|
+
risk: {
|
|
83
|
+
riskOfRuin: string;
|
|
84
|
+
healthScore: number;
|
|
85
|
+
trend: "up" | "down" | "flat";
|
|
86
|
+
};
|
|
87
|
+
strategy: {
|
|
88
|
+
current: "aggressive" | "balanced" | "conservative" | "adaptive";
|
|
89
|
+
recommended: import("./types").StrategyMode;
|
|
90
|
+
confidence: string;
|
|
91
|
+
reasoning: string;
|
|
92
|
+
};
|
|
93
|
+
tournament: {
|
|
94
|
+
id: string;
|
|
95
|
+
stack: string;
|
|
96
|
+
handsPlayed: number;
|
|
97
|
+
active: boolean;
|
|
98
|
+
} | null;
|
|
99
|
+
actions: string;
|
|
100
|
+
}>;
|
|
101
|
+
/**
|
|
102
|
+
* Simulate a hand
|
|
103
|
+
*/
|
|
104
|
+
playHand(handType: string, stackSizeInBuyins: number): Promise<void>;
|
|
105
|
+
/**
|
|
106
|
+
* Check if should quit tournament early
|
|
107
|
+
*/
|
|
108
|
+
shouldQuitTournament(): boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Export agent state as JSON
|
|
111
|
+
*/
|
|
112
|
+
toJSON(): Promise<{
|
|
113
|
+
agent: {
|
|
114
|
+
id: string;
|
|
115
|
+
name: string;
|
|
116
|
+
address: `0x${string}`;
|
|
117
|
+
chain: "base" | "monad";
|
|
118
|
+
skillLevel: "beginner" | "intermediate" | "advanced" | "expert";
|
|
119
|
+
strategy: "aggressive" | "balanced" | "conservative" | "adaptive";
|
|
120
|
+
};
|
|
121
|
+
bankroll: {
|
|
122
|
+
current: string;
|
|
123
|
+
initial: string;
|
|
124
|
+
minimum: string;
|
|
125
|
+
};
|
|
126
|
+
metrics: BankrollMetrics;
|
|
127
|
+
status: {
|
|
128
|
+
agent: {
|
|
129
|
+
id: string;
|
|
130
|
+
name: string;
|
|
131
|
+
address: `0x${string}`;
|
|
132
|
+
skillLevel: "beginner" | "intermediate" | "advanced" | "expert";
|
|
133
|
+
currentStrategy: "aggressive" | "balanced" | "conservative" | "adaptive";
|
|
134
|
+
};
|
|
135
|
+
bankroll: {
|
|
136
|
+
current: string;
|
|
137
|
+
initial: string;
|
|
138
|
+
inUSDC: string;
|
|
139
|
+
buyinsRemaining: string;
|
|
140
|
+
status: import("./types").BankrollStatus;
|
|
141
|
+
};
|
|
142
|
+
risk: {
|
|
143
|
+
riskOfRuin: string;
|
|
144
|
+
healthScore: number;
|
|
145
|
+
trend: "up" | "down" | "flat";
|
|
146
|
+
};
|
|
147
|
+
strategy: {
|
|
148
|
+
current: "aggressive" | "balanced" | "conservative" | "adaptive";
|
|
149
|
+
recommended: import("./types").StrategyMode;
|
|
150
|
+
confidence: string;
|
|
151
|
+
reasoning: string;
|
|
152
|
+
};
|
|
153
|
+
tournament: {
|
|
154
|
+
id: string;
|
|
155
|
+
stack: string;
|
|
156
|
+
handsPlayed: number;
|
|
157
|
+
active: boolean;
|
|
158
|
+
} | null;
|
|
159
|
+
actions: string;
|
|
160
|
+
};
|
|
161
|
+
createdAt: number;
|
|
162
|
+
updatedAt: number;
|
|
163
|
+
}>;
|
|
164
|
+
}
|
|
165
|
+
export default Agent;
|
|
166
|
+
//# sourceMappingURL=arena-agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arena-agent.d.ts","sourceRoot":"","sources":["../../src/agents/arena-agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAmB,eAAe,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAIzI;;GAEG;AACH,qBAAa,KAAM,YAAW,UAAU;IAEtC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,aAAa,EAAE,KAAK,MAAM,EAAE,CAAC;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IAGxB,UAAU,EAAE,UAAU,GAAG,cAAc,GAAG,UAAU,GAAG,QAAQ,CAAC;IAChE,QAAQ,EAAE,YAAY,GAAG,UAAU,GAAG,cAAc,GAAG,UAAU,CAAC;IAClE,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAGlB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAG/B,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,eAAe,CAAC,CAAkB;gBAE9B,MAAM,EAAE,WAAW;IAsB/B;;OAEG;IACG,cAAc,CAAC,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAwD7E;;OAEG;IACH,cAAc,CACZ,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GACZ,IAAI;IAgCP;;OAEG;IACG,yBAAyB,IAAI,OAAO,CAAC,sBAAsB,CAAC;IAKlE;;OAEG;IACG,sBAAsB,IAAI,OAAO,CAAC,OAAO,CAAC;IAoBhD;;OAEG;IACH,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC;;;;;IAY9C;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,eAAe,CAAC;IAI5C;;OAEG;IACG,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA0Cf;;OAEG;IACG,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA+B1E;;OAEG;IACH,oBAAoB,IAAI,OAAO;IAa/B;;OAEG;IACG,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqBb;AAED,eAAe,KAAK,CAAC"}
|