SOL, Lamports y Unidades
Solana almacena toda la moneda nativa como lamports, enteros sin signo de 64 bits. Comprender las denominaciones evita errores de redondeo, transacciones fallidas y cálculos de tarifas incorrectos.
Receta
Tarjeta de referencia rápida - lista para copiar y pegar.
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);
}Cuándo usar esto:
- Convertir cantidades de SOL visibles para el usuario a lamports en la cadena antes de construir instrucciones
- Mostrar saldos obtenidos de RPC sin pérdida de precisión
- Calcular depósitos mínimos exentos de alquiler para nuevas cuentas
- Comparar tarifas de prioridad (microlamports por CU) con tarifas base (lamports por firma)
- Validar cantidades de tokens SPL contra los
decimalsde la mint (separado del SOL nativo)
Ejemplo de Trabajo
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");
// El usuario introduce "0.25" SOL en un formulario de interfaz de usuario
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(
`Insuficiente: tienes ${Number(lamports(balance)) / 1e9} SOL, necesitas ${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("Mensaje de transferencia construido para", amountLamports, "lamports");Lo que esto demuestra:
- La entrada del usuario se convierte a lamports
bigintantes de cualquier comparación en la cadena getBalancedevuelve lamports - compara enteros, no flotantes- La utilidad
lamports()de Kit envuelve valores brutos para mayor claridad de tipo - Las cantidades de transacciones son siempre enteros de lamports completos
Análisis Profundo
Cómo Funciona
- El génesis y toda la contabilidad en tiempo de ejecución utilizan lamports como unidad atómica
- 1 SOL = 10^9 lamports - la misma relación que wei a ETH, pero con 9 decimales
- Los saldos de cuentas, transferencias, alquiler y tarifas son todos valores de lamports u64
- Los tipos de punto flotante no pueden representar todos los valores de lamports exactamente a escala
Denominaciones de un Vistazo
| Unidad | Lamports | Uso Típico |
|---|---|---|
| 1 lamport | 1 | Unidad nativa más pequeña |
| 1 SOL | 1,000,000,000 | Visualización para el usuario |
| Tarifa de prioridad | microlamports/CU | Programa de Presupuesto de Cómputo |
| Tarifa base | 5,000 lamports/firma | Costo por firma (predeterminado actual) |
Notas de 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; // evitar en producción
// Preferir: el usuario suministra lamports directamente, o usar un crate de punto fijo
require!(lamports > 0, ErrorCode::ZeroAmount);
Ok(())
}- Nunca conviertas
f64au64en código financiero de producción - usa entrada entera anchor_langproporciona el alias de tipoLamportsen algunos contextos- Usa
checked_add,checked_subpara la aritmética de saldos en programas
Trampas
- Redondeo de flotantes de JavaScript -
0.1 + 0.2 !== 0.3puede producir cantidades de lamports incorrectas. Solución: analiza las cadenas de usuario abigintmediante aritmética entera o una biblioteca decimal. - Mostrar u64 en JS - los valores por encima de
Number.MAX_SAFE_INTEGERpierden precisión. Solución: formatea los lamports comobiginto usa un formateador basado en cadenas. - Mezclar SOL y lamports en APIs - algunas banderas de CLI usan SOL, RPC devuelve lamports. Solución: lee la documentación de cada API y normaliza en el límite de tu aplicación.
- Los decimales de los tokens SPL difieren - USDC usa 6 decimales, SOL usa 9. Solución: lee siempre
mint.decimalsantes de convertir cantidades de tokens. - Cálculo de alquiler en SOL - los desarrolladores a veces redondean el alquiler a 0. Solución: usa RPC
getMinimumBalanceForRentExemptiony almacena el valor exacto de lamports. - Unidades de tarifa de prioridad - microlamports por CU no es lo mismo que lamports por firma. Solución: establece ambos mediante instrucciones de Presupuesto de Cómputo por separado.
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
bigint en TypeScript | Todo el manejo de cantidades en la cadena | Necesitas soporte de navegador heredado sin polyfills |
Decimal.js / bignumber.js | Analizar cadenas decimales de usuario de forma segura | Dentro de programas Rust en la cadena |
| Solo enteros de lamports (sin tipo SOL) | Argumentos de instrucciones del programa | Construir interfaces de billetera visibles para el usuario |
Ayudante lamports() de @solana/kit | Tuberías de Kit seguras en cuanto a tipo | Scripts RPC brutos donde Kit es excesivo |
Preguntas Frecuentes
¿Cuántos lamports hay en un SOL?
1,000,000,000 (10^9). Esto es fijo y nunca cambia.
¿Por qué Solana usa enteros en lugar de decimales en la cadena?
La ejecución determinista en todos los validadores requiere aritmética exacta. El punto flotante varía según el hardware; los enteros u64 no.
¿Cuál es la cantidad mínima transferible de SOL?
1 lamport. En la práctica, las tarifas de transacción (5,000 lamports por firma por defecto) hacen que las transferencias sub-lamport no tengan sentido.
¿Cómo convierto de forma segura una cadena SOL introducida por el usuario a 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);
}¿Devuelve getBalance SOL o lamports?
Lamports. Divide por 1e9 solo para mostrar - nunca para instrucciones en la cadena.
¿Qué son los microlamports en las tarifas de prioridad?
1 microlamport = 0.000001 lamports. Las tarifas de prioridad se cotizan en microlamports por unidad de cómputo a través del Programa de Presupuesto de Cómputo.
¿Pueden los saldos de lamports desbordar u64?
Teóricamente, con un suministro total de ~18.4 mil millones de SOL, no es una preocupación práctica, pero la lógica del programa aún debe usar aritmética verificada.
¿Cómo se calcula la exención de alquiler?
Basado en el tamaño de los datos de la cuenta en bytes. RPC getMinimumBalanceForRentExemption(dataSize) devuelve el depósito exacto de lamports requerido.
¿Debería almacenar cantidades como SOL o lamports en mi base de datos?
Almacena lamports como enteros (o cadenas para valores muy grandes). Convierte a SOL solo en la capa de presentación.
¿Qué sucede si envío una transferencia con una cantidad de 0?
El Programa del Sistema rechaza las transferencias de cero lamports. Usa un mínimo significativo o omite la instrucción.
¿Los montos de los tokens SPL están en lamports?
No. Los tokens SPL usan el campo decimals de la mint. Una cantidad de USDC de 1_000_000 significa 1 USDC (6 decimales), no lamports.
¿Cómo formato los lamports para mostrarlos sin pérdida de precisión?
Divide los lamports bigint en partes enteras y fraccionarias con aritmética de cadenas, o usa una biblioteca. Evita Number(lamports) para valores que volverás a enviar en la cadena.
Relacionados
- Fundamentos de Solana - orientación sobre cuentas y transacciones
- Claves y Direcciones - quién posee los lamports
- Clusters y Redes - cantidades de airdrop en devnet
Versiones de Stack: Esta página fue 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, y LiteSVM 0.6.x.