Description
The project is named SentientFi and prominently features Reflector oracle integration as a core feature (README, architecture diagrams, smart contract code), but the ReflectorService class in backend/src/services/reflector.ts exclusively fetches prices from CoinGecko. No call to the Stellar Reflector oracle contract is made anywhere in the backend. The service name is misleading and the feature is not implemented.
Evidence
README claims Reflector integration
The README lists as a key feature:
"Reflector oracle integration for accurate on-chain price feeds"
Smart contract implements Reflector correctly
contracts/src/reflector.rs defines a proper ReflectorClient:
mod reflector_interface {
use soroban_sdk::{contractclient, Env, Symbol};
#[contractclient(name = "ReflectorClient")]
pub trait ReflectorInterface {
fn lastprice(env: Env, asset: soroban_sdk::Symbol) -> Option<PriceData>;
}
}
contracts/src/lib.rs line 125 calls it during execute_rebalance:
let price_data = ReflectorClient::new(&env, &reflector_address)
.lastprice(&asset_symbol);
Backend ReflectorService only uses CoinGecko
backend/src/services/reflector.ts:
// Line 1: unused import
import SorobanRpc from '@stellar/stellar-sdk/rpc' // ← Imported but never used
// Line 105: actual price fetch
const url = `https://api.coingecko.com/api/v3/simple/price?ids=${coinIds.join(',')}&vs_currencies=usd&include_24hr_change=true`
const response = await fetch(url, { ... })
There is no code path in the backend that ever calls a Soroban RPC endpoint to query the Reflector contract. The SorobanRpc import on line 1 being unused confirms this is a placeholder that was never implemented.
Fallback prices are hardcoded (not from cache)
When CoinGecko fails, the backend falls back to:
const fallbackPrices = {
XLM: { price: 0.358878, ... },
BTC: { price: 111150, ... },
ETH: { price: 4384.56, ... },
USDC: { price: 0.999781, ... },
}
These are hardcoded values, not a recent snapshot from Reflector.
Impact
- Single point of failure: All price data depends entirely on CoinGecko. If CoinGecko rate-limits the API key (or if the free tier is used), price data goes stale immediately
- Incorrect documentation: Users and auditors expect on-chain price feeds from the advertised Reflector integration
- Smart contract / backend mismatch: The contract uses on-chain Reflector prices for rebalancing decisions; the backend uses CoinGecko prices for drift detection. The two systems may use different prices for the same asset at the same moment, causing incorrect rebalancing triggers
Proposed Fix
Implement the Reflector oracle backend integration:
// backend/src/services/reflector.ts
import SorobanRpc from '@stellar/stellar-sdk/rpc'
import { Contract, scValToNative, xdr } from '@stellar/stellar-sdk'
const REFLECTOR_CONTRACT_ID = process.env.REFLECTOR_CONTRACT_ID!
const SOROBAN_RPC_URL = process.env.SOROBAN_RPC_URL || 'https://soroban-testnet.stellar.org'
async function fetchPriceFromReflector(asset: string): Promise<number | null> {
const rpc = new SorobanRpc.Server(SOROBAN_RPC_URL)
const contract = new Contract(REFLECTOR_CONTRACT_ID)
try {
const result = await rpc.simulateTransaction(
contract.call('lastprice', /* asset Symbol */)
)
if (SorobanRpc.Api.isSimulationSuccess(result)) {
const priceData = scValToNative(result.result!.retval)
return priceData?.price ?? null
}
} catch (err) {
logger.warn(`[Reflector] Price fetch failed for ${asset}:`, err)
}
return null
}
Then use Reflector as primary source and CoinGecko as fallback:
Price request → Reflector contract (on-chain) → CoinGecko fallback → hardcoded fallback
Add to .env.example:
REFLECTOR_CONTRACT_ID=CDOR33VMS...
SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
Files Affected
backend/src/services/reflector.ts — implement Reflector calls
backend/.env.example — add REFLECTOR_CONTRACT_ID, SOROBAN_RPC_URL
README.md — clarify current status (CoinGecko only) until fix is merged
Description
The project is named SentientFi and prominently features Reflector oracle integration as a core feature (README, architecture diagrams, smart contract code), but the
ReflectorServiceclass inbackend/src/services/reflector.tsexclusively fetches prices from CoinGecko. No call to the Stellar Reflector oracle contract is made anywhere in the backend. The service name is misleading and the feature is not implemented.Evidence
README claims Reflector integration
The README lists as a key feature:
Smart contract implements Reflector correctly
contracts/src/reflector.rsdefines a properReflectorClient:contracts/src/lib.rsline 125 calls it duringexecute_rebalance:Backend
ReflectorServiceonly uses CoinGeckobackend/src/services/reflector.ts:There is no code path in the backend that ever calls a Soroban RPC endpoint to query the Reflector contract. The
SorobanRpcimport on line 1 being unused confirms this is a placeholder that was never implemented.Fallback prices are hardcoded (not from cache)
When CoinGecko fails, the backend falls back to:
These are hardcoded values, not a recent snapshot from Reflector.
Impact
Proposed Fix
Implement the Reflector oracle backend integration:
Then use Reflector as primary source and CoinGecko as fallback:
Add to
.env.example:Files Affected
backend/src/services/reflector.ts— implement Reflector callsbackend/.env.example— addREFLECTOR_CONTRACT_ID,SOROBAN_RPC_URLREADME.md— clarify current status (CoinGecko only) until fix is merged