mcpField
S
surfpool

surfpool

github.com/sendaifunDevelopment130220 installsUpdated 13w ago
Repository

About surfpool

surfpool is a local development environment for Solana developers and a drop-in replacement for `solana-test-validator`, fetching Mainnet data as needed. It combines state controls, deployment automation, and transaction analysis for testing against on-chain accounts.

Key features

  1. 01Fork Mainnet accounts and programs on demand
  2. 02Control state and time with RPC cheatcodes
  3. 03Auto-detect Anchor projects and deploy programs
  4. 04Inspect transactions and compute usage in Surfpool Studio
  5. 05Write reproducible deployments with txtx DSL

Use cases

  1. 01Test Solana programs against Mainnet account state
  2. 02Set balances, account data, or network time for edge cases
  3. 03Analyze transaction compute usage and inspect account state
  4. 04Export reproducible transaction snapshots for tests and CI

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/sendaifun/skills --skill surfpool

After installing, type/surfpoolin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

docs/
troubleshooting.md
examples/basic/
getting-started.ts
examples/cheatcodes/
state-manipulation.ts
examples/iac/
deployment.tx
resources/
cheatcodes.md
cli-reference.md
github-repos.md
templates/
Surfpool.toml
test-setup.ts

Details

From the project README

Surfpool - Solana Development Environment

The definitive guide for Surfpool - where developers start their Solana journey. A drop-in replacement for solana-test-validator that enables local program simulation using Mainnet accounts fetched just-in-time.

What is Surfpool?

Surfpool is a comprehensive development environment that combines local-first testing with real Mainnet data access:

  • Mainnet Forking - Clone accounts, programs, and token balances from Mainnet instantly
  • Cheatcodes - Special RPC methods for time travel, balance manipulation, and state control
  • Infrastructure as Code - Reproducible, auditable deployments using txtx DSL
  • Surfpool Studio - Embedded dashboard with transaction inspection and profiling
  • Universal Faucet - Get SOL, USDC, USDT, BONK from a single interface
Key Benefits
FeatureDescription
Instant BootNo 2TB snapshots, runs on Raspberry Pi
Lazy ForkingCopy-on-read strategy pulls mainnet data as needed
Full CompatibilityWorks with solana-cli, Anchor, wallets, explorers
Zero ConfigAuto-detects Anchor projects and deploys programs
Statistics
  • 460+ GitHub stars
  • 100+ forks
  • Apache 2.0 license
  • Current version: v1.0.0

Installation

Automated Installer (Recommended)
curl -sL https://run.surfpool.run/ | bash
Homebrew (macOS)
brew install txtx/taps/surfpool
From Source
git clone https://github.com/txtx/surfpool.git
cd surfpool
cargo surfpool-install
Docker
docker pull surfpool/surfpool
docker run -p 8899:8899 -p 18488:18488 surfpool/surfpool

Quick Start

Start Local Network
# Start with default configuration
surfpool start

# Start with custom RPC source
surfpool start -u https://api.mainnet-beta.solana.com

# Start without terminal UI
surfpool start --no-tui

# Start with debug logging
surfpool start --debug
Access Points
ServiceURLDescription
RPC Endpointhttp://127.0.0.1:8899Standard Solana RPC
WebSocketws://127.0.0.1:8900Real-time subscriptions
Surfpool Studiohttp://127.0.0.1:18488Web dashboard

CLI Commands

surfpool start

Start the local Surfnet network.

surfpool start [OPTIONS]

Options:

OptionDefaultDescription
-m, --manifest-file-path./Surfpool.tomlPath to manifest file
-p, --port8899RPC port
-o, --host127.0.0.1Host address
-s, --slot-time400Slot time in ms
-u, --rpc-urlhttps://api.mainnet-beta.solana.comSource RPC URL
--no-tui-Disable terminal UI
--debug-Enable debug logs
--no-deploy-Disable auto deployments
-r, --runbookdeploymentRunbooks to execute
-a, --airdrop-Pubkeys to airdrop
-q, --airdrop-amount10000000000000Airdrop amount (lamports)
-k, --airdrop-keypair-path-Keypair path for airdrop
--no-explorer-Disable explorer
Example Usage
# Start with airdrop to specific address
surfpool start -a YOUR_PUBKEY -q 100000000000

# Start with custom slot time (faster blocks)
surfpool start -s 100

# Start with specific runbook
surfpool start -r deployment -r setup

Surfpool.toml Configuration

Create a Surfpool.toml in your project root:

[network]
slot_time = 400
epoch_duration = 432000
rpc_url = "https://api.mainnet-beta.solana.com"

[behavior]
# Fork from mainnet genesis
genesis = false
# Fork from specific point
point_fork = true

[accounts]
# Pre-clone specific accounts
clone = [
  "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",  # Token Program
  "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", # ATA Program
]

[programs]
# Auto-deploy local programs
deploy = ["./target/deploy/my_program.so"]

[airdrop]
# Default airdrop recipients
addresses = ["YOUR_PUBKEY"]
amount = 10000000000000  # 10,000 SOL

Cheatcodes

Surfpool provides special RPC methods for advanced state manipulation during testing.

Account Manipulation
surfnet_setAccount

Set arbitrary account data:

await connection.send("surfnet_setAccount", [
  {
    pubkey: "AccountPubkey...",
    lamports: 1000000000,
    data: "base64EncodedData",
    owner: "OwnerPubkey...",
    executable: false,
  },
]);
surfnet_setTokenAccount

Create or modify token accounts:

await connection.send("surfnet_setTokenAccount", [
  {
    owner: "OwnerPubkey...",
    mint: "MintPubkey...",
    tokenProgram: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
    update: {
      amount: "1000000000",
      delegate: null,
      state: "initialized",
    },
  },
]);
surfnet_cloneProgramAccount

Clone a program from mainnet:

await connection.send("surfnet_cloneProgramAccount", [
  {
    source: "SourceProgramPubkey...",
    destination: "DestinationPubkey...",
  },
]);
surfnet_resetAccount

Reset account to mainnet state:

await connection.send("surfnet_resetAccount", [
  {
    pubkey: "AccountPubkey...",
    includeOwnedAccounts: true,
  },
]);
Time Control
surfnet_timeTravel

Advance network time:

await connection.send("surfnet_timeTravel", [
  {
    epoch: 100,
    slot: 50000,
    timestamp: 1700000000,
  },
]);
surfnet_pauseClock / surfnet_resumeClock

Control block production:

// Pause
await connection.send("surfnet_pauseClock", []);

// Resume
await connection.send("surfnet_resumeClock", []);
surfnet_advanceClock

Advance clock incrementally:

await connection.send("surfnet_advanceClock", [
  { slots: 100 },
]);
Transaction Profiling
surfnet_profileTransaction

Profile transaction execution:

const result = await connection.send("surfnet_profileTransaction", [
  {
    transaction: "base64EncodedTx",
    tag: "my-test-tag",
  },
]);

console.log("Compute units:", result.computeUnits);
console.log("Account changes:", result.accountChanges);
surfnet_getProfileResults

Get profiling results by tag:

const results = await connection.send("surfnet_getProfileResults", [
  { tag: "my-test-tag" },
]);
Network Control
surfnet_resetNetwork

Reset entire network to initial state:

await connection.send("surfnet_resetNetwork", []);
surfnet_getClock

Get current network time:

const clock = await connection.send("surfnet_getClock", []);
console.log("Slot:", clock.slot);
console.log("Epoch:", clock.epoch);
console.log("Timestamp:", clock.timestamp);

Surfpool Studio

Access the web dashboard at http://127.0.0.1:18488 for:

  • Transaction Inspector - View transaction details with byte-level diffs
  • Account Browser - Explore account state and history
  • Compute Profiler - Analyze compute unit usage per instruction
  • Universal Faucet - Request SOL and tokens
  • Network Status - Monitor slots, epochs, and block production

Infrastructure as Code

Surfpool integrates txtx DSL for reproducible deployments.

Runbook Structure
# deployment.tx

// Define signers
signer "deployer" "svm::secret_key" {
  secret_key = env.DEPLOYER_KEY
}

// Deploy program
action "deploy_program" "svm::deploy_program" {
  program_path = "./target/deploy/my_program.so"
  signer = signer.deployer
}

// Initialize program
action "initialize" "svm::send_transaction" {
  transaction {
    instruction {
      program_id = action.deploy_program.program_id
      data = encode_instruction("initialize", {})
    }
  }
  signers = [signer.deployer]
}
Running Runbooks
# Run specific runbook
surfpool start -r deployment

# Run in unsupervised mode
surfpool start -r deployment --unsupervised

Scenarios and Fixtures

Scenarios

Define account state sequences for testing:

await connection.send("surfnet_registerScenario", [
  {
    name: "high-volume-trading",
    slots: [
      {
        slot: 100,
        accounts: {
          "PoolPubkey...": { lamports: 1000000000000 },
        },
      },
      {
        slot: 200,
        accounts: {
          "PoolPubkey...": { lamports: 500000000000 },
        },
      },
    ],
  },
]);
Fixtures

Export transaction fixtures for reproducible tests:

const fixture = await connection.send("surfnet_exportSnapshot", [
  {
    transaction: "txSignature...",
    format: "json",
  },
]);

// Save fixture for CI/CD
fs.writeFileSync("fixtures/my-test.json", JSON.stringify(fixture));

Integration with Anchor

Surfpool auto-detects Anchor projects and handles deployment:

# In an Anchor project directory
surfpool start
# Programs in target/deploy/ are automatically deployed
Testing with Anchor
import * as anchor from "@coral-xyz/anchor";

describe("My Program", () => {
  // Use local Surfnet
  const provider = anchor.AnchorProvider.local("http://127.0.0.1:8899");
  anchor.setProvider(provider);

  it("works with mainnet state", async () => {
    // Your tests automatically have access to mainnet accounts
  });
});

Best Practices

1. Use Cheatcodes for Setup
// Set up test state before each test
beforeEach(async () => {
  await connection.send("surfnet_resetNetwork", []);
  await connection.send("surfnet_setTokenAccount", [...]);
});
2. Profile Critical Paths
// Tag transactions for profiling
const result = await connection.send("surfnet_profileTransaction", [
  { transaction: tx, tag: "swap-operation" },
]);

expect(result.computeUnits).toBeLessThan(200000);
3. Use Scenarios for Edge Cases
// Test with specific mainnet conditions
await connection.send("surfnet_registerScenario", [
  { name: "low-liquidity", slots: [...] },
]);
4. Export Fixtures for CI
// Create reproducible test fixtures
const fixture = await connection.send("surfnet_exportSnapshot", [...]);

Resources

Official Links
Community
Tutorials

Skill Structure

surfpool/
├── SKILL.md                    # This file
├── resources/
│   ├── cheatcodes.md           # Complete cheatcodes reference
│   ├── cli-reference.md        # CLI commands reference
│   └── github-repos.md         # Repository links
├── examples/
│   ├── basic/
│   │   └── getting-started.ts  # Basic setup example
│   ├── cheatcodes/
│   │   └── state-manipulation.ts # Cheatcode examples
│   └── iac/
│       └── deployment.tx       # Infrastructure as Code example
├── templates/
│   ├── Surfpool.toml           # Configuration template
│   └── test-setup.ts           # Test setup template
└── docs/
    └── troubleshooting.md      # Common issues

Comments

Markdown supported