Sol.College

Oracles: Pyth and Switchboard

Programs can't fetch off-chain data, so oracles publish it into accounts the program reads. A Pyth consumer passes a price update account into the instruction and checks freshness (for example a maximum age) and confidence before using the price. Never trust an oracle account without verifying its owner and feed ID.

Reference: Pyth on Solana · Switchboard docs

Real code, line by line

5 excerpts from different projects. Each caption links the exact lines at the fork's pinned commit. The notes below each excerpt explain the lines that matter.

sevenlabs-hq/carbon · decoders/kamino-lending-decoder/src/instructions/refresh_reserve.rs L43–64 @ bebd108 · MIT · original
        let mut iter = accounts.iter();         let reserve = next_account(&mut iter)?;        let lending_market = next_account(&mut iter)?;        let pyth_oracle = next_account(&mut iter);        let switchboard_price_oracle = next_account(&mut iter);        let switchboard_twap_oracle = next_account(&mut iter);        let scope_prices = next_account(&mut iter);         let remaining = iter.as_slice();         Some(RefreshReserveInstructionAccounts {            reserve,            lending_market,            pyth_oracle,            switchboard_price_oracle,            switchboard_twap_oracle,            scope_prices,            remaining: remaining.to_vec(),        })    }}
Shobhit2205/winisol · src/components/winisol/winisol-data-access.tsx L715–739 @ 1930ba0 · MIT · original
      }      const sbRandomnessPubkey = res.data.randomnessKeys.sbRandomnessPubKey;      const sbQueuePubkey = res.data.randomnessKeys.sbQueuePubKey;      const isdevnet = SOLANA_ENVIRONMENT === 'devnet';      const switchboardIDL = await Program.fetchIdl(        isdevnet ? sb.ON_DEMAND_DEVNET_PID : sb.ON_DEMAND_MAINNET_PID,        { connection: new web3.Connection(CONNECTION_ENDPOINT) }      ) as Idl;        const switchboardProgram = new Program(switchboardIDL, provider);       // const queueAccount = new sb.Queue(switchboardProgram, new web3.PublicKey(sbQueuePubkey));      const randomnessAccount = new sb.Randomness(switchboardProgram, new web3.PublicKey(sbRandomnessPubkey));      const queueAccount = new sb.Queue(switchboardProgram, new web3.PublicKey(sbQueuePubkey));      try {        await queueAccount.loadData();      } catch (error) {        console.log(error);        process.exit(1);      }      const sbRevealIx = await randomnessAccount.revealIx();              const revealWinnerIx = await program.methods.revealWinner(lottery_id).accounts({        randomnessAccount: randomnessAccount.pubkey      }).instruction();
solana-foundation/program-examples · oracles/pyth/anchor/programs/pythexample/src/lib.rs L1–24 @ de09019 · MIT · original
use pyth_solana_receiver_sdk::price_update::PriceUpdateV2;use anchor_lang::prelude::*; declare_id!("GUkjQmrLPFXXNK1bFLKt8XQi6g3TjxcHVspbjDoHvMG2"); #[program]pub mod anchor_test {    use super::*;     pub fn read_price(ctx: Context<ReadPrice>) -> Result<()> {        let price_update = &ctx.accounts.price_update;        msg!("Price feed id: {:?}", price_update.price_message.feed_id);        msg!("Price: {:?}", price_update.price_message.price);        msg!("Confidence: {:?}", price_update.price_message.conf);        msg!("Exponent: {:?}", price_update.price_message.exponent);        msg!("Publish Time: {:?}", price_update.price_message.publish_time);        Ok(())    }} #[derive(Accounts)]pub struct ReadPrice<'info> {    pub price_update: Account<'info, PriceUpdateV2>,}
  1. Line 1 use pyth_solana_receiver_sdk::price_update::PriceUpdateV2;: Reads a Pyth price and enforces a maximum age.
  2. Line 12 msg!("Price feed id: {:?}", price_update.price_message.feed_id);: Logs to the program log, which is visible in explorers and the test output.
otter-sec/anchor · ts/packages/spl-token-lending/program/lib.rs L129–154 @ 541295d · Apache-2.0 · original
    #[account(mut)]    reserve_collateral_mint: AccountInfo<'info>,    #[account(mut)]    reserve_collateral_supply: AccountInfo<'info>,    pyth_product: AccountInfo<'info>,    pyth_price: AccountInfo<'info>,    lending_market: AccountInfo<'info>,    lending_market_authority: AccountInfo<'info>,    lending_market_owner: Signer<'info>,    user_transfer_authority: Signer<'info>,    clock: Sysvar<'info, Clock>,    rent: Sysvar<'info, Rent>,    token_program: Program<'info, Token>,} #[derive(Accounts)]pub struct RefreshReserve<'info> {    #[account(mut)]    reserve: AccountInfo<'info>,    reserve_liquidity_oracle: AccountInfo<'info>,    clock: Sysvar<'info, Clock>,} #[derive(Accounts)]pub struct DepositReserveLiquidity<'info> {    #[account(mut)]
  1. Line 137 lending_market_owner: Signer<'info>,: Requires this account to have signed the transaction.
anza-xyz/agave · storage-bigtable/proto/google.api.rs L613–638 @ 5770743 · Apache-2.0 · original
    pub common: ::core::option::Option<CommonLanguageSettings>,    /// Experimental features to be included during client library generation.    #[prost(message, optional, tag = "2")]    pub experimental_features: ::core::option::Option<        python_settings::ExperimentalFeatures,    >,}/// Nested message and enum types in `PythonSettings`.pub mod python_settings {    /// Experimental features to be included during client library generation.    /// These fields will be deprecated once the feature graduates and is enabled    /// by default.    #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]    pub struct ExperimentalFeatures {        /// Enables generation of asynchronous REST clients if `rest` transport is        /// enabled. By default, asynchronous REST clients will not be generated.        /// This feature will be enabled by default 1 month after launching the        /// feature in preview packages.        #[prost(bool, tag = "1")]        pub rest_async_io_enabled: bool,        /// Enables generation of protobuf code using new types that are more        /// Pythonic which are included in `protobuf>=5.29.x`. This feature will be        /// enabled by default 1 month after launching the feature in preview        /// packages.        #[prost(bool, tag = "2")]        pub protobuf_pythonic_types_enabled: bool,

Go further

Related lessons

Topics: DeFi · Learning path · Glossary