Skip to content

Lamports and the SOL Unit

The overview set out the question this whole part answers: on a single global state machine running at hardware speed, what does it cost to touch state, and who pays? Before we can talk about fees, rent, or rewards, we need the unit those costs are measured in. Every price in this part — the base fee, the rent-exempt minimum, a validator’s per-vote outlay, a block reward — is a count of one thing: lamports.

This page defines that unit precisely, explains why the protocol insists on counting in whole integer lamports rather than in fractional SOL, and shows that the number is not an accounting convenience but a correctness decision baked into the runtime. Get this right and every later figure reads unambiguously; get it wrong and you will be off by a factor of a billion.

SOL is the token you see quoted on exchanges and in wallets — the unit a human thinks in. But SOL is a display unit. The protocol itself never stores a balance as “1.5 SOL.” Underneath, there is one indivisible base unit, and SOL is just a large, round multiple of it.

That base unit is the lamport. It is the smallest amount of value the Solana protocol can represent or move — you cannot hold, send, or burn a fraction of a lamport. The relationship is exact and fixed:

1 SOL = 1,000,000,000 lamports (10^9)
1 lamport = 0.000000001 SOL
1,000 lamports = 0.000001 SOL (one "micro-SOL")
5,000 lamports = 0.000005 SOL (Solana's base transaction fee — you'll meet it next page)

So a wallet showing “2.5 SOL” is, to the runtime, holding exactly 2_500_000_000 lamports. The decimal point you see in a wallet is applied at the last moment, for your eyes only. The chain moved integers the whole way.

The same reason every serious money system has one. If the protocol let balances be arbitrary decimals, two questions become impossible to answer cleanly: what is the smallest transfer? and do two independent additions of balances always agree to the last digit? A fixed indivisible unit answers both. The smallest transfer is one unit. And because everything is an integer count of that unit, arithmetic is exact — there is no “0.1 + 0.2 = 0.30000000000000004” hiding in a validator somewhere. On a machine where thousands of validators must independently compute the same balances and agree to the last bit, “exact” is not a nicety; it is the whole game. Disagreement by one lamport is a fork.

Why the protocol counts in integer lamports

Section titled “Why the protocol counts in integer lamports”

Recall the Account from the account model — the struct at the heart of the runtime:

pub struct Account {
pub lamports: u64, // native balance — an INTEGER count of lamports
pub data: Vec<u8>, // opaque program state
pub owner: Pubkey, // the program allowed to write this account
}

The balance field is a u64: an unsigned 64-bit integer. It is not f64, not a decimal type, not “SOL.” It is a plain count of lamports. That single type choice carries three guarantees the state machine cannot live without.

Exact arithmetic, no rounding drift. Floating-point numbers cannot represent most decimal fractions exactly — 0.1 in an f64 is really a nearby binary approximation. Add millions of such approximations across millions of transactions and the errors accumulate. For money that is fatal: balances that should be identical on two validators drift apart, and the network can no longer agree on state. Integers have no such error. a + b is exactly a + b, forever, on every machine. Every debit and credit in the runtime is integer addition and subtraction on u64 lamports.

Determinism across validators. Consensus requires that every validator, replaying the same transactions, computes bit-for-bit identical balances. Integer arithmetic is deterministic by definition. Floating-point results can differ subtly across compilers, CPUs, and optimization settings — exactly the kind of platform-dependent behavior that would let two honest validators reach two different states from the same input. u64 closes that door.

A hard ceiling that the type enforces. A u64 holds values up to 2^64 − 1 ≈ 1.84 × 10^19 lamports — about 1.8 × 10^10 SOL, roughly eighteen billion SOL, comfortably above the total supply. Because the field is a u64, an overflow is a typed event the runtime must handle (with checked or saturating arithmetic), not a silent wraparound. The type makes “we ran out of headroom” impossible to ignore.

Here is the transfer program from the runtime doing exactly this — moving an integer count of lamports, no floats anywhere:

impl Program for TransferProgram {
fn process(&self, accounts: &mut [Account], data: &[u8]) -> Result<()> {
let amount = read_u64(data)?; // amount is in lamports, a u64
let have = accounts[0].lamports; // source balance, in lamports
if have < amount {
return Err(SolError::InsufficientFunds { have, need: amount });
}
accounts[0].lamports = have - amount; // integer subtract
accounts[1].lamports = accounts[1].lamports.saturating_add(amount); // integer add
Ok(())
}
}

The instruction data carries the amount as a little-endian u64 — again, lamports. There is no place in this path where SOL, decimals, or floating point appear. Lamports are the native unit programs move directly. When a transfer, a fee deduction, or a reward payout happens, what changes is an integer in an Account.lamports field.

The unit is named for Leslie Lamport, the computer scientist whose work underpins how distributed systems agree on anything at all — logical clocks (the “happened-before” relation that orders events without a shared wall clock), the theory of consensus, and Byzantine fault tolerance. That naming is not decoration. This entire book is about building one global state machine out of many machines that must order and agree on events, and Lamport’s work is the intellectual bedrock of that problem. Solana’s Proof of History is, in spirit, a Lamport clock made verifiable. Putting his name on the base unit is the protocol tipping its hat to the reason the whole thing can work.

If you have read the sibling books, this shape is familiar. Every serious cryptocurrency separates a human-facing display unit from an integer base unit, for exactly the reasons above:

ChainDisplay unitBase unitRelationshipInteger type
BitcoinBTCsatoshi1 BTC = 100,000,000 sat (10^8)64-bit int
EthereumETHwei1 ETH = 1,000,000,000,000,000,000 wei (10^18)256-bit int
SolanaSOLlamport1 SOL = 1,000,000,000 lamports (10^9)u64

The takeaway is that lamports are not a Solana quirk — they are Solana’s instance of a universal design. Bitcoin’s satoshi and Ethereum’s wei exist for the same first-principles reason: money must be counted in exact integers of an indivisible smallest unit, or independent machines cannot agree on balances. What differs is only the scale factor (10^8, 10^18, 10^9) and the integer width. Notice Ethereum needs a 256-bit integer for wei because 10^18 is large; Solana’s 10^9 scale fits comfortably in a u64, which is cheaper to store and to reason about — a small design economy that suits a chain optimizing for speed.

Every figure in this part is a lamport count

Section titled “Every figure in this part is a lamport count”

This is the payoff, and the reason this page comes second. From here on, every economic quantity in this part is denominated in lamports, whatever unit we quote it in for readability:

  • The base transaction fee — 5,000 lamports per signature — is deducted from the fee payer’s Account.lamports as an integer. See Transaction Fees and Local Fee Markets.
  • The rent-exempt minimum — the balance an account must hold to persist — is a lamport threshold computed from the account’s byte size. See Rent and Rent-Exemption.
  • Block rewards and staking yield — the new lamports minted by inflation and paid to validators and delegators — are lamport credits to accounts. See Inflation and Staking Rewards.
  • A validator’s vote costs — the fees it spends to keep voting — are lamport debits every slot. See Validator Economics and Vote Costs.

When a later page says “a fee of 0.000005 SOL,” read it as “5,000 lamports,” because that is the integer the runtime actually subtracts. The SOL figure is the human gloss; the lamport figure is the ground truth.

  • Why does it exist? Because a global state machine needs one indivisible, integer base unit so that every validator computes identical balances and agrees to the last digit. The lamport is that unit; SOL is a display multiple (10^9) of it.
  • What problem does it solve? Rounding drift and non-determinism. Integer lamports make every balance operation exact and bit-for-bit reproducible across every machine, which is the precondition for consensus on state.
  • What are the trade-offs? You gain exactness and determinism; you give up the convenience of writing fractional amounts directly. Every human-facing amount must be scaled by 10^9 and rounded to a whole lamport before it can exist on-chain — a sub-lamport simply cannot be represented.
  • When should I avoid it? Never in protocol or program logic — always compute in integer lamports there. “Avoid” only the display unit inside math: convert to SOL only at the very last step, for presentation, never mid-calculation, or you reintroduce the floating-point error the base unit exists to prevent.
  • What breaks if I remove it? Exact consensus. Without a fixed integer base unit, two honest validators could compute balances that differ by a rounding error, disagree on state, and fork the chain. The lamport is what makes “the same balance everywhere” mechanically true.
  1. State the exact relationship between SOL and lamports, and explain what it means to call the lamport “indivisible.”
  2. The Account.lamports field is a u64, not an f64. Give two distinct reasons the protocol tracks balances as integers rather than floating-point SOL.
  3. A wallet displays a balance of 0.75 SOL. What integer does the runtime actually store, and where does the decimal point come from?
  4. Bitcoin has the satoshi (10^8) and Ethereum the wei (10^18). What single first-principles reason do all three base units share, and what differs between them?
  5. A later page quotes “a base fee of 5,000 lamports.” Restate that in SOL, and explain why the page insists the lamport figure — not the SOL figure — is the “ground truth.”
Show answers
  1. 1 SOL = 1,000,000,000 lamports (10^9), exactly. “Indivisible” means the lamport is the smallest representable amount — you cannot hold, send, or burn a fraction of one; every on-chain amount is a whole integer number of lamports.
  2. Any two of: (a) exactness — integer arithmetic has no rounding drift, whereas floating point cannot represent most decimals exactly and accumulates error; (b) determinism — integer results are identical across compilers, CPUs, and machines, which consensus requires, whereas float results can differ subtly; (c) enforced ceiling — a u64 makes overflow a typed event to handle rather than a silent wraparound.
  3. It stores the integer 750_000_000 lamports (0.75 × 10^9). The decimal point is a display-only conversion the wallet applies by dividing the stored lamport count by 10^9; the chain itself only ever moved and stored the integer.
  4. The shared reason: money must be counted in exact integers of an indivisible smallest unit, or independent machines cannot agree on balances (no rounding, deterministic arithmetic). What differs is only the scale factor (10^8 for BTC, 10^18 for ETH, 10^9 for SOL) and the integer width used to hold it (Ethereum needs 256-bit for wei; Solana’s 10^9 fits a u64).
  5. 5,000 lamports = 0.000005 SOL (5,000 / 10^9). The lamport figure is ground truth because it is the exact integer the runtime subtracts from the fee payer’s Account.lamports; the SOL figure is a human-readable gloss produced by dividing by 10^9, and only whole lamports can actually exist on-chain.