All articles
solanasurfpooltestinglocal-dev

Surfpool: mainnet-fork test validator with RPC cheatcodes

Surfpool is solana-test-validator with Mainnet forking and cheatcodes — fork state instantly, manipulate accounts via RPC, run real protocols locally.

Surfpool is what solana-test-validator should have been. It's a local validator that can fork Mainnet state instantly, exposes RPC cheatcodes for manipulating accounts and time, and runs from a single binary with no setup. Now maintained under the Solana Foundation at solana-foundation/surfpool.

Install + run

sh
curl -sL https://run.surfpool.run/ | bash

surfpool start
# Validator runs on http://localhost:8899
# Studio dashboard opens automatically at http://localhost:8488

Mainnet forking

Clone any account, token balance, or program from Mainnet to your local network with one RPC call:

sh
# Clone a single account from Mainnet
curl -X POST http://localhost:8899 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "surfnet_setAccount",
    "params": [
      "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
      { "clone": "mainnet" }
    ]
  }'

# Or fork all of Mainnet on startup
surfpool start --fork mainnet

Once cloned, the account behaves exactly as on Mainnet for the purposes of your local txs — same balance, same data, same owner. Modify it locally without touching Mainnet.

The cheatcode surface

Surfpool exposes a surfnet_* RPC family that gives you superpowers a real network would never allow:

text
surfnet_setAccount             Overwrite any account's data + lamports + owner
surfnet_setTokenAccount        Create a token account at any address
surfnet_setTokenBalance        Set any wallet's token balance to anything
surfnet_setProgramData         Replace a deployed program's bytecode
surfnet_timeTravel             Jump forward N slots or epochs
surfnet_resetNetwork           Reset everything back to a clean state
surfnet_simulateTransaction    Like simulateTransaction but with state
                               overrides applied before execution
surfnet_subscribeAccountStream Real-time push for any account change

Concrete recipe: testing your liquidation logic against the actual mainnet USDC mint, with the user having $50k USDC and your protocol's vault pre-funded with collateral, all without depositing a single real dollar:

typescript
// 1. Fork USDC mint into local
await rpc.send("surfnet_setAccount", [
  "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  { clone: "mainnet" },
])

// 2. Set the user's USDC balance to 50,000
await rpc.send("surfnet_setTokenBalance", [
  userTokenAccount.toBase58(),
  50_000_000_000,    // 50k USDC (6 decimals)
])

// 3. Pre-fund your vault
await rpc.send("surfnet_setTokenBalance", [
  vaultTokenAccount.toBase58(),
  1_000_000_000_000,
])

// 4. Run your liquidation flow against real Mainnet program shapes
//    All txs execute locally, no real funds at risk
const sig = await yourProtocol.liquidate(/* ... */)

Comparison with the alternatives

text
                         Surfpool         solana-test-validator   LiteSVM
─────────────────────────────────────────────────────────────────────────────
Real validator process   Yes              Yes                      No (in-process)
Mainnet fork             Yes (built in)   No                       No
RPC cheatcodes           Yes              No                       N/A (direct API)
Setup time               <5s              30s+                     0s (library)
Account-level speed      ~real validator  ~real validator          microseconds
JSON-RPC compatible      Yes              Yes                      Limited
Use for                  Integration test Integration test         Unit test

When to reach for it

  • Testing against real on-chain state. Your protocol depends on USDC's actual freeze authority, or Jupiter's actual program ID, or the exact lookup table Pyth uses — fork Mainnet and your tests see what production sees.
  • Time-dependent logic. Vesting schedules, warmup periods, governance proposal deadlines — jump the clock via surfnet_timeTravel instead of mocking it.
  • Reproducing a Mainnet bug locally. Fork the exact slot the bug occurred at, set your wallet up identically, replay the failing transaction.
  • Demo / development. Show off your protocol interacting with real liquidity, real tokens, real users without spending real SOL.

Studio dashboard

Surfpool ships a web UI at localhost:8488 showing live account state, recent transactions, program logs, and CU breakdowns. Particularly useful when you're iterating fast and want to see what changed after each tx without scraping explorer pages.

References

For anything past unit-tests, Surfpool is the right default local environment for Solana in 2026. LiteSVM stays the right tool for microsecond-fast unit tests; Surfpool is the integration-test environment where Mainnet's real state becomes accessible.

Surfpool: mainnet-fork test validator with RPC cheatcodes | devrels.xyz