BasketOracle
Inherits: AggregatorV3Interface, Ownable2Step
Title: BasketOracle
Aggregates multiple Chainlink feeds into a normalized weighted plDXY basket price.
Price = Sum(Weight_i * Price_i / BasePrice_i). Normalization preserves intended currency weights.
Note: security-contact: contact@plether.com
Constants
DECIMALS
Chainlink standard decimals for fiat/USD pairs.
uint8 public constant DECIMALS = 8
DESCRIPTION
Oracle description string.
string public constant DESCRIPTION = "plDXY Fixed Basket (Bounded)"
TIMELOCK_DELAY
Timelock delay for Curve pool updates (7 days).
uint256 public constant TIMELOCK_DELAY = 7 days
MAX_DEVIATION_BPS
Maximum allowed deviation from Curve spot (basis points).
uint256 public immutable MAX_DEVIATION_BPS
CAP
Protocol CAP price (8 decimals). Theoretical price is clamped to this before deviation check.
uint256 public immutable CAP
State Variables
components
Array of currency components (EUR, JPY, GBP, CAD, SEK, CHF).
Component[] public components
curvePool
Curve pool for deviation validation.
ICurvePool public curvePool
pendingCurvePool
Pending Curve pool for timelock-protected updates.
address public pendingCurvePool
hasPendingProposal
Whether a proposal is active (needed because address(0) is a valid proposal).
bool public hasPendingProposal
curvePoolActivationTime
Timestamp when pending Curve pool can be finalized.
uint256 public curvePoolActivationTime
Functions
constructor
Creates basket oracle with currency components.
constructor(
address[] memory _feeds,
uint256[] memory _quantities,
uint256[] memory _basePrices,
uint256 _maxDeviationBps,
uint256 _cap,
address _owner
) Ownable(_owner);
Parameters
| Name | Type | Description |
|---|---|---|
_feeds | address[] | Array of Chainlink feed addresses. |
_quantities | uint256[] | Array of basket weights (1e18 precision). |
_basePrices | uint256[] | Array of base prices for normalization (8 decimals). |
_maxDeviationBps | uint256 | Maximum deviation from Curve (e.g., 200 = 2%). |
_cap | uint256 | Protocol CAP price (8 decimals). Clamps theoretical price in deviation check. |
_owner | address | Admin address for Curve pool management. |
setCurvePool
Sets the Curve pool for deviation validation (initial setup only).
function setCurvePool(
address _curvePool
) external onlyOwner;
Parameters
| Name | Type | Description |
|---|---|---|
_curvePool | address | Curve USDC/plDXY-BEAR pool address. |
proposeCurvePool
Proposes a new Curve pool (requires 7-day timelock).
function proposeCurvePool(
address _newPool
) external onlyOwner;
Parameters
| Name | Type | Description |
|---|---|---|
_newPool | address | New Curve pool address. |
finalizeCurvePool
Finalizes the Curve pool update after timelock expires.
function finalizeCurvePool() external onlyOwner;
latestRoundData
Returns the aggregated basket price from all component feeds.
function latestRoundData() public view returns (uint80, int256, uint256, uint256, uint80);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint80 | roundId Mock round ID (always 1). |
<none> | int256 | answer The calculated basket price in 8 decimals. |
<none> | uint256 | startedAt Oldest component updatedAt (no separate round start; same as updatedAt). |
<none> | uint256 | updatedAt Oldest component updatedAt (weakest link for staleness checks). |
<none> | uint80 | answeredInRound Mock answered round (always 1). |
_checkDeviation
Validates basket price against Curve spot. Reverts on excessive deviation. Intentionally acts as a global circuit breaker: if Chainlink and Curve EMA diverge beyond MAX_DEVIATION_BPS, all consumers (SyntheticSplitter, MorphoOracle, StakedOracle) are frozen — including Morpho liquidations. This is the desired behavior: large divergence signals either a compromised feed or a manipulated pool, and freezing is safer than acting on potentially bad price data.
function _checkDeviation(
uint256 theoreticalDxy8Dec
) internal view;
Parameters
| Name | Type | Description |
|---|---|---|
theoreticalDxy8Dec | uint256 | Computed basket price (8 decimals). |
decimals
Returns oracle decimals (8).
function decimals() external pure returns (uint8);
description
Returns oracle description.
function description() external pure returns (string memory);
version
Returns oracle version (1).
function version() external pure returns (uint256);
getRoundData
Returns data for a specific round ID.
Only round ID 1 is supported (synthetic basket has no historical rounds).
function getRoundData(
uint80 _roundId
) external view returns (uint80, int256, uint256, uint256, uint80);
Events
CurvePoolProposed
Emitted when a new Curve pool is proposed.
event CurvePoolProposed(address indexed newPool, uint256 activationTime);
CurvePoolUpdated
Emitted when Curve pool is updated.
event CurvePoolUpdated(address indexed oldPool, address indexed newPool);
Errors
BasketOracle__InvalidPrice
Thrown when a component feed returns invalid price.
error BasketOracle__InvalidPrice(address feed);
BasketOracle__LengthMismatch
Thrown when feeds and quantities arrays have different lengths.
error BasketOracle__LengthMismatch();
BasketOracle__PriceDeviation
Thrown when basket price deviates too far from Curve spot.
error BasketOracle__PriceDeviation(uint256 theoretical, uint256 spot);
BasketOracle__AlreadySet
Thrown when Curve pool is already configured.
error BasketOracle__AlreadySet();
BasketOracle__TimelockActive
Thrown when timelock period has not elapsed.
error BasketOracle__TimelockActive();
BasketOracle__InvalidProposal
Thrown when no pending proposal exists.
error BasketOracle__InvalidProposal();
BasketOracle__InvalidDeviation
Thrown when max deviation is zero.
error BasketOracle__InvalidDeviation();
BasketOracle__InvalidBasePrice
Thrown when a base price is zero.
error BasketOracle__InvalidBasePrice();
BasketOracle__InvalidWeights
Thrown when quantities don’t sum to 1e18.
error BasketOracle__InvalidWeights();
BasketOracle__InvalidRoundId
error BasketOracle__InvalidRoundId();
Structs
Component
Component feed with its basket weight and base price for normalization.
struct Component {
AggregatorV3Interface feed;
uint256 quantity;
uint256 basePrice;
}