Skip to content

feat(solana): add Solana x402 payment support + SDK migration#54

Open
tenequm wants to merge 13 commits intoBlockRunAI:mainfrom
tenequm:feat/solana-support
Open

feat(solana): add Solana x402 payment support + SDK migration#54
tenequm wants to merge 13 commits intoBlockRunAI:mainfrom
tenequm:feat/solana-support

Conversation

@tenequm
Copy link

@tenequm tenequm commented Feb 26, 2026

Summary

Add Solana x402 payment support alongside existing EVM (Base) payments, and migrate from hand-rolled x402 implementation to official @x402/fetch, @x402/evm, and @x402/svm SDKs.

Key changes:

  • BIP-39/BIP-44 HD wallet derivation - single mnemonic derives both EVM and Solana keys
  • Dual-chain x402 payment signing via registerExactEvmScheme + registerExactSvmScheme
  • Solana USDC balance monitoring with configurable RPC (CLAWROUTER_SOLANA_RPC_URL)
  • Payment chain logging via x402.onAfterPaymentCreation() hook
  • /wallet export now includes mnemonic + Solana address for full backup
  • /wallet setup-solana command for existing EVM-only users
  • Fund-loss protection: refuses to overwrite mnemonic if wallet.key is deleted
  • ProxyOptions refactored to accept wallet: WalletConfig object (prevents callers from forgetting to forward Solana keys)

Files added:

  • src/wallet.ts - BIP-39 mnemonic + BIP-44 key derivation
  • src/solana-balance.ts - Solana USDC balance checker
  • src/spend-control.ts - Time-windowed spending limits
  • src/wallet.test.ts (14 tests), src/x402-sdk.test.ts (7 tests), src/spend-control.test.ts (23 tests)
  • test/test-solana-e2e.ts - E2E test against real blockrun.ai with dual-chain proxy

Files removed (replaced by SDK):

  • src/x402.ts, src/payment-cache.ts, src/x402.test.ts

Three wallet scenarios supported:

  1. wallet.key exists, no mnemonic - EVM-only mode
  2. wallet.key + mnemonic exist - dual-chain mode
  3. Nothing exists - generates BIP-39 mnemonic, derives both chains

Test plan

  • TypeScript typecheck passes (npx tsc --noEmit)
  • Build succeeds (npm run build)
  • 256 unit/integration tests pass (npm test)
  • Solana E2E test passes against real blockrun.ai (npx tsx test/test-solana-e2e.ts)
  • Payment chain logging verified in E2E output: [ClawRouter] Payment signed on Base (EVM) (eip155:8453)
  • Wallet migration scenarios traced through code for all 3 paths + edge cases

- Add Solana USDC payment signing via @x402/svm ExactSvmScheme
- Replace hand-rolled x402.ts with official @x402/fetch + @x402/evm SDK
- Add BIP-39 mnemonic generation + BIP-44 key derivation (EVM + Solana)
- Add SolanaBalanceMonitor for USDC balance checking on Solana
- Add SpendControl with per-request, hourly, daily, session limits
- Add /wallet setup-solana command for existing EVM-only users
- Dual-chain display in wallet status (EVM + Solana balances)
- Remove payment-cache.ts and pre-auth optimization (SDK handles retries)
- Dynamic Solana module loading (only when Solana key is present)
- Remove unused generatePrivateKey import from auth.ts
- Replace manual x402.register() with registerExactSvmScheme() helper
  which registers solana:* wildcard + V1 compat names
- Remove unused solanaRpcUrl from ProxyOptions
- Remove stale "Payment cache" comment from proxy.ts header
- Update cost buffer comment (was referencing removed pre-auth)
- Convert SolanaBalanceMonitor to dynamic import in index.ts
  so CLI users don't load @solana/kit at startup
- wallet.test.ts (14 tests): BIP-39 generation, BIP-44 derivation for
  both EVM and Solana, determinism, Solana signer creation
- x402-sdk.test.ts (7 tests): client creation, EVM + Solana scheme
  registration, wrapFetchWithPayment pass-through, streaming, 402 flow
- spend-control.test.ts (23 tests): per-request/hourly/daily/session
  limits, window expiry, persistence, validation, formatDuration
If a user deletes wallet.key but mnemonic file exists (from setup-solana),
generateAndSaveWallet() would silently overwrite the mnemonic, destroying
the Solana wallet derived from it. Now refuses to generate and tells the
user to restore their EVM key instead.
CLI entry point was not destructuring or forwarding Solana key bytes
from resolveOrGenerateWalletKey(), so standalone CLI users would never
get Solana payments registered even with a valid mnemonic file.
ProxyOptions.wallet now accepts either a plain key string (EVM-only,
backward compat for tests) or the full WalletResolution object from
resolveOrGenerateWalletKey(). This prevents callers from accidentally
forgetting to forward solanaPrivateKeyBytes.

- Export WalletResolution type from auth.ts
- Add WalletConfig union type to proxy.ts
- Update cli.ts, index.ts, test/integration/setup.ts to pass wallet object
- Solana now auto-registers in integration tests (previously missing)
…letKey:

22 occurrences across 12 test files updated to match the new
ProxyOptions.wallet interface.
… v0.11.0

- Add x402 onAfterPaymentCreation hook to log which chain (Base/Solana)
  is used for each payment
- Update /wallet export to include mnemonic and Solana address when
  available, with restore instructions for both chains
- Add test/test-solana-e2e.ts validating dual-chain proxy startup,
  wallet derivation, and 402 flow against real blockrun.ai
- Update README with Solana badge, dual-chain payment docs, setup-solana
  command, and CLAWROUTER_SOLANA_RPC_URL config
- Bump version to 0.11.0 for Solana support release
blockrun.ai/api only offers EVM payment options. Solana payments
require sol.blockrun.ai/api. Default to Solana endpoint when
Solana keys are present.
Tests all wallet scenarios on real disk with temp HOME:
- Fresh install: generates mnemonic + both keys, verifies 0o600 permissions
- Existing wallet.key only: EVM-only path, no Solana
- wallet.key + setup-solana: creates mnemonic, leaves EVM untouched
- Edge cases: protective error on missing wallet.key, duplicate setup-solana
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant