Skip to main content

Developer Resources

Solana SDK

Quick Links

Libraries

Clone the Switchboard x Solana SDK to get started:

git clone https://github.com/switchboard-xyz/solana-sdk

Examples

Functions​

Create a Scheduled Function​

The examples below show how to create a Switchboard Function that runs the switchboardlabs/basic-binance-oracle:latest container from dockerhub every 30 seconds.

import { parseMrEnclave } from "@switchboard-xyz/common";
import type { SwitchboardProgram } from "@switchboard-xyz/solana.js";
import {
AttesationQueueAccount,
FunctionAccount,
} from "@switchboard-xyz/solana.js";

let program: SwitchboardProgram;
const attestationQueueAccount = new AttesationQueueAccount(
program,
"2ie3JZfKcvsRLsJaP5fSo43gUo1vsurnUAtAgUdUAiDG" // mainnet attestation queue
);

const [functionAccount] = await FunctionAccount.create(program, {
name: "FUNCTION_NAME",
metadata: "FUNCTION_METADATA",
schedule: "30 * * * * *", // every 30 seconds
container: "switchboardlabs/basic-binance-oracle",
containerRegistry: "dockerhub",
version: "latest",
mrEnclave: parseMrEnclave("0xABC123"),
attestationQueue: attestationQueueAccount,
});

Read a Function​

Switchboard Functions allow you to execute arbitrary instructions as long as the functions enclave.signer has signed the transaction. This keypair gets generated within the enclave so we can prove the transaction was built securely.

This example shows how to verify that the functions `enclave.signer` has signed your custom instructions.

use switchboard_solana::FunctionAccountData;

#[derive(Accounts)]
pub struct SaveDataInstruction<'info> {
// ... your required accounts to modify your program's state

// We use this to derive and verify the functions enclave state
#[account(
constraint =
function.load()?.validate(
&enclave_signer.to_account_info()
)?
)]
pub function: AccountLoader<'info, FunctionAccountData>,
pub enclave_signer: Signer<'info>,
}

Debug a Function​

Coming Soon!

The Switchboard Function developer tooling is still in its early stages. By the end of Q3 we will support a function simulation server, an endpoint to view container logs, and some helper scripts to manage your protocols functions.

Data Feeds​

Create a Data Feed​

import type {
JobAccount,
SwitchboardProgram,
} from "@switchboard-xyz/solana.js";
import { OracleQueueAccount } from "@switchboard-xyz/solana.js";

let program: SwitchboardProgram;
let jobAccount: JobAccount;

const queueAccount = new OracleQueueAccount(
program,
"uPeRMdfPmrPqgRWSrjAnAkH78RqAhe5kXoW6vBYRqFX"
); // devnet

const [aggregatorAccount] = await queueAccount.createFeed({
batchSize: 1,
minRequiredOracleResults: 1,
minRequiredJobResults: 1,
minUpdateDelaySeconds: 60,
fundAmount: 2.5,
enable: true,
jobs: [
// existing job account
{ pubkey: jobAccount.publicKey },
// or create a new job account with the feed
{
weight: 2,
data: OracleJob.encodeDelimited(
OracleJob.fromObject({
tasks: [
{
valueTask: {
value: 1,
},
},
],
})
).finish(),
},
],
});

Read a Data Feed​

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

use std::convert::TryInto;

// Instruction accounts
#[derive(Accounts)]
#[instruction(params: ReadFeedParams)]
pub struct ReadFeed<'info> {
pub aggregator: AccountLoader<'info, AggregatorAccountData>,
}

// Instruction params
#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
pub struct ReadFeedParams {
pub max_confidence_interval: Option<f64>,
}

// Instruction logic
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

Ok(())
}

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