-
Notifications
You must be signed in to change notification settings - Fork 0
Description
x402 V2 Migration Plan (Deepened)
Created: January 1, 2026
Deepened: January 1, 2026 via /deepen-plan
Author: SAGE
Deadline: January 14, 2026 (Cronos Hackathon Phase 1)
Enhancement Summary (from /deepen-plan)
Review Agents Used: security-sentinel, kieran-python-reviewer, kieran-typescript-reviewer, architecture-strategist, data-integrity-guardian, best-practices-researcher
Key Improvements:
| Priority | Finding | Fix |
|---|---|---|
| CRITICAL | Chain detection bypassable via signature heuristics | Use explicit chain field from payment network |
| CRITICAL | Nonce consumed before verification complete | Two-phase reserve/commit/release pattern |
| CRITICAL | Unbounded local cache (memory exhaustion) | Add TTL + size limit (10k max) |
| HIGH | No nonce format validation | Regex: ^[a-zA-Z0-9_-]{16,64}$ |
| HIGH | TypeScript uses unsafe unknown types |
Zod schemas with CAIP-2 validation |
| HIGH | Wallet validation is Solana-only | Chain-aware validation (EVM: 0x..., Solana: base58) |
| MEDIUM | CDP Facilitator is SPOF | Circuit breaker per chain |
| MEDIUM | Bare exception handling | Specific exception types |
Executive Summary
Migrate the existing SAGE x402 DeFi API from x402 V1 to V2. The core API (12 exchange integrations, arbitrage analysis, caching, alerts) is production-ready and unchanged. This migration focuses solely on the payment verification layer.
Scope: ~50-100 lines of code changes
Risk: Low (core API untouched)
Outcome: Multi-chain x402 V2 API discoverable on Bazaar
1. Context & Background
1.1 What is x402?
x402 is an open protocol that operationalizes HTTP 402 "Payment Required" for machine-to-machine micropayments. Instead of API keys or subscriptions, agents pay per-request using stablecoins (USDC).
V1 Flow (current):
Request → 402 Response → Client signs payment → X-Payment header → Server verifies → Success
V2 Flow (target):
Request → 402 Response with PAYMENT-REQUIRED header → Client signs → PAYMENT-SIGNATURE header → Server verifies → Success
V2 Key Changes:
- New headers:
PAYMENT-SIGNATUREandPAYMENT-REQUIRED(replacesX-Payment) - Multi-chain via CAIP-2 standard (single endpoint, multiple chains)
- Plugin architecture (
@x402/evm,@x402/svm) - Reusable sessions (Sign-In-With-X) for reduced latency
- Bazaar discovery extension for agent discoverability
1.2 Why Migrate Now?
- V1 is deprecated -
X-Paymentheader no longer works with V2 clients - Solana dominance - 72% of x402 volume is on Solana (400ms finality vs 2s on Base)
- Cronos Hackathon - 300+ builders seeking DeFi APIs (ends Jan 23, 2026)
- CDP fees started Jan 1 - need proper facilitator integration
2. Current State Analysis
2.1 Architecture Overview
x402/
├── main.py # FastAPI app entry point
├── config.py # Configuration (NETWORK, PRICE_PER_CALL, WALLET_ADDRESS)
├── utils.py # create_402_response() - NEEDS V2 UPDATE
├── routers/
│ ├── funding_rates.py # Main API endpoints - NEEDS V2 UPDATE
│ └── ...
├── services/
│ ├── exchange_service.py # 12 exchange integrations (unchanged)
│ ├── rate_limiter.py # Wallet-based rate limiting (unchanged)
│ └── ...
└── packages/
└── x402-payment/ # TypeScript payment module - NEEDS V2 UPDATE
├── package.json # Currently: @coinbase/x402: ^0.7.1 (V1)
└── src/index.ts # Payment verification logic
2.2 What's Working (Don't Touch)
| Component | File | Status |
|---|---|---|
| 12 Exchange Integrations | exchanges/*.py |
Production-ready |
| Arbitrage Analysis | services/analysis_service.py |
Production-ready |
| Redis Caching | services/cache_service.py |
Production-ready |
| Rate Limiting | services/rate_limiter.py |
Production-ready |
3. Target State
3.1 V2 Architecture
Client → PAYMENT-SIGNATURE header → FastAPI
│
parse_payment()
│
validate_wallet(chain) ← NEW: chain-aware
│
+------- chain routing -------+
│ │
EVMVerifier SolanaVerifier
│ │
+--- circuit breaker ---+ +--- circuit breaker ---+ ← NEW
│ │
CDP Facilitator CDP Facilitator
│ │
+----- nonce check (Redis, fail-closed) ----+ ← NEW: two-phase
│
rate_limit (Redis/memory)
│
API Response
3.2 V2 402 Response Schema
{
"x402Version": "2",
"accepts": [
{
"scheme": "exact",
"network": "eip155:8453",
"maxAmountRequired": "10000",
"resource": "/api/funding-rates",
"payTo": "0xae3cDa2A4c50782868EAD3be4bFAedd96D07c17e",
"token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
},
{
"scheme": "exact",
"network": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
"maxAmountRequired": "10000",
"resource": "/api/funding-rates",
"payTo": "<solana-wallet-address>",
"token": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
}
]
}4. Migration Steps (Updated with Research)
Step 1: Update TypeScript SDK
File: packages/x402-payment/package.json
{
"dependencies": {
"@x402/core": "^2.0.0",
"@x402/evm": "^2.1.0",
"@x402/svm": "^2.0.0",
"@coinbase/x402": "^2.0.0",
"zod": "^3.22.0"
}
}Research Finding: Add CAIP-2 type system:
type EVMChainId = 'eip155:1' | 'eip155:8453' | 'eip155:84532';
type SVMChainId = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp';
export type ChainId = EVMChainId | SVMChainId;
type ChainConfig =
| { chainType: 'evm'; chainId: EVMChainId; wallet: `0x${string}` }
| { chainType: 'svm'; chainId: SVMChainId; wallet: string };Research Finding: Add Zod validation:
const PaymentPayloadSchema = z.object({
x402Version: z.literal(2),
network: z.string().regex(/^(eip155|solana):/), // CAIP-2
signature: z.string()
});Step 2: Update Python Config
File: config.py
X402_VERSION = "2"
NETWORKS = {
"base": "eip155:8453",
"ethereum": "eip155:1",
"solana": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
}
USDC_ADDRESSES = {
"base": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"solana": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
}Step 3: Update 402 Response
File: utils.py
- Change
x402Versionfrom "1" to "2" - Use CAIP-2 network identifiers
- Add
PAYMENT-REQUIREDheader
Step 4: Update Payment Verification (CRITICAL FIXES)
File: routers/funding_rates.py
Research Finding - Chain Detection Fix:
def detect_payment_chain(payment_data: dict) -> str:
"""Use explicit chain from payment network, not signature format."""
network = payment_data.get("network", "")
chain = network.split(":")[0]
if chain == "eip155":
return "evm"
elif chain == "solana":
return "solana"
raise ValueError(f"Unsupported chain: {chain}")Research Finding - Error Handling Fix:
# Instead of bare except Exception:
except json.JSONDecodeError as e:
return False, None, f"Invalid payment signature: {e}"
except PaymentVerificationError as e:
return False, None, f"Payment verification failed: {e}"
except (ConnectionError, TimeoutError) as e:
return False, None, f"Network error: {e}"Step 5: Add Nonce Service (CRITICAL - NEW)
File: services/nonce_service.py
Research Finding - Two-Phase Pattern:
class NonceService:
NONCE_TTL = 86400
MAX_LOCAL_CACHE = 10000
NONCE_PATTERN = re.compile(r'^[a-zA-Z0-9_-]{16,64}$')
async def reserve_nonce(self, nonce: str, ttl: int = 60) -> bool:
"""Reserve nonce temporarily during verification."""
if not self.NONCE_PATTERN.match(nonce):
raise ValueError("Invalid nonce format")
key = f"nonce:pending:{nonce}"
return await self.redis.set(key, "1", nx=True, ex=ttl) is not None
async def commit_nonce(self, nonce: str) -> bool:
"""Permanently consume after successful verification."""
pipe = self.redis.pipeline()
pipe.delete(f"nonce:pending:{nonce}")
pipe.set(f"nonce:{nonce}", str(int(time.time())), nx=True, ex=self.NONCE_TTL)
results = await pipe.execute()
return results[1] is not None
async def release_nonce(self, nonce: str):
"""Release on verification failure."""
await self.redis.delete(f"nonce:pending:{nonce}")Research Finding - Fail Closed:
if not self.redis:
raise NonceServiceUnavailable("Redis required for replay protection")Step 6: Add Bazaar Metadata Endpoint
File: routers/discovery.py (NEW)
@router.get("/.well-known/x402")
async def get_x402_metadata():
return {
"x402Version": "2",
"name": "sage-defi-oracle",
"endpoints": [...],
"networks": [...]
}5. Critical Research Findings (Detailed)
Security Review (security-sentinel)
-
Chain detection is bypassable - Any JSON with "signature" key routes to EVM, any base64 to Solana. Fix: use explicit
networkfield. -
Local nonce cache has no TTL - Memory exhaustion DoS + replay after restart. Fix:
OrderedDictwith max size + TTL. -
Nonce format not validated - Empty/malformed nonces pass through. Fix: regex validation.
Data Integrity Review (data-integrity-guardian)
-
Nonce consumed before verification - If verification fails, nonce is burned, user can't retry. Fix: two-phase reserve/commit/release.
-
In-memory fallback is risky - Replay attacks possible across instances. Fix: fail closed for nonces.
TypeScript Review (kieran-typescript-reviewer)
-
Type-unsafe
unknownwith forced assertions - Runtime crashes possible. Fix: Zod schemas. -
Missing CAIP-2 type system - Invalid chains pass compile-time checks. Fix: discriminated unions.
-
Wallet validation is Solana-only - EVM wallets fail. Fix: chain-aware validation.
Architecture Review (architecture-strategist)
-
CDP Facilitator is SPOF - Both chains route through single point. Fix: circuit breaker per chain.
-
Error boundaries undefined - Chain-specific errors not normalized. Fix: error taxonomy.
6. Success Criteria
- 402 response returns V2 schema with CAIP-2 networks
- Chain detection uses explicit field, not signature heuristics
- Nonce uses two-phase reserve/commit/release pattern
- Nonce service fails closed without Redis
- Local cache bounded with TTL
- TypeScript uses CAIP-2 types with Zod validation
- Wallet validation is chain-aware
- Circuit breakers per chain
- Exception handling is specific, not bare
- All existing tests pass
- Listed on x402 Bazaar
7. Design Decisions (Confirmed)
- Solana via CDP Facilitator: ✅ Confirmed available. CDP supports both Base and Solana with fee-free USDC payments.
- EVM chains beyond Base: ❌ No. Base only for Phase 1. Rationale: Base is 28% of volume, Solana is 72%. Other EVM chains have minimal x402 volume. Can add later if demand exists.
- Traffic ratio: ~30% EVM (Base) / ~70% Solana. Solana flipped Base in Dec 2025 due to 400ms finality. Most agent builders are on Solana now.
8. Reference Links
- x402 V2 Spec: https://www.x402.org/writing/x402-v2-launch
- Migration Guide: https://docs.cdp.coinbase.com/x402/migration-guide
- CAIP-2 Standard: https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md
- Stripe Idempotency: https://stripe.com/blog/idempotency
- Redis Distributed Locks: https://redis.io/docs/latest/develop/clients/patterns/distributed-locks/