mcpField
S
surfpool

surfpool

github.com/sendaifun開発130220 回インストール13 週間前に更新
リポジトリ

surfpool について

surfpool は Solana 開発者向けのローカル開発環境で、`solana-test-validator` の代替として必要に応じて Mainnet のデータを取得します。状態操作、デプロイ自動化、トランザクション分析を組み合わせ、オンチェーンアカウントを使ったテストに対応します。

主な機能

  1. 01Mainnet のアカウントとプログラムを必要時にフォーク
  2. 02RPC チートコードで状態と時刻を操作
  3. 03Anchor プロジェクトを検出してプログラムを自動デプロイ
  4. 04Surfpool Studio でトランザクションと計算量を確認
  5. 05txtx DSL で再現可能なデプロイを記述

活用シーン

  1. 01Mainnet のアカウント状態を使った Solana プログラムのテスト
  2. 02残高、アカウントデータ、ネットワーク時刻を設定した境界条件の確認
  3. 03トランザクションの計算量分析とアカウント状態の確認
  4. 04テストや CI 用の再現可能なトランザクションスナップショットの出力

インストール

コマンドをコピーしてターミナルで実行します。

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

インストール後、Claude Code で/surfpoolを入力して読み込まれたか確認します。

同梱ファイル

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

詳細

Surfpool - Solana 開発環境

Surfpool の決定版ガイドです。開発者が Solana の開発を始める場所です。solana-test-validator のドロップイン代替として、Mainnet のアカウントを必要なタイミングで取得し、ローカルでプログラムをシミュレーションできます。

Surfpool とは?

Surfpool は、ローカル優先のテストと実際の Mainnet データへのアクセスを組み合わせた、包括的な開発環境です。

  • Mainnet フォーク - Mainnet のアカウント、プログラム、トークン残高を即座に複製します
  • チートコード - 時間の操作、残高の変更、状態の制御に使える特別な RPC メソッドです
  • Infrastructure as Code - txtx DSL を使用して、再現可能で監査可能なデプロイを実現します
  • Surfpool Studio - トランザクションの検査とプロファイリング機能を備えた組み込みダッシュボードです
  • ユニバーサル・フォーセット - 1 つのインターフェースから SOL、USDC、USDT、BONK を取得できます
主なメリット
機能説明
即時起動2 TB のスナップショットは不要で、Raspberry Pi でも動作します
遅延フォーク読み取り時にコピーする方式で、必要に応じて mainnet データを取得します
完全な互換性solana-cli、Anchor、ウォレット、エクスプローラーで動作します
設定不要Anchor プロジェクトを自動検出し、プログラムをデプロイします
統計
  • GitHub スター 460 件以上
  • フォーク 100 件以上
  • Apache 2.0 ライセンス
  • 現在のバージョン:v1.0.0

インストール

自動インストーラー(推奨)
curl -sL https://run.surfpool.run/ | bash
Homebrew(macOS)
brew install txtx/taps/surfpool
ソースからインストール
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

クイックスタート

ローカルネットワークを起動する
# 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
アクセスポイント
サービスURL説明
RPC エンドポイントhttp://127.0.0.1:8899標準の Solana RPC
WebSocketws://127.0.0.1:8900リアルタイムのサブスクリプション
Surfpool Studiohttp://127.0.0.1:18488Web ダッシュボード

CLI コマンド

surfpool start

ローカルの Surfnet ネットワークを起動します。

surfpool start [OPTIONS]

オプション:

オプションデフォルト説明
-m, --manifest-file-path./Surfpool.tomlマニフェストファイルのパス
-p, --port8899RPC ポート
-o, --host127.0.0.1ホストアドレス
-s, --slot-time400スロット時間(ms)
-u, --rpc-urlhttps://api.mainnet-beta.solana.comソース RPC URL
--no-tui-ターミナル UI を無効にします
--debug-デバッグログを有効にします
--no-deploy-自動デプロイを無効にします
-r, --runbookdeployment実行するランブック
-a, --airdrop-エアドロップ先の公開鍵
-q, --airdrop-amount10000000000000エアドロップ量(lamports)
-k, --airdrop-keypair-path-エアドロップに使うキーペアのパス
--no-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 setup

Surfpool.toml の設定

プロジェクトのルートに Surfpool.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 SOL

チートコード

Surfpool は、テスト中に高度な状態操作を行うための特別な RPC メソッドを提供します。

アカウント操作
surfnet_setAccount

任意のアカウントデータを設定します。

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

トークンアカウントを作成または変更します。

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

mainnet からプログラムを複製します。

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

アカウントを mainnet の状態にリセットします。

await connection.send("surfnet_resetAccount", [
  {
    pubkey: "AccountPubkey...",
    includeOwnedAccounts: true,
  },
]);
時間制御
surfnet_timeTravel

ネットワークの時間を進めます。

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

ブロック生成を制御します。

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

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

クロックを段階的に進めます。

await connection.send("surfnet_advanceClock", [
  { slots: 100 },
]);
トランザクションのプロファイリング
surfnet_profileTransaction

トランザクションの実行をプロファイリングします。

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

タグを指定してプロファイリング結果を取得します。

const results = await connection.send("surfnet_getProfileResults", [
  { tag: "my-test-tag" },
]);
ネットワーク制御
surfnet_resetNetwork

ネットワーク全体を初期状態にリセットします。

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

現在のネットワーク時刻を取得します。

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

Surfpool Studio

http://127.0.0.1:18488 でウェブダッシュボードにアクセスすると、次の機能を利用できます。

  • トランザクションインスペクター - バイトレベルの差分とともにトランザクションの詳細を表示します
  • アカウントブラウザー - アカウントの状態と履歴を確認します
  • コンピュートプロファイラー - 命令ごとのコンピュートユニットの使用量を分析します
  • ユニバーサルファウセット - SOL とトークンをリクエストします
  • ネットワークステータス - スロット、エポック、ブロック生成を監視します

Infrastructure as Code

Surfpool は、再現可能なデプロイのために txtx DSL と連携します。

Runbook の構造
# 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]
}
Runbook の実行
# Run specific runbook
surfpool start -r deployment

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

シナリオとフィクスチャ

シナリオ

テスト用のアカウント状態のシーケンスを定義します。

await 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));

Anchor との連携

Surfpool は Anchor プロジェクトを自動検出し、デプロイを処理します。

# In an Anchor project directory
surfpool start
# Programs in target/deploy/ are automatically deployed
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
  });
});

ベストプラクティス

1. セットアップにはチートコードを使用する
// Set up test state before each test
beforeEach(async () => {
  await connection.send("surfnet_resetNetwork", []);
  await connection.send("surfnet_setTokenAccount", [...]);
});
2. 重要な処理経路をプロファイリングする
// Tag transactions for profiling
const result = await connection.send("surfnet_profileTransaction", [
  { transaction: tx, tag: "swap-operation" },
]);

expect(result.computeUnits).toBeLessThan(200000);
3. エッジケースにはシナリオを使用する
// Test with specific mainnet conditions
await connection.send("surfnet_registerScenario", [
  { name: "low-liquidity", slots: [...] },
]);
4. CI 用にフィクスチャをエクスポートする
// 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

コメント