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-demo
cd chainlink-solana-demo
Set the Solana cluster (network) to Devnet:
solana config set --url https://api.devnet.solana.com
Create 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-wallet
solana-keygen new --outfile ./solana-wallet/keypair.json
Fund your account. On Devnet, you can use
solana airdrop
to 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 pubkey
to 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-bpf
Deploy 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.json
If 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: AZRurZi6N2VTPpFJZ8DB45rCBn2MsBBYaHJfuAS7Tm4v
Copy 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
client
directory and runyarn
to install Node.js dependencies:cd client
yarn
Run
yarn start
to execute the script:yarn start
The 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.rs
file 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.ts
script defines the process for connecting to the cluster, establishing fee payment, and verifying that your Solana program deployed correctly. The script also callsgetPrice
andreportPrice
in thehello_world.ts
file.The
getPrice
function definesconst priceFeedAccount
to specify which data feed to use. Then, it createsconst instruction
with 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
entrypoint
insrc/lib.rs
. This is the Rust program that you built and deployed to the Solana Devnet.The
process_instruction
function inlib.rs
receives 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.toml
file. See theCargo.toml
file, which maps thechainlink-solana
package 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-program
crate 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