Desarrolladores

Dos formas de leer los precios de Chainlink en Stellar: Data Feeds y Data Streams

Author

Stellar Development Foundation

Publishing date

Nota del editor: El ecosistema de oráculos de la red Stellar está creciendo. Esta publicación es una guía técnica para desarrolladores y equipos que crean en la red Stellar. Cubre cómo funcionan Chainlink Data Feeds y Data Streams en los contratos inteligentes de Stellar, tras su lanzamiento en mainnet, junto con otros proveedores disponibles. Stellar Development Foundation (SDF) no avala, recomienda ni garantiza ningún proveedor específico de oráculos, y esta publicación no constituye asesoramiento de inversión, financiero ni legal. Los desarrolladores deben realizar su propia diligencia debida antes de integrar cualquier servicio de terceros.

Chainlink Data Feeds y Data Streams ya están disponibles en la mainnet de Stellar, llevando la infraestructura de oráculos líder del mercado de Chainlink y datos de alta calidad a desarrolladores que crean en Stellar. Con estos dos modelos complementarios de entrega de datos, los desarrolladores pueden acceder a precios de referencia onchain confiables para aplicaciones como mercados de préstamos y stablecoins, o a datos de mercado de baja latencia y verificables criptográficamente bajo demanda para aplicaciones sensibles al tiempo como perpetuos y liquidaciones.

Cuál encaja depende de qué tan frescos necesites que sean tus precios y quién paga por ponerlos onchain. Esta publicación recorre ambas. En el espíritu de “no confíes, verifica”, también muestra cómo comprobar tú mismo los despliegues, desde leer un precio en vivo de mainnet hasta mostrar que el verificador de Streams rechaza datos manipulados, sin gastar un solo stroop.

Quién debería mirar esto primero

Chainlink en Stellar es útil si estás creando:

  • Mercados de préstamos, bóvedas o lógica de stablecoins que necesitan precios confiables para XLM, BTC, ETH, USDC, USDT o EURC y requieren una tasa de referencia compartida y actualizada regularmente
  • Perpetuos, opciones o motores de liquidación que necesitan un precio fresco en el momento en que se ejecuta una transacción
  • Protocolos que ya aprovechan Chainlink en otras blockchains y que desean expandirse a Stellar usando la misma infraestructura de oráculos segura

Qué está disponible en el lanzamiento

Data Feeds en la mainnet de Stellar cubren nueve activos al momento de escribir esto, todos valorados contra USD (los feeds cambian con el tiempo, así que toma la tabla de abajo como una instantánea). La lista de feeds de Stellar tiene el data_id para cada uno.

Feed

Clase de activo

Umbral (Si un precio cambia en 0.5% o más, se entregará un valor nuevo)

Heartbeat (En caso de que el umbral no se rompa por 24 horas, los datos se actualizarán desde la fuente)

XLM / USD

Cripto

0.5

24h

BTC / USD

Cripto

0.5

24h

ETH / USD

Cripto

0.5

24h

LINK / USD

Cripto

0.5

24h

USDC / USD

Stablecoin

0.5

24h

USDT / USD

Stablecoin

0.5

24h

EURC / USD

Stablecoin

0.5

24h

Tasa de referencia XAUM

Materia prima (oro)

0.1

24h

FLHY / USD

RWA

0.5

24h

Elegir entre Chainlink Data Feeds y Data Streams

Ambas soluciones brindan acceso a datos de mercado de Chainlink, pero atienden requisitos de aplicación diferentes.

Data Feeds están diseñados para aplicaciones que necesitan precios de referencia onchain actualizados regularmente, como mercados de préstamos, stablecoins y bóvedas. Los precios se actualizan según umbrales de desviación predefinidos e intervalos de heartbeat, lo que permite a los contratos inteligentes leer los datos más recientes disponibles directamente onchain.

Data Streams están diseñados para aplicaciones que necesitan datos de mercado frescos en la ejecución, como exchanges de perpetuos y motores de liquidación. Las aplicaciones obtienen reportes de precios firmados offchain y los envían para verificación onchain cuando se necesite.

La elección correcta depende de los requisitos de tu aplicación respecto a frescura de datos, frecuencia de actualización, activos admitidos y costos de transacción. Para aplicaciones que gestionan colateral volátil o fondos de usuarios, los desarrolladores también deben implementar comprobaciones de frescura y controles de riesgo adecuados.

Cómo funciona la integración

Data Feeds: un modelo push

Chainlink Data Feeds proporcionan datos de mercado confiables y descentralizados para contratos inteligentes que dependen de precios de referencia onchain disponibles de forma constante. Al agregar datos mediante redes de oráculos de Chainlink, Data Feeds reducen la necesidad de que los desarrolladores obtengan, agreguen y mantengan su propia infraestructura de precios.

En Stellar, un único contrato proxy sirve a cada feed. No necesitas una dirección separada por activo, pasas un identificador de 32 bytes llamado data_id.

  • Proxy de mainnet: CDQBHEUGLDHMSUHG4IH33RJBUTMNCZOT4JIAQR4WZFRDZW6DR6S32ZLZ
  • Proxy de testnet: CBUF6IADAWPWIDWRTHJNINKXHG2UTIQ6TU2F2HRAXWAI7OT3KJPKK6O4

Tu contrato lee un feed con una sola llamada entre contratos:

#[contractclient(name = "DataFeedsProxyClient")]
pub trait DataFeedsProxy {
    fn latest_round(env: Env, data_id: BytesN<32>, decimals: u32) -> Result<Round, ProxyReadError>;
}

pub fn read_latest_price(env: Env, proxy: Address, data_id: BytesN<32>) -> I256 {
    let client = DataFeedsProxyClient::new(&env, &proxy);
    // The generated client returns the Round directly and panics on error;
    // use try_latest_round to handle ProxyReadError yourself.
    let round = client.latest_round(&data_id, &18);
    round.answer
}

Fragmento adaptado de la guía de Chainlink sobre Stellar Data Feeds, que tiene el ejemplo completo funcionando, incluyendo los Round y ProxyReadError tipos.

Cada Round devuelve round_id, answer (un I256) y timestamp. Los feeds se almacenan con 18 decimales. Si pides menos, la respuesta se trunca, no se redondea, así que tenlo en cuenta.

💡 Consejo: El ejemplo devuelve la respuesta sin mirar timestamp. En producción, compara timestamp con la hora del ledger y rechaza los precios más antiguos que el latido del feed. Son 24 horas para los feeds actuales de Stellar.

Data Streams: un modelo pull

Con Streams, nada se escribe onchain hasta que tu aplicación necesita un precio:

1. Offchain, obtienes un informe firmado desde la API de Data Streams de Chainlink vía REST, WebSocket o los SDKs de Go, TypeScript o Rust. Es un producto por suscripción.

2. Onchain, un contrato verificador revisa las firmas. El verificador de mainnet es CAKA3NBYPC6OBEUEGNIYGNYG3ES2GPQK736B5SR7ASGUXRDAKXI2JCQI. Su verify función analiza el reporte, busca la configuración de oráculo registrada, recupera cada firmante vía ECDSA y requiere exactamente f+1 firmas válidas y únicas de oráculos registrados. Verifica quién firmó un reporte, no su antigüedad, así que decodifica el observationsTimestamp y expiresAt campos y aplica tus propias reglas de frescura.

3. Tu contrato consume los bytes verificados:

pub fn consume_price_data(env: Env, verifier_address: Address, signed_report: Bytes, sender: Address) -> Bytes {
    sender.require_auth();
    let verifier = VerifierClient::new(&env, &verifier_address);
    // Verifies all ECDSA signatures and returns the decoded report data.
    let report_data = verifier.verify(&signed_report, &sender);
    // First 32 bytes are the feed_id; remaining fields are feed-specific.
    report_data
}

Fragmento de el tutorial de Data Streams de Chainlink para Stellar. Chainlink señala que el ejemplo no está auditado.

Verifica el despliegue por tu cuenta

Ejecutamos todos los comandos de abajo antes de publicar, contra mainnet y testnet. Muestran que los contratos se comportan como se describe; no sustituyen una auditoría. Siempre confirma las direcciones de contrato con la documentación oficial de Chainlink antes de integrar; las direcciones pueden cambiar.

Todo lo siguiente usa la simulación de Stellar RPC (--send=no): no se envía ninguna transacción y no se pagan comisiones. La simulación ejecuta el WASM real del contrato contra el estado real del ledger, por lo que los resultados reflejan el comportamiento actual del contrato en el momento en que los ejecutes. Usa la dirección pública de cualquier cuenta existente (G…) como --source-account; no se necesita clave secreta. Cualquier proveedor de Stellar RPC funciona en lugar del mostrado.

1. Lee un feed de mainnet. Lee el feed XLM/USD desde el proxy de mainnet:

stellar contract invoke \
  --id CDQBHEUGLDHMSUHG4IH33RJBUTMNCZOT4JIAQR4WZFRDZW6DR6S32ZLZ \
  --rpc-url https://mainnet.sorobanrpc.com \
  --network-passphrase "Public Global Stellar Network ; September 2015" \
  --source-account <ANY_PUBLIC_ADDRESS> --send=no \
  -- latest_round \
  --data_id 017be2f55a000332000000000000000000000000000000000000000000000000 \
  --decimals 18

description devuelve "XLM/USD", y latest_round devuelve la ronda actual, por ejemplo {"answer":"176026152984863900", "round_id":1637, "timestamp":1792426484}, que es $0.1760 a 18 decimales en el momento de escribir esto. Pasar un data_id falla con Error(Contract, #50), que es NoDataPresent.

2. Verifica un reporte auténtico de Streams. El tutorial de Chainlink publica un reporte real firmado de testnet. Pásalo directamente al verificador de testnet (CA7GVHWH4GRHE6GI7MHEKQZAOYO4GE7KRGSU3EOS3HYJRVLX3XEA4ONQ) con -- verify --signed_report <hex> --sender <ANY_PUBLIC_ADDRESS>. La simulación devuelve un verified evento y el reporte decodificado: ID del feed, timestamps y precios de referencia, bid y ask.

3. Intenta hacer trampa. Cambia un byte del precio de referencia dentro del reporte y llama de nuevo:

error: transaction simulation failed: HostError: Error(Contract, #12)

El Error #12 es BadVerification. Cambiar el reporte significa que el firmante recuperado ya no coincide con un oráculo registrado, por lo que el verificador lo rechaza. Esto muestra al verificador rechazando un reporte modificado.

4. Confirma que mainnet está configurado por separado. Envía el mismo reporte auténtico de testnet al verificador de mainnet. Falla con Error(Contract, #9), que es DigestNotSet. Mainnet solo acepta reportes firmados bajo su propia configuración de oráculo registrada. is_initialized en el verificador de mainnet devuelve true.

Descargo de responsabilidad: SDF proporciona esta publicación solo con fines informativos y educativos. Las referencias a proyectos, productos o servicios específicos no constituyen respaldo, recomendación ni garantía por parte de SDF. Los ejemplos de código son ilustrativos y no han sido auditados por SDF; los desarrolladores deben verificar de forma independiente todo el código antes de implementarlo en mainnet. SDF no es responsable del rendimiento, la seguridad ni la disponibilidad de ningún oráculo o fuente de datos de terceros. Nada en esta publicación pretende ser asesoramiento de inversión, financiero o legal.