mcpbeat

Solana Rpc

agiprolabs/solana-rpc

Direct Solana blockchain interaction via JSON-RPC — account lookups, token balances, transaction submission, and program queries

11k tokens
context cost
the whole folder, loaded on every use
6
files
ships runnable scripts
0
copies elsewhere
how many repositories repackaged it
257
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/agiprolabs/claude-trading-skills --skill solana-rpc

The instruction itself

23 sections, as written by the author

Solana RPC — Direct Blockchain Interaction

The Solana JSON-RPC API provides direct read/write access to the blockchain. Use it for account state queries, token balance lookups, transaction building and submission, and program account enumeration. This is the low-level foundation when higher-level APIs (Birdeye, Helius, SolanaTracker) don't have the data you need.

Quick Start

import httpx

RPC = os.getenv("SOLANA_RPC_URL", "https://api.mainnet-beta.solana.com")

def rpc_call(method: str, params: list = None) -> dict:
    resp = httpx.post(RPC, json={
        "jsonrpc": "2.0", "id": 1,
        "method": method, "params": params or [],
    }, timeout=30.0)
    return resp.json()

# Get SOL balance
result = rpc_call("getBalance", ["WALLET_PUBKEY"])
sol_balance = result["result"]["value"] / 1e9

# Get latest blockhash
result = rpc_call("getLatestBlockhash")
blockhash = result["result"]["value"]["blockhash"]

RPC Providers

| Provider | Free Tier | Paid | Notes |

|----------|-----------|------|-------|

| Helius | 50K credits/day | $49+/mo | Enhanced RPCs, DAS API |

| QuickNode | Limited | $49+/mo | Multi-chain, WebSocket |

| Triton | No free tier | ~$300+/mo | Yellowstone gRPC bundled |

| Shyft | Limited | $49+/mo | Yellowstone gRPC bundled |

| Alchemy | 300M CU/mo | Scaling | Good free tier |

| Public (mainnet-beta) | Free | — | Rate limited, unreliable |

Recommendation: Use Helius or QuickNode for development. Never use public RPC for production trading.

Core Read Methods

Account & Balance

# SOL balance (in lamports, divide by 1e9 for SOL)
getBalance(pubkey, {commitment: "confirmed"})

# Full account info (data, owner, lamports, executable)
getAccountInfo(pubkey, {encoding: "jsonParsed"})

# Multiple accounts in one call
getMultipleAccounts([pubkey1, pubkey2], {encoding: "jsonParsed"})

Token Accounts

# All SPL token accounts owned by a wallet
getTokenAccountsByOwner(wallet_pubkey, {
    "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
}, {"encoding": "jsonParsed"})

# Token balance for a specific token account
getTokenAccountBalance(token_account_pubkey)

# Largest token accounts (top holders)
getTokenLargestAccounts(mint_pubkey)

# Total supply of a token
getTokenSupply(mint_pubkey)

Transaction Data

# Get parsed transaction by signature
getTransaction(signature, {
    "encoding": "jsonParsed",
    "maxSupportedTransactionVersion": 0,
})

# Recent transaction signatures for an address
getSignaturesForAddress(pubkey, {
    "limit": 20,
    "before": "optional_signature",  # pagination cursor
})

# Transaction status
getSignatureStatuses([sig1, sig2])

Block & Slot

# Current slot
getSlot({commitment: "confirmed"})

# Block data
getBlock(slot, {
    "encoding": "jsonParsed",
    "transactionDetails": "full",
    "maxSupportedTransactionVersion": 0,
})

# Latest blockhash (needed for tx building)
getLatestBlockhash({commitment: "confirmed"})

# Slot leader schedule
getLeaderSchedule()

Program Accounts

# All accounts owned by a program (with filters)
getProgramAccounts(program_pubkey, {
    "encoding": "jsonParsed",
    "filters": [
        {"dataSize": 165},  # Filter by account data size
        {"memcmp": {         # Filter by data content
            "offset": 32,
            "bytes": "base58_encoded_value",
        }},
    ],
})

Warning: getProgramAccounts without filters can return millions of results and timeout. Always use dataSize and/or memcmp filters.

Priority Fees

# Recent priority fee estimates
getRecentPrioritizationFees([account_pubkey])
# Returns array of { slot, prioritizationFee } for recent slots

# Minimum rent for account
getMinimumBalanceForRentExemption(data_length)

Write Methods

Send Transaction

# Send a signed, serialized transaction
sendTransaction(base64_tx, {
    "encoding": "base64",
    "skipPreflight": False,
    "preflightCommitment": "confirmed",
    "maxRetries": 3,
})

# Simulate before sending
simulateTransaction(base64_tx, {
    "encoding": "base64",
    "sigVerify": False,
    "commitment": "confirmed",
})

Transaction Confirmation

import time

def confirm_transaction(rpc_url: str, signature: str, timeout: float = 30.0) -> bool:
    """Poll for transaction confirmation."""
    start = time.time()
    while time.time() - start < timeout:
        result = rpc_call("getSignatureStatuses", [[signature]])
        statuses = result.get("result", {}).get("value", [None])
        if statuses[0] is not None:
            status = statuses[0]
            if status.get("err"):
                return False
            if status.get("confirmationStatus") in ("confirmed", "finalized"):
                return True
        time.sleep(0.5)
    return False

Commitment Levels

| Level | Description | Use When |

|-------|-------------|----------|

| processed | Single node confirmation | Speed over safety |

| confirmed | Supermajority (2/3+) | Default for trading |

| finalized | Maximum supermajority + 31 slots | Critical operations |

Always specify commitment explicitly. Default varies by provider.

Common Patterns

Get All Token Holdings for a Wallet

def get_wallet_tokens(wallet: str) -> list[dict]:
    """Get all SPL token holdings with metadata."""
    result = rpc_call("getTokenAccountsByOwner", [
        wallet,
        {"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"},
        {"encoding": "jsonParsed"},
    ])
    tokens = []
    for acct in result["result"]["value"]:
        info = acct["account"]["data"]["parsed"]["info"]
        tokens.append({
            "mint": info["mint"],
            "amount": int(info["tokenAmount"]["amount"]),
            "decimals": info["tokenAmount"]["decimals"],
            "ui_amount": info["tokenAmount"]["uiAmount"],
        })
    return [t for t in tokens if t["amount"] > 0]

Get Top Holders of a Token

def get_top_holders(mint: str) -> list[dict]:
    """Get the 20 largest holders of a token."""
    result = rpc_call("getTokenLargestAccounts", [mint])
    supply_result = rpc_call("getTokenSupply", [mint])
    total_supply = int(supply_result["result"]["value"]["amount"])

    holders = []
    for acct in result["result"]["value"]:
        amount = int(acct["amount"])
        holders.append({
            "address": acct["address"],
            "amount": amount,
            "decimals": acct["decimals"],
            "ui_amount": acct["uiAmount"],
            "percentage": amount / total_supply * 100 if total_supply > 0 else 0,
        })
    return holders

Batch RPC Calls

def rpc_batch(calls: list[tuple[str, list]]) -> list[dict]:
    """Execute multiple RPC calls in a single HTTP request."""
    payload = [
        {"jsonrpc": "2.0", "id": i, "method": method, "params": params}
        for i, (method, params) in enumerate(calls)
    ]
    resp = httpx.post(RPC, json=payload, timeout=30.0)
    results = resp.json()
    results.sort(key=lambda r: r["id"])
    return [r.get("result") for r in results]

Key Program IDs

| Program | ID |

|---------|-----|

| System | 11111111111111111111111111111111 |

| SPL Token | TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA |

| Token-2022 | TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb |

| Associated Token | ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL |

| Raydium AMM | 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 |

| Raydium CLMM | CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK |

| Orca Whirlpool | whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc |

| Meteora DLMM | LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo |

| PumpFun | 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P |

| Jupiter v6 | JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 |

| Compute Budget | ComputeBudget111111111111111111111111111111 |

When to Use Direct RPC vs Higher-Level APIs

| Need | Use |

|------|-----|

| Token balance check | Direct RPC (getTokenAccountsByOwner) |

| Top 20 holders | Direct RPC (getTokenLargestAccounts) |

| Historical OHLCV | Birdeye or SolanaTracker |

| Parsed transaction history | Helius Enhanced Transactions |

| Token metadata (name, image) | Helius DAS API |

| Real-time streaming | Yellowstone gRPC |

| Wallet PnL tracking | SolanaTracker |

| Token risk scoring | SolanaTracker |

| Cross-chain data | DexScreener or CoinGecko |

Files

References

  • references/methods.md — Complete RPC method reference with parameters and response schemas
  • references/error_handling.md — Error codes, rate limits, timeout handling, retry strategies
  • references/providers.md — RPC provider comparison with pricing and features

Scripts

  • scripts/wallet_scanner.py — Scan wallet for all token holdings with balances
  • scripts/token_holders.py — Get top holders and concentration metrics for any token

How to use it

Copy the folder

Take agiprolabs/solana-rpc from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.