oracle_lib¶
Internal Vyper library for redundant Chainlink price reads. Initialized by TareEngine; not deployed standalone.
Source: TARE-Stablecoin/src/oracle_lib.vy (Vyper 0.4.3)
Concept guide: Collateral & oracles
Consumer: TareEngine — oracle_lib._get_price on every collateral valuation.
Implementation overview¶
Redundant feed reader used per collateral asset:
- Defensive reads —
raw_callonlatestRoundData(); bad feeds return(False, 0)instead of reverting. - Staleness — 3h
TIMEOUT; round completeness; positive answer; futureupdated_atguard (TARE-3). - Circuit-breaker bands — reject prices pinned at
minAnswer/maxAnswerwhen exposed (TARE-4). - Dual-feed agreement — when primary + fallback healthy, must agree within
max_deviation_bps. - Fallback — single surviving feed used when other dead.
- L2 sequencer — optional uptime feed (skipped on Sepolia/mainnet with empty address).
flowchart TD
GP[_get_price] --> Seq{sequencer up?}
Seq --> P[_try_get_price primary]
Seq --> F[_try_get_price fallback]
P --> Both{both OK?}
F --> Both
Both -->|yes| Dev[_within_deviation]
Both -->|one| Return[return surviving]
Both -->|none| Revert[revert]
Constants¶
| Name | Value | Role |
|---|---|---|
TIMEOUT |
3 hours | Max feed staleness |
BPS |
10_000 | Deviation math denominator |
Internal functions¶
_try_get_price¶
oracle_lib._try_get_price(feed) -> (bool, uint256)
Soft-read one Chainlink feed via raw_call on latestRoundData(). Never reverts — returns (False, 0) on any failure.
| Param | Type | Description |
|---|---|---|
feed |
address |
Chainlink aggregator; empty(address) → (False, 0) |
Returns: (healthy, price) — price in feed's native decimals (typically 8 for USD pairs).
Checks when healthy: round complete, updated_at fresh (≤3h, not future), answer > 0, not at min/max circuit-breaker band.
Access: @internal @view — called by _get_price.
Source (TARE-Stablecoin/src/oracle_lib.vy:51-111):
@internal
@view
def _try_get_price(feed: address) -> (bool, uint256):
success, response = raw_call(feed, method_id("latestRoundData()"), ...)
# staleness, future updated_at, answer > 0, _within_answer_band
return (True, convert(answer, uint256))
Example:
Cross-links: _within_answer_band · _get_price · TareEngine get_usd_value
_try_read_int¶
oracle_lib._try_read_int(feed, selector) -> (bool, int256)
Soft static read of a zero-arg getter returning int256 (e.g. minAnswer(), maxAnswer()).
| Param | Type | Description |
|---|---|---|
feed |
address |
Chainlink aggregator |
selector |
Bytes[4] |
Method id (e.g. method_id("minAnswer()")) |
Returns: (ok, value) — (False, 0) if call fails or response < 32 bytes.
Access: @internal @view — helper for _within_answer_band.
Source (TARE-Stablecoin/src/oracle_lib.vy:114-129):
@internal
@view
def _try_read_int(feed: address, selector: Bytes[4]) -> (bool, int256):
success, response = raw_call(feed, selector, max_outsize=32, is_static_call=True, revert_on_failure=False)
if (not success) or (len(response) < 32):
return (False, 0)
return (True, abi_decode(response, int256))
Cross-links: _within_answer_band · _try_get_price
_within_answer_band¶
oracle_lib._within_answer_band(feed, answer) -> bool
Returns False if Chainlink answer is pinned at minAnswer/maxAnswer circuit-breaker bounds (stale floor/ceiling, not real price).
| Param | Type | Description |
|---|---|---|
feed |
address |
Chainlink aggregator |
answer |
int256 |
Price from latestRoundData |
Returns: bool — True if OK to use price; True also when feed doesn't expose bounds (common proxy case).
Access: @internal @view — called from _try_get_price.
Source (TARE-Stablecoin/src/oracle_lib.vy:132-157):
@internal
@view
def _within_answer_band(feed: address, answer: int256) -> bool:
min_ok, min_answer = self._try_read_int(feed, method_id("minAnswer()"))
max_ok, max_answer = self._try_read_int(feed, method_id("maxAnswer()"))
if not (min_ok and max_ok):
return True # no band exposed — skip check
if answer <= min_answer or answer >= max_answer:
return False
return True
Cross-links: _try_read_int · _try_get_price
_within_deviation¶
oracle_lib._within_deviation(a, b, max_deviation_bps) -> bool
Pure math: true if two prices agree within max_deviation_bps basis points.
| Param | Type | Description |
|---|---|---|
a |
uint256 |
First price (feed native decimals) |
b |
uint256 |
Second price |
max_deviation_bps |
uint256 |
Max allowed disagreement in bps (10_000 = 100%) |
Returns: bool — True if |a - b| / max(a, b) <= max_deviation_bps / BPS.
Access: @internal @pure — dual-feed agreement check in _get_price.
Source (TARE-Stablecoin/src/oracle_lib.vy:160-172):
@internal
@pure
def _within_deviation(a: uint256, b: uint256, max_deviation_bps: uint256) -> bool:
if a == b:
return True
high: uint256 = a if a > b else b
low: uint256 = b if a > b else a
return (high - low) * BPS <= max_deviation_bps * high
Cross-links: _get_price · TareEngine add_collateral
_sequencer_is_up¶
oracle_lib._sequencer_is_up(feed, grace_period) -> bool
L2 Chainlink sequencer uptime check. Skipped on Sepolia/mainnet when engine passes empty(address) feed.
| Param | Type | Description |
|---|---|---|
feed |
address |
L2 sequencer uptime aggregator |
grace_period |
uint256 |
Seconds after restart before trusting prices |
Returns: bool — True if sequencer up past grace window. answer == 0 means up; 1 means down.
Access: @internal @view — asserted in _get_price when feed non-empty.
Source (TARE-Stablecoin/src/oracle_lib.vy:175-215):
@internal
@view
def _sequencer_is_up(feed: address, grace_period: uint256) -> bool:
# latestRoundData: answer != 0 => down
if block.timestamp - started_at <= grace_period:
return False
return True
Cross-links: _get_price · TareEngine pricing
_get_price¶
oracle_lib._get_price(primary, fallback, max_deviation_bps, sequencer_uptime_feed, sequencer_grace_period) -> uint256
Main entry: resolve redundant Chainlink price for one collateral asset.
| Param | Type | Description |
|---|---|---|
primary |
address |
Primary Chainlink feed (required) |
fallback |
address |
Secondary feed or empty(address) |
max_deviation_bps |
uint256 |
Max disagreement when both feeds live |
sequencer_uptime_feed |
address |
L2 sequencer feed or empty(address) to skip |
sequencer_grace_period |
uint256 |
Post-restart grace (ignored if sequencer feed empty) |
Returns: uint256 — price in feeds' native decimals.
Resolution order:
- If sequencer feed set → must pass
_sequencer_is_upor revert. - Both feeds healthy → require
_within_deviation; return primary. - One healthy → return that price.
- None → revert
"OracleLib: no healthy feed".
Access: @internal @view — called by TareEngine _get_usd_value / _get_token_amount_from_usd.
Source (TARE-Stablecoin/src/oracle_lib.vy:218-274):
@internal
@view
def _get_price(primary, fallback, max_deviation_bps, sequencer_uptime_feed, sequencer_grace_period) -> uint256:
if sequencer_uptime_feed != empty(address):
assert self._sequencer_is_up(...), "OracleLib: sequencer down"
primary_ok, primary_price = self._try_get_price(primary)
if fallback == empty(address):
assert primary_ok, "OracleLib: primary feed unavailable"
return primary_price
# dual-feed: deviation check or fallback to surviving feed
raise "OracleLib: no healthy feed"
Cross-links: _try_get_price · _within_deviation · _sequencer_is_up · TareEngine add_collateral
- TareEngine
add_collateral— per-asset feeds + deviation bps - TareEngine
get_usd_value— engine-side decimal scaling - PegKeeper API — also depends on oracle correctness for Curve peg