Day 24 of #100DaysOfSolana
Yesterday I built a terminal account explorer. But that data field kept staring back at me a blob of base64 with no obvious meaning.
Today I cracked it open.
The problem
Every Solana account stores its state as a flat byte array. There's no JSON, no column names, no built-in schema. The program that owns the account defines how those bytes are laid out using a serialization format called Borsh (Binary Object Representation Serializer for Hashing).
To read account data, you need either:
- A pre-built codec for that account type, or
- The byte-level specification to decode it manually
What I decoded
I used the Wrapped SOL mint account on mainnet as my target a well-known SPL Token account with a fixed 82-byte layout.
Method 1 Pre-built codec (the easy path)
import { getMintDecoder } from "@solana-program/token";
const decoded = getMintDecoder().decode(accountData);
console.log(decoded);
One line. Returns a fully structured object with supply, decimals, mintAuthority, and more. This is what you'd use in production.
Method 2 Manual byte decoding (the learning path)
The 82-byte Mint layout:
| Bytes | Field | Type |
|---|---|---|
| 0–3 | mintAuthorityOption | u32 |
| 4–35 | mintAuthority | 32-byte pubkey |
| 36–43 | supply | u64 (little-endian) |
| 44 | decimals | u8 |
| 45 | isInitialized | bool |
| 46–49 | freezeAuthorityOption | u32 |
| 50–81 | freezeAuthority | 32-byte pubkey |
const view = new DataView(data.buffer);
const supply = view.getBigUint64(36, true); // true = little-endian
const decimals = view.getUint8(44);
const isInitialized = view.getUint8(45) === 1;
Two things to understand here:
DataView lets you read multiple adjacent bytes as a single typed value (u32, u64, etc). You'd use it to parse any binary format, not just Solana.
Little-endian flag (true) Solana stores all multi-byte numbers least significant byte first. Forgetting this flag is the single most common decoding bug. Every multi-byte read needs true.
Method 3 RPC jsonParsed (the shortcut)
const { value } = await rpc.getAccountInfo(address, {
encoding: "jsonParsed"
}).send();
The RPC decodes it server-side for known programs. Great for quick checks but only works for well-known programs. For custom programs, you bring your own decoder.
All three methods returned identical values. ✅
The three encodings you'll see everywhere
| Encoding | When you see it |
|---|---|
| Base64 | RPC account data responses |
| Base16 (hex) | Debugging 1 byte = 2 chars, easy to count |
| Base58 | Solana addresses |
They're all just different spellings of the same underlying bytes.
Why this matters
When you write your own Solana programs, you'll define Rust structs → Borsh serializes them into byte arrays → your frontend deserializes them back. Today I proved I can do that translation by hand.
No more mystery blobs.
Day 24 down. Still shipping daily as part of 100 Days of Solana with MLH
Top comments (0)