SOL, Lamports e Unidades
A Solana armazena toda moeda nativa como lamports - inteiros sem sinal de 64 bits. Entender denominações previne bugs de arredondamento, transações com falha e cálculos incorretos de taxa.
Receita
Cartão de receita de referência rápida - pronto para copiar.
import { lamports } from "@solana/kit";
const ONE_SOL = 1_000_000_000n;
const halfSol = lamports(500_000_000n);
function solToLamports(sol: number): bigint {
return BigInt(Math.round(sol * 1e9));
}
function lamportsToSol(lps: bigint): string {
return (Number(lps) / 1e9).toFixed(9);
}Quando usar:
- Converter valores de SOL voltados ao usuário em lamports on-chain antes de montar instruções
- Exibir saldos buscados via RPC sem perda de precisão
- Calcular depósitos mínimos isentos de rent para novas contas
- Comparar priority fees (microlamports por CU) com taxas base (lamports por signature)
- Validar valores de token SPL contra
decimalsdo mint (separado de SOL nativo)
Exemplo Prático
import { createSolanaRpc, address, lamports } from "@solana/kit";
import { getTransferSolInstruction } from "@solana-program/system";
import {
createTransactionMessage,
setTransactionMessageFeePayer,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstruction,
pipe,
} from "@solana/kit";
const rpc = createSolanaRpc("https://api.devnet.solana.com");
const sender = address("SENDER_PUBKEY");
const recipient = address("RECIPIENT_PUBKEY");
// Usuário digita "0.25" SOL em formulário da UI
const userInputSol = 0.25;
const amountLamports = BigInt(Math.round(userInputSol * 1_000_000_000));
const { value: balance } = await rpc.getBalance(sender).send();
if (balance < amountLamports) {
throw new Error(
`Insufficient: have ${Number(lamports(balance)) / 1e9} SOL, need ${userInputSol}`,
);
}
const { value: blockhash } = await rpc.getLatestBlockhash().send();
const transferIx = getTransferSolInstruction({
source: sender,
destination: recipient,
amount: amountLamports,
});
const message = pipe(
createTransactionMessage({ version: 0 }),
(m) => setTransactionMessageFeePayer(sender, m),
(m) => setTransactionMessageLifetimeUsingBlockhash(blockhash, m),
(m) => appendTransactionMessageInstruction(transferIx, m),
);
console.log("Transfer message built for", amountLamports, "lamports");O que isso demonstra:
- Input do usuário é convertido para lamports
bigintantes de qualquer comparação on-chain getBalanceretorna lamports - compare inteiros, não floats- Helper
lamports()do Kit envolve valores brutos para clareza de tipo - Valores de transação são sempre inteiros de lamport
Aprofundamento
Como Funciona
- O genesis e toda contabilidade de runtime usam lamports como unidade atômica
- 1 SOL = 10^9 lamports - mesma relação que wei para ETH, mas com 9 decimals
- Saldos de conta, transferências, rent e taxas são valores u64 em lamports
- Tipos de ponto flutuante não representam todos os valores de lamport com exatidão em escala
Denominações em Resumo
| Unidade | Lamports | Uso Típico |
|---|---|---|
| 1 lamport | 1 | Menor unidade nativa |
| 1 SOL | 1.000.000.000 | Exibição voltada ao usuário |
| Priority fee | microlamports/CU | Compute Budget Program |
| Taxa base | 5.000 lamports/signature | Custo por signature (padrão atual) |
Notas Rust
use anchor_lang::prelude::*;
const LAMPORTS_PER_SOL: u64 = 1_000_000_000;
pub fn transfer_amount(ctx: Context<Transfer>, sol: f64) -> Result<()> {
let lamports = (sol * LAMPORTS_PER_SOL as f64) as u64; // evite em produção
// Prefira: usuário fornece lamports diretamente, ou use crate fixed-point
require!(lamports > 0, ErrorCode::ZeroAmount);
Ok(())
}- Nunca faça cast
f64parau64em código financeiro de produção - use input inteiro anchor_langfornece alias de tipoLamportsem alguns contextos- Use
checked_add,checked_subpara aritmética de saldo em programas
Erros Comuns
- Arredondamento float JavaScript -
0.1 + 0.2 !== 0.3pode produzir lamports errados. Correção: parse strings de usuário parabigintvia matemática inteira ou biblioteca decimal. - Exibir u64 em JS - valores acima de
Number.MAX_SAFE_INTEGERperdem precisão. Correção: formate lamports comobigintou use formatador baseado em string. - Misturar SOL e lamports em APIs - algumas flags CLI usam SOL, RPC retorna lamports. Correção: leia docs de cada API e normalize na borda do app.
- Decimals SPL diferem - USDC usa 6 decimals, SOL usa 9. Correção: sempre leia
mint.decimalsantes de converter valores de token. - Cálculo de rent em SOL - desenvolvedores às vezes arredondam rent para 0. Correção: use RPC
getMinimumBalanceForRentExemptione armazene valor exato em lamports. - Unidades de priority fee - microlamports por CU não é o mesmo que lamports por signature. Correção: defina ambos via instruções Compute Budget separadamente.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
bigint em TypeScript | Todo tratamento de valor on-chain | Precisa suporte legacy de browser sem polyfills |
Decimal.js / bignumber.js | Parse seguro de strings decimais de usuário | Dentro de programas Rust on-chain |
| Apenas lamports inteiros (sem tipo SOL) | Args de instrução de programa | Montando UIs de carteira voltadas ao usuário |
Helper lamports() do @solana/kit | Pipelines Kit type-safe | Scripts RPC brutos onde Kit é excesso |
FAQs
Quantos lamports há em um SOL?
1.000.000.000 (10^9). Isso é fixo e nunca muda.
Por que a Solana usa inteiros em vez de decimals on-chain?
Execução determinística entre validadores exige aritmética exata. Ponto flutuante varia por hardware; inteiros u64 não.
Qual é a menor quantidade transferível de SOL?
1 lamport. Na prática, taxas de transação (5.000 lamports por signature por padrão) tornam transferências sub-lamport sem sentido.
Como converter com segurança uma string SOL digitada pelo usuário em lamports?
function parseSolToLamports(input: string): bigint {
const [whole, frac = ""] = input.split(".");
const padded = (frac + "000000000").slice(0, 9);
return BigInt(whole) * 1_000_000_000n + BigInt(padded);
}getBalance retorna SOL ou lamports?
Lamports. Divida por 1e9 só para exibição - nunca para instruções on-chain.
O que são microlamports em priority fees?
1 microlamport = 0.000001 lamport. Priority fees são precificadas em microlamports por compute unit via Compute Budget Program.
Saldos de lamport podem estourar u64?
Teoricamente com ~18,4 bilhões de SOL de supply total não é preocupação prática, mas lógica de programa ainda deve usar aritmética verificada.
Como é calculada a isenção de rent?
Baseada no tamanho de dados da conta em bytes. RPC getMinimumBalanceForRentExemption(dataSize) retorna o depósito exato em lamports exigido.
Devo armazenar valores como SOL ou lamports no banco de dados?
Armazene lamports como inteiros (ou strings para valores muito grandes). Converta para SOL só na camada de apresentação.
O que acontece se enviar transferência com amount 0?
O System Program rejeita transferências de zero lamport. Use mínimo significativo ou pule a instrução.
Valores de token SPL estão em lamports?
Não. Tokens SPL usam o campo decimals do mint. Um valor USDC de 1_000_000 significa 1 USDC (6 decimals), não lamports.
Como formatar lamports para exibição sem perda de precisão?
Divida lamports bigint em partes inteiras e fracionárias com matemática de string, ou use biblioteca. Evite Number(lamports) para valores que reenviará on-chain.
Relacionado
- Noções Básicas de Solana - orientação a contas e transações
- Keypairs e Endereços - quem detém os lamports
- Clusters e Redes - valores de airdrop devnet
Versões da stack: Esta página foi escrita para Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0 e LiteSVM 0.6.x.