Using Data Feeds Onchain (Stellar)
Chainlink Data Feeds are the quickest way to connect your smart contracts to the real-world market prices of assets. This guide demonstrates how to deploy a Soroban contract in Rust to the Stellar Testnet and read a price onchain by calling the Chainlink Data Feeds proxy contract. To learn how to read price feed data using offchain applications, see the Using Data Feeds Offchain guide.
To get the full list of available Chainlink Data Feeds on Stellar, see the Price Feed Contract Addresses page with Stellar selected.
Available data feeds on Stellar
The following table shows all available data feeds on Stellar. Each feed is identified by its data_id (the Feed ID), which you pass to the proxy contract to read that feed's data.
Networks
Stellar Mainnet
Unlike EVM chains, Stellar uses a single proxy contract for all feeds. Instead of a per-feed contract address, you select a feed by its feed ID (data_id) shown below. See the Using Data Feeds on Stellar guide to learn how to read these feeds.
- Data Feeds proxy contract on Stellar Mainnet: CDQBHEUGLDHMSUHG4IH33RJBUTMNCZOT4JIAQR4WZFRDZW6DR6S32ZLZ
Prerequisites
Before you begin, you should have:
- Familiarity with Rust programming
- Understanding of Stellar and Soroban smart contracts
- Understanding of how Chainlink Data Feeds on Stellar work, including the
data_idaddressing scheme
Requirements
To complete this guide, you'll need:
-
Stellar CLI: Install the Stellar CLI. Run
stellar --versionto verify your installation. This guide uses Stellar CLI v25 or later. -
Rust toolchain: Install Rust using rustup. Run
cargo --versionto verify your installation. -
soroban-sdk: The
stellar contract initcommand scaffolds a project that depends on the latestsoroban-sdk(v25 or later). The contract in this guide compiles againstsoroban-sdkv21 and later. If you pin an older version, use v21 or later. -
Testnet XLM: You'll need testnet XLM to deploy your contract. Fund a Stellar Testnet account using the friendbot faucet. Testnet XLM has no real value.
Set up your Stellar testnet account
-
Create a new directory for your project and navigate to it in your terminal:
mkdir stellar-data-feeds && cd stellar-data-feeds -
Generate a keypair for your testnet account:
stellar keys generate --network testnet my-accountExpect an output similar to the following:
Secret key already exists for key my-account -
Fund your account with testnet XLM using the friendbot faucet:
stellar keys fund my-account --network testnetExpect an output similar to the following:
Funded account <YOUR_PUBLIC_KEY> with 10000.0000000 XLM
Create the Soroban contract
-
Initialize a Soroban contract project:
stellar contract init consumer --name consumerThis creates a
consumerdirectory with a default Soroban contract scaffold. -
Open the
consumer/contracts/consumer/src/lib.rsfile and replace its contents with the following contract. This contract calls the Chainlink Data Feeds proxy contract to read the latest price for a givendata_idand returns the answer. The proxy interface is defined in the chainlink-stellar repository:#![no_std] use soroban_sdk::{contract, contractimpl, contractclient, contracterror, contracttype, Address, BytesN, Env, I256}; #[contractclient(name = "DataFeedsProxyClient")] pub trait DataFeedsProxy { fn latest_round(env: Env, data_id: BytesN<32>, decimals: u32) -> Result<Round, ProxyReadError>; } #[contracttype] #[derive(Clone, Debug)] pub struct Round { pub round_id: u64, pub answer: I256, pub timestamp: u64, } #[contracterror] #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[repr(u32)] pub enum ProxyReadError { NoDataPresent = 50, InvalidDecimals = 51, RoundsToZero = 52, } #[contract] pub struct Consumer; #[contractimpl] impl Consumer { /// Read the latest round for a feed and return its answer. pub fn read_latest_price(env: Env, proxy: Address, data_id: BytesN<32>) -> I256 { let client = DataFeedsProxyClient::new(&env, &proxy); let round = client.latest_round(&data_id, &18); round.answer } }This contract calls the proxy's
latest_roundfunction with a singledata_idand requests the answer at18decimal places. The returnedRoundcontains theround_id,answer, andtimestampfields for the feed.
Build and deploy the contract
-
Build the contract:
stellar contract buildExpect an output similar to the following:
Compiling consumer... Finished `release` profile [optimized] target(s) in 5.00s -
Deploy the contract to the Stellar Testnet:
stellar contract deploy \ --wasm target/wasm32v1-none/release/consumer.wasm \ --source my-account \ --network testnetExpect an output similar to the following:
<YOUR_CONTRACT_ADDRESS>Note the contract address that is printed. You use it to invoke the contract in the next step.
Invoke the contract
-
Invoke the
read_latest_pricefunction on your deployed contract, passing the proxy contract address and thedata_idfor the feed you want to read. The proxy contract on Stellar Testnet isCBUF6IADAWPWIDWRTHJNINKXHG2UTIQ6TU2F2HRAXWAI7OT3KJPKK6O4, and the BTC/USDdata_idis01a0b4d920000332000000000000000000000000000000000000000000000000. You can find thedata_idfor other assets on the Price Feed Contract Addresses page with Stellar selected.Because
read_latest_priceis a read-only function, use the--send=noflag to simulate the call without submitting a transaction:stellar contract invoke \ --id <YOUR_CONTRACT_ADDRESS> \ --source my-account \ --network testnet \ --send=no \ -- read_latest_price \ --proxy CBUF6IADAWPWIDWRTHJNINKXHG2UTIQ6TU2F2HRAXWAI7OT3KJPKK6O4 \ --data_id 01a0b4d920000332000000000000000000000000000000000000000000000000Expect an output similar to the following:
"86400288421531180000000"Where the value is the latest BTC/USD price for the feed, stored at 18 decimal places. For example,
86400288421531180000000represents a price of86400.29.