Skip to main content

Read Data Feed On-Chain

This guide will show you how to read a Switchboard data feed.

In order to read a Switchboard data feed using Anchor, we will need to:

  1. Add the switchboard-solana dependency
  2. Create the ReadResult Accounts context containing the Switchboard data feed
  3. Create the read_result instruction with the ReadResult Accounts context
  4. Submit a transaction on-chain with the read_result instruction

View the 01_feed_client example on Github.

Not using Anchor?

View the 02_spl_native example on Github.

1. Add switchboard-solanaโ€‹

Add the switchboard-solana crate to your Cargo.toml file:

switchboard-solana = "0.9"

2. ReadResult Contextโ€‹

Anchor provides the anchor-lang AccountLoader trait to:

  • verify the account has the correct discriminator (all AggregatorAccounts share the same first 8 bytes)
  • the account is owned by the program ID defined in the switchboard-solana crate

The ReadResult Accounts context would look like:

use anchor_lang::prelude::*;
use switchboard_solana::{AggregatorAccountData};

pub struct ReadResult<'info> {
pub switchboard_aggregator: AccountLoader<'info, AggregatorAccountData>,

You should store the aggregator's pubkey somewhere in your program state and verify the expected aggregator was passed into your instruction.

If you are building a DeFi market you may have a MyMarket account type storing the SOL/USD Switchboard feed address in the field switchboard_aggregator. You can then verify this pubkey in the Accounts context like the following:

use anchor_lang::prelude::*;
use switchboard_solana::{AggregatorAccountData};

pub struct MyMarket {
pub bump: u8,
pub switchboard_aggregator: Pubkey,

pub struct ReadResult<'info> {
has_one = switchboard_aggregator
pub market: AccountLoader<'info, MyMarket>,
pub switchboard_aggregator: AccountLoader<'info, AggregatorAccountData>,

3. read_result Instructionโ€‹

Now lets add a read_result instruction to our program and pass in the ReadResult context.

First, we will deserialize the account data into the AggregatorAccountData ( struct.

Next, we will use the TryInto trait to convert the SwitchboardDecimal ( into the f64 primitive because it's easier to work with.


The SwitchboardDecimal struct is a basic wrapper around the rust-decimal ( implementation.

Finally, we will verify the feed was updated in the last 300 seconds so we aren't consuming a stale value.

use anchor_lang::prelude::*;
use anchor_lang::solana_program::clock;

use std::convert::TryInto;

pub mod anchor_feed_parser {
use super::*;

pub fn read_result(
ctx: Context<ReadResult>
) -> anchor_lang::Result<()> {
let feed = &ctx.accounts.switchboard_aggregator.load()?;

// get result
let val: f64 = feed.get_result()?.try_into()?;

// check whether the feed has been updated in the last 300 seconds
feed.check_staleness(clock::Clock::get().unwrap().unix_timestamp, 300)
.map_err(|_| error!(FeedErrorCode::StaleFeed))?;

msg!("Current feed result is {}!", val);

// Your custom logic here


#[derive(Eq, PartialEq)]
pub enum FeedErrorCode {
#[msg("Switchboard feed has not been updated in 5 minutes")]

4. Off-Chain: Read the result!โ€‹

We will need to build a Solana transaction that contains our aggregator address to read.

import * as anchor from "@coral-xyz/anchor";
import { sleep } from "@switchboard-xyz/common";
import {
} from "@switchboard-xyz/solana.js";
import assert from "assert";
import { AnchorFeedParser } from "../target/types/anchor_feed_parser";

describe("anchor-feed-parser test", () => {
const provider = anchor.AnchorProvider.env();

const feedParserProgram: anchor.Program<AnchorFeedParser> =

let switchboard: SwitchboardProgram;
let aggregatorAccount: AggregatorAccount;

it("Reads a Switchboard data feed", async () => {
const signature = await feedParserProgram.methods
.accounts({ switchboardAggregator: aggregatorAccount.publicKey })

// wait for RPC
await sleep(2000);

const logs = await provider.connection.getParsedTransaction(

console.log(JSON.stringify(logs?.meta?.logMessages, undefined, 2));

const match = JSON.stringify(logs?.meta?.logMessages ?? []).match(
new RegExp(/Current feed result is (?<feed_result>\d+)/)
const feedResult = Number(match?.groups?.feed_result ?? null);
console.log(`Feed Result: ${feedResult}`);