Price Feed Sources
Just as adapters interact with external "integratees," so do price feeds interact with sources that provide them with the data they need to provide rates.
AavePriceFeed
Prices Aave aTokens
, which are pegged 1:1 with the value of their underlying, e.g., 1 aAAVE
is equal to 1 AAVE
. aTokens
accrue interest via a formulaic rebasing mechanism.
Docs: https://docs.aave.com/developers/the-core-protocol/atokens
Mainnet contracts:
ProtocolDataProvider
: 0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d
Considerations: Always directly returns the input amount as the output amount (i.e., 1:1 pegging)
AlphaHomoraV1PriceFeed
Provides a price for ibETH
.
Docs: https://github.com/AlphaFinanceLab/alphahomora/blob/master/contracts/5/Bank.sol
Mainnet contracts:
Bank
(ibETH
): 0x67B66C99D3Eb37Fa76Aa3Ed1ff33E8e39F0b9c7A
Considerations: Uses cached rate
ChainlinkPriceFeed
Each rate pair (we use those quoted in either USD or ETH) is provided by a Chainlink "aggregator," and we interact with the proxy contracts for those aggregators.
Docs: https://docs.chain.link/docs/using-chainlink-reference-contracts
Mainnet contracts: each aggregator
Considerations:
We do not check timestamps on every price lookup, rather we provide a function to allow quickly removing an aggregator that is considered to be stale. If an aggregator is removed, the corresponding primitive will cease to produce a price from the feed and will revert, causing any function that relies on that price to fail until it is re-instituted. This is the desired behavior.
ChaiPriceFeed
This price feed mimics how Chai
determines its rate in its codebase, by interacting with Maker DAO's DSR Pot
contract.
Docs: https://github.com/dapphub/chai
Mainnet contracts:
Pot
- 0x197E90f9FAD81970bA7976f33CbD77088E5D7cf7
Considerations:
We do not call Pot.drip()
before calculating price as in Chai
, in order to save gas (drip()
updates storage). The CHAI-DAI rate changes negligibly for even long periods of time.
CompoundPriceFeed
Queries each Compound Token (cToken) directly for its rate.
Docs: https://compound.finance/docs
Mainnet contracts: each cToken
Considerations:
We query the cached rate instead of the live rate for gas savings. Like CHAI
, cTokens rates change negligibly for long periods of time.
CurvePriceFeed
Provides prices for all Curve LP tokens, both staked and unstaked. Staking LP tokens to the pool's "liquidity gauge" (or to a liquidity gauge wrapper contract) returns an equal amount of tokens representing the stake in that liquidity gauge. i.e., 1 LP token is equivalent to 1 liquidity gauge token in value.
Remembering that deriving the underlying value for a derivative in Enzyme consists of returning underlying asset(s) and amount(s), there are two components for returning a value:
Underlying asset: each LP token (staked or unstaked) is arbitrarily assigned an "invariant proxy asset," a supported asset in the protocol that is chosen to be the proxy (i.e., representative) of the pool invariant (e.g., WETH in the case of the stETH pool).
Underlying amount: the amount of the invariant proxy asset is calculated via the pool's "virtual price" (provided natively in all Curve pools).
Considerations:
Since an arbitrary asset is chosen for the single underlying asset returned by the price feed (rather than considering all values and balances of the pool's underlyings), the live value of an LP token within Enzyme will always deviate from the redeemable value by some small percentage. This deviation is insignificant for a couple reasons:
Assets that temporarily lose their peg will generally lose it in the downward direction, which would cause the redeemable value of an LP token to be less than its virtual price-derived Enzyme value. This condition is not susceptible to investor-side arbitrage in Enzyme funds, where the concern is preventing the purchase of discounted shares (whereas using the virtual price results in temporarily inflated share price). Further, as long as the loss of peg is assumed to be temporary, using the virtual price rather than this ephemeral imbalance protects the fund from discounted shares.
In the more extreme case of permanent loss of peg, Curve only works if all pooled assets generally hold their peg to the invariant. If any one asset were to permanently lose its peg to the invariant, the redeemable value of the LP token itself would capitulate, as arbitragers drain the pool of all but the fallen asset.
IdlePriceFeed
Provides a value for each IdleToken
to its underlying asset.
Docs: https://developers.idle.finance/
Mainnet contracts: each IdleToken
Considerations: Does not take into account user-specific fees (i.e., relative to the vault) that are charged upon redeeming IdleToken
for its underlying
LidoStethPriceFeed
Immediately returns that the input amount of Lido Staked ETH (stETH) is equal to the same numerical amount (at a 1:1 ratio) of WETH.
RevertingPriceFeed
Immediately reverts upon any price lookup.
The purpose of the RevertingPriceFeed
is to be able to keep an asset in our asset universe, while disabling any actions that rely on accurate GAV calculation. It is only to-be-used as a temporary stop gap to allow the continued functionality of integrations, at the cost of limited functionality in the core system.
Tracking an asset that uses the RevertingPriceFeed causes an action that depends on GAV to revert, affecting, for example:
deposits
fees that depend on GAV
policies that depend on GAV
Note that reverting fees are skipped during shares redemption, which would affect a fund that has GAV-dependent fees that settle upon redemption (e.g., PerformanceFee
) and that tracks any asset that uses the RevertingPriceFeed.
StakehoundEthPriceFeed
Immediately returns that the input amount of Stakehound Staked ETH (stETH) is equal to the same numerical amount (at a 1:1 ratio) of WETH.
SynthetixPriceFeed
Queries the Synthetix Exchanger
contract to get the rate for a Synth in terms of sUSD
.
Docs: https://docs.synthetix.io/
Mainnet contracts:
AddressResolver
-0x61166014E3f04E40C953fe4EAb9D9E40863C83AE
Considerations: Live prices
UniswapV2PoolPriceFeed
Uses a special pool manipulation-resistant formula that takes into consideration the current underlying asset balances and pool token balance in the given Uniswap pool (UniswapV2Pair
) along with a trusted rate between the two underlying tokens.
Docs: https://uniswap.org/docs/v2/
Mainnet contracts:
UniswapV2Factory
:0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f
instances of
UniswapV2Pair
See also the sample implementation we based this on: https://github.com/Uniswap/uniswap-v2-periphery/blob/267ba44471f3357071a2fe2573fe4da42d5ad969/contracts/libraries/UniswapV2LiquidityMathLibrary.sol
Considerations: Live prices
WDGLDPriceFeed
This price feed uses a known formula for pricing DGLD based on the current rate of XAU. It uses Chainlink aggregators directly.
Docs: https://dgld.ch/
Mainnet Contracts:
XAU/USD Aggregator:
0x214eD9Da11D2fbe465a6fc601a91E62EbEc1a0D6
ETH/USD Aggregator
0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419
Considerations: Live prices
YearnVaultV2PriceFeed
Provides a value for each yVault
(Yearn vault v2) in terms of its underlying asset
Docs: https://docs.yearn.finance/
Mainnet contracts:
Registry/Deployer:
0x50c1a2eA0a861A967D9d0FFE2AE4012c2E053804
Considerations:
Live prices
Note that while all Yearn vault v2 instances adhere to the same interface, each individual instance uses one of many particular versioned implementations (see registry contract above). Only the price feed interactions with expected behaviors of interface functions can be realistically audited.
Last updated