This oracle contract integrates multiple oracles, applying stored_rates to tokens with an existing rate oracle. By chaining two oracles together, it facilitates the creation of lending oracle contracts without requiring the collateral asset to be paired directly against crvUSD.
GitHub
The source code of the CryptoFromPoolsRate.vy and all other oracle contracts can be found on GitHub.
Oracle Immutability
The oracle contracts are fully immutable. Once deployed, they cannot change any parameters, stop the price updates, or alter the pools used to calculate the prices. All relevant data required for the oracle to function is passed into the __init__ function during the deployment of the contract.
__init__
@externaldef__init__(pools:DynArray[Pool,MAX_POOLS],borrowed_ixs:DynArray[uint256,MAX_POOLS],collateral_ixs:DynArray[uint256,MAX_POOLS]):POOLS=poolspool_count:uint256=0no_arguments:DynArray[bool,MAX_POOLS]=empty(DynArray[bool,MAX_POOLS])use_rates:DynArray[bool,MAX_POOLS]=empty(DynArray[bool,MAX_POOLS])foriinrange(MAX_POOLS):ifi==len(pools):asserti!=0,"Wrong pool counts"pool_count=ibreak# Find NN:uint256=0forjinrange(MAX_COINS+1):success:bool=Falseres:Bytes[32]=empty(Bytes[32])success,res=raw_call(pools[i].address,_abi_encode(j,method_id=method_id("coins(uint256)")),max_outsize=32,is_static_call=True,revert_on_failure=False)ifnotsuccess:assertj!=0,"No coins(0)"N=jbreakassertborrowed_ixs[i]!=collateral_ixs[i]assertborrowed_ixs[i]<Nassertcollateral_ixs[i]<N# Init variables for raw callsuccess:bool=False# Check and record if pool requires coin id in argument or noifN==2:res:Bytes[32]=empty(Bytes[32])success,res=raw_call(pools[i].address,_abi_encode(empty(uint256),method_id=method_id("price_oracle(uint256)")),max_outsize=32,is_static_call=True,revert_on_failure=False)ifnotsuccess:no_arguments.append(True)else:no_arguments.append(False)else:no_arguments.append(False)res:Bytes[1024]=empty(Bytes[1024])success,res=raw_call(pools[i].address,method_id("stored_rates()"),max_outsize=1024,is_static_call=True,revert_on_failure=False)stored_rates:DynArray[uint256,MAX_COINS]=empty(DynArray[uint256,MAX_COINS])ifsuccessandlen(res)>0:stored_rates=_abi_decode(res,DynArray[uint256,MAX_COINS])u:bool=Falseforrinstored_rates:ifr!=10**18:u=Trueuse_rates.append(u)
The price is determined by combining two different oracle prices. When necessary, stored_rates are used to adjust the final computed price from these combined oracles.
Example
For example, suppose the oracle price of Token/ETH is 0.05, and the oracle price of ETH/crvUSD is 1000. The computed price of Token/crvUSD would then be calculated as follows:
This calculation indicates that one Token is equivalent to 50 crvUSD.
Getter for the price of the collateral denominated against the borrowed token. E.g. a market with pufETH as collateral and crvUSD borrowable, the price will return the pufETH price with regard to crvUSD.
This function calculates and writes the price while updating cached_rate and cached_timestamp. It is invoked whenever the _exchange function is called within the AMM contract of the lending market.
The oracle contract utilizes the stored_rates from a stableswap pool and considers these rates accordingly. The application of these rates is governed by the USE_RATES variable. If set to true, the rates are applied; if set to false, they are not.
Source code
RATE_MAX_SPEED:constant(uint256)=10**16/60# Max speed of Rate change@internal@viewdef_stored_rate()->(uint256,bool):use_rates:bool=Falserate:uint256=0rate,use_rates=self._raw_stored_rate()ifnotuse_rates:returnrate,use_ratescached_rate:uint256=self.cached_rateifcached_rate==0orcached_rate==rate:returnrate,use_ratesifrate>cached_rate:returnmin(rate,cached_rate*(10**18+RATE_MAX_SPEED*(block.timestamp-self.cached_timestamp))/10**18),use_rateselse:returnmax(rate,cached_rate*(10**18-min(RATE_MAX_SPEED*(block.timestamp-self.cached_timestamp),10**18))/10**18),use_rates
Based on the values of rate and cached_rate, specific calculations are required to account for changes in rates:
If the cached_rate is 0 (indicating that no rates need to be applied) or equal to the actual rate (meaning no rate changes have occurred since the last update), there is no need to do additional calculations to obtain the rate value.
If rate > cached_rate, the rate is calculated as follows: This calculation aims to smoothly increase the rate, capping it at a calculated maximum based on the RATE_MAX_SPEED and the time elapsed since the last cache update.
In all other cases, where the rate has decreased, it is calculated as follows: This formula ensures that the rate does not decrease too rapidly, with the reduction bounded by a minimum that considers the RATE_MAX_SPEED and the elapsed time.
>>>CryptoFromPoolsRate.USE_RATES(0)# checks for pufETH/wETH pool'true'# true, because the `stored_rates` of this pool are used>>>CryptoFromPoolsRate.USE_RATES(0)# checks for tryLSD pool'false'# false, because no rates are used
Getter for the index of the borrowed token in the chain together pools. If the oracle contract is for an asset that has a rate, this method will return the coin indices of the "base asset". E.g., for pufETH, this method will return the index of wstETH in the pools and later, when calculating the price of pufETH, the rates are applied.