Context
Health-factor computation needs USD prices. Chainlink is the primary source; per BSC asset we configure the feed address, then poll latestRoundData each block. Stale feeds are rejected (threshold 10 min) to avoid valuing positions against dead oracles.
Scope
charon-scanner/src/price.rs with a PriceCache struct
sol! macro bindings for AggregatorV3Interface.latestRoundData()
- Per-asset config:
[chainlink.<chain>.<asset>] feed_address = "0x..."
- Top-5 BSC assets for v0.1: BNB, USDT, USDC, BTC, ETH
- Stale price check: reject if
updatedAt < now() - 10 min (configurable)
- Cache stores
{ price: U256, decimals: u8, updated_at: u64 }
- Updates alongside the block listener
Acceptance criteria
References
Context
Health-factor computation needs USD prices. Chainlink is the primary source; per BSC asset we configure the feed address, then poll
latestRoundDataeach block. Stale feeds are rejected (threshold 10 min) to avoid valuing positions against dead oracles.Scope
charon-scanner/src/price.rswith aPriceCachestructsol!macro bindings forAggregatorV3Interface.latestRoundData()[chainlink.<chain>.<asset>] feed_address = "0x..."updatedAt < now() - 10 min(configurable){ price: U256, decimals: u8, updated_at: u64 }Acceptance criteria
charon-scannercompiles with Chainlink ABI bindingsPriceCache::refresh()fetches all configured feeds in one multicallPriceCache::get(&asset) -> Option<Price>returnsNoneif stale / missingReferences