mcpField
S
solana-tx-building

solana-tx-building

github.com/agiprolabs開発456446 回インストール8 週間前に更新
リポジトリ

solana-tx-building について

solana-tx-buildingは、Solanaトランザクションの構築、シミュレーション、検査を行う開発者向けスキルです。命令形式、バージョン付きトランザクション、計算予算、手数料、デコードを扱い、スクリプトは実際の署名や送信を行いません。

主な機能

  1. 01トランザクション命令の構築
  2. 02バージョン付き形式とALTの利用
  3. 03計算上限と優先手数料の設定
  4. 04送信せずにトランザクションをシミュレーション
  5. 05オンチェーントランザクションの取得とデコード

活用シーン

  1. 01複数アカウントを含むSolanaトランザクションの準備
  2. 02シミュレーションによる動作テスト
  3. 03確定済みトランザクションの内容確認

インストール

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

$npx skills add https://github.com/agiprolabs/claude-trading-skills --skill solana-tx-building

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
common_instructions.md
transaction_anatomy.md
scripts/
build_transfer.py
decode_transaction.py

詳細

Solana トランザクションの構築

このスキルでは、Solana トランザクションをプログラムで構築、シミュレーション、検査する方法を説明します。生の命令エンコードから、バージョン付きトランザクション形式、コンピュートバジェット管理、優先手数料、アドレスルックアップテーブルまで、Solana トランザクションの全体的な構造を扱います。

安全性:このスキルはトランザクションの構築と分析のみを対象とします。このスキルのスクリプトが実際のトランザクションに署名したり、送信したりすることは決してありません。送信前には必ずシミュレーションしてください。自動署名は絶対に行わないでください。

トランザクションの構造

Solana トランザクションは次の要素で構成されます。

  1. 署名:1 つ以上の Ed25519 署名(各 64 バイト)
  2. メッセージ:次の内容を含むシリアライズ可能なペイロード
    • ヘッダー:必須署名者、読み取り専用署名者、読み取り専用の非署名者の数
    • アカウントキー:命令が参照するすべての公開鍵の配列
    • 最新ブロックハッシュ:リプレイ保護のための 32 バイトのハッシュ(約 60~90 秒で期限切れ)
    • 命令:プログラム呼び出しの配列
トランザクションサイズの上限

シリアライズされたトランザクション全体の上限は 1232 バイトです。この制限により、含められる命令やアカウントの数が限られます。上限内に収める方法は次のとおりです。

  • アドレスルックアップテーブル(ALT)を使用するバージョン付きトランザクションを使う
  • 命令ごとのアカウント数を最小限にする
  • サポートされている場合は、関連する操作を 1 つの命令にまとめる
  • 複雑な操作を複数のトランザクションに分割する
命令の形式

各命令には 3 つのフィールドがあります。

Instruction {
    program_id_index: u8,      // Index into the account keys array
    accounts: [u8],            // Indices into account keys array
    data: [u8],                // Opaque byte array interpreted by the program
}
アカウントメタデータ

命令で参照される各アカウントには、メタデータがあります。

AccountMeta {
    pubkey: Pubkey,            // 32-byte public key
    is_signer: bool,           // Must sign the transaction
    is_writable: bool,         // Will be written to by this instruction
}

次の 4 つの組み合わせによって、アカウントの役割が決まります。

is_signeris_writable役割
truetrue手数料支払者、転送を実行するトークン所有者
truefalseマルチシグの共同署名者、読み取り専用の権限者
falsetrue宛先アカウント、書き込み対象の PDA
falsefalseプログラム ID、sysvar、クロック

レガシートランザクションとバージョン付きトランザクション

レガシートランザクション

従来の形式です。すべてのアカウントをアカウントキー配列に含める必要があります。1232 バイトの制限では、命令データのサイズにもよりますが、およそ 20~35 個のアカウントを含められます。

バージョン付きトランザクション(v0)

**アドレスルックアップテーブル(ALT)**をサポートするために導入されました。v0 トランザクションには次のものが含まれます。

  • バージョンプレフィックスの 1 バイト(v0 の場合は 0x80)
  • レガシーと同じメッセージ構造
  • 追加の address_table_lookups 配列

ALT を使うと、完全な 32 バイトの公開鍵を含める代わりに、オンチェーンテーブル内のコンパクトなインデックスでアカウントを参照できます。これにより、トランザクションが参照できるアカウント数が大幅に増えます。

AddressTableLookup {
    account_key: Pubkey,           // The ALT account address
    writable_indexes: [u8],        // Indices for writable accounts
    readonly_indexes: [u8],        // Indices for read-only accounts
}

v0 を使う場合:参照するアカウントが約 20 個を超えるトランザクション、複数ホップのルートを使う Jupiter スワップ、複雑な DeFi の操作。

コンピュートバジェット

各トランザクションには、消費できるコンピュートユニット(CU)の数と支払う優先手数料を決めるコンピュートバジェットがあります。

コンピュートバジェット命令

Compute Budget Program(ComputeBudget111111111111111111111111111111)の主な命令は 2 つあります。

1. コンピュートユニット上限の設定

Instruction data: [0x02, <units as u32 LE>]

このトランザクションが消費できる CU の最大数を設定します。デフォルトは命令ごとに 200,000(トランザクションごとの最大値は 1,400,000)です。必要量より低く設定するとトランザクションは失敗します。高く設定するとバジェットを無駄にしますが、コストは増えません(支払うのは実際の消費量ではなく、要求した量に対してです)。

2. コンピュートユニット価格の設定

Instruction data: [0x03, <micro_lamports as u64 LE>]

CU あたりの価格をマイクロラムポートで設定します。これが優先手数料の仕組みです。優先手数料の合計は次のとおりです。

priority_fee = compute_unit_limit * compute_unit_price / 1_000_000
優先手数料の見積もり

適切な優先手数料を見積もるには、次の手順を実行します。

  1. トランザクションが使用するアカウントを指定して、RPC メソッド getRecentPrioritizationFees を呼び出す
  2. 最近のスロットにおける手数料の中央値または 75 パーセンタイルを確認する
  3. 混雑時には手数料が急増するため、状況を監視して動的に調整する
import httpx

def get_priority_fees(rpc_url: str, accounts: list[str]) -> list[dict]:
    """Fetch recent prioritization fees for given accounts."""
    resp = httpx.post(rpc_url, json={
        "jsonrpc": "2.0",
        "id": 1,
        "method": "getRecentPrioritizationFees",
        "params": [accounts]
    })
    return resp.json()["result"]

一般的なトランザクションパターン

1. SOL の転送

最もシンプルなトランザクションである、System Program の転送です。

# System Program transfer instruction data layout:
# [2, 0, 0, 0]  (u32 LE = instruction index 2 = Transfer)
# + amount as u64 LE (lamports)
import struct

def build_sol_transfer_data(lamports: int) -> bytes:
    """Build instruction data for a SOL transfer."""
    return struct.pack("<I", 2) + struct.pack("<Q", lamports)

必要なアカウント:

  1. 送信者(署名者、書き込み可能)
  2. 受取人(書き込み可能)
2. SPL トークンの転送

SPL トークンを転送するには、Token Program が必要です。

# Token Program transfer instruction:
# [3]  (instruction index 3 = Transfer)
# + amount as u64 LE
def build_token_transfer_data(amount: int) -> bytes:
    """Build instruction data for an SPL token transfer."""
    return bytes([3]) + struct.pack("<Q", amount)

必要なアカウント:

  1. 送信元トークンアカウント(書き込み可能)
  2. 送信先トークンアカウント(書き込み可能)
  3. オーナー/デリゲート(署名者)
3. 関連付けトークンアカウント(ATA)の作成

トークンを転送する前に、受取人が関連付けトークンアカウントを持っている必要があります。

# ATA Program: instruction index 0 = Create
# No instruction data needed (empty bytes)
ATA_PROGRAM_ID = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"

必要なアカウント(順番どおり):

  1. 支払者(署名者、書き込み可能) — レントを支払います
  2. 関連付けトークンアカウント(書き込み可能) — 作成する ATA です
  3. ウォレットアドレス — 新しい ATA のオーナーです
  4. トークンミント
  5. System Program
  6. Token Program
4. Jupiter スワップ

Jupiter は、あらかじめ構築されたインストラクションを返す /swap-instructions エンドポイントを提供しています。詳細は jupiter-api スキルを参照してください。

一般的なフロー:

  1. /quote から見積もりを取得します
  2. /swap-instructions からスワップインストラクションを取得します
  3. セットアップインストラクション、スワップインストラクション、クリーンアップインストラクションを使ってトランザクションを構築します
  4. コンピュートバジェットのインストラクションを追加します
  5. シミュレーションを行い、その後署名して送信します

シミュレーション

送信前には必ずシミュレーションしてください。simulateTransaction RPC メソッドを使用します。

def simulate_transaction(rpc_url: str, tx_base64: str) -> dict:
    """Simulate a transaction without submitting it.

    Args:
        rpc_url: Solana RPC endpoint URL.
        tx_base64: Base64-encoded serialized transaction.

    Returns:
        Simulation result with logs and compute units consumed.
    """
    resp = httpx.post(rpc_url, json={
        "jsonrpc": "2.0",
        "id": 1,
        "method": "simulateTransaction",
        "params": [
            tx_base64,
            {"encoding": "base64", "replaceRecentBlockhash": True}
        ]
    })
    result = resp.json()["result"]
    if result["value"]["err"]:
        print(f"Simulation failed: {result['value']['err']}")
        for log in result["value"].get("logs", []):
            print(f"  {log}")
    else:
        cu = result["value"].get("unitsConsumed", 0)
        print(f"Simulation OK — {cu} compute units consumed")
    return result

replaceRecentBlockhash: True フラグを使うと、ブロックハッシュの有効期限が切れていてもシミュレーションできます。時間に追われずにトランザクションの構築をテストする場合に便利です。

エラー処理

よくあるトランザクションエラーとその原因:

エラー原因対処法
BlockhashNotFoundブロックハッシュの有効期限切れ(約60~90秒)新しいブロックハッシュを取得して再構築します
InsufficientFunds手数料と転送額に対して SOL が不足しています構築前に残高を確認します
AccountNotFoundトークンアカウントが存在しません先に ATA を作成します
ProgramFailedToCompleteコンピュートバジェットを超過しましたコンピュートユニットの上限を増やします
TransactionTooLarge1232 バイトを超えていますALT を使用するか、複数のトランザクションに分割します
InvalidAccountDataインストラクションに誤ったアカウントが渡されましたアカウントの導出を確認します
SignatureVerificationFailed署名者が不足しているか、誤っていますすべての is_signer アカウントが署名していることを確認します
再試行戦略
import time

def send_with_retry(
    rpc_url: str,
    build_fn,
    max_retries: int = 3,
    base_delay: float = 0.5
) -> dict:
    """Build and send a transaction with blockhash refresh on expiry.

    Args:
        rpc_url: Solana RPC endpoint.
        build_fn: Callable that takes a blockhash and returns a signed tx.
        max_retries: Maximum retry attempts.
        base_delay: Base delay between retries in seconds.

    Returns:
        Send result from RPC.
    """
    for attempt in range(max_retries):
        blockhash = get_latest_blockhash(rpc_url)
        tx = build_fn(blockhash)
        result = send_transaction(rpc_url, tx)
        if "error" not in result:
            return result
        err = result["error"]
        if "BlockhashNotFound" in str(err):
            time.sleep(base_delay * (attempt + 1))
            continue
        raise RuntimeError(f"Transaction failed: {err}")
    raise RuntimeError("Max retries exceeded")

トランザクションのデコード

チェーン上の既存のトランザクションをデコードするには:

def decode_transaction(rpc_url: str, signature: str) -> dict:
    """Fetch and return a parsed transaction.

    Args:
        rpc_url: Solana RPC endpoint.
        signature: Transaction signature (base58).

    Returns:
        Parsed transaction data.
    """
    resp = httpx.post(rpc_url, json={
        "jsonrpc": "2.0",
        "id": 1,
        "method": "getTransaction",
        "params": [
            signature,
            {"encoding": "jsonParsed", "maxSupportedTransactionVersion": 0}
        ]
    })
    return resp.json()["result"]

他のスキルとの連携

  • solana-rpc:トランザクションの送信と照会に使う RPC 接続レイヤーを提供します
  • jupiter-api:このスキルがトランザクションに組み込むスワップインストラクションを提供します
  • dex-execution:このスキルで構築したトランザクションを使用して、実行フロー全体を調整します
  • mev-analysis:送信前に、構築したトランザクションの MEV リスクを評価します
  • helius-api:トランザクションの高度な解析と、Webhook による確認状況の追跡を提供します

安全性チェックリスト

メインネットにトランザクションを送信する前に、以下を確認してください。

  1. まずシミュレーションする — sendTransaction の前に必ず simulateTransaction を呼び出します
  2. アカウントを検証する — すべてのアカウントアドレスが正しいことを確認します(特にトークン転送の場合)
  3. 残高を確認する — 手数料と転送額に対して十分な SOL があることを確認します
  4. コンピュートバジェットを確認する — シミュレーションに基づいて適切な CU 上限を設定します
  5. 優先手数料を確認する — 現在のネットワーク手数料を確認し、払いすぎないようにします
  6. 自動署名しない — 署名の前に、ユーザーに明示的な確認を求めます
  7. テストには devnet を使う — メインネットを使う前に devnet で構築とテストを行います
  8. すべてを記録する — トランザクション署名、シミュレーション結果、エラーを記録します

ファイル

参考資料
  • references/transaction_anatomy.md — メッセージ形式、バージョン付きトランザクション、コンピュートバジェット、ブロックハッシュ管理
  • references/common_instructions.md — System、Token、ATA、Compute Budget、Memo、Jupiter プログラムのインストラクション構造
スクリプト
  • scripts/build_transfer.py — SOL 転送トランザクションを構築してシミュレーションします(デモモード、署名は行いません)
  • scripts/decode_transaction.py — オンチェーントランザクションを取得し、プログラムを特定してデコードします

コメント