Skip to content

Commit 45038fb

Browse files
feat(v2): implement x402 v2 protocol with multi-chain support (#25)
* implement * feat(v2): add EVM signer with EIP-3009 support Implement Phase 4 of v2 protocol - EVM signer with EIP-3009 authorization: - v2/internal/eip3009: EIP-712 typed data and signature creation utilities - v2/signers/evm: Signer implementation for Ethereum-compatible chains - NewSigner/NewSignerFromKey constructors - CanSign/Sign methods for payment payload generation - Support for max amount limits via WithMaxAmount option - CAIP-2 network identifier support Tests use Foundry/Anvil default test key for consistency and clarity. * feat(v2): add SVM signer with Solana transaction building Implement the v2 SVM (Solana) signer for the x402 protocol v2. New files: - v2/internal/solana/solana.go - Utility functions for Solana - BuildTransferCheckedInstruction: SPL Token TransferChecked builder - BuildSetComputeUnitLimitInstruction: Compute budget instruction - BuildSetComputeUnitPriceInstruction: Priority fee instruction - DeriveAssociatedTokenAddress: ATA derivation - GetRPCURL: CAIP-2 network to RPC URL mapping - v2/signers/svm/signer.go - SVM Signer implementation - NewSigner: Create from base58 private key - NewSignerFromKey: Create from existing key - NewSignerFromKeygenFile: Create from Solana keygen JSON file - Full v2.Signer interface implementation - CAIP-2 network validation (rejects EVM networks) - Fee payer extraction from requirements.Extra Key differences from v1: - Uses CAIP-2 network identifiers (e.g., solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp) - Returns v2.SVMPayload type directly - Uses v2.PaymentRequirements with Amount field - Sets X402Version to 2 This completes Phase 5 of the v2 implementation plan. * feat(v2): add HTTP transport layer with middleware, client, and transport Implements Phase 6 of the v2 protocol implementation plan. New files: - v2/http/internal/helpers/helpers.go - HTTP helper functions - ParsePaymentHeader, SendPaymentRequired, AddPaymentResponseHeader - ParsePaymentRequirements, ParseSettlement, BuildPaymentHeader - BuildResourceURL for constructing resource URLs from requests - v2/http/middleware.go - HTTP payment middleware - Config struct with facilitator options, authorization, and hooks - NewX402Middleware factory with automatic requirement enrichment - settlementInterceptor for deferred settlement on success - Support for verify-only mode and fallback facilitators - GetPaymentFromContext for handler access to payment info - v2/http/transport.go - HTTP transport with 402 handling - X402Transport implementing http.RoundTripper - Automatic 402 detection and payment retry - Payment callbacks for monitoring (attempt, success, failure) - v2/http/client.go - HTTP client wrapper - NewClient with functional options pattern - WithSigner, WithSelector, WithHTTPClient options - WithPaymentCallback, WithPaymentCallbacks options - GetSettlement helper for extracting settlement from response All tests pass with race detection enabled. * feat(v2): add Gin framework middleware adapter Implements Phase 7 of the v2 protocol plan. - Add v2/http/gin/middleware.go with Gin-compatible middleware - Support CAIP-2 network identifiers (e.g., eip155:84532) - Add PaymentContextKey for storing verified payment in Gin context - Add GetPaymentFromContext helper function - Support verify-only mode - Support primary and fallback facilitators - Add comprehensive test coverage The middleware follows the same pattern as v1 Gin middleware but uses v2 types with x402Version: 2 and restructured PaymentRequired/PaymentPayload. * feat(v2): add MCP integration with server and client transport Implements Phase 8 of the v2 protocol plan - MCP (Model Context Protocol) integration for payment-gated AI tools. Server-side components: - v2/mcp/types.go: MCP-specific payment requirements type (v2 format) - v2/mcp/errors.go: MCP-specific error types and payment error wrapper - v2/mcp/server/config.go: Server configuration with tool payment mapping - v2/mcp/server/server.go: X402Server wrapping MCP server with payment support - v2/mcp/server/handler.go: HTTP handler for payment verification/settlement - v2/mcp/server/facilitator.go: HTTP facilitator client for MCP server - v2/mcp/server/requirements.go: Requirement validation for MCP tools Client-side components: - v2/mcp/client/config.go: Client configuration with signers and callbacks - v2/mcp/client/transport.go: Transport wrapper for automatic 402 handling Key v2 protocol features: - CAIP-2 network identifiers (e.g., eip155:84532) - Resource info object in payment requirements - Extensions passthrough support - Payment in _meta['x402/payment'] for tool calls - Settlement response in _meta['x402/payment-response'] in results Tests cover: - Free and paid tool handling - Payment verification and settlement flow - VerifyOnly mode - Tool execution error handling (no settlement) - Payment requirements extraction (v2 format) - Configuration options * feat(v2): add example applications for HTTP, Gin, and MCP Add Phase 9 examples demonstrating v2 protocol usage: - examples/v2/http/main.go: HTTP server/client with payment middleware - examples/v2/gin/main.go: Gin framework integration example - examples/v2/mcp/main.go: MCP server with paid tools and client All examples demonstrate: - CAIP-2 network identifiers (e.g., eip155:84532) - v2 PaymentRequirements configuration - EVM and SVM signer creation - Automatic payment handling - Payment event callbacks This completes Phase 9 of the v2 implementation plan. * test(v2): add comprehensive tests for EIP-3009 authorization Add unit tests for the internal eip3009 package covering: - GenerateNonce: randomness, uniqueness, non-zero values - CreateAuthorization: field population, time bounds, nonce uniqueness - SignAuthorization: signature format, determinism, chain separation These tests ensure the cryptographic foundations of EVM payment signing work correctly across different chains, tokens, and amounts. * chore: remove beads issue tracking references from AGENTS.md * fix: resolve all golangci-lint issues - Fix errcheck: add explicit error handling for json.Encode and w.Write calls - Fix staticcheck SA5011: use t.Fatal instead of t.Error for nil checks - Fix staticcheck SA4006: properly use nonce variable in eip3009_test.go - Remove unused mockSigner2 type and math/big import from client_test.go * fix(v2/mcp): handle nil error data in 402 responses properly Return ErrNoPaymentRequirements when resp.Error.Data is nil or empty instead of attempting to unmarshal and causing 'unexpected end of JSON input' errors. This provides clearer error messages for clients when payment requirements are missing from 402 responses. * fix(svm): fix critical address matching and amount validation bugs - Fix case-insensitive base58 address comparison (Solana base58 is case-sensitive) - Add uint64 overflow check before converting big.Int amounts - Add nil requirements validation in CanSign - Add negative/zero amount validation - Add token decimals range validation (0-255) - Add explicit token not found error when asset doesn't match - Update test to expect case-sensitive behavior This fixes a critical security issue where incorrect token addresses could match due to case-insensitive comparison, and prevents silent truncation of large amounts during uint64 conversion. * fix(solana): correct error wrapping format for proper unwrapping Fix error wrapping in GetRPCURL to place sentinel error at end with %w verb, allowing errors.Is/As to properly unwrap v2.ErrInvalidNetwork. Previous format broke error chain unwrapping. * fix(svm): add ATA creation instruction to transfers Add idempotent associated token account creation instruction before SPL token transfers to ensure the destination ATA exists. The facilitator sponsors the rent-exempt balance as fee payer. Without this instruction, transfers fail when the recipient's ATA does not exist, which is a functional requirement of the exact_svm specification. Fixes critical issue from code review: v2/signers/svm/signer.go lines 283-314 * fix(http): ensure settlement before connection hijack Fixes issue where Hijack() could bypass payment settlement for WebSocket upgrades and other connection takeover scenarios. Now settles payment first before allowing hijack, preventing potential payment bypass. * fix(mcp): return value instead of pointer to copy in GetPaymentConfig The GetPaymentConfig function was returning a pointer to a local copy of the map value, which is misleading for callers who might expect to modify the stored configuration. Changed the signature to return (ToolPaymentConfig, bool) for clearer read-only semantics that match Go idioms (similar to map lookups). * fix(mcp): return errors instead of panicking in handler constructors Replace panic() with error returns in NewX402Handler and initializeFacilitators. Panicking in library code crashes consuming applications; returning errors allows callers to handle configuration failures gracefully. Changes: - NewX402Handler now returns (*X402Handler, error) instead of *X402Handler - initializeFacilitators now returns (Facilitator, Facilitator, error) - Handler() methods in X402Server now return (http.Handler, error) - Updated Start() methods to handle handler creation errors - All tests pass with race detection Fixes issue from scratch/comments.md (v2/mcp/server/handler.go:72-79) * fix(mcp): validate X402Version in payment extraction Reject payment payloads with unsupported x402Version to prevent processing incompatible payments. This ensures verify/settle logic only operates on version 2 payloads as expected by the protocol. * fix(http): add context parameter to EnrichRequirements - Change EnrichRequirements signature to accept context.Context as first parameter - Allows callers to control timeouts and cancellation for facilitator requests - Update all call sites to use context.WithTimeout(context.Background(), RequestTimeout) - Add context import to http/pocketbase/middleware.go - Update both v1 and v2 implementations for consistency - All tests pass with race detection * fix(mcp): guard against nil signers in WithSigner option * fix(http): add timeouts to HTTP clients in middleware - Set HTTP client timeout to DefaultTimeouts.RequestTimeout in all middleware - Prevents indefinite hangs when facilitator is unresponsive - Affects v1 and v2 standard middleware, Gin middleware, and PocketBase middleware - All 6 facilitator client instantiations now have explicit timeout - Tests pass with race detection Resolves issue from scratch/comments.md: HTTP clients without timeout configuration * fix(mcp): set Success=true in verify-only mode when verification succeeds * fix(svm): add timeout to Solana RPC blockhash fetch The GetLatestBlockhash call was using context.Background() which could hang indefinitely if the RPC node is unresponsive. Now uses a timeout context with DefaultTimeouts.VerifyTimeout to prevent hangs. * fix(config): add RequestTimeout validation to TimeoutConfig * fix(test): use time.Duration for HTTP client timeout instead of int * cleanup * fix(svm): use idempotent ATA creation instruction for token transfers Replace non-idempotent NewCreateInstruction with CreateIdempotent (instruction index 1) to prevent transaction failures when the destination Associated Token Account already exists. * Update v2/http/facilitator.go Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix(svm): inject mock RPC client in tests to prevent real network calls Add RPCClient interface to enable dependency injection for Solana RPC operations. Update TestSign_ValidPayment and TestTransactionStructure to use a mock client with deterministic blockhash, eliminating flaky tests caused by real mainnet RPC calls. * refactor(svm): generate test wallets at runtime instead of hardcoded key Remove the hardcoded testPrivateKeyBase58 constant and replace with newTestWallet() helper that generates fresh Solana wallets for each test. This eliminates static secrets from the repository. * refactor(v2): align types with reference implementation - Add InvalidMessage field to VerifyResponse for human-readable error messages - Add ErrorMessage field to SettleResponse for human-readable error messages - Change PaymentRequired.Resource from value to pointer type for optional semantics - Update validation to handle nil Resource (now optional) - Update all middleware and helpers to use pointer for Resource - Update all test files for pointer type compatibility These changes align with the Coinbase x402 Go reference implementation. * Update v2/signers/svm/signer_test.go Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update v2/types.go Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * refactor(v2): add nil guards and error context to helpers - Add ErrCodeUnsupportedVersion error code for version mismatches - Update ParsePaymentHeader to use ErrCodeUnsupportedVersion instead of ErrCodeUnsupportedScheme for protocol version errors - Add nil input guards to AddPaymentResponseHeader and BuildPaymentHeader - Wrap errors with function context for better debugging - Add sentinel errors ErrNilSettlement and ErrNilPayment - Add tests for nil guard behavior and error code verification * fix(svm): remove duplicate import block in signer_test.go Merge artifact from remote caused duplicate import declarations. Consolidated imports and added missing 'errors' package to original block. * refactor(v2): improve error handling and input validation - Fix WithDetails nil map panic by lazily initializing Details map - Update SendPaymentRequired to return error and wrap encoding failures - Add nil guards to ParsePaymentRequirements for resp and resp.Body - Update middleware to handle SendPaymentRequired errors (logged only) - Add negative input validation to AmountToBigInt (decimals < 0, amount < 0) - Add comprehensive tests for all new behavior * iteratr * Update .iteratr.hooks.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent 5d563bb commit 45038fb

Some content is hidden

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

57 files changed

+13916
-119
lines changed

.iteratr.hooks.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
version: 1
2+
3+
hooks:
4+
post_iteration:
5+
- command: "golangci-lint run ./..."
6+
timeout: 120
7+
pipe_output: true
8+
- command: "go vet ./..."
9+
timeout: 5
10+
pipe_output: true

AGENTS.md

Lines changed: 0 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,104 +1,5 @@
11
# Agent Development Guidelines for x402-go
22

3-
## Issue Tracking with bd (beads)
4-
5-
**IMPORTANT**: This project uses **bd (beads)** for ALL issue tracking. Do NOT use markdown TODOs, task lists, or other tracking methods.
6-
7-
### Why bd?
8-
9-
- Dependency-aware: Track blockers and relationships between issues
10-
- Git-friendly: Auto-syncs to JSONL for version control
11-
- Agent-optimized: JSON output, ready work detection, discovered-from links
12-
- Prevents duplicate tracking systems and confusion
13-
14-
### Quick Start
15-
16-
**Check for ready work:**
17-
```bash
18-
bd ready --json
19-
```
20-
21-
**Create new issues:**
22-
```bash
23-
bd create "Issue title" -t bug|feature|task -p 0-4 --json
24-
bd create "Issue title" -p 1 --deps discovered-from:bd-123 --json
25-
```
26-
27-
**Claim and update:**
28-
```bash
29-
bd update bd-42 --status in_progress --json
30-
bd update bd-42 --priority 1 --json
31-
```
32-
33-
**Complete work:**
34-
```bash
35-
bd close bd-42 --reason "Completed" --json
36-
```
37-
38-
### Issue Types
39-
40-
- `bug` - Something broken
41-
- `feature` - New functionality
42-
- `task` - Work item (tests, docs, refactoring)
43-
- `epic` - Large feature with subtasks
44-
- `chore` - Maintenance (dependencies, tooling)
45-
46-
### Priorities
47-
48-
- `0` - Critical (security, data loss, broken builds)
49-
- `1` - High (major features, important bugs)
50-
- `2` - Medium (default, nice-to-have)
51-
- `3` - Low (polish, optimization)
52-
- `4` - Backlog (future ideas)
53-
54-
### Workflow for AI Agents
55-
56-
1. **Check ready work**: `bd ready` shows unblocked issues
57-
2. **Claim your task**: `bd update <id> --status in_progress`
58-
3. **Work on it**: Implement, test, document
59-
4. **Discover new work?** Create linked issue:
60-
- `bd create "Found bug" -p 1 --deps discovered-from:<parent-id>`
61-
5. **Complete**: `bd close <id> --reason "Done"`
62-
63-
### Auto-Sync
64-
65-
bd automatically syncs with git:
66-
- Exports to `.beads/issues.jsonl` after changes (5s debounce)
67-
- Imports from JSONL when newer (e.g., after `git pull`)
68-
- No manual export/import needed!
69-
70-
### MCP Server (Recommended)
71-
72-
If using Claude or MCP-compatible clients, install the beads MCP server:
73-
74-
```bash
75-
pip install beads-mcp
76-
```
77-
78-
Add to MCP config (e.g., `~/.config/claude/config.json`):
79-
```json
80-
{
81-
"beads": {
82-
"command": "beads-mcp",
83-
"args": []
84-
}
85-
}
86-
```
87-
88-
Then use `mcp__beads__*` functions instead of CLI commands.
89-
90-
### Important Rules
91-
92-
- ✅ Use bd for ALL task tracking
93-
- ✅ Always use `--json` flag for programmatic use
94-
- ✅ Link discovered work with `discovered-from` dependencies
95-
- ✅ Check `bd ready` before asking "what should I work on?"
96-
- ❌ Do NOT create markdown TODO lists
97-
- ❌ Do NOT use external issue trackers
98-
- ❌ Do NOT duplicate tracking systems
99-
100-
For more details, see README.md and QUICKSTART.md.
101-
1023
## Build & Test Commands
1034
- **Build**: `go build ./...` - Builds all packages
1045
- **Test All**: `go test -race ./...` - Runs all tests with race detection

0 commit comments

Comments
 (0)