Free guide
What is a lamport? Solana’s smallest unit
A lamport is one billionth of a SOL. Every balance, fee, and deposit on Solana is really a count of lamports, and once you write programs, the SOL never comes back: on-chain, only the integer exists.
One billionth of a SOL
The conversion is a single number, in both directions:
- 1 SOL = 1,000,000,000 lamports (109).
- 1 lamport = 0.000000001 SOL.
- SOL to lamports: multiply by a billion. 0.5 SOL is 500,000,000 lamports; 2 SOL is 2,000,000,000.
Client libraries carry the constant so nobody types nine zeros by hand:
@solana/web3.js exports LAMPORTS_PER_SOL, and the tests in the
official program examples fund and transfer with it, as in
new BN(LAMPORTS_PER_SOL) for exactly one SOL. Rust code on the program side
rarely needs the constant at all, because it never sees SOL in the first place.
Why the chain counts in integers
An account’s balance is a u64: a whole number of lamports. There is no
decimal type anywhere in the runtime, and that is a feature. Floating-point arithmetic
rounds, and money that rounds is money that leaks. Integer lamports make every
addition and subtraction exact, so “0.1 SOL” is not a fraction the chain must
approximate but the integer 100,000,000 it can count. SOL is a display convention; the
wallet divides by a billion before showing you the number.
One place goes finer still: priority fees are quoted in micro-lamports per compute unit, a millionth of a lamport, so that tiny per-unit prices survive integer math too. The fractions exist only in the pricing; what any account holds is still whole lamports.
The name
The unit honors Leslie Lamport, the computer scientist whose 1978 paper on logical clocks gave distributed systems their notion of event ordering, whose Paxos protocol underpins modern consensus, and who wrote LaTeX. A network that is one large distributed systems argument settled every 400 milliseconds could hardly pick a better patron. This press is named for the same unit, which tells you what we think of it.
Every account carries a lamport balance
On Solana, all state lives in accounts, and an account is three things: a lamport balance, a byte array of data, and an owner. The balance is not an optional feature for wallet-like accounts; a program’s state account, a token mint, even an executable program is an account holding lamports. How accounts work is its own guide — what matters here is that lamports are a field on every one of them, and two mechanics in every program touch that field directly: rent and transfers.
Rent: bytes priced in lamports
Storing an account’s bytes on every validator forever is not free. Solana prices it as a one-time deposit rather than a recurring bill: fund the account with enough lamports to cover roughly two years of theoretical storage rent and it is rent-exempt — kept indefinitely, for as long as the balance stays above the threshold. Close the account and the deposit comes back.
The official rent example computes that deposit by hand, from the real
serialized size of the data it is about to store:
// programs/rent-example/src/lib.rs
let account_span = anchor_lang::prelude::borsh::to_vec(&address_data)?.len();
let lamports_required = (Rent::get()?).minimum_balance(account_span);
Serialize the data, take the byte length, and minimum_balance turns bytes
into lamports at the network’s current rate. Anchor’s init
constraint runs this same calculation automatically every time a program creates an
account; the example only does it manually so you can see the price being computed.
Moving lamports: ownership picks the mechanism
The official transfer-sol example teaches the rule that governs every SOL
transfer on the chain. Only an account’s owning program may subtract lamports from
it; anyone may add lamports to a writable account. So moving SOL out of a normal wallet,
owned by the System Program, means asking the System Program to do it — a
cross-program invocation:
// programs/transfer-sol/src/lib.rs
system_program::transfer(
CpiContext::new(
ctx.accounts.system_program.key(),
system_program::Transfer {
from: ctx.accounts.payer.to_account_info(),
to: ctx.accounts.recipient.to_account_info(),
},
),
amount,
)?;
But when the account being debited belongs to your own program, there is no one to ask. The transfer collapses to arithmetic on the lamport field itself:
// programs/transfer-sol/src/lib.rs
pub fn transfer_sol_with_program(
ctx: Context<TransferSolWithProgram>,
amount: u64,
) -> Result<()> {
**ctx.accounts.payer.try_borrow_mut_lamports()? -= amount;
**ctx.accounts.recipient.try_borrow_mut_lamports()? += amount;
Ok(())
}
From
solana-foundation/program-examples
(basics/rent and basics/transfer-sol),
MIT licensed, © Solana Foundation, pinned to commit 9389865.
Note the amount: u64 in the signature. The instruction does not take SOL;
no instruction on Solana does. By the time a transfer reaches a program, the number is
already lamports, which is where this guide came in.