Reading from Network
This section explores how to read data from the Solana network by fetching different accounts to understand the structure of a Solana account.
On Solana, all data exists in "accounts". You can think of data on Solana as a public database with a single "Accounts" table, where each entry is an account with the same base Account type.
#[derive(PartialEq, Eq, Clone, Default)]pub struct Account {/// lamports in the accountpub lamports: u64,/// data held in this account#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]pub data: Vec<u8>,/// the program that owns this account. If executable, the program that loads this account.pub owner: Pubkey,/// this account's data contains a loaded program (and is now read-only)pub executable: bool,/// the epoch at which this account will next owe rentpub rent_epoch: Epoch,}
Accounts
Accounts on Solana can store "state" or "executable" programs. Each account has an "address" (public key) that serves as its unique ID used to locate its corresponding on-chain data.
Solana accounts contain either:
- State: Data that meant to be read from and persisted. For example, information about tokens, user data, or other data defined within a program.
- Executable Programs: Accounts containing the actual code of Solana programs. These accounts store instructions that users can invoke.
This separation of program code and program state is a key feature of Solana's Account Model. For more details, refer to the Solana Account Model page.
Fetch Wallet Account
This example demonstrates how to:
- Generate a new keypair (public/private key pair).
- Request an airdrop of SOL to fund the new address.
- Retrieve the account data for the funded address.
On Solana, funding a new address with SOL automatically creates an account owned by the System Program. All "wallet" accounts are simply System Program owned accounts that hold SOL and can sign transactions.
import { Keypair, Connection, LAMPORTS_PER_SOL } from "@solana/web3.js";const keypair = Keypair.generate();console.log(`Public Key: ${keypair.publicKey}`);const connection = new Connection("http://localhost:8899", "confirmed");// Funding an address with SOL automatically creates an accountconst signature = await connection.requestAirdrop(keypair.publicKey,LAMPORTS_PER_SOL);await connection.confirmTransaction(signature, "confirmed");const accountInfo = await connection.getAccountInfo(keypair.publicKey);console.log(JSON.stringify(accountInfo, null, 2));
A "wallet" on Solana is an account owned by the
System Program,
which is one of Solana’s built-in programs. Wallet accounts are primarily used
to hold SOL (tracked in the lamports
field) and to sign transactions.
When you fetch a wallet account, the response includes the fields shown in the example output.
{"data": {"type": "Buffer","data": []},"executable": false,"lamports": 1000000000,"owner": "11111111111111111111111111111111","rentEpoch": 0,"space": 0}
The data
field contains the account's data stored as bytes.
For wallet accounts, this field is empty (0 bytes). Other accounts use this field to store either program state or executable program code.
{"data": {"type": "Buffer","data": []},"executable": false,"lamports": 1000000000,"owner": "11111111111111111111111111111111","rentEpoch": 0,"space": 0}
The executable
field indicates if the account's data
field contains
executable program code.
For wallet and accounts that store program state, this field is false
.
{"data": {"type": "Buffer","data": []},"executable": false,"lamports": 1000000000,"owner": "11111111111111111111111111111111","rentEpoch": 0,"space": 0}
The lamports
field contains the account's SOL balance, denominated in
lamports.
Lamports are the smallest unit of SOL. 1 SOL = 1,000,000,000 lamports.
{"data": {"type": "Buffer","data": []},"executable": false,"lamports": 1000000000,"owner": "11111111111111111111111111111111","rentEpoch": 0,"space": 0}
The owner
field shows the program that owns the account.
For wallets, the owner is always the System Program, with the address
11111111111111111111111111111111
.
{"data": {"type": "Buffer","data": []},"executable": false,"lamports": 1000000000,"owner": "11111111111111111111111111111111","rentEpoch": 0,"space": 0}
The rentEpoch
field is a legacy field from a deprecated mechanism where
accounts were charged "rent" (in lamports) to maintain its data on the network.
This field is currently unused, but is included for backwards compatibility.
{"data": {"type": "Buffer","data": []},"executable": false,"lamports": 1000000000,"owner": "11111111111111111111111111111111","rentEpoch": 0,"space": 0}
The space
field shows the number of bytes in the data
field. This is not a
field in the Account
type itself, but included in the response.
In this example, the space
field is 0 because the data
field contains 0
bytes of data.
{"data": {"type": "Buffer","data": []},"executable": false,"lamports": 1000000000,"owner": "11111111111111111111111111111111","rentEpoch": 0,"space": 0}
Fetch Token Program
This example fetches the Token Program to demonstrate the difference between wallet and program accounts.
The program account stores the compiled bytecode for the Token Program's source code. You can view this program account on the Solana Explorer.
import { Connection, PublicKey } from "@solana/web3.js";const connection = new Connection("https://api.mainnet-beta.solana.com","confirmed");const address = new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");const accountInfo = await connection.getAccountInfo(address);
The Token Program is an executable program account on Solana. Like wallet accounts, programs have the same underlying Account data structure, but with key differences in its fields.
{"data": {"type": "Buffer","data": [127, "...truncated, total bytes: 134080...", 0]},"executable": true,"lamports": 4522329612,"owner": "BPFLoader2111111111111111111111111111111111","rentEpoch": 18446744073709552000,"space": 134080}
The executable
field is set to true
, indicating that this account's data
field contains executable program code.
{"data": {"type": "Buffer","data": [127, "...truncated, total bytes: 134080...", 0]},"executable": true,"lamports": 4522329612,"owner": "BPFLoader2111111111111111111111111111111111","rentEpoch": 18446744073709552000,"space": 134080}
For program accounts, the data
field stores the program's executable code. In
contrast, wallet accounts have an empty data field.
When you deploy a Solana program, the program's executable code is stored in an
account's data
field.
{"data": {"type": "Buffer","data": [127, "...truncated, total bytes: 134080...", 0]},"executable": true,"lamports": 4522329612,"owner": "BPFLoader2111111111111111111111111111111111","rentEpoch": 18446744073709552000,"space": 134080}
Executable program accounts also have a program designated as the owner
of the
of the account.
All program accounts are owned by a Loader program, which is a category of built-in programs that own executable program accounts on Solana.
For the Token Program, the owner
is the BPFLoader2 program.
{"data": {"type": "Buffer","data": [127, "...truncated, total bytes: 134080...", 0]},"executable": true,"lamports": 4522329612,"owner": "BPFLoader2111111111111111111111111111111111","rentEpoch": 18446744073709552000,"space": 134080}
Fetch Mint Account
This example fetches the USD Coin (USDC) Mint account to show how programs on Solana store state in separate accounts.
A Mint account is an account owned by the Token Program. It stores global metadata for a specific token, including the total supply, number of decimals, and the accounts authorized to mint or freeze tokens. The Mint account's address uniquely identifies a token on the Solana network.
import { Connection, PublicKey } from "@solana/web3.js";const connection = new Connection("https://api.mainnet-beta.solana.com","confirmed");const address = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");const accountInfo = await connection.getAccountInfo(address);
The key point to note in this example is that the Mint account stores state, not executable code.
Mint accounts are owned by the Token Program, which includes instructions that define how to create and update Mint accounts.
{"data": {"type": "Buffer","data": [1, "...truncated, total bytes: 82...", 103]},"executable": false,"lamports": 407438077149,"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA","rentEpoch": 18446744073709552000,"space": 82}
The executable
field is false
because the mint account's data
field stores
state, not executable code.
The Token Program defines the Mint
data type, which is stored in the mint
account's data
field.
{"data": {"type": "Buffer","data": [1, "...truncated, total bytes: 82...", 103]},"executable": false,"lamports": 407438077149,"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA","rentEpoch": 18446744073709552000,"space": 82}
The data
field contains the serialized Mint
account state, such as the mint
authority, total supply, number of decimals.
To read from a Mint account, you must deserialize the data
field into the
Mint
data type. This is covered in the next step.
{"data": {"type": "Buffer","data": [1, "...truncated, total bytes: 82...", 103]},"executable": false,"lamports": 407438077149,"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA","rentEpoch": 18446744073709552000,"space": 82}
The Token Program (TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
) owns the mint
account.
This means that the mint account's data
field can only be modified by the
instructions defined in the Token Program.
{"data": {"type": "Buffer","data": [1, "...truncated, total bytes: 82...", 103]},"executable": false,"lamports": 407438077149,"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA","rentEpoch": 18446744073709552000,"space": 82}
Deserialize Mint Account
The data
field of a Solana account contains raw bytes. To interpret this data
meaningfully, you must deserialize it into the appropriate data type defined by
the program that owns the account.
Most Solana programs provide client libraries with helper functions that abstract away the deserialization process. These functions convert the raw account bytes into structured data types, making it easier to work with the account data.
For example, @solana/spl-token
includes the
getMint()
function to help deserialize a Mint account's
data
field into the
Mint
data type.
import { PublicKey, Connection } from "@solana/web3.js";import { getMint } from "@solana/spl-token";const connection = new Connection("https://api.mainnet-beta.solana.com","confirmed");const address = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");const mintData = await getMint(connection, address, "confirmed");
pub struct Mint {/// Optional authority used to mint new tokens. The mint authority may only/// be provided during mint creation. If no mint authority is present/// then the mint has a fixed supply and no further tokens may be/// minted.pub mint_authority: COption<Pubkey>,/// Total supply of tokens.pub supply: u64,/// Number of base 10 digits to the right of the decimal place.pub decimals: u8,/// Is `true` if this structure has been initializedpub is_initialized: bool,/// Optional authority to freeze token accounts.pub freeze_authority: COption<Pubkey>,}
The getMint()
function deserializes a mint account's data
field into the
Mint
data type defined by the Token Program.
{"data": {"type": "Buffer","data": [1, "...truncated, total bytes: 82...", 103]},"executable": false,"lamports": 407438077149,"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA","rentEpoch": 18446744073709552000,"space": 82}
You can view the fully deserialized Mint Account data on the Solana Explorer.
{"address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v","mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG","supply": "8985397351591790","decimals": 6,"isInitialized": true,"freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar","tlvData": {"type": "Buffer","data": []}}
The address
field contains the Mint account's address.
The mint account's address is used to identify the token on the Solana network.
{"address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v","mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG","supply": "8985397351591790","decimals": 6,"isInitialized": true,"freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar","tlvData": {"type": "Buffer","data": []}}
The mintAuthority
field shows the authority allowed to mint new tokens.
This is the only account that can create new units of the token.
{"address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v","mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG","supply": "8985397351591790","decimals": 6,"isInitialized": true,"freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar","tlvData": {"type": "Buffer","data": []}}
The supply
field shows the total number of tokens that have been minted.
This value is in the smallest unit of the token. To get the total supply in
standard units, adjust the value of the supply
field by the decimals
.
{"address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v","mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG","supply": "8985397351591790","decimals": 6,"isInitialized": true,"freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar","tlvData": {"type": "Buffer","data": []}}
The decimals
field shows the number of decimal places for the token.
{"address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v","mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG","supply": "8985397351591790","decimals": 6,"isInitialized": true,"freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar","tlvData": {"type": "Buffer","data": []}}
The isInitialized
field indicates if the Mint account has been initialized.
This field is a security check used in the Token Program.
{"address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v","mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG","supply": "8985397351591790","decimals": 6,"isInitialized": true,"freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar","tlvData": {"type": "Buffer","data": []}}
The freezeAuthority
field shows the authority allowed to freeze token
accounts.
A token account that is frozen cannot transfer or burn the token in the account.
{"address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v","mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG","supply": "8985397351591790","decimals": 6,"isInitialized": true,"freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar","tlvData": {"type": "Buffer","data": []}}
The tlvData
field contains extra data for Token Extensions (requires further
deserialization).
This field is only relevant to accounts created by the Token Extension Program (Token2022).
{"address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v","mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG","supply": "8985397351591790","decimals": 6,"isInitialized": true,"freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar","tlvData": {"type": "Buffer","data": []}}
Is this page helpful?