Skip to content

Commit 8b12be2

Browse files
authored
Refactor facilitator v2 account (#142)
* Fix facilitator v2 init * Refactor facilitator v2 account * fixup * fix v2 settle * fix PaymentPayload * fixup
1 parent eb013e7 commit 8b12be2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+2126
-888
lines changed

facilitator/README.md

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,22 +58,24 @@ FACILITATOR_V2_STRICT_MODE=false # Allow both v1 and v2 formats
5858

5959
#### Network Formats
6060

61-
| Network | v1 Format | v2 Format (CAIP-2) |
62-
|---------|-----------|-------------------|
63-
| Base Sepolia | `base-sepolia` | `eip155:84532` |
64-
| Base Mainnet | `base` | `eip155:8453` |
65-
| X-Layer Testnet | `x-layer-testnet` | `eip155:1952` |
66-
| X-Layer Mainnet | `x-layer` | `eip155:196` |
67-
| BSC Testnet | `bsc-testnet` | `eip155:97` |
68-
| BSC Mainnet | `bsc` | `eip155:56` |
61+
| Network | v1 Format | v2 Format (CAIP-2) |
62+
| --------------- | ----------------- | ------------------ |
63+
| Base Sepolia | `base-sepolia` | `eip155:84532` |
64+
| Base Mainnet | `base` | `eip155:8453` |
65+
| X-Layer Testnet | `x-layer-testnet` | `eip155:1952` |
66+
| X-Layer Mainnet | `x-layer` | `eip155:196` |
67+
| BSC Testnet | `bsc-testnet` | `eip155:97` |
68+
| BSC Mainnet | `bsc` | `eip155:56` |
6969

7070
#### Version Dispatch Rules
7171

7272
1. **Client Request Format Detection**:
73+
7374
- If `network` matches CAIP-2 pattern (`eip155:*`) → Route to v2 stack
7475
- If `network` matches v1 pattern (human-readable) → Route to v1 stack
7576

7677
2. **Response Format**:
78+
7779
- `/supported` endpoint returns supported kinds for both versions
7880
- All other endpoints use the requested version's format
7981

@@ -1595,18 +1597,21 @@ This checklist helps you safely roll out v2 support while maintaining v1 compati
15951597
**☐ Staging Environment Testing**
15961598

15971599
1. **Enable Dual-Stack Mode**:
1600+
15981601
```env
15991602
FACILITATOR_ENABLE_V2=true
16001603
FACILITATOR_V2_STRICT_MODE=false
16011604
```
16021605

16031606
2. **Verify v1 Functionality**:
1607+
16041608
- Test all existing v1 clients work without changes
16051609
- Verify `/supported` returns both v1 and v2 kinds
16061610
- Test `/verify` and `/settle` with v1 network names
16071611
- Confirm SettlementRouter v1 flows work
16081612

16091613
3. **Test v2 Functionality**:
1614+
16101615
- Test `/supported` includes CAIP-2 networks
16111616
- Verify `/verify` and `/settle` with v2 CAIP-2 network identifiers
16121617
- Test SettlementRouter v2 flows
@@ -1621,6 +1626,7 @@ This checklist helps you safely roll out v2 support while maintaining v1 compati
16211626
**☐ Configuration Validation**
16221627

16231628
5. **Environment Variables**:
1629+
16241630
```env
16251631
# Dual-stack configuration
16261632
FACILITATOR_ENABLE_V2=true
@@ -1642,6 +1648,7 @@ This checklist helps you safely roll out v2 support while maintaining v1 compati
16421648
**☐ Client Compatibility**
16431649

16441650
7. **Update Client SDKs**:
1651+
16451652
- Update `@x402x/client` to latest version
16461653
- Test v1 client with dual-stack facilitator
16471654
- Test v2 client with dual-stack facilitator
@@ -1657,18 +1664,22 @@ This checklist helps you safely roll out v2 support while maintaining v1 compati
16571664
**☐ Blue-Green Deployment**
16581665

16591666
9. **Deploy with v1 Only**:
1667+
16601668
```env
16611669
FACILITATOR_ENABLE_V2=false # Start with v1 only
16621670
```
1671+
16631672
- Deploy new version with v2 code but disabled
16641673
- Monitor v1 functionality for regressions
16651674
- Verify all existing integrations work
16661675

16671676
10. **Enable Dual-Stack Mode**:
1677+
16681678
```env
16691679
FACILITATOR_ENABLE_V2=true
16701680
FACILITATOR_V2_STRICT_MODE=false
16711681
```
1682+
16721683
- Update environment to enable v2 support
16731684
- Monitor `/supported` endpoint includes both versions
16741685
- Test v2 functionality with canary clients
@@ -1682,6 +1693,7 @@ This checklist helps you safely roll out v2 support while maintaining v1 compati
16821693
**☐ Validation**
16831694

16841695
12. **End-to-End Testing**:
1696+
16851697
- Test complete payment flows for both versions
16861698
- Verify SettlementRouter works for both versions
16871699
- Test error scenarios and recovery
@@ -1698,6 +1710,7 @@ This checklist helps you safely roll out v2 support while maintaining v1 compati
16981710
**☐ Monitoring & Maintenance**
16991711

17001712
14. **Metrics Dashboard**:
1713+
17011714
- Track v1 vs v2 usage over time
17021715
- Monitor error rates by version
17031716
- Alert on version detection failures
@@ -1712,21 +1725,25 @@ This checklist helps you safely roll out v2 support while maintaining v1 compati
17121725
#### Troubleshooting Guide
17131726

17141727
**Version Detection Issues**:
1728+
17151729
- Check network format matches expected patterns
17161730
- Verify `FACILITATOR_ENABLE_V2` is set correctly
17171731
- Review logs for version routing errors
17181732

17191733
**Network Mapping Problems**:
1734+
17201735
- Validate CAIP-2 identifiers are correct
17211736
- Check SettlementRouter address consistency
17221737
- Test both network formats work
17231738

17241739
**Performance Degradation**:
1740+
17251741
- Monitor request latency by version
17261742
- Check for version detection overhead
17271743
- Optimize dual-stack routing if needed
17281744

17291745
**Rollback Procedure**:
1746+
17301747
1. Set `FACILITATOR_ENABLE_V2=false` to disable v2
17311748
2. Restart service with v1-only configuration
17321749
3. Verify v1 functionality restored
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
# V2 AccountPool Refactor - Implementation Summary
2+
3+
## Overview
4+
5+
Successfully refactored the x402 Facilitator V2 implementation to use the shared V1 AccountPool, enabling V2 to benefit from multi-account support, queue management, and duplicate payer detection.
6+
7+
## Motivation
8+
9+
**Before:**
10+
11+
- V1 used AccountPool with multi-account support (`EVM_PRIVATE_KEY_1`, `EVM_PRIVATE_KEY_2`, etc.)
12+
- V2 only used a single `EVM_PRIVATE_KEY`
13+
- V2 had no queue management or duplicate payer detection
14+
- V2 created its own wallet clients independently
15+
16+
**After:**
17+
18+
- Both V1 and V2 use the same shared AccountPool
19+
- V2 benefits from all AccountPool features:
20+
- Multi-account parallel processing
21+
- Serial queue per account (to avoid nonce conflicts)
22+
- Round-robin account selection
23+
- Duplicate payer detection (to prevent double-spending)
24+
- Queue depth limits
25+
26+
## Architecture Changes
27+
28+
### Before
29+
30+
```
31+
V1: Request → PoolManager → AccountPool → v1Settle
32+
V2: Request → RouterSettlementFacilitator (single key) → v2Settle
33+
```
34+
35+
### After
36+
37+
```
38+
V1: Request → PoolManager → AccountPool → v1Settle
39+
V2: Request → PoolManager → AccountPool → v2Settle (new)
40+
```
41+
42+
## Implementation Details
43+
44+
### 1. Extended V2 Settlement API
45+
46+
**File:** `typescript/packages/facilitator_v2/src/settlement.ts`
47+
48+
Added `executeSettlementWithWalletClient()` function to accept external WalletClient:
49+
50+
```typescript
51+
export async function executeSettlementWithWalletClient(
52+
walletClient: WalletClient,
53+
publicClient: PublicClient,
54+
paymentRequirements: any,
55+
paymentPayload: any,
56+
config: { ... }
57+
): Promise<SettleResponse>
58+
```
59+
60+
This allows V2 settlement to use signers provided by AccountPool.
61+
62+
### 2. Refactored VersionDispatcher
63+
64+
**File:** `facilitator/src/version-dispatcher.ts`
65+
66+
Modified `settleV2()` to execute through AccountPool:
67+
68+
```typescript
69+
private async settleV2(...): Promise<SettleResponse> {
70+
// Get account pool (same as V1)
71+
const accountPool = this.deps.poolManager.getPool(network);
72+
73+
// Execute in account pool with payer address for duplicate detection
74+
return accountPool.execute(async (signer) => {
75+
// Use signer from AccountPool to execute V2 settlement
76+
return executeSettlementWithWalletClient(signer, ...);
77+
}, paymentPayload.payer);
78+
}
79+
```
80+
81+
Key changes:
82+
83+
- Removed separate `v2Facilitator` instance
84+
- V2 now uses AccountPool.execute() like V1
85+
- Passes payer address for duplicate detection
86+
- Uses dynamic imports for V2 modules
87+
88+
### 3. Simplified Configuration
89+
90+
**File:** `facilitator/src/config.ts`
91+
92+
Removed V2-specific private key configuration:
93+
94+
```typescript
95+
export interface V2Config {
96+
enabled: boolean;
97+
// Removed: signer?: string;
98+
// Removed: privateKey?: string;
99+
allowedRouters?: Record<string, string[]>;
100+
}
101+
```
102+
103+
V2 now uses the shared `evmPrivateKeys` configuration.
104+
105+
### 4. Updated Application Initialization
106+
107+
**Files:**
108+
109+
- `facilitator/src/index.ts`
110+
- `facilitator/src/routes/index.ts`
111+
- `facilitator/src/routes/settle.ts`
112+
- `facilitator/src/routes/verify.ts`
113+
114+
Removed passing of `v2Signer` and `v2PrivateKey` to routes and VersionDispatcher.
115+
116+
### 5. Added Comprehensive Tests
117+
118+
**File:** `facilitator/test/unit/version-dispatcher-v2-accountpool.test.ts`
119+
120+
Created 6 test cases to verify:
121+
122+
-V2 uses AccountPool.execute for settlement
123+
-Multiple accounts work in parallel for V2
124+
-Payer address passed for duplicate detection
125+
-Errors from AccountPool handled gracefully
126+
-V1 and V2 work together using same AccountPool
127+
-V2 verification doesn't use AccountPool (read-only)
128+
129+
All tests pass! (352 tests total)
130+
131+
## Configuration Changes
132+
133+
### Before
134+
135+
```env
136+
# V1 accounts
137+
EVM_PRIVATE_KEY_1=0x...
138+
EVM_PRIVATE_KEY_2=0x...
139+
140+
# V2 separate config (removed)
141+
FACILITATOR_V2_SIGNER=0x...
142+
EVM_PRIVATE_KEY=0x... # Used only for V2
143+
```
144+
145+
### After
146+
147+
```env
148+
# Shared accounts for V1 and V2
149+
EVM_PRIVATE_KEY_1=0x...
150+
EVM_PRIVATE_KEY_2=0x...
151+
EVM_PRIVATE_KEY_3=0x...
152+
153+
# V2 config (simplified)
154+
FACILITATOR_ENABLE_V2=true
155+
FACILITATOR_V2_ALLOWED_ROUTERS={"eip155:84532":["0x..."]}
156+
```
157+
158+
## Benefits
159+
160+
1. **Code Reuse**: V2 benefits from all AccountPool features without duplication
161+
2. **Multi-Account Support**: V2 can now use multiple accounts for parallel processing
162+
3. **Queue Management**: Serial queue per account prevents nonce conflicts
163+
4. **Duplicate Detection**: Prevents double-spend attempts across V1 and V2
164+
5. **Simpler Configuration**: One set of private keys for both V1 and V2
165+
6. **Better Scalability**: Round-robin account selection distributes load
166+
167+
## Testing Results
168+
169+
All 352 tests pass:
170+
171+
- 26 test files passed
172+
- 352 tests passed
173+
- New V2 AccountPool integration tests: 6/6 passed
174+
175+
## Files Modified
176+
177+
### Core Implementation
178+
179+
1. `typescript/packages/facilitator_v2/src/settlement.ts` - Added `executeSettlementWithWalletClient()`
180+
2. `typescript/packages/facilitator_v2/src/index.ts` - Exported new function
181+
3. `facilitator/src/version-dispatcher.ts` - Refactored V2 settlement to use AccountPool
182+
4. `facilitator/src/config.ts` - Simplified V2Config
183+
184+
### Application Setup
185+
186+
5. `facilitator/src/index.ts` - Removed V2 separate config passing
187+
6. `facilitator/src/routes/index.ts` - Updated VersionDispatcher creation
188+
7. `facilitator/src/routes/settle.ts` - Updated SettleRouteDependencies
189+
8. `facilitator/src/routes/verify.ts` - Updated VerifyRouteDependencies
190+
191+
### Tests
192+
193+
9. `facilitator/test/unit/version-dispatcher-v2-accountpool.test.ts` - New comprehensive test suite
194+
195+
## Migration Guide
196+
197+
No breaking changes for existing deployments:
198+
199+
1. V1 continues to work exactly as before
200+
2. V2 now automatically uses the same account pool as V1
201+
3. If you had separate V2 config, you can remove:
202+
- `FACILITATOR_V2_SIGNER` (no longer used)
203+
- Separate `EVM_PRIVATE_KEY` for V2 (uses numbered keys now)
204+
205+
## Conclusion
206+
207+
The refactor successfully unifies V1 and V2 account management, providing V2 with enterprise-grade features from AccountPool while maintaining backward compatibility and improving code maintainability.

0 commit comments

Comments
 (0)