Konten ini sedang diterjemahkan dan akan tersedia di sini ketika siap.
Accounts and Ownership
Accounts are Solana's fundamental data structure. In Solana's architecture, everything is an account. You need to understand account structure, ownership rules, and the rent mechanism to build programs or use applications.
Every Solana account has the same basic structure, follows the same ownership rules, and requires the same minimum balance (rent) to persist on the blockchain.
Account Structure
Every account contains five fields:
pub struct Account {
/// lamports in the account
pub lamports: u64,
/// data held in this account
pub data: Vec<u8>,
/// the program that owns 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 rent
pub rent_epoch: Epoch,
}Lamports: The account's balance in lamports (1 SOL = 1,000,000,000 lamports). All accounts need lamports for rent-exemption. Accounts can receive additional lamports beyond the minimum.
Data: Arbitrary bytes storing whatever the owning program requires. This can be user profiles, token balances, NFT metadata, game state, or any other information. Maximum size is 10 megabytes (10,485,760 bytes).
Owner: The program that controls this account. Only the owner can modify the account's data or withdraw its lamports. This field is a 32-byte public key identifying the owning program.
Executable: A boolean flag indicating whether this account contains executable program code. Program accounts have this set to true. Data accounts have this set to false.
Rent epoch: Historical field from when rent was deducted periodically. No longer actively used but remains in the account structure.
Every account has a unique 32-byte address, displayed as a base58-encoded string like 14grJpemFaf88c8tiVb77W7TYg2W3ir6pfkKz3YjhhZ5. This address serves as the account's identifier on the blockchain.
Account Types
All accounts share the same structure but serve different purposes based on their owner and executable flag.
System Accounts: Owned by the System Program. These are basic wallet accounts that users interact with directly for sending and receiving SOL. When you create a wallet, you're creating a System Account. The System Program allows the account holder (whoever has the private key) to transfer SOL and reallocate the account to other programs.
Token Accounts: Owned by the Token Program. These store SPL token balances and metadata. Every token you hold (USDC, BONK, any SPL token) exists in a token account owned by the Token Program. The Token Program enforces transfer rules and maintains balances.
Data Accounts: Owned by custom programs. These store application-specific state: user profiles, game data, NFT metadata, lending positions, or any other information your program needs. The owning program defines the data format and access rules.
Program Accounts: Contain executable code and have the executable flag set to true. These accounts store compiled program bytecode. When transactions call a program, the runtime loads code from these accounts.
Rent and Rent-Exemption
Accounts require a minimum lamport balance to stay alive. This minimum depends on account size. You get it back when you close the account.
The rent-exempt minimum depends on account size:
rent_exempt_minimum = base_cost + (account_data_size * cost_per_byte)Specific numbers:
Base cost for any account: approximately 0.00089 SOL
Cost per byte: approximately 0.00000348 SOL
A 165-byte account (common size): approximately 0.00114 SOL
These values can change through governance but remain relatively stable.
Example calculation:
// Account with 1000 bytes of data
let rent = Rent::default();
let account_size = 1000;
let minimum_balance = rent.minimum_balance(account_size);
// minimum_balance ≈ 0.00437 SOLRent-exempt balance: Once an account has the minimum balance for its size, it is "rent-exempt." No further rent will be charged. The account persists indefinitely as long as it maintains this minimum.
Closing accounts: When you no longer need an account, closing it recovers the rent deposit. The account's data is wiped, its lamports are transferred out (typically back to the creator), and the account ceases to exist. This makes rent a truly refundable deposit.
Creating accounts costs SOL. When you mint an NFT, create a token account, or initialize program state, you pay the rent-exempt minimum. These costs are small but accumulate. Applications with thousands of accounts need to budget for total rent costs.
Ownership Rules
Only the owner can modify an account. Ownership determines what operations are possible.
The owning program can:
Modify the account's data
Decrease the account's lamport balance (withdraw funds)
Change the account's size (with reallocation)
Change the account's owner (transfer ownership to another program)
Anyone can:
Increase the account's lamport balance (send funds to it)
Read the account's data (all account data is public)
The account holder (whoever has the private key corresponding to the account's address) can:
Sign transactions that include this account
If owned by System Program: transfer SOL, close the account, or reassign ownership
Having the private key for an account's address is different from the program that owns it. If you create an account owned by System Program, you control it with your private key. If you then assign ownership to a custom program, that program gains control—your private key can no longer directly modify it. You can only interact through the owning program's instructions.
Example:
You create a token account for USDC
The Token Program owns this account
You have the private key for your main wallet
But the Token Program controls the token account's data
You transfer tokens by calling the Token Program's transfer instruction
The Token Program verifies you own the tokens and executes the transfer
You cannot directly modify the token account's data—only the Token Program can
Creating Accounts
Solana accounts must be explicitly created and funded before use.
System Program creates accounts:
The System Program provides the create_account instruction:
pub fn create_account(
from: &Pubkey, // Who pays for the account
to: &Pubkey, // Address of the new account
lamports: u64, // Rent-exempt minimum + any extra
space: u64, // Size of data in bytes
owner: &Pubkey, // Which program will own it
) -> InstructionThis instruction:
Allocates space for the account
Transfers lamports from the payer to the new account
Sets the account's owner
Marks the account as initialized
Example:
// 1. Generate a new keypair for the account address
let account = Keypair::new();
// 2. Calculate rent-exempt minimum
let rent = Rent::default();
let account_size = 165; // bytes
let lamports = rent.minimum_balance(account_size);
// 3. Create the account
let instruction = system_instruction::create_account(
&payer.pubkey(),
&account.pubkey(),
lamports,
account_size as u64,
&my_program_id,
);
// 4. Send transaction with both payer and new account as signersWorking with Account Data
Programs read and write account data. They serialize and deserialize account data using this pattern:
use borsh::{BorshSerialize, BorshDeserialize};
#[derive(BorshSerialize, BorshDeserialize)]
pub struct UserAccount {
pub name: String,
pub balance: u64,
pub posts: Vec<u32>,
}
pub fn update_user_data(accounts: &[AccountInfo], new_name: String) -> ProgramResult {
let user_account = &accounts[0];
// Deserialize existing data
let mut user_data = UserAccount::try_from_slice(&user_account.data.borrow())?;
// Modify the data
user_data.name = new_name;
// Serialize back to account
user_data.serialize(&mut &mut user_account.data.borrow_mut()[..])?;
Ok(())
}The program:
Reads bytes from the account's data field
Deserializes bytes into a structured type
Modifies the data in memory
Serializes the modified data back to bytes
Writes bytes back to the account's data field
Programs work with structured data in memory but store it as raw bytes on-chain.
Associated Token Accounts
Each user can have multiple token accounts—one for USDC, one for BONK, one for each SPL token they hold.
Without a standard, finding a user's token account for a specific token mint would require manual tracking. Associated Token Accounts (ATAs) solve this with deterministic address derivation:
associated_token_address = derive_address(
seeds: [wallet_address, token_program_id, token_mint_address],
program: associated_token_program_id
)Given a wallet address and token mint address, there's exactly one associated token account address. Wallets automatically find your USDC account, programs know where to send your tokens, and you don't need to manage addresses manually.
When someone sends you tokens for the first time, the associated token account may not exist yet. The sender (or a helpful wallet) creates it as part of the transaction, paying the rent-exempt minimum on your behalf.
Viewing Accounts on Explorers
All account data is public. You can view any account using block explorers like Solana Explorer (https://explorer.solana.com) or Solscan (https://solscan.io). Both let you view lamport balances, account owners, raw data, and transaction history. Solscan has better data visualization and is easier to use for non-technical users.
Try viewing the USDC token mint: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
You'll see:
It's owned by the Token Program
It's marked as executable (false)
It contains mint data (supply, decimals, authorities)
Its entire history of transactions
Anyone can verify any data at any time without requiring permission.
Accounts store data. Programs operate on that data through transactions, processing instructions that read and modify account state.