Loading...
Loading...
Complete Surfpool development environment for Solana - drop-in replacement for solana-test-validator with mainnet forking, cheatcodes, Infrastructure as Code, and Surfpool Studio. The fastest way to develop and test Solana programs.
npx skill4agent add sendaifun/skills surfpoolsolana-test-validator| Feature | Description |
|---|---|
| Instant Boot | No 2TB snapshots, runs on Raspberry Pi |
| Lazy Forking | Copy-on-read strategy pulls mainnet data as needed |
| Full Compatibility | Works with solana-cli, Anchor, wallets, explorers |
| Zero Config | Auto-detects Anchor projects and deploys programs |
curl -sL https://run.surfpool.run/ | bashbrew install txtx/taps/surfpoolgit clone https://github.com/txtx/surfpool.git
cd surfpool
cargo surfpool-installdocker pull surfpool/surfpool
docker run -p 8899:8899 -p 18488:18488 surfpool/surfpool# 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| Service | URL | Description |
|---|---|---|
| RPC Endpoint | | Standard Solana RPC |
| WebSocket | | Real-time subscriptions |
| Surfpool Studio | | Web dashboard |
surfpool start [OPTIONS]| Option | Default | Description |
|---|---|---|
| | Path to manifest file |
| | RPC port |
| | Host address |
| | Slot time in ms |
| | Source RPC URL |
| - | Disable terminal UI |
| - | Enable debug logs |
| - | Disable auto deployments |
| | Runbooks to execute |
| - | Pubkeys to airdrop |
| | Airdrop amount (lamports) |
| - | Keypair path for airdrop |
| - | Disable explorer |
# 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 setupSurfpool.toml[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 SOLawait connection.send("surfnet_setAccount", [
{
pubkey: "AccountPubkey...",
lamports: 1000000000,
data: "base64EncodedData",
owner: "OwnerPubkey...",
executable: false,
},
]);await connection.send("surfnet_setTokenAccount", [
{
owner: "OwnerPubkey...",
mint: "MintPubkey...",
tokenProgram: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
update: {
amount: "1000000000",
delegate: null,
state: "initialized",
},
},
]);await connection.send("surfnet_cloneProgramAccount", [
{
source: "SourceProgramPubkey...",
destination: "DestinationPubkey...",
},
]);await connection.send("surfnet_resetAccount", [
{
pubkey: "AccountPubkey...",
includeOwnedAccounts: true,
},
]);await connection.send("surfnet_timeTravel", [
{
epoch: 100,
slot: 50000,
timestamp: 1700000000,
},
]);// Pause
await connection.send("surfnet_pauseClock", []);
// Resume
await connection.send("surfnet_resumeClock", []);await connection.send("surfnet_advanceClock", [
{ slots: 100 },
]);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);const results = await connection.send("surfnet_getProfileResults", [
{ tag: "my-test-tag" },
]);await connection.send("surfnet_resetNetwork", []);const clock = await connection.send("surfnet_getClock", []);
console.log("Slot:", clock.slot);
console.log("Epoch:", clock.epoch);
console.log("Timestamp:", clock.timestamp);http://127.0.0.1:18488# 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]
}# Run specific runbook
surfpool start -r deployment
# Run in unsupervised mode
surfpool start -r deployment --unsupervisedawait connection.send("surfnet_registerScenario", [
{
name: "high-volume-trading",
slots: [
{
slot: 100,
accounts: {
"PoolPubkey...": { lamports: 1000000000000 },
},
},
{
slot: 200,
accounts: {
"PoolPubkey...": { lamports: 500000000000 },
},
},
],
},
]);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));# In an Anchor project directory
surfpool start
# Programs in target/deploy/ are automatically deployedimport * 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
});
});// Set up test state before each test
beforeEach(async () => {
await connection.send("surfnet_resetNetwork", []);
await connection.send("surfnet_setTokenAccount", [...]);
});// Tag transactions for profiling
const result = await connection.send("surfnet_profileTransaction", [
{ transaction: tx, tag: "swap-operation" },
]);
expect(result.computeUnits).toBeLessThan(200000);// Test with specific mainnet conditions
await connection.send("surfnet_registerScenario", [
{ name: "low-liquidity", slots: [...] },
]);// Create reproducible test fixtures
const fixture = await connection.send("surfnet_exportSnapshot", [...]);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