Consuming Data Feeds (Solana)
Price data feeds are available on the following networks:
- Solana network
- EVM-compatible networks
The full list of price data feeds for each network is available on the Data Feed Contracts page.
Chainlink Data Feeds are live on the Solana Devnet with sub-second updates. Chainlink’s Solana deployment has no dependencies on external blockchain networks such as Ethereum. To learn more about the Solana programming model, see the Solana Documentation.
To get the full list of Chainlink Data Feeds running on the Solana Devnet, see the Solana Feeds page.
You can view the program ID that owns these feeds in the Solana Devnet Explorer.
Note
This guide shows you how to deploy and retrieve data using the Solana network. If you need to use EVM-compatible networks, see Consuming Data Feeds (EVM).
Overview
Solana supports on-chain programs in the Rust or C languages. This guide demonstrates the following tasks:
- Write and deploy programs to the Solana Devnet using Rust.
- Retrieve data using the Solana Web3 JavaScript API with Node and Yarn.
In Solana, storage and smart contract logic are separate. Programs store all the logic similar to an EVM smart contract. The accounts store all the data. Solana programs are stateless, so you don't always need to deploy your program to the network to test it. Compared to Solidity, the combination of an account and a program is equivalent to a smart contract on an EVM chain. State and logic are separate in Solana. This example shows you how to work with a program that you deploy, but you can refactor the client section to work with a program ID of your choice.
Requirements
This guide requires the following tools:
- Build and deploying Solana programs:
- Call the deployed program to read the data feed for the SOL / USD price:
Create and deploy a program to the Solana Devnet
Clone the chainlink-solana-demo repository:
git clone https://github.com/smartcontractkit/chainlink-solana-democd chainlink-solana-demoSet the Solana cluster (network) to Devnet:
solana config set --url https://api.devnet.solana.comCreate a keypair for your account that you can use for testing and development. For production deployments, follow the security best practices for Command Line Wallets.
mkdir solana-walletsolana-keygen new --outfile ./solana-wallet/keypair.jsonFund your account. On Devnet, you can use
solana airdropto add tokens to your account:solana airdrop 5 $(solana-keygen pubkey solana-wallet/keypair.json)If the command line faucet doesn't work, use
solana-keygen pubkeyto see your public key value and request tokens from SolFaucet:solana-keygen pubkey ./solana-wallet/keypair.json
Build the program using the Solana BPF:
cargo build-bpfDeploy the program. The output from the previous step will give you the command to execute to deploy the program. It should look similar to this:
solana program deploy target/deploy/chainlink_solana_demo.so --keypair solana-wallet/keypair.jsonIf the deployment is successful, it prints your program ID:
RPC URL: https://api.devnet.solana.com Default Signer Path: solana-wallet/keypair.json Commitment: confirmed Program Id: AZRurZi6N2VTPpFJZ8DB45rCBn2MsBBYaHJfuAS7Tm4vCopy the program ID and look it up in the Solana Devnet Explorer.
Call a deployed program
After you deploy the program, you can use it to retrieve data from a feed. The code for this part of the guide is in the client folder from the chainlink-solana-demo repository.
Change to the
clientdirectory and runyarnto install Node.js dependencies:cd clientyarnRun
yarn startto execute the script:yarn startThe script completes the following steps. This does require SOL tokens. If the script cannot run due to insufficient funds, airdrop more funds to your Devnet account again.
If the script executes correctly, you will see output with the current price of SOL/USD.
Review the example code
You can view the Rust code and Typescript for this example on GitHub. See the chainlink-solana-demo repository. The example code has a few main components:
- The client Typescript files that establish a connection to the deployed program, determine the fees associated with retrieving the feed data, handle serialization and deserialization of data, and report the returned price from the specified data feed. In this case, the script tells your deployed Solana program to retrieve the price of SOL / USD from FmAmfoyPXiA8Vhhe6MZTr3U6rZfEZ1ctEHay1ysqCqcf.
- The
./src/lib.rsfile that defines the on-chain program for retrieving price data from a specified Solana Data Feed. This program also imports some methods from the main smartcontractkit/chainlink-solana repository. - The program imports some dependencies from the chainlink-solana repository.
The example code operates using the following process:
The client
main.tsscript defines the process for connecting to the cluster, establishing fee payment, and verifying that your Solana program deployed correctly. The script also callsgetPriceandreportPricein thehello_world.tsfile.The
getPricefunction definesconst priceFeedAccountto specify which data feed to use. Then, it createsconst instructionwith a formatted transaction that your deployed Solana program can process. The script sends that instruction and waits for the transaction to confirm that it is complete.export async function getPrice(): Promise<void> { console.log('Getting data from ', readingPubkey.toBase58()) const priceFeedAccount = "FmAmfoyPXiA8Vhhe6MZTr3U6rZfEZ1ctEHay1ysqCqcf" const AggregatorPublicKey = new PublicKey(priceFeedAccount) const instruction = new TransactionInstruction({ keys: [{ pubkey: readingPubkey, isSigner: false, isWritable: true }, { pubkey: AggregatorPublicKey, isSigner: false, isWritable: false }], programId, data: Buffer.alloc(0), // All instructions are hellos }) await sendAndConfirmTransaction( connection, new Transaction().add(instruction), [payer], ) }Your deployed program receives the request and starts processing at the
entrypointinsrc/lib.rs. This is the Rust program that you built and deployed to the Solana Devnet.The
process_instructionfunction inlib.rsreceives the transaction with the specified feed address and handles the steps to retrieve and store the price data on-chain. The function also callsget_price()from the chainlink-solana package, which gets imported from GitHub in theCargo.tomlfile. See theCargo.tomlfile, which maps thechainlink-solanapackage tochainlink.pub fn process_instruction( _program_id: &Pubkey, // Ignored accounts: &[AccountInfo], // Public key of the account to read price data from _instruction_data: &[u8], // Ignored ) -> ProgramResult { msg!("Chainlink Solana Demo program entrypoint"); let accounts_iter = &mut accounts.iter(); // This is the account of our our account let my_account = next_account_info(accounts_iter)?; // This is the account of the data feed for prices let feed_account = next_account_info(accounts_iter)?; const DECIMALS: u32 = 9; let price = chainlink::get_price(&chainlink::id(), feed_account)?; if let Some(price) = price { let decimal = Decimal::new(price, DECIMALS); msg!("Price is {}", decimal); } else { msg!("No current price"); } // Store the price ourselves let mut price_data_account = PriceFeedAccount::try_from_slice(&my_account.data.borrow())?; price_data_account.answer = price.unwrap_or(0); price_data_account.serialize(&mut &mut my_account.data.borrow_mut()[..])?; Ok(()) }After the deployed Solana program finishes storing the data on-chain, the script retrieves the price data from the on-chain storage and prints it to the console.
export async function reportPrice(): Promise<void> { // const priceFeedAccount = "FmAmfoyPXiA8Vhhe6MZTr3U6rZfEZ1ctEHay1ysqCqcf" // const AggregatorPublicKey = new PublicKey(priceFeedAccount) const accountInfo = await connection.getAccountInfo(readingPubkey) if (accountInfo === null) { throw new Error('Error: cannot find the aggregator account') } const latestPrice = borsh.deserialize( AggregatorSchema, AggregatorAccount, accountInfo.data, ) console.log("Current price of SOL/USD is: ", latestPrice.answer.toString()) }
In addition to the main functions of this example, several smaller components are required:
- The
solana-programcrate provides necessary functions for on-chain transactions. - The communications between the script and the deployed program are serialized and deserialized using Borsh.
- The Solana JavaScript API handles RPCs required to retrieve account data.
If you want to experiment with the code yourself to learn how it works, see this example code on GitHub.
To learn more about Solana, head to the Solana Documentation, as well as our blog post on How to Build and Deploy a Solana Smart Contract