Logo
Nuevos usuarios de RPC: 35% de descuento el primer mesVer oferta
OnFinality Learn
Guías de red y protocolo12 min de lectura

Lectura de cuentas de Solana: getAccountInfo, exención de alquiler y saldos de tokens

Aprende cómo funcionan los datos de cuentas, el alquiler y los saldos de tokens SPL en Solana, y qué método RPC usar para cada lectura.

TL;DR

Cada estado en Solana reside en una cuenta: una dirección de 32 bytes, un saldo en lamports, un programa propietario, un indicador de ejecutable, una época de alquiler y un búfer de datos opaco. Para leer el saldo de SOL de una billetera usa getBalance; para leer metadatos completos y datos de la cuenta usa getAccountInfo; para leer tenencias de tokens SPL debes consultar las cuentas de token mediante getTokenAccountsByOwner, no el saldo de lamports de la billetera. La exención de alquiler se aplica manteniendo un saldo mínimo en lamports que escala con el tamaño de los datos de la cuenta, consultable mediante getMinimumBalanceForRentExemption. Esta guía explica los mecanismos y proporciona ejemplos ejecutables para evitar errores comunes de lectura.

Respuesta directa: ¿Qué método RPC deberías usar?

Si necesitas el saldo de SOL (lamports) de una billetera, llama a getBalance con la dirección de la billetera. Si necesitas el estado completo de la cuenta (propietario, indicador de ejecutable, época de alquiler y el búfer de datos sin procesar), llama a getAccountInfo. Si necesitas saldos de tokens SPL (por ejemplo, USDC o un NFT), no llames a getBalance en la billetera ni en el mint; en su lugar, llama a getTokenAccountsByOwner para listar las cuentas de token propiedad de la billetera, opcionalmente filtradas por mint. Para el suministro total de un mint o los tenedores más grandes, usa getTokenSupply y getTokenLargestAccounts. Esta distinción es la raíz de la mayoría de los errores de 'cuenta en blanco' o 'saldo cero'.

La referencia JSON-RPC de Solana en solana.com/developers es la fuente autorizada para la semántica de los métodos. La página de endpoints y proveedores RPC de Solana (Asistente RPC) de OnFinality lista endpoints que soportan estos métodos.

  • getBalance – devuelve solo el saldo en lamports de cualquier cuenta (billetera, mint, cuenta de token).
  • getAccountInfo – devuelve el objeto de cuenta completo: lamports, propietario, ejecutable, rentEpoch y datos.
  • getTokenAccountsByOwner – devuelve las cuentas de token (con sus saldos) propiedad de una billetera, opcionalmente filtradas por mint.
  • getTokenLargestAccounts – devuelve las cuentas de token más grandes para un mint dado.
  • getTokenSupply – devuelve el suministro total de un mint.

Cómo almacena Solana el estado: el modelo de cuentas

Solana no es un almacén clave-valor tradicional con tablas separadas para saldos y almacenamiento de contratos inteligentes. En cambio, cada estado es una cuenta: una estructura de datos única con un encabezado fijo y una matriz de bytes opaca. El encabezado contiene: lamports (el saldo de SOL en lamports, 1 SOL = 1e9 lamports), owner (el programa que posee esta cuenta y puede modificar sus datos), executable (si la cuenta es un programa), rent_epoch (la próxima época en la que se cobrará el alquiler) y data (un búfer de bytes de longitud variable).

Los data de la cuenta son completamente opacos para el runtime; solo el programa propietario puede escribir en ellos. Para una cuenta propiedad del sistema (como una billetera), los datos están vacíos. Para una cuenta de token SPL, los datos son una estructura binaria de 165 bytes que codifica el mint, el propietario, el saldo y otros campos. Este diseño explica por qué leer un saldo de token requiere deserializar los datos de la cuenta, no solo leer un número.

La documentación de Solana sobre cuentas y la estructura AccountInfo proporcionan el modelo canónico. La descripción general de la red Solana de OnFinality brinda contexto sobre cómo encajan las cuentas en la cadena en general.

  • Dirección de cuenta: clave pública ed25519 de 32 bytes.
  • Lamports: la unidad más pequeña de SOL; 1 SOL = 1,000,000,000 lamports.
  • Propietario: el programa que puede modificar los datos de la cuenta.
  • Ejecutable: verdadero solo para cuentas de programa.
  • Época de alquiler: la próxima época en que vence el alquiler (si no está exenta).
  • Datos: una matriz de bytes opaca, a menudo serializada con bincode o diseños personalizados.

Alquiler y exención de alquiler: por qué existen los saldos mínimos

Para evitar la hinchazón del estado, Solana cobra alquiler a las cuentas que almacenan datos. El alquiler se paga desde el saldo de lamports de la cuenta en cada límite de época. Sin embargo, si una cuenta tiene al menos el saldo mínimo para exención de alquiler, está exenta de alquiler para siempre. Este mínimo depende del tamaño: los búferes de datos más grandes requieren un depósito mayor en lamports.

El método RPC getMinimumBalanceForRentExemption devuelve la cantidad exacta de lamports necesaria para un tamaño de datos dado. Por ejemplo, una cuenta de token SPL con 165 bytes de datos requiere un mínimo específico (documentado en el código fuente de Solana, pero puedes consultarlo en vivo). Si una cuenta cae por debajo de este umbral, se convierte en 'pagadora de alquiler' y puede ser recolectada si su saldo llega a cero.

Cuando creas una cuenta de token a través del programa SPL Token, el sistema transfiere automáticamente el mínimo de exención de alquiler desde la billetera que financia. Por eso a menudo ves un pequeño saldo de SOL en las cuentas de token. La documentación sobre alquiler de Solana explica la justificación económica. Para uso práctico de RPC, siempre llama a getMinimumBalanceForRentExemption con la longitud de datos de la cuenta que planeas crear.

  • El alquiler se cobra a las cuentas que no están exentas de alquiler.
  • Las cuentas exentas de alquiler no pagan alquiler y nunca se recolectan.
  • Saldo mínimo = f(tamaño de datos), consultable mediante getMinimumBalanceForRentExemption.
  • Las cuentas de token generalmente se crean exentas de alquiler por la billetera que las financia.

Lectura de datos de cuenta con getAccountInfo

getAccountInfo es el caballo de batalla para leer el estado completo de cualquier cuenta. Acepta una dirección y configuración opcional: commitment, encoding (base58, base64 o base64+zstd) y dataSlice para obtener solo una parte de los datos. La respuesta incluye lamports, owner, executable, rentEpoch y data como una matriz de [encodedData, encoding].

Un error común es que getAccountInfo devuelve null para cuentas que no existen, no un objeto vacío. Si ves null, la cuenta nunca se ha creado o ha sido eliminada. Además, la codificación predeterminada es base58, que es ineficiente para datos grandes; usa base64 para cuentas de programa o cuentas de token.

El siguiente ejemplo con curl obtiene la información de la cuenta del propio programa SPL Token (dirección TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA). Ten en cuenta que los datos son grandes y están codificados en base64.

curl https://api.mainnet-beta.solana.com -X POST -H "Content-Type: application/json" -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "getAccountInfo",
  "params": [
    "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
    {
      "encoding": "base64",
      "commitment": "confirmed"
    }
  ]
}'

# Expected output (truncated):
# {
#   "jsonrpc": "2.0",
#   "result": {
#     "context": { "slot": 123456 },
#     "value": {
#       "data": ["base64string...", "base64"],
#       "executable": true,
#       "lamports": 1000000000,
#       "owner": "BPFLoader2111111111111111111111111111111111111",
#       "rentEpoch": 0
#     }
#   }
# }

Cuentas de token SPL: el diseño de 165 bytes y la deserialización

Las cuentas de token SPL son cuentas propiedad del programa SPL Token (TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA). Sus datos tienen exactamente 165 bytes y siguen un diseño fijo: mint (32 bytes), owner (32 bytes), amount (u64, little-endian), delegate (32 bytes, todos ceros si no hay), state (1 byte: 0=no inicializado, 1=inicializado, 2=congelado), is_native (1 byte), delegated_amount (u64), close_authority (32 bytes, opcional).

Para leer el saldo, debes deserializar el campo amount en el offset 64 (después de mint y owner). Muchos SDK proporcionan ayudas: @solana/spl-token tiene unpackAccount, y @solana/web3.js tiene AccountInfo pero no análisis específico de tokens. El siguiente ejemplo en Node.js usa @solana/spl-token para obtener y analizar una cuenta de token.

El código fuente del programa SPL Token es la referencia autorizada para el diseño. Para una verificación manual rápida, puedes usar getAccountInfo y dividir los datos.

// npm install @solana/web3.js @solana/spl-token
import { Connection, PublicKey } from '@solana/web3.js';
import { getAccount, unpackAccount } from '@solana/spl-token';

const connection = new Connection('https://api.mainnet-beta.solana.com');
const tokenAccountAddress = new PublicKey('YOUR_TOKEN_ACCOUNT_ADDRESS');

// Using getAccount (high-level)
const account = await getAccount(connection, tokenAccountAddress);
console.log('Balance:', account.amount.toString());

// Using unpackAccount (lower-level)
const info = await connection.getAccountInfo(tokenAccountAddress);
const parsed = unpackAccount(tokenAccountAddress, info);
console.log('Owner:', parsed.owner.toBase58());
console.log('Mint:', parsed.mint.toBase58());
console.log('Amount:', parsed.amount.toString());

Billetera vs cuenta de token asociada: por qué los saldos pueden ser cero

El saldo de SOL de una billetera se almacena en la cuenta del sistema de la billetera. El saldo de tokens de una billetera no se almacena en la cuenta de la billetera; se almacena en una o más cuentas de token separadas que son propiedad del programa SPL Token. La cuenta de token más común es la cuenta de token asociada (ATA), cuya dirección se deriva determinísticamente de la billetera y el mint usando findProgramAddress con semillas [wallet, TOKEN_PROGRAM_ID, mint].

Si un usuario nunca ha creado una ATA para un mint en particular, puede que aún posea tokens en una cuenta de token creada manualmente, o puede que tenga cero tokens. Por lo tanto, consultar getBalance en la billetera devuelve solo SOL, y consultar getAccountInfo en la billetera devuelve datos vacíos. Para encontrar todas las cuentas de token de una billetera, usa getTokenAccountsByOwner.

La fórmula de derivación de ATA es: findProgramAddress([owner, TOKEN_PROGRAM_ID, mint], TOKEN_PROGRAM_ID). La documentación de la cuenta de token asociada SPL explica esto. El siguiente ejemplo deriva una ATA y obtiene su saldo.

// Node.js example to derive ATA and get balance
import { Connection, PublicKey } from '@solana/web3.js';
import { getAssociatedTokenAddress } from '@solana/spl-token';

const connection = new Connection('https://api.mainnet-beta.solana.com');
const wallet = new PublicKey('YOUR_WALLET_ADDRESS');
const mint = new PublicKey('YOUR_MINT_ADDRESS');

const ata = await getAssociatedTokenAddress(mint, wallet);
console.log('ATA:', ata.toBase58());

const info = await connection.getAccountInfo(ata);
if (info === null) {
  console.log('ATA does not exist. User may have no tokens or uses a non-ATA token account.');
} else {
  const balance = await connection.getTokenAccountBalance(ata);
  console.log('Token balance:', balance.value.amount);
}

Tenencia de tokens: getTokenAccountsByOwner, getTokenLargestAccounts y getTokenSupply

Para listar todas las cuentas de token propiedad de una billetera, usa getTokenAccountsByOwner. Este método acepta la dirección del propietario y filtros opcionales: mint (para filtrar por un token específico) y programId (para filtrar por programa de token, útil para token-2022). Devuelve una matriz de objetos { pubkey, account }, donde cada account es un AccountInfo estándar con datos en base64. Debes deserializar cada uno para obtener el saldo.

El método soporta paginación mediante los parámetros before y limit, donde before es un cursor de pubkey de cuenta de token. Esto es esencial para billeteras con muchas cuentas de token.

Para estadísticas agregadas de un mint, getTokenSupply devuelve el suministro total, y getTokenLargestAccounts devuelve las N cuentas de token más grandes por saldo. Estos son útiles para análisis, pero no te dicen qué billetera posee una cuenta de token a menos que también obtengas el campo de propietario de la cuenta.

El siguiente ejemplo con curl obtiene todas las cuentas de token USDC para una billetera. Reemplaza la dirección de la billetera con una real.

curl https://api.mainnet-beta.solana.com -X POST -H "Content-Type: application/json" -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "getTokenAccountsByOwner",
  "params": [
    "WALLET_ADDRESS",
    {
      "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
    },
    {
      "encoding": "jsonParsed"
    }
  ]
}'

# Expected output (truncated):
# {
#   "jsonrpc": "2.0",
#   "result": {
#     "context": { "slot": 123456 },
#     "value": [
#       {
#         "pubkey": "TOKEN_ACCOUNT_ADDRESS",
#         "account": {
#           "data": {
#             "parsed": {
#               "info": {
#                 "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
#                 "owner": "WALLET_ADDRESS",
#                 "state": "initialized",
#                 "tokenAmount": {
#                   "amount": "1000000",
#                   "decimals": 6,
#                   "uiAmount": 1.0
#                 }
#               },
#               "type": "account"
#             },
#             "program": "spl-token",
#             "space": 165
#           },
#           "executable": false,
#           "lamports": 2039280,
#           "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
#           "rentEpoch": 0
#         }
#       }
#     ]
#   }
# }

Versión de escritura de cuenta y codificación: evitando errores comunes

Cuando obtienes datos de cuenta, el campo data se devuelve como una matriz [encoded, encoding]. La codificación puede ser base58, base64 o base64+zstd. Para datos grandes, base58 es ineficiente y puede alcanzar los límites de tamaño de respuesta. Siempre usa base64 para cuentas de programa o cuentas de token.

Otro error es la versión de escritura de cuenta, un concepto del runtime de Solana que rastrea cuántas veces se ha escrito una cuenta. Esto no se expone en getAccountInfo, pero es relevante para la simulación de transacciones y transacciones versionadas. Para leer el estado, generalmente no lo necesitas, pero ten en cuenta que algunas respuestas RPC incluyen un campo version en el contexto.

Cuando usas la codificación jsonParsed (como en el ejemplo anterior), el nodo RPC deserializa automáticamente las cuentas de token conocidas, dándote un objeto tokenAmount legible. Esta es la forma más fácil de leer saldos de token sin deserialización manual. Sin embargo, jsonParsed solo funciona para cuentas propiedad de programas conocidos (como SPL Token). Para programas personalizados, debes usar base64 y deserializar tú mismo.

La documentación RPC de Solana detalla las opciones de codificación. El servicio API de OnFinality soporta estas codificaciones en todos sus endpoints.

  • Usa base64 para datos grandes y evitar la hinchazón de base58.
  • Usa jsonParsed para cuentas de token SPL y obtener saldos pre-deserializados.
  • Para programas personalizados, obtén base64 y deserializa según el diseño del programa.
  • Los datos de cuenta se devuelven como [data, encoding]; no los trates como una cadena simple.

Lista de verificación de solución de problemas: por qué ves cero o datos vacíos

Si obtienes null de getAccountInfo, la cuenta no existe. Esto es normal para una ATA que nunca se ha creado. Si obtienes una cuenta pero los datos están vacíos, puede que estés mirando una cuenta del sistema (billetera) en lugar de una cuenta de token. Si obtienes una cuenta de token pero el saldo es cero, la cuenta puede estar no inicializada o congelada.

El nivel de compromiso importa: processed puede devolver datos antes de la finalización, mientras que finalized asegura que el estado sea canónico. Para la mayoría de las lecturas, confirmed es un buen valor predeterminado. Si ves resultados inconsistentes entre llamadas, verifica tu compromiso.

La falta de coincidencia de codificación es otro problema común: si solicitas base58 pero esperas un objeto JSON analizado, obtendrás una cadena. Siempre haz coincidir la codificación con tu lógica de análisis.

Finalmente, recuerda que getBalance en un mint de token devuelve el saldo de lamports del mint (el SOL utilizado para financiar la cuenta del mint), no el suministro de tokens. Para obtener el suministro de tokens, usa getTokenSupply.

  • Cuenta null → no existe; créala o verifica la dirección.
  • Datos vacíos en una billetera → eso es normal; los saldos de tokens están en cuentas separadas.
  • Saldo de token cero → verifica si la cuenta de token está inicializada y no congelada.
  • Compromiso incorrecto → usa confirmed o finalized para lecturas consistentes.
  • Falta de coincidencia de codificación → solicita jsonParsed para cuentas de token o analiza base64 correctamente.
  • getBalance en un mint → devuelve lamports, no el suministro de tokens.

Limitaciones y compensaciones

Leer datos de cuenta a través de RPC tiene limitaciones inherentes. Primero, getAccountInfo devuelve el búfer de datos completo, que puede ser grande para cuentas de programa (por ejemplo, el programa SPL Token tiene más de 100 KB). Obtener tales datos repetidamente puede ser ineficiente; considera usar dataSlice para obtener solo los bytes que necesitas.

Segundo, los proveedores de RPC a menudo imponen límites de tasa y límites de tamaño de carga útil. Los números exactos están documentados/varían según el proveedor; la página de precios de RPC de OnFinality lista los planes, pero los límites específicos no se publican aquí. Siempre consulta la documentación de tu proveedor.

Tercero, getTokenAccountsByOwner puede devolver una gran cantidad de cuentas para una billetera con muchos tokens. La paginación es obligatoria para uso en producción. El parámetro limit del método está limitado por el proveedor (documentado/varía según el proveedor).

Finalmente, los datos de cuenta son tan frescos como el slot que consultas. Para aplicaciones en tiempo real, usa suscripciones WebSocket (por ejemplo, accountSubscribe) para monitorear cambios. La guía de OnFinality sobre Monitoreo de endpoints RPC y salud del nodo cubre esto.

  • Los búferes de datos grandes pueden ralentizar las respuestas; usa dataSlice.
  • Los límites de tasa y límites del proveedor varían; consulta tu plan.
  • La paginación es necesaria para billeteras con muchas cuentas de token.
  • Para actualizaciones en tiempo real, usa suscripciones WebSocket en lugar de sondeos.

Próximos pasos y lecturas adicionales

Ahora que comprendes el modelo de cuentas y los métodos RPC, puedes construir indexadores y dApps confiables. Para profundizar, explora los endpoints y proveedores RPC de Solana (Asistente RPC) para elegir el mejor endpoint para tus necesidades. Para el estado histórico de cuentas, consulta Lectura de datos históricos de transacciones de Solana a través de RPC.

Si estás construyendo en otras cadenas, los mismos principios se aplican: Acceso a datos históricos de blockchain cubre patrones generales, y Pruebas de estado con eth_getProof muestra cómo lo hace Ethereum.

Para una visión general más amplia de Solana, visita la página de red de Solana. Y no olvides consultar el centro de aprendizaje de OnFinality para más tutoriales. Si necesitas acceso RPC de grado de producción, revisa las páginas de servicio API y precios de RPC.

  • Prueba los ejemplos con tus propias direcciones y compara resultados.
  • Usa una tabla de relleno para registrar tus mediciones: método, dirección, compromiso, codificación, resultado y notas.
  • Experimenta con dataSlice para obtener solo el campo amount de una cuenta de token.

Nunca te preocupes por la infraestructura nuevamente

OnFinality elimina la carga pesada de DevOps para que puedas construir de forma más inteligente y rápida.

Comenzar