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 stake y estado de delegación de Solana vía RPC

Guía práctica para leer cuentas de stake y el estado de delegación de Solana mediante JSON-RPC, incluyendo el descubrimiento con getProgramAccounts, la decodificación con getAccountInfo, las comprobaciones de activación y cooldown, y un ejemplo ejecutable en Node.js.

TL;DR

Las cuentas de stake de Solana son cuentas on-chain propiedad del programa Stake (Stake11111111111111111111111111111111111111) cuyos datos codifican una sección Meta (reserva exenta de renta, staker y withdrawer autorizados, lockup) y un estado Stake que es uno de Uninitialized, Initialized, Stake (delegación) o RewardsPool. Puedes descubrir cuentas de stake con getProgramAccounts acotado al id del programa Stake, obtener una sola cuenta con getAccountInfo usando jsonParsed para leer los campos de delegación, y consultar la delegación mínima del clúster con getStakeMinimumDelegation. La delegación se activa a lo largo de una rampa de warmup que puede abarcar varios epochs, y la desactivación establece un epoch de desactivación tras el cual la cuenta se enfría antes del retiro. Este artículo muestra cómo leer esos campos vía JSON-RPC, calcular si una cuenta de stake está totalmente activa o es retirable, y evitar errores comunes como escaneos de getProgramAccounts sin filtros y errores de límite de tasa.

Modelo de cuenta del programa Stake y máquina de estados

Una cuenta de stake de Solana es una cuenta on-chain propiedad del programa Stake, cuyo id de programa es Stake11111111111111111111111111111111111111. Los datos de la cuenta codifican dos partes lógicas: una sección Meta que contiene la reserva exenta de renta, las pubkeys autorizadas de staker y withdrawer, y un lockup opcional, y un estado Stake que es uno de Uninitialized, Initialized, Stake (delegación) o RewardsPool. El estado Stake es la parte que lleva la información de delegación, como la pubkey del votante, los lamports delegados, el epoch de activación y el epoch de desactivación.

La máquina de estados importa porque la misma cuenta puede pasar de Initialized a Stake cuando se delega, y de Stake de vuelta hacia retirable cuando se desactiva. Leer la cuenta vía JSON-RPC te da una instantánea de ese estado en un nivel de commitment específico. Para obtener contexto sobre cómo el commitment afecta lo que ves, consulta Niveles de commitment y confirmación de transacciones en Solana.

El layout binario y la forma jsonParsed están definidos por el programa Stake y la versión del parser del nodo RPC. Eso significa que los nombres exactos de los campos y el anidamiento que ves pueden variar según el cliente y el runtime, así que trata la salida parseada como un comportamiento documentado que puede cambiar entre actualizaciones, en lugar de un esquema congelado.

  • Propietario: Stake11111111111111111111111111111111111111
  • Meta: reserva exenta de renta, staker autorizado, withdrawer autorizado, lockup
  • Estado Stake: Uninitialized, Initialized, Stake (delegación), RewardsPool
  • Campos de delegación: pubkey del votante, lamports en stake, activationEpoch, deactivationEpoch

Descubrimiento de cuentas de stake con getProgramAccounts

Para encontrar cuentas de stake, llama a getProgramAccounts con el id del programa Stake como dirección del programa. Debido a que el programa Stake posee muchas cuentas, una llamada sin filtros puede devolver un conjunto de resultados muy grande y resulta costosa para el nodo. La referencia de getProgramAccounts de Solana documenta filtros como dataSize y memcmp que te permiten acotar el escaneo. Usa dataSize para apuntar al tamaño de una cuenta de stake y memcmp para hacer coincidir bytes en un offset conocido cuando necesites un campo específico.

En la práctica, el código de producción debería filtrar de forma estrecha o usar un indexador en lugar de escanear todas las cuentas de stake. Si debes paginar un conjunto de resultados grande, solicita un rango acotado y continúa desde la última cuenta vista. Los patrones de paginación de Paginación de getSignaturesForAddress en Solana son un modelo mental útil para lecturas tipo cursor, aunque el método sea distinto.

El comportamiento del proveedor varía: algunos endpoints permiten escaneos grandes de getProgramAccounts y otros no. Si tu solicitud es rechazada o limitada, eso está documentado / varía según el proveedor, y deberías reducir el alcance del filtro o cambiar a una fuente de datos indexada.

  • Acota la llamada al id del programa Stake
  • Usa dataSize para coincidir con el tamaño de la cuenta de stake
  • Usa memcmp para coincidir con un campo en un offset conocido
  • Pagina resultados grandes y evita escaneos sin límite

Obtención de una sola cuenta de stake con getAccountInfo

Para una dirección de cuenta de stake conocida, getAccountInfo devuelve los datos de la cuenta. Solicitar la codificación jsonParsed pide al nodo que decodifique el layout del programa Stake en campos con nombre, que es la forma más rápida de leer la estructura de delegación. La referencia de getAccountInfo de Solana documenta el layout de la cuenta de stake en jsonParsed, incluidos los campos de delegación parseados.

Cuando jsonParsed no está disponible o necesitas control a nivel de bytes, solicita base64 y decodifica el layout binario tú mismo. La ruta base64 es más estable entre cambios de parser, pero requiere que sigas el layout del programa Stake. Para un tratamiento más amplio de lecturas de cuentas, renta y cuentas de tokens, consulta getAccountInfo, renta y cuentas de tokens en Solana.

La delegación parseada normalmente expone la pubkey del votante, el stake delegado en lamports, el epoch de activación y el epoch de desactivación. Compara esos campos con el epoch actual para razonar sobre el warmup y el cooldown.

  • Usa jsonParsed para campos de delegación con nombre
  • Usa base64 cuando necesites control a nivel de bytes
  • Lee voter, lamports en stake, activationEpoch, deactivationEpoch
  • Compara epochs para determinar el estado activo o en enfriamiento

Lectura de la delegación mínima del clúster con getStakeMinimumDelegation

getStakeMinimumDelegation devuelve la delegación mínima actual del clúster en lamports. La referencia de getStakeMinimumDelegation de Solana documenta que el valor de retorno son los lamports de delegación mínima. Este valor condiciona si una nueva cuenta de stake se activará realmente: si delegas menos que el mínimo, la delegación puede no llegar a activarse.

El mínimo es un parámetro de la cadena, por lo que está documentado / varía según el clúster y la actualización. No lo codifiques de forma fija. Léelo en tiempo de ejecución y compáralo con la cantidad que pretendes delegar antes de enviar una transacción de delegación.

Si estás construyendo un flujo de staking, llama primero a getStakeMinimumDelegation y luego valida la cantidad del usuario contra ese valor. Esto evita un estado confuso en el que la cuenta está Initialized pero nunca llega a ser Stake.

  • Devuelve los lamports de delegación mínima
  • Parámetro de la cadena: varía según el clúster y la actualización
  • Valida la cantidad a delegar antes de enviar
  • Evita cuentas Initialized que nunca se activan

Warmup de activación y sincronización de epochs

La delegación no se vuelve totalmente activa de inmediato. Pasa por una rampa de activación (warmup) que puede abarcar varios epochs. El campo activationEpoch marca el epoch en el que la delegación comenzó a activarse, y el stake se vuelve totalmente activo según el calendario de activación de stake. Para calcular cuándo una delegación se vuelve totalmente activa, lee el epoch actual con getEpochInfo y compáralo con activationEpoch.

La sincronización de epochs del clúster no es una constante de reloj de pared. La duración del epoch depende de la sincronización de slots y la configuración del clúster, así que deberías razonar en epochs en lugar de segundos. Si necesitas una estimación en tiempo real, derívala del tiempo de inicio del epoch actual y la tasa de slots observada, y trátala como una estimación.

Una comprobación práctica es: si el epoch actual es mayor que activationEpoch más el lapso de warmup, la delegación está totalmente activa. El lapso exacto de warmup está definido por el programa de stake y puede cambiar, así que verifícalo contra el clúster que estás consultando.

  • activationEpoch marca el inicio del warmup
  • El warmup puede abarcar varios epochs
  • Usa getEpochInfo para el epoch actual
  • La duración del epoch no es una constante fija de reloj de pared

Cooldown de desactivación y capacidad de retiro

La desactivación establece un epoch de desactivación. Después de eso, la cuenta se enfría a lo largo de los epochs siguientes antes de que los SOL puedan retirarse. Para detectar 'desactivando pero aún no retirable', compara deactivationEpoch con el epoch actual: si el epoch actual es menor o igual que deactivationEpoch, la cuenta todavía se está enfriando.

Una vez que el cooldown termina, el stake ya no está delegado y el withdrawer puede mover los lamports. La ruta de retiro es una transacción contra el programa Stake, no una lectura JSON-RPC, pero la lectura te dice cuándo es seguro intentarlo.

Si estás monitoreando muchas cuentas, rastrea deactivationEpoch y el epoch actual juntos. Una regla simple es: retirable cuando el epoch actual es mayor que deactivationEpoch más el lapso de cooldown. Al igual que con el warmup, verifica el lapso de cooldown contra el clúster.

  • deactivationEpoch marca el inicio del cooldown
  • El cooldown abarca los epochs siguientes
  • Retirable cuando el epoch actual supera deactivationEpoch más el cooldown
  • Lee el estado antes de intentar una transacción de retiro

Ejemplo ejecutable en Node.js: delegación mínima, cuenta parseada y escaneo del programa

El siguiente ejemplo en Node.js usa @solana/web3.js para llamar a getStakeMinimumDelegation, obtener una cuenta de stake conocida con getAccountInfo jsonParsed, llamar a getProgramAccounts en el programa Stake con un filtro dataSize, e imprimir si cada cuenta está activándose o enfriándose. Reemplaza el endpoint RPC y la dirección de la cuenta de stake de ejemplo con tus propios valores.

El ejemplo es intencionalmente pequeño para que puedas adaptarlo. Imprime la delegación mínima, los campos de delegación parseados, un recuento de cuentas de stake y un estado de activación o cooldown por cuenta basado en el epoch actual.

const { Connection, PublicKey } = require('@solana/web3.js');

const RPC_ENDPOINT = process.env.SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com';
const STAKE_PROGRAM_ID = new PublicKey('Stake11111111111111111111111111111111111111');
const SAMPLE_STAKE_ACCOUNT = new PublicKey('YOUR_STAKE_ACCOUNT_ADDRESS');

async function main() {
  const connection = new Connection(RPC_ENDPOINT, 'confirmed');

  // 1. Minimum delegation
  const minDelegation = await connection.getStakeMinimumDelegation();
  console.log('Minimum delegation (lamports):', minDelegation);

  // 2. Parsed stake account
  const accountInfo = await connection.getParsedAccountInfo(SAMPLE_STAKE_ACCOUNT);
  console.log('Parsed account:', JSON.stringify(accountInfo.value?.data, null, 2));

  // 3. Program accounts with dataSize filter
  const accounts = await connection.getProgramAccounts(STAKE_PROGRAM_ID, {
    filters: [{ dataSize: 200 }],
  });
  console.log('Stake accounts found:', accounts.length);

  // 4. Activation / cooldown status
  const epochInfo = await connection.getEpochInfo();
  const currentEpoch = epochInfo.epoch;
  for (const { pubkey, account } of accounts.slice(0, 10)) {
    const parsed = account.data;
    const delegation = parsed?.parsed?.info?.stake?.delegation;
    if (!delegation) continue;
    const activationEpoch = delegation.activationEpoch;
    const deactivationEpoch = delegation.deactivationEpoch;
    const activating = currentEpoch <= activationEpoch;
    const coolingDown = deactivationEpoch !== '18446744073709551615' && currentEpoch <= deactivationEpoch;
    console.log(pubkey.toBase58(), { currentEpoch, activationEpoch, deactivationEpoch, activating, coolingDown });
  }
}

main().catch((err) => {
  console.error(err);
  process.exit(1);
});

Tabla de resultados reproducibles para lecturas de cuentas de stake

Usa la tabla a continuación para registrar lo que tu propio endpoint devuelve para cada cuenta de stake. Complétala ejecutando el ejemplo anterior y copiando los valores. Esto mantiene tus observaciones separadas del comportamiento documentado y de los resultados específicos del proveedor.

Debido a que la forma parseada y la delegación mínima pueden variar según el clúster y la actualización, la tabla es la forma honesta de capturar tu entorno. No asumas que los valores que ves en un clúster se aplican a otro.

  • Dirección: la pubkey de la cuenta de stake
  • Estado: Uninitialized, Initialized, Stake o RewardsPool
  • Votante: la pubkey del votante delegado
  • Lamports delegados: la cantidad en stake
  • Epoch de activación: cuándo comenzó el warmup
  • Epoch de desactivación: cuándo comenzó el cooldown
  • Epoch actual: de getEpochInfo
  • ¿Totalmente activa?: epoch actual más allá del warmup
  • ¿Retirable?: epoch actual más allá del cooldown

Limitaciones, comportamiento del proveedor y compensaciones

El layout binario y la forma jsonParsed están definidos por el programa Stake y la versión del parser del nodo RPC. Esto está documentado / varía según el cliente y el runtime, por lo que un campo que aparece en un cliente puede tener otro nombre o estar ausente en otro. Valida siempre la forma antes de confiar en ella en producción.

getProgramAccounts con un conjunto de resultados grande es pesado y a menudo desencadena un límite de tasa o un 429. El código de producción debería filtrar de forma estrecha, paginar resultados o usar un indexador. Si necesitas capacidad RPC gestionada, revisa Precios de RPC y las opciones de Servicio de API.

La sincronización de epochs del clúster no es una constante de reloj de pared, por lo que cualquier estimación de cuándo una delegación se vuelve totalmente activa o retirable debe expresarse en epochs y volver a comprobarse contra el clúster. Para la selección de endpoints y detalles de red, consulta Redes de Solana.

  • La forma parseada varía según el cliente y el runtime
  • Los escaneos grandes de getProgramAccounts desencadenan límites de tasa
  • La sincronización de epochs no es una constante fija de reloj de pared
  • Prefiere filtros estrechos o un indexador para producción

Solución de problemas comunes en lecturas de cuentas de stake

Si getProgramAccounts devuelve un 429 o se agota el tiempo, reduce el alcance del filtro, añade un filtro dataSize o cambia a una fuente indexada. Si jsonParsed devuelve una forma inesperada, recurre a base64 y decodifica el layout del programa Stake tú mismo. Si getStakeMinimumDelegation no está disponible en tu endpoint, comprueba el soporte de métodos del proveedor, porque la disponibilidad está documentada / varía según el proveedor.

Si una delegación nunca se activa, compara la cantidad delegada con getStakeMinimumDelegation. Si una cuenta parece desactivarse pero no es retirable, compara deactivationEpoch con el epoch actual de getEpochInfo. Para lecturas basadas en suscripciones y elecciones de codificación, consulta Codificación de accountSubscribe en Solana.

En caso de duda, vuelve a leer la cuenta en un nivel de commitment más alto y confirma el epoch. Una instantánea obsoleta es una causa común de estados confusos.

  • 429 o timeout: acota el filtro o usa un indexador
  • Forma parseada inesperada: recurre a base64
  • Método no disponible: comprueba el soporte del proveedor
  • Nunca activa: compara con la delegación mínima
  • No retirable: compara deactivationEpoch con el epoch actual

Próximos pasos para el monitoreo de cuentas de stake

Una vez que puedas leer una sola cuenta de stake, extiende el patrón para monitorear muchas cuentas a lo largo del tiempo. Rastrea activationEpoch y deactivationEpoch, y alerta cuando una cuenta pase de activarse a totalmente activa o de enfriarse a retirable. Usa la Guía de API de Solana (RPC Assistant) para contexto a nivel de método y el centro de aprendizaje de OnFinality para guías relacionadas.

Para cargas de trabajo en producción, elige un endpoint que soporte los métodos que necesitas y los tamaños de escaneo que requieres. Revisa Redes de Solana y Precios de RPC para ajustar la capacidad a tus patrones de lectura.

Por último, mantén actualizada la tabla de resultados de este artículo para tu clúster. Es la forma más fiable de separar el comportamiento documentado del comportamiento específico del proveedor y de tus propias mediciones.

  • Monitorea activationEpoch y deactivationEpoch a lo largo del tiempo
  • Alerta sobre transiciones de estado
  • Elige un endpoint que soporte tus tamaños de escaneo
  • Mantén una tabla de resultados por clúster

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