Reading Chain Data
Python services read Solana state through JSON-RPC (getAccountInfo, getTokenAccountsByOwner, getSignaturesForAddress) and, for NFTs and compressed assets, the Digital Asset Standard (DAS) API. Use solana-py for core RPC and httpx for DAS HTTP endpoints on Agave 4.1.1 providers.
Recipe
Quick-reference recipe card - copy-paste ready.
from solders.pubkey import Pubkey
from solana.rpc.api import Client
client = Client("https://api.devnet.solana.com")
mint = Pubkey.from_string("<MINT_PUBKEY>")
info = client.get_account_info(mint)
print(info.value.lamports if info.value else "missing")
tokens = client.get_token_accounts_by_owner_json_parsed(
Pubkey.from_string("<OWNER>"),
{"mint": str(mint)},
)When to reach for this:
- Backends serving portfolio balances and history.
- Bots monitoring account state changes between sends.
- ETL jobs hydrating warehouses from on-chain accounts.
- NFT/cNFT dashboards via DAS
getAssetand search methods.
Working Example
import asyncio
import httpx
from solders.pubkey import Pubkey
from solana.rpc.async_api import AsyncClient
RPC = "https://api.devnet.solana.com"
DAS = "https://devnet.helius-rpc.com/?api-key=<KEY>" # provider with DAS enabled
OWNER = Pubkey.from_string("<OWNER_PUBKEY>")
async def fetch_portfolio():
async with AsyncClient(RPC) as client:
sol = await client.get_balance(OWNER)
sigs = await client.get_signatures_for_address(OWNER, limit=10)
token_resp = await client.get_token_accounts_by_owner_json_parsed(
OWNER,
{"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"},
)
tokens = token_resp.value
async with httpx.AsyncClient() as http:
das_resp = await http.post(
DAS,
json={
"jsonrpc": "2.0",
"id": 1,
"method": "getAssetsByOwner",
"params": {"ownerAddress": str(OWNER), "page": 1, "limit": 50},
},
)
assets = das_resp.json()["result"]
return {
"lamports": sol.value,
"recent_signatures": [s.signature for s in sigs.value],
"spl_tokens": len(tokens),
"das_assets": len(assets.get("items", [])),
}
print(asyncio.run(fetch_portfolio()))What this demonstrates:
- Core RPC reads SOL balance, signatures, and SPL token accounts.
- JSON-parsed token accounts avoid manual layout decoding.
- DAS complements RPC for NFT/cNFT metadata aggregation.
- Async gathers I/O-bound provider calls efficiently.
Deep Dive
How It Works
- Accounts store lamports + opaque bytes; interpretation depends on owner program.
- SPL Token accounts use a well-known layout - RPC
jsonParsedreturns structured fields. - Signatures for address paginate backwards in time with
beforecursor. - DAS indexes compressed and standard digital assets - not a replacement for all RPC reads.
Read API Map
| Need | Method | Client |
|---|---|---|
| Raw account bytes | getAccountInfo | solana-py |
| SOL balance | getBalance | solana-py |
| SPL balances | getTokenAccountsByOwner (jsonParsed) | solana-py |
| Tx history | getSignaturesForAddress | solana-py |
| NFT metadata | getAsset / searchAssets | DAS HTTP |
| Program accounts scan | getProgramAccounts + memcmp | solana-py (careful) |
Python Notes
# Decode Anchor account with AnchorPy after fetching raw data
# account = await program.account["MyState"].fetch(pubkey)
# Paginate signatures
before = None
while True:
batch = await client.get_signatures_for_address(addr, before=before, limit=1000)
if not batch.value:
break
before = batch.value[-1].signatureGotchas
getProgramAccountswithout filters - downloads entire program state. Fix: memcmp on discriminator; use an indexer.- Assuming DAS on every RPC URL - public devnet may lack DAS. Fix: use a DAS-capable provider explicitly.
- Encoding confusion -
base64vsjsonParsedchanges response shape. Fix: pick per call and document. - Rate limits during backfills - sequential scans trip 429s. Fix: throttle, shard by slot, or export from BigTable.
- Closed token accounts - zero balance accounts may be omitted. Fix: handle empty lists; track mints separately.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Geyser gRPC stream | Real-time indexing | Simple one-off reads |
@solana/kit in frontend | User wallet reads | Python analytics |
| Helius / Triton enhanced APIs | DAS + parsed history | Air-gapped devnet only |
| Warehouse replica (ClickHouse) | Analytics at scale | Single balance check |
FAQs
Do I need DAS for SPL tokens?
No - SPL token accounts are available via standard RPC jsonParsed encoding.
When is DAS required?
Compressed NFTs, unified NFT search, and rich metadata without manual PDA walks.
How fresh is DAS data?
Provider-dependent - check indexer lag SLAs for your vendor.
getMultipleAccounts?
Batch up to provider limit (often 100) for hot paths.
Historical balances?
RPC is point-in-time; use archival RPC or your indexer for history.
Parse Anchor accounts without AnchorPy?
Possible with Borsh layouts - AnchorPy is simpler when IDL exists.
WebSocket subscriptions?
solana-py supports account and logs subscriptions for bots.
Devnet vs mainnet URLs?
Never share one client instance across clusters - separate configs.
BigQuery public dataset?
Good for batch analytics; not for low-latency trading loops.
Compliance logging?
Log which RPC provider served each read for audit trails.
Related
- solders & solana-py - RPC client setup
- Data Analysis - pandas/Polars export
- The DAS API - DAS reference
- RPC Basics - JSON-RPC core
Stack versions: This page was written for Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, and LiteSVM 0.6.x.