10 minutos de lectura
Hay varias formas de supervisar los cambios en tiempo real en Solana. Si no estás seguro de cuál es el enfoque más adecuado para tu caso de uso, echa un vistazo a nuestra entrada del blog, donde encontrarás una comparación de las opciones. Si estás listo para empezar a desarrollar con WebSockets utilizando Solana Web3js (versión 1.x), sigue leyendo (si prefieres la versión 2.x, ¡consulta nuestra guía aquí!).
Resumen
Crear detectores de eventos es una forma eficaz de avisar a tu aplicación o a tus usuarios de que algo que estás supervisando ha cambiado. Solana cuenta con varios detectores de eventos integrados muy útiles, también conocidos como «suscripciones», que facilitan enormemente la detección de cambios en la cadena de bloques de Solana. ¿No sabes muy bien cómo utilizarlos? Aquí tienes un par de ejemplos en los que esto podría resultar útil: un bot de Discord que busca interacciones con un programa en cadena (por ejemplo, un bot de ventas), una dApp que comprueba si hay errores en la transacción de un usuario o una notificación en el móvil cuando cambia el saldo de la cartera de un usuario.
¿Prefieres un tutorial en vídeo? Sigue a Sahil para aprender a crear suscripciones WebSocket a la cadena de bloques de Solana en 4 minutos.
Tus funciones
En esta guía, aprenderás a utilizar varios métodos de escucha de eventos de Solana y los puntos finales WebSocket de Quicknode (WSS://) para detectar cambios en la cadena. En concreto, crearás una sencilla aplicación en TypeScript para realizar un seguimiento de los cambios en una cuenta (o monedero). A continuación, aprenderás a utilizar los métodos de cancelación de suscripción de Solana para eliminar un oyente de tu aplicación. También abordaremos los conceptos básicos de algunos de los otros métodos de escucha de Solana.
Lo que necesitarás
- Node.js instalado (versión 16.15 o superior)
- npm o yarn instalados (utilizaremos yarn para inicializar nuestro proyecto e instalar los paquetes necesarios. Si lo prefieres, puedes utilizar npm en su lugar, si es tu gestor de paquetes preferido)
- Experiencia con TypeScript y ts-node instalado
- Solana Web3
Configura tu entorno
Crea un nuevo directorio de proyecto en tu terminal con:
mkdir solana-subscriptions
cd solana-subscriptions
Crea un archivo llamado app.ts:
echo > app.ts
Inicializa tu proyecto con el indicador «yes» para utilizar los valores predeterminados en tu nuevo paquete:
hilo init --sí
#o
npm init --yes
Instalar las dependencias de Solana Web3:
hilo añadir @solana/web3.js@1
#o
npm instalar @solana/web3.js@1
Abre el archivo app.ts en tu editor de código preferido y, en la línea 1, importa Connection, PublicKey y LAMPORTS_PER_SOL de la biblioteca Solana Web3:
import { Connection, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";
¡Muy bien! Ya estamos listos para empezar.
Configura tu punto de acceso de Quicknode
Para desarrollar en Solana, necesitarás un punto final de API para conectarte a la red. Puedes utilizar nodos públicos o implementar y gestionar tu propia infraestructura; sin embargo, si quieres tiempos de respuesta 8 veces más rápidos, puedes dejarnos a nosotros el trabajo pesado.
Descubre por qué más del 50 % de los proyectos de Solana eligen Quicknode y regístrate aquí para crear una cuenta.
Vamos a utilizar un nodo de la red de desarrollo de Solana. Copia los enlaces del proveedor HTTP y del proveedor WSS:

Crea dos nuevas variables en las líneas 3 y 4 del archivo app.js para almacenar estas URL:
const WSS_ENDPOINT = 'wss://example.solana-devnet.quiknode.pro/000/'; // sustituye por tu URL
const HTTP_ENDPOINT = 'https://example.solana-devnet.quiknode.pro/000/'; // sustituye por tu URL
Establecer una conexión con Solana
En la línea 5, crea una nueva conexión con Solana:
const solanaConnection = new Connection(HTTP_ENDPOINT,{wsEndpoint:WSS_ENDPOINT});
Si ya has creado instancias de Connection para Solana anteriormente, quizá notes alguna diferencia en nuestros parámetros, sobre todo la inclusión de {wsEndpoint:WSS\_ENDPOINT}. Profundicemos un poco más.
El constructor de la clase Connection nos permite pasar un objeto commitmentOrConfig opcional. Hay algunas opciones interesantes que podemos incluir con el ConnectionConfig, pero hoy nos vamos a centrar en el parámetro opcional wsEndpoint. Se trata de una opción que te permite proporcionar una URL de punto final al punto final WebSocket de PubSub JSON RPC del nodo completo. En nuestro caso, se trata de nuestro punto final WSS que definimos anteriormente, WSS_ENDPOINT.
¿Qué ocurre si no se pasa un wsEndpoint? Pues bien, Solana tiene en cuenta esta posibilidad mediante una función, makeWebsocketUrl, que sustituye «https» por «wss» o «http» por «ws» en la URL de tu punto final (fuente). Dado que todos los puntos finales HTTP de Quicknode tienen un punto final WSS correspondiente con el mismo token de autenticación, puedes omitir este parámetro a menos que desees utilizar un punto final independiente para tus consultas WebSocket.
¡Vamos a crear algunas suscripciones!
Crear una cuenta Suscripción
Para realizar un seguimiento de un monedero en Solana, tendremos que llamar al método `onAccountChange` de nuestro `solanaConnection`. Le pasaremos `ACCOUNT_TO_WATCH`, la clave pública del monedero que queremos supervisar, y una función de devolución de llamada. Hemos creado un registro sencillo que nos avisa de que se ha detectado un evento y registra el nuevo saldo de la cuenta. Añade este fragmento de código a tu código después de la declaración de `solanaConnection`, en la línea 7:
(async()=>{
const ACCOUNT_TO_WATCH = new PublicKey('vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg'); // Replace with your own Wallet Address
const subscriptionId = await solanaConnection.onAccountChange(
ACCOUNT_TO_WATCH,
(updatedAccountInfo) =>
console.log(`---Event Notification for ${ACCOUNT_TO_WATCH.toString()}--- \nNew Account Balance:`, updatedAccountInfo.lamports / LAMPORTS_PER_SOL, ' SOL'),
"confirmed"
);
console.log('Starting web socket, subscription ID: ', subscriptionId);
})()
Crear una prueba sencilla
Este código está listo para ejecutarse tal cual, pero vamos a añadir una funcionalidad más que nos ayude a comprobar que funciona correctamente. Para ello, añadiremos una función «sleep» (para introducir un retraso) y una solicitud de «airdrop ». Antes del bloque de código asíncrono de la línea 6, añade:
const sleep = (ms:number) => {
return new Promise(resolve => setTimeout(resolve, ms));
}
A continuación, dentro del bloque de código asíncrono, después del mensaje de registro «Starting web socket», añade esta llamada a Airdrop:
esperar dormir(10000); //Esperar 10 segundos para la prueba de socket
await solanaConnection.requestAirdrop(CUENTA_A_VIGILAR, LAMPORTS_PER_SOL);
Tu código esperará efectivamente 10 segundos después de que el socket se haya iniciado para solicitar un airdrop a la cartera (nota: esto solo funcionará en devnet y testnet).
Nuestro código queda ahora así:
import { Connection, PublicKey, LAMPORTS_PER_SOL, } from "@solana/web3.js";
const WSS_ENDPOINT = 'wss://example.solana-devnet.quiknode.pro/000/'; // replace with your URL
const HTTP_ENDPOINT = 'https://example.solana-devnet.quiknode.pro/000/'; // replace with your URL
const solanaConnection = new Connection(HTTP_ENDPOINT, { wsEndpoint: WSS_ENDPOINT });
const sleep = (ms:number) => {
return new Promise(resolve => setTimeout(resolve, ms));
}
(async () => {
const ACCOUNT_TO_WATCH = new PublicKey('vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg');
const subscriptionId = await solanaConnection.onAccountChange(
ACCOUNT_TO_WATCH,
(updatedAccountInfo) =>
console.log(`---Event Notification for ${ACCOUNT_TO_WATCH.toString()}--- \nNew Account Balance:`, updatedAccountInfo.lamports / LAMPORTS_PER_SOL, ' SOL'),
"confirmed"
);
console.log('Starting web socket, subscription ID: ', subscriptionId);
await sleep(10000); //Wait 10 seconds for Socket Testing
await solanaConnection.requestAirdrop(ACCOUNT_TO_WATCH, LAMPORTS_PER_SOL);
})()
¡Pon en marcha tu Socket!
Vamos a probarlo. En tu terminal, puedes escribir «ts-node app.ts» para iniciar tu WebSocket. Al cabo de unos 10 segundos, deberías ver un registro de callbacks en la terminal como este:
solana-subscriptions % ts-node app.ts
Starting web socket, subscription ID: 0
---Event Notification for vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg---
New Account Balance: 88790.51694709 SOL
¡Excelente! Te darás cuenta de que tu aplicación sigue abierta incluso después de la notificación del evento. Esto se debe a que nuestra suscripción sigue a la espera de cambios en nuestra cuenta. Necesitamos una forma de dar de baja el listener. Pulsa Ctrl^C para detener el proceso.
Darse de baja del servicio de notificación de cambios en la cuenta
Solana ha creado un método integrado que podemos utilizar para dar de baja nuestra suscripción al listener de cambios de cuenta: `removeAccountChangeListener`. El método acepta un `subscriptionId` válido (un número) como único parámetro. Dentro de tu bloque asíncrono, añade otra llamada a `sleep` después del airdrop para dar tiempo a que se procese la transacción y, a continuación, llama a `removeAccountChangeListener`:
await sleep(10000); //Wait 10 for Socket Testing
await solanaConnection.removeAccountChangeListener(subscriptionId);
console.log(`Websocket ID: ${subscriptionId} closed.`);
Ahora vuelve a ejecutar el código y deberías ver la misma secuencia, seguida del cierre del WebSocket:
solana-subscriptions % ts-node app.ts
Starting web socket, subscription ID: 0
---Event Notification for vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg---
New Account Balance: 88791.51694709 SOL
Websocket ID: 0 closed.
¡Buen trabajo! Como puedes ver, esto puede resultar útil si quieres desactivar un oyente después de que haya ocurrido algo (por ejemplo, que haya transcurrido un tiempo determinado, que se haya alcanzado un umbral concreto, que se haya alcanzado un número determinado de notificaciones, etc.).
Hemos publicado el código definitivo de este script en nuestro repositorio de GitHub para que lo consultéis.
Otras suscripciones a WebSocket de Solana
Solana cuenta con otros métodos similares de suscripción y cancelación de suscripción a WebSocket que también resultan útiles. Los describiremos brevemente en esta sección.
- onProgramAccountChange: Registra una llamada de retorno que se activará cada vez que cambien las cuentas propiedad del programa especificado. Se debe pasar la clave pública (PublicKey) del programa y una matriz opcional de filtros de cuentas. Entre otras cosas, esto puede resultar útil para realizar un seguimiento de los cambios en la cuenta de tokens de un usuario. Para darse de baja, utiliza removeProgramAccountChangeListener.
- onLogs: Registra una función de devolución de llamada que se invocará cada vez que se emitan registros; se puede utilizar de forma similar a onAccountChange pasando una clave pública válida. La función de devolución de llamada devolverá el ID de la transacción más reciente. Para darse de baja, utilice removeOnLogsListener.
- onSlotChange: Registra una función de devolución de llamada que se ejecutará cuando se produzcan cambios en las ranuras. A este método solo se le pasa una función de devolución de llamada. Para cancelar la suscripción, utiliza removeSlotChangeListener.
- onSignature: Registra una función de llamada inversa que se invocará cuando se actualicen las firmas, pasando una firma de transacción válida. La función de llamada inversa indicará si se ha producido algún error en la transacción. Para cancelar la suscripción, utiliza removeSignatureListener. onRootChange: Registra una función de llamada inversa que se invocará cuando se produzcan cambios en la raíz. A este método solo se le pasa una función de llamada inversa. Para cancelar la suscripción, utiliza removeRootChangeListener.
*Nota: todos los métodos para darse de baja requieren un parámetro «subscriptionId» (número). Puedes encontrar más información sobre estos métodos en nuestra documentación en quicknode.com/docs/solana. No dudes en probar cada uno de ellos realizando pequeñas modificaciones en el archivo app.js para experimentar con algunas de estas otras suscripciones.
Facturación y optimización
Los créditos de facturación para los métodos WebSocket se basan en el número de respuestas recibidas, no en el número de suscripciones. Por ejemplo, si abres un cambio de cuenta Si te suscribes y recibes 100 respuestas, se te cobrarán 5.000 créditos en tu cuenta (50 créditos por respuesta X 100 respuestas).
Para optimizar tus suscripciones y asegurarte de que no se te cobran suscripciones innecesarias ni respuestas irrelevantes, deberías tener en cuenta lo siguiente:
- utiliza los métodos de cancelación de suscripción para eliminar los oyentes cuando ya no te interese recibir datos y
- Utiliza los filtros de los métodos correspondientes para obtener únicamente los datos relevantes.
Formas de darse de baja
Los siguientes métodos se utilizan para eliminar los oyentes de las suscripciones:
cuenta/Darse de baja: Deja de enviar actualizaciones a una cuenta.registros/cancelar suscripción: Deja de recibir los registros.Darse de baja del programa: Deja de recibir las actualizaciones de la cuenta del programa.slotUnsubscribe: Deja de recibir actualizaciones sobre las franjas horarias.firma/Darse de baja: Deja de recibir actualizaciones de la firma.rootDesuscribirse: Deja de recibir las actualizaciones de root.
Uso de filtros con registrosSuscribirse
El registrosSuscribirse Este método te permite filtrar los registros de transacciones, lo que puede reducir considerablemente el número de respuestas que recibes. He aquí un ejemplo:
// To subscribe to all logs (expensive and not recommended):
const subscriptionId = await connection.onLogs(
'all',
(logs) => {
console.log('New log:', logs);
}
);
// To subscribe only to logs mentioning a specific address:
const EXAMPLE_PUBLIC_KEY = new PublicKey('YOUR_ADDRESS_HERE');
const specificAddressSubscriptionId = await connection.onLogs(
EXAMPLE_PUBLIC_KEY,
(logs) => {
console.log('Log mentioning specific address:', logs);
}
);
Uso de filtros con programSubscribe
El programaSuscribirse Este método es muy eficaz, pero puede generar muchas respuestas. Utiliza filtros para reducir la cantidad de datos que recibes:
const filters = [
{
memcmp: {
offset: 0, // Specify the offset in the account data
bytes: 'base58_encoded_bytes_here' // Specify the bytes to compare
}
},
{
dataSize: 128 // If your account data is fixed, you can filter by data size - update this value to match your account's data size
}
];
const subscriptionId = await connection.onProgramAccountChange(
new PublicKey('Your_Program_ID_Here'),
(accountInfo) => {
console.log('Account changed:', accountInfo);
},
'confirmed',
filters
);
En este ejemplo, utilizamos tanto memcmp y tamaño de los datos filtros. El memcmp El filtro compara una serie de bytes en una posición específica dentro de los datos de la cuenta, mientras que tamaño de los datos filtra las cuentas en función del volumen de datos que contienen. Esta combinación puede reducir considerablemente el número de respuestas que recibes, centrándose únicamente en las cuentas que cumplen tus criterios específicos. Para obtener más información sobre cómo utilizar GetProgramAccountsFilter, consulta el Documentación del RPC de Solana.
Buenas prácticas para la optimización
-
Sé específico con tus filtros: cuanto más específicos sean tus filtros, menos respuestas irrelevantes recibirás.
-
Utiliza los niveles de compromiso adecuados para tu caso de uso: los niveles de compromiso más altos (como «finalizado») pueden dar lugar a menos actualizaciones, pero más fiables.
-
Revisa periódicamente y elimina las suscripciones que no utilices: revisa tus suscripciones activas y elimina aquellas que ya no necesites.
-
Controla tu uso: lleva un registro del número de respuestas que recibes y ajusta tus filtros o tu estrategia de suscripción si es necesario (panel de control de Quicknode).
Al aplicar estas estrategias de optimización, te asegurarás de recibir únicamente los datos que necesitas, lo que te permitirá reducir al mínimo el uso innecesario de crédito de facturación sin mermar la eficacia de tu aplicación de Solana.
Soluciones alternativas
Quicknode ofrece varias soluciones para obtener datos en tiempo real de Solana. Echa un vistazo a las siguientes opciones para encontrar la herramienta más adecuada para tu caso de uso:
- WebSockets: Tal y como se explica en esta guía, los WebSockets ofrecen conexiones directas con los nodos de Solana para obtener actualizaciones en tiempo real; son ideales para aplicaciones sencillas y un desarrollo rápido. Si quieres utilizar los WebSockets de Solana con Solana Kit, consulta nuestra guía «Supervisar cuentas de Solana mediante WebSockets y Solana Kit» para saber cómo configurar una suscripción a WebSockets en Solana utilizando Solana Kit.
- Solana gRPC (Geyser gRPC compatible con Yellowstone): Solana gRPC ofrece una potente interfaz gRPC para la transmisión de datos de Solana, con filtrado integrado y compatibilidad con datos históricos.
- Streams: Solución gestionada para el procesamiento y el enrutamiento de datos de Solana a múltiples destinos, con filtrado integrado y compatibilidad con datos históricos.
Para obtener más información, echa un vistazo a nuestra entrada del blog.
Conclusión
¡Buen trabajo! Ahora ya deberías saber cómo utilizar las suscripciones a WebSockets en Solana. ¿Cómo estás utilizando los WebSockets de Solana? ¡Nos encantaría ver lo que estás creando! Comparte tu aplicación con nosotros en Discord o Twitter.
Para obtener más información, echa un vistazo a algunos de nuestros otros tutoriales sobre Solana aquí, y si te han gustado las suscripciones a WebSocket, plantéate suscribirte a nuestro boletín informativo.
¡Nos encanta recibir comentarios!
Si tienes algún comentario o sugerencia sobre nuevos temas, no dudes en hacérnoslo saber. Nos encantaría saber tu opinión.
