Esc

    Integrate

    On-chain prices

    Read the oracle's median price on the Internet Computer (ICP), from the registry canister or as a certified document over HTTPS.

    The nodes push their signed prices to the registry canister on the Internet Computer (ICP). The canister checks each signature against the registry and serves the median of the nodes for each priced feed. Use it when your code runs on the Internet Computer, or when one certified document is enough and you do not want a connection to every node.

    On-chain Rust SDK
    Who takes the median The canister Your service
    Update rate Each feed every 30 s, and at once on a 10 bp move Each node publish, about every second
    Client key None Listed by governance
    Feeds 14 All the network's feeds

    From a canister

    1. Add the types you need. Candid ignores the fields you leave out.

      rust
      use candid::{CandidType, Deserialize, Principal};
      use ic_cdk::call::Call;
      use serde_bytes::ByteBuf;
      
      #[derive(CandidType, Deserialize, PartialEq)]
      enum PriceStatus { Ok, Degraded, Halted }
      
      #[derive(CandidType, Deserialize)]
      struct PriceRecord {
          status: PriceStatus,
          price: Option<i64>,
          conf: Option<u64>,
          expo: i32,
          publish_time_ns: u64,
      }
    2. Call get_price with the feed's 32-byte id. The id is keccak256 of the symbol; the feeds reference lists them.

      rust
      // CRYPTO.BTC/USD
      let feed_id = hex::decode("0523e79c7ed211911a19afaa4def68c896bc72d674bf33c5c64d4d7089e320e2")?;
      let oracle = Principal::from_text("xb5gv-diaaa-aaaaf-qg5qa-cai")?;
      let reply = Call::bounded_wait(oracle, "get_price")
          .with_arg(ByteBuf::from(feed_id))
          .await?;
      let btc: Option<PriceRecord> = reply.candid()?;
    3. Use the price only when the status is Ok or Degraded. The price is price × 10^expo, and the band is conf × 10^expo.

      rust
      if let Some(record) = btc.filter(|record| record.status != PriceStatus::Halted) {
          let price = record.price.unwrap_or_default() as f64 * 10f64.powi(record.expo);
      }

    The canister resolves the price when you call it. A feed whose nodes stop pushing goes Halted after the canister's price window, so a price is never older than that window. get_price_window returns it in seconds: 75 by default, and about three push intervals once governance sets it. get_prices returns every feed, and get_feeds lists the feeds and their ids.

    Field Meaning
    status Ok, Degraded or Halted.
    price, conf The median of the nodes and its band, as integers at expo.
    publish_time_ns The newest publish time of the nodes that count.
    nodes The nodes that count. At least the registry's quorum, or the feed halts.
    concerns Why the price is not Ok, such as node_divergence.
    resolved_at_ns When the canister resolved it.

    Over HTTPS

    bash
    curl https://xb5gv-diaaa-aaaaf-qg5qa-cai.icp0.io/prices.json

    The gateway checks the canister's certificate before it serves the document. Each entry has the fields of the Rust SDK's resolved price, with decimals as strings.

    The canister writes the document when a node's frame arrives, so the document can be older than the certificate. Check resolved_at_ns, and treat a document older than the price window as halted.

    To check the certificate yourself, fetch from the raw domain, https://xb5gv-diaaa-aaaaf-qg5qa-cai.raw.icp0.io/prices.json, and verify it with ic-response-verification, as the Rust SDK does for the registry.

    /frames.json holds the signed batches and frames that carry each node's latest update, for a client that checks the nodes' signatures itself. Each entry names its node, its kind (batch or price) and its feeds. A batch is a list of price updates under one signature; the signing reference gives its layout. The entries can be as old as the price window.

    What you trust

    The canister checks the frames as the Rust SDK does and takes the same median. You trust the canister's code and its controllers, as you already trust them for the registry. See the trust model.