Welcome to the complete guide for integrating Reflector price oracles into your Stellar Soroban smart contracts! This tutorial is designed for beginners and will walk you through everything you need to know.
- What is Reflector?
- Architecture Overview
- Prerequisites
- Setting Up Your Environment
- Basic Integration
- Code Examples
- Troubleshooting
- Resources
Reflector is a decentralized price oracle protocol for the Stellar network that provides reliable, real-time price data for your smart contracts. Think of it as a bridge between the blockchain and real-world financial data.
Real World Data β Blockchain
βββββββββββββββββ ββββββββββ
β’ Stock prices β’ Smart contracts
β’ Crypto prices β’ DeFi protocols
β’ Exchange rates β’ Trading bots
β’ Market data β’ Automated systems
- β Real-time price feeds updated every 5 minutes
- β SEP-40 compliant (Stellar standard)
- β Decentralized consensus from multiple data sources
- β Free to use with no limitations
- β 24-hour data retention guaranteed
Here's how Reflector works:
βββββββββββββββββββ ββββββββββββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
β Your Contract β β Reflector Smartcontract β β Reflector Nodes β β Data Sources β
β β β β β β β β
β β’ Read prices βββββΆβ β’ Publish feed βββββΆβ β’ Aggregate data βββββΆβ β’ CEX APIs β
β β’ Make decisionsβ β β’ Enforce validation β β β’ Validate feeds β β β’ DEX protocols β
β β’ Execute logic β β β’ Expose interface β β β’ Reach consensusβ β β’ Market APIs β
βββββββββββββββββββ ββββββββββββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
- Collection: Reflector nodes gather price data from multiple sources
- Validation: Data is validated and normalized
- Consensus: Nodes reach agreement on accurate prices
- Storage: Validated data is stored on-chain in smart contracts
- Access: Your contract reads the price data when needed
Before starting, make sure you have:
- Basic knowledge of Rust programming
- Understanding of blockchain concepts
- Familiarity with Stellar network
- A development environment set up
- Rust (stable toolchain)
- Stellar CLI
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Install stable toolchain with WASM target
rustup install stable
rustup +stable target add wasm32v1-none# Install Stellar CLI
brew install stellar-cli
# # Create a new Soroban project
stellar contract init hello-reflector
cd hello-reflectorUpdate your Cargo.toml:
[package]
name = "hello-reflector"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
soroban-sdk = "21.0.0"
[dev-dependencies]
soroban-sdk = { version = "21.0.0", features = ["testutils"] }
[profile.release]
opt-level = "z"
overflow-checks = true
debug = 0
strip = "symbols"
debug-assertions = false
panic = "abort"
codegen-units = 1
lto = true
[profile.release-with-logs]
inherits = "release"
debug-assertions = trueReflector implements the SEP-40 standard, which defines a common interface for price oracles:
// SEP-40 Oracle Interface
pub trait PriceOracle {
// Get the latest price for an asset
fn lastprice(env: Env, asset: Symbol) -> Option<PriceData>;
// Get price at specific timestamp
fn price(env: Env, asset: Symbol, timestamp: u64) -> Option<PriceData>;
// Get multiple prices in a time range
fn prices(env: Env, asset: Symbol, records: u32) -> Vec<PriceData>;
}pub struct PriceData {
pub price: i128, // Price with decimal precision
pub timestamp: u64, // Unix timestamp
}First, save the Reflector interface so your contract can call it.
Save as reflector.rs
// ... code
pub trait Contract {
fn lastprice(e: Env, asset: Asset) -> Option<PriceData>;
// ... more code
}Let's create a new contract in lib.rs and import the Reflector traits.
#![no_std]
use reflector::{Asset as ReflectorAsset, ReflectorClient};
use soroban_sdk::{contract, contractimpl, Address, Env, Symbol};
mod reflector;
// ... more code coming soonNow, save the TESTNET Reflector contract address.
// ... imports and other things
#[contract]
pub struct Contract;
#[contractimpl]
impl Contract {
pub fn __constructor(env: Env) {
let oracle_address = Address::from_str(&env, "CCYOZJCOPG34LLQQ7N24YXBM7LL62R7ONMZ3G6WZAAYPB5OYKOMJRN63");
env.storage().instance().set(&Symbol::new(&env, "oracle"), &oracle_address);
}
}
// ... more code coming soonFinally, implement the function that interacts with Reflector:
- Read the oracle address from storage (set in the constructor)
- Create the Reflector client
- Instantiate the asset "XLM"
- Call the Reflector contract
- Handle the result safely
- Return the price
// ... rest of code
pub fn hello_xlm(env: Env) -> i128 {
let oracle_address: Address = env.storage().instance().get(&Symbol::new(&env, "oracle")).unwrap();
let reflector_client = ReflectorClient::new(&env, &oracle_address);
let xlm_asset = ReflectorAsset::Other(Symbol::new(&env, "XLM"));
let price_data = reflector_client.lastprice(&xlm_asset);
match price_data {
Some(data) => data.price,
None => -1,
}
}
// DONE!See the full result here
Deploy to testnet using:
stellar contract deploy --wasm target/wasm32v1-none/release/hello_world.wasm --source aliceRemember: you need an account named alice with funds to deploy.
Now that the deploy succeeded, invoke the contract:
stellar contract invoke --id YOUR_CONTRACT_ADDRESS_HERE --source-account alice --network testnet -- hello_xlm- Cause: Asset not supported by oracle or network issues
- Solution: Check supported assets list and network connectivity
- Cause: Oracle hasn't updated recently
- Solution: Implement fallback mechanisms or increase staleness tolerance
- Cause: Incorrect oracle address or interface mismatch
- Solution: Verify oracle contract address and SEP-40 compliance
| Feed | Contract | Base symbol | Decimals | Sampling | Retention |
|---|---|---|---|---|---|
| External CEX & DEX | CAFJZQWSED6YAWZU3GWRTOCNPPCGBN32L7QV43XX5LZLFTK6JLN34DLN | USD | 14 | 5 minutes | 24 hours |
| Stellar Pubnet | CALI2BYU2JE6WVRUFYTS6MSBNEHGJ35P4AVCZYF3B6QOE3QKOB2PLE6M | USDCcentre.io | 14 | 5 minutes | 24 hours |
| Foreign Exchange Rates | CBKGPWGKSKZF52CFHMTRR23TBWTPMRDIYZ4O2P5VS65BMHYH4DXMCJZC | USD | 14 | 5 minutes | 24 hours |
| Feed | Contract | Base symbol | Decimals | Sampling | Retention |
|---|---|---|---|---|---|
| External CEX & DEX | CCYOZJCOPG34LLQQ7N24YXBM7LL62R7ONMZ3G6WZAAYPB5OYKOMJRN63 | USD | 14 | 5 minutes | 24 hours |
| Stellar Pubnet | CAVLP5DH2GJPZMVO7IJY4CVOD5MWEFTJFVPD2YY2FQXOQHRGHK4D6HLP | USDCcentre.io | 14 | 5 minutes | 24 hours |
| Foreign Exchange Rates | CCSSOHTBL3LEWUCBBEB5NJFC2OKFRC74OWEIJIZLRJBGAAU4VMU5NV4W | USD | 14 | 5 minutes | 24 hours |
You now have a solid foundation for integrating Reflector price oracles into your Soroban smart contracts! Remember to:
- Always validate price freshness
- Implement proper error handling
- Test thoroughly on testnet
- Follow security best practices
- Join the community for support
Happy building! π