As crvusd markets use interal oracles, they utilizes in-house liquidity pools to aggregate the price of collateral. But there is a possibility to use Chainlink oracle prices as safety limits.
Warning
Every market has its own price oracle contract, which can be fetched by calling price_oracle_contract within the controller of the market. The wstETH oracle will be used for the purpose of this documentation. Please be aware that oracle contracts can vary based on the collateral token.
Tip
The formulas below use slightly different terminologies than the code to make them easier to read. For abbreviations, see here.
@internal@viewdef_raw_price(tvls:uint256[N_POOLS],agg_price:uint256)->uint256:weighted_price:uint256=0weights:uint256=0foriinrange(N_POOLS):p_crypto_r:uint256=TRICRYPTO[i].price_oracle(TRICRYPTO_IX[i])# d_usdt/d_ethp_stable_r:uint256=STABLESWAP[i].price_oracle()# d_usdt/d_stp_stable_agg:uint256=agg_price# d_usd/d_stifIS_INVERSE[i]:p_stable_r=10**36/p_stable_rweight:uint256=tvls[i]# Prices are already EMA but weights - not so muchweights+=weightweighted_price+=p_crypto_r*p_stable_agg/p_stable_r*weight# d_usd/d_ethcrv_p:uint256=weighted_price/weightsuse_chainlink:bool=self.use_chainlink# Limit ETH priceifuse_chainlink:chainlink_lrd:ChainlinkAnswer=CHAINLINK_AGGREGATOR_ETH.latestRoundData()ifblock.timestamp-min(chainlink_lrd.updated_at,block.timestamp)<=CHAINLINK_STALE_THRESHOLD:chainlink_p:uint256=convert(chainlink_lrd.answer,uint256)*10**18/CHAINLINK_PRICE_PRECISION_ETHlower:uint256=chainlink_p*(10**18-BOUND_SIZE)/10**18upper:uint256=chainlink_p*(10**18+BOUND_SIZE)/10**18crv_p=min(max(crv_p,lower),upper)p_staked:uint256=STAKEDSWAP.price_oracle()# d_eth / d_steth# Limit STETH priceifuse_chainlink:chainlink_lrd:ChainlinkAnswer=CHAINLINK_AGGREGATOR_STETH.latestRoundData()ifblock.timestamp-min(chainlink_lrd.updated_at,block.timestamp)<=CHAINLINK_STALE_THRESHOLD:chainlink_p:uint256=convert(chainlink_lrd.answer,uint256)*10**18/CHAINLINK_PRICE_PRECISION_STETHlower:uint256=chainlink_p*(10**18-BOUND_SIZE)/10**18upper:uint256=chainlink_p*(10**18+BOUND_SIZE)/10**18p_staked=min(max(p_staked,lower),upper)p_staked=min(p_staked,10**18)*WSTETH.stEthPerToken()/10**18# d_eth / d_wstethreturnp_staked*crv_p/10**18
weighted price of ETH total weighted price of ETH price oracle of eth in the tricrypto pools w.r.t usdc/usdt price oracle of stableswap pool price oracle of crvusd price of stETH w.r.t ETH amount of stETH for 1 wstETH
@external@viewdefraw_price()->uint256:returnself._raw_price()@internal@viewdef_raw_price(tvls:uint256[N_POOLS],agg_price:uint256)->uint256:weighted_price:uint256=0weights:uint256=0foriinrange(N_POOLS):p_crypto_r:uint256=TRICRYPTO[i].price_oracle(TRICRYPTO_IX[i])# d_usdt/d_ethp_stable_r:uint256=STABLESWAP[i].price_oracle()# d_usdt/d_stp_stable_agg:uint256=agg_price# d_usd/d_stifIS_INVERSE[i]:p_stable_r=10**36/p_stable_rweight:uint256=tvls[i]# Prices are already EMA but weights - not so muchweights+=weightweighted_price+=p_crypto_r*p_stable_agg/p_stable_r*weight# d_usd/d_ethcrv_p:uint256=weighted_price/weightsuse_chainlink:bool=self.use_chainlink# Limit ETH priceifuse_chainlink:chainlink_lrd:ChainlinkAnswer=CHAINLINK_AGGREGATOR_ETH.latestRoundData()ifblock.timestamp-min(chainlink_lrd.updated_at,block.timestamp)<=CHAINLINK_STALE_THRESHOLD:chainlink_p:uint256=convert(chainlink_lrd.answer,uint256)*10**18/CHAINLINK_PRICE_PRECISION_ETHlower:uint256=chainlink_p*(10**18-BOUND_SIZE)/10**18upper:uint256=chainlink_p*(10**18+BOUND_SIZE)/10**18crv_p=min(max(crv_p,lower),upper)p_staked:uint256=STAKEDSWAP.price_oracle()# d_eth / d_steth# Limit STETH priceifuse_chainlink:chainlink_lrd:ChainlinkAnswer=CHAINLINK_AGGREGATOR_STETH.latestRoundData()ifblock.timestamp-min(chainlink_lrd.updated_at,block.timestamp)<=CHAINLINK_STALE_THRESHOLD:chainlink_p:uint256=convert(chainlink_lrd.answer,uint256)*10**18/CHAINLINK_PRICE_PRECISION_STETHlower:uint256=chainlink_p*(10**18-BOUND_SIZE)/10**18upper:uint256=chainlink_p*(10**18+BOUND_SIZE)/10**18p_staked=min(max(p_staked,lower),upper)p_staked=min(p_staked,10**18)*WSTETH.stEthPerToken()/10**18# d_eth / d_wstethreturnp_staked*crv_p/10**18
The oracle contracts have the option to utilize Chainlink prices, which serve as safety limits. When enabled, these limits are triggered if the Chainlink price deviates by more than 1.5% (represented by BOUND_SIZE) from the internal price oracles.
Chainlink limits can be turned on and off by calling set_use_chainlink(do_it: bool), which can only be done by the admin of the Factory contract.
Getter for the index of ETH in the tricrypto pool w.r.t the coin at index 0.
Returns: Index of ETH price oracle in the tricrypto pool (uint256).
Tip
Returns 1, as ETH price oracle index in the tricrypto pool is 1. If the same index would be 0, it would return the price oracle of ETH. Their prices are all w.r.t the coin at index 0 (USDC or USDT).
Function to calculate the raw price of the collateral token.
Returns: raw price (uint256).
Source code
@external@viewdefprice()->uint256:returnself._raw_price(self._ema_tvl(),STABLESWAP_AGGREGATOR.price())@internal@viewdef_raw_price(tvls:uint256[N_POOLS],agg_price:uint256)->uint256:weighted_price:uint256=0weights:uint256=0foriinrange(N_POOLS):p_crypto_r:uint256=TRICRYPTO[i].price_oracle(TRICRYPTO_IX[i])# d_usdt/d_ethp_stable_r:uint256=STABLESWAP[i].price_oracle()# d_usdt/d_stp_stable_agg:uint256=agg_price# d_usd/d_stifIS_INVERSE[i]:p_stable_r=10**36/p_stable_rweight:uint256=tvls[i]# Prices are already EMA but weights - not so muchweights+=weightweighted_price+=p_crypto_r*p_stable_agg/p_stable_r*weight# d_usd/d_ethcrv_p:uint256=weighted_price/weightsuse_chainlink:bool=self.use_chainlink# Limit ETH priceifuse_chainlink:chainlink_lrd:ChainlinkAnswer=CHAINLINK_AGGREGATOR_ETH.latestRoundData()ifblock.timestamp-min(chainlink_lrd.updated_at,block.timestamp)<=CHAINLINK_STALE_THRESHOLD:chainlink_p:uint256=convert(chainlink_lrd.answer,uint256)*10**18/CHAINLINK_PRICE_PRECISION_ETHlower:uint256=chainlink_p*(10**18-BOUND_SIZE)/10**18upper:uint256=chainlink_p*(10**18+BOUND_SIZE)/10**18crv_p=min(max(crv_p,lower),upper)p_staked:uint256=STAKEDSWAP.price_oracle()# d_eth / d_steth# Limit STETH priceifuse_chainlink:chainlink_lrd:ChainlinkAnswer=CHAINLINK_AGGREGATOR_STETH.latestRoundData()ifblock.timestamp-min(chainlink_lrd.updated_at,block.timestamp)<=CHAINLINK_STALE_THRESHOLD:chainlink_p:uint256=convert(chainlink_lrd.answer,uint256)*10**18/CHAINLINK_PRICE_PRECISION_STETHlower:uint256=chainlink_p*(10**18-BOUND_SIZE)/10**18upper:uint256=chainlink_p*(10**18+BOUND_SIZE)/10**18p_staked=min(max(p_staked,lower),upper)p_staked=min(p_staked,10**18)*WSTETH.stEthPerToken()/10**18# d_eth / d_wstethreturnp_staked*crv_p/10**18