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.

Prerequisites

Before you begin, you should have:

Requirements

To complete this guide, you'll need:

  • Stellar CLI: Install the Stellar CLI. Run stellar --version to verify your installation.

  • Rust toolchain: Install Rust using rustup. Run cargo --version to verify your installation.

  • 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

  1. Create a new directory for your project and navigate to it in your terminal:

    mkdir stellar-data-feeds && cd stellar-data-feeds
    
  2. Generate a keypair for your testnet account:

    stellar keys generate --network testnet my-account
    

    Expect an output similar to the following:

    Secret key already exists for key my-account
    
  3. Fund your account with testnet XLM using the friendbot faucet:

    stellar keys fund my-account --network testnet
    

    Expect an output similar to the following:

    Funded account <YOUR_PUBLIC_KEY> with 10000.0000000 XLM
    

Create the Soroban contract

  1. Initialize a Soroban contract project:

    stellar contract init consumer --name consumer
    

    This creates a consumer directory with a default Soroban contract scaffold.

  2. Open the consumer/contracts/consumer/src/lib.rs file and replace its contents with the following contract. This contract calls the Chainlink Data Feeds proxy contract to read the latest price for a given data_id and 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).unwrap();
            round.answer
        }
    }
    

    This contract calls the proxy's latest_round function with a single data_id and requests the answer at 18 decimal places. The returned Round contains the round_id, answer, and timestamp fields for the feed.

Build and deploy the contract

  1. Build the contract:

    stellar contract build
    

    Expect an output similar to the following:

    Compiling consumer...
    Finished `release` profile [optimized] target(s) in 5.00s
    
  2. Deploy the contract to the Stellar Testnet:

    stellar contract deploy \
    --wasm target/wasm32v1-none/release/consumer.wasm \
    --source my-account \
    --network testnet
    

    Expect 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

  1. Invoke the read_latest_price function on your deployed contract, passing the proxy contract address and the data_id for the feed you want to read. The proxy contract on Stellar Testnet is CBUF6IADAWPWIDWRTHJNINKXHG2UTIQ6TU2F2HRAXWAI7OT3KJPKK6O4, and the BTC/USD data_id is 01a0b4d920000332000000000000000000000000000000000000000000000000. You can find the data_id for other assets on the Price Feed Contract Addresses page with Stellar selected.

    Because read_latest_price is a read-only function, use the --send=no flag 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 01a0b4d920000332000000000000000000000000000000000000000000000000
    

    Expect 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, 86400288421531180000000 represents a price of 86400.29.

What's next

Get the latest Chainlink content straight to your inbox.