Developer Hub

Consume Data on Cardano (Beta)

Consume and verify Pyth Pro price updates in Cardano smart contracts

Cardano integration is currently in Beta and the API may change before release.

This guide is intended to serve users who want to consume prices from Pyth Pro on Cardano.

Integrating with Pyth Pro in Cardano smart contracts as a consumer is a three-step process:

  1. Use the pyth-lazer-cardano Aiken library in your on-chain code.
  2. Subscribe to Pyth Pro websocket to receive signed price updates.
  3. Include those updates in a Cardano transaction by doing a zero withdrawal from the Pyth withdraw script.

Use the Aiken library in your on-chain code

Add the Pyth Lazer Cardano library to your aiken.toml file:

[[dependencies]]
name = "pyth-network/pyth-lazer-cardano"
version = "main"
source = "github"

Your contract should read verified updates from the transaction, not verify the signatures itself. The Aiken library exposes pyth.get_updates, which reads:

  • the Pyth state from the transaction's reference_inputs
  • the verified update bytes from the redeemer of the Pyth withdraw script

Here is a minimal example that searches for the ADA/USD feed (Pyth Pro feed ID 16) and converts the result into Aiken's Rational type:

use aiken/collection/list
use aiken/math/rational.{Rational}
use cardano/assets.{PolicyId}
use cardano/transaction.{Transaction}
use pyth
use types/u32

fn read_ada_usd_price(pyth_id: PolicyId, self: Transaction) -> Rational {
  expect [update] = pyth.get_updates(pyth_id, self)
  expect Some(feed) = list.find(update.feeds, fn(feed) {
    u32.as_int(feed.feed_id) == 16
  })
  expect Some(Some(price)) = feed.price
  expect Some(exponent) = feed.exponent
  expect Some(multiplier) = rational.from_int(10) |> rational.pow(exponent)

  rational.from_int(price) |> rational.mul(multiplier)
}

The returned PriceUpdate values include:

  • timestamp_us
  • channel_id
  • feeds

Each Feed includes fields such as feed_id, price, best_bid_price, best_ask_price, exponent, confidence, ema_price, and feed_update_timestamp.

pyth.get_updates requires the Pyth state UTxO to be present as a reference input. If you omit that reference input, your validator will fail when it tries to locate the Pyth State NFT and withdraw-script hash.

Fetch a signed price update off-chain

Pyth Pro provides a TypeScript SDK for fetching signed updates. Request the solana format for the binary update - this is a little-endian format signed by an Ed25519 key, which we use for both Cardano and Solana integrations.

The example below follows fetch-and-verify.ts and fetches one signed update that can be passed into the verification script redeemer:

import { PythLazerClient } from "@pythnetwork/pyth-lazer-sdk";

const lazer = await PythLazerClient.create({ token: LAZER_TOKEN });
const latestPrice = await lazer.getLatestPrice({
  channel: "fixed_rate@200ms",
  formats: ["solana"],
  jsonBinaryEncoding: "hex",
  priceFeedIds: [16],
  properties: ["price", "exponent"],
});

if (!latestPrice.solana?.data) {
  throw new Error("Missing update payload");
}

const update = Buffer.from(latestPrice.solana.data, "hex");

If you need a streaming integration instead of a one-shot fetch, consult How to subscribe to prices. Regardless of transport, the transaction must receive the signed update as raw bytes.

Include the updates into the Cardano transaction

Pyth's own Cardano integration builds a transaction with the following shape:

  1. Set a short validity window.
  2. Add the Pyth state UTxO as a reference input.
  3. Withdraw 0 lovelace from the Pyth withdraw script, with the list of signed updates as the redeemer.
  4. Include your own script in the same transaction so that your validator can call pyth.get_updates(pyth_id, self).

The pyth_id below is the Pyth deployment policy ID for your network. The Pyth state UTxO is the UTxO holding the Pyth State NFT under that policy ID.

import { ScriptHash } from "@evolution-sdk/evolution";
import {
  getPythScriptHash,
  getPythState,
} from "@pythnetwork/pyth-lazer-cardano-js";

const client = createClient({ network, provider });

const pythState = await getPythState(POLICY_ID, client);
const pythScript = getPythScriptHash(pythState);

// In your own transaction, include Pyth State UTxO as a reference input, and
// trigger 0-withdrawal on the verification script, together with the price
// update as a redeemer, to perform price verification on-chain.

const wallet = client.attachWallet({
  mnemonic: CARDANO_MNEMONIC,
  type: "seed"
});

const now = BigInt(Date.now());
const tx = wallet
  .newTx()
  .setValidity({ from: now - 60_000n, to: now + 60_000n })
  .readFrom({ referenceInputs: [pythState] })
  .withdraw({
    amount: 0n,
    redeemer: [update],
    stakeCredential: ScriptHash.fromHex(pythScript),
  });

// Add your own scripts and transaction data...

// Sign and execute the transaction:
const builtTx = await tx.build();
const digest = await builtTx.signAndSubmit();

The zero-withdrawal and your consuming validator must be in the same transaction. pyth.get_updates reads the withdrawal redeemer directly from the transaction that is currently being validated.

Additional Resources

You may find these additional resources helpful for consuming prices from Pyth Pro in Cardano smart contracts.

Price Feed IDs

Pyth Pro supports a wide range of price feeds. Consult the Price Feed IDs page for a complete list of supported price feeds.

Contract Sources

The Cardano contract implementation lives in lazer/contracts/cardano.

The off-chain flow shown above comes from fetch-and-verify.ts.

On this page