pubfnexample(ctx:Context<Example>) ->Result<()> {let feed_account = ctx.accounts.feed.data.borrow();let feed =PullFeedAccountData::parse(feed_account).unwrap();let feed_id: [u8; 32] =get_feed_id_from_hex("0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43")?;// Get the value, a https://docs.rs/rust_decimal/latest/rust_decimal/struct.Decimal.htmllet price = feed.value();// Log the Decimal Valuemsg!("price: {:?}", price);Ok(())}
Updating Off-chain Code
The Pyth network leverages hermes, a middleman server, to distribute encoded pythnet update data to end-users. Switchboard applies a similar approach with Crossbar, but on Solana it's unnecessary since it's Switchboard's home-base.
Step 1: Updating Imports
Pyth has 2 imports, one for connecting to Hermes for price updates, and another for formatting price updates into Solana-compatible data. Switchboard has the on-demand ts-sdk for interacting with oracles and updating Solana feeds.
Pyth leverages the hermes server, Switchboard on Solana will pull directly from oracles. In the future, we may employ Crossbar servers to broker data by protocol.
Pyth
// You will need a Connection from @solana/web3.js and a Wallet from @coral-xyz/anchor to create// the receiver.constconnection:Connection;constwallet:Wallet;// Connect to HermesconstpriceServiceConnection=newPriceServiceConnection("https://hermes.pyth.network/", { priceFeedRequestConfig: { binary:true } });// Get latest price dataconstpriceUpdateData:string[] =awaitpriceServiceConnection.getLatestVaas(["0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43",]);// Get Solana ReceiverconstpythSolanaReceiver=newPythSolanaReceiver({ connection, wallet });
Switchboard
import { web3, AnchorProvider, Program } from"@coral-xyz/anchor";import { PullFeed, loadLookupTables, SB_ON_DEMAND_PID} from"@switchboard-xyz/on-demand";constconnection:Connection;constwallet:Wallet;// Get the Switchboard Programconstprovider=newAnchorProvider(connection, wallet, {});constidl= (awaitProgram.fetchIdl(programId, provider))!;constswitchboard=newProgram(idl, provider);// Replace with your feed pubkeyconstfeed=newPullFeed(switchboard,newPublicKey("6qmsMwtMmeqMgZEhyLv1Pe4wcqT5iKwJAWnmzmnKjf83"));// Fetch the update data const [pullIx,responses,success] =awaitfeed.fetchUpdateIx();
Step 3: Submitting Updates
Pyth price updates are generated with a transaction builder using their client SDK which sends multiple transactions when needed. Clients would build their transaction in the addPriceConsumerInstructions callback, sending them all in the sendAll instruction at the very end
// ... constpythSolanaReceiver=newPythSolanaReceiver({ connection, wallet });// Create Transaction builder and add update data instructions to the TXconsttransactionBuilder=pythSolanaReceiver.newTransactionBuilder({ closeUpdateAccounts:false,});awaittransactionBuilder.addPostPriceUpdates(priceUpdateData);// Adds your custom instructions using price updates to the TX awaittransactionBuilder.addPriceConsumerInstructions(async ( getPriceUpdateAccount: (priceFeedId:string) => PublicKey ):Promise<InstructionWithEphemeralSigners[]> => {// ... get instructions to use price update herereturn []; });// Send the TX'sawaitpythSolanaReceiver.provider.sendAll(awaittransactionBuilder.buildVersionedTransactions({ computeUnitPriceMicroLamports:50000, }), { skipPreflight:true });// Done!
Switchboard
// Get the update instruction for switchboard and lookup tables to make the instruction lighterconst [pullIx,responses,success] =awaitfeedAccount.fetchUpdateIx({ crossbarClient: crossbar });constlookupTables=awaitloadLookupTables([...responses.map((x) =>x.oracle), feedAccount]);// Set priority fee for that the txconstpriorityFeeIx=web3.ComputeBudgetProgram.setComputeUnitPrice({ microLamports:100_000,});// Get the latest contextconst { context: { slot: minContextSlot }, value: { blockhash,lastValidBlockHeight },} =awaitconnection.getLatestBlockhashAndContext();// Get Transaction Message constmessage=newweb3.TransactionMessage({ payerKey: publicKey, recentBlockhash: blockhash, instructions: [addPriorityFee, pullIx, myIx],}).compileMessageV0(lookupTables);// Get Versioned Transactionconstvtx=newweb3.VersionedTransaction(message);constsigned=awaitwallet.signTransaction(vtx);// Send the transaction constsignature=awaitconnection.sendRawTransaction(signed.serialize(), { maxRetries:0, skipPreflight:true,});// Wait for confirmationawaitconnection.confirm({ signature, blockhash, lastValidBlockHeight,});// Done!