// SPDX-License-Identifier: agpl-3.0 pragma solidity ^0.6.8; import '../interfaces/IReserveInterestRateStrategy.sol'; import '../libraries/WadRayMath.sol'; import '../configuration/LendingPoolAddressesProvider.sol'; import '../interfaces/ILendingRateOracle.sol'; import '@openzeppelin/contracts/math/SafeMath.sol'; /** * @title DefaultReserveInterestRateStrategy contract * @notice implements the calculation of the interest rates depending on the reserve parameters. * @dev if there is need to update the calculation of the interest rates for a specific reserve, * a new version of this contract will be deployed. * @author Aave **/ contract DefaultReserveInterestRateStrategy is IReserveInterestRateStrategy { using WadRayMath for uint256; using SafeMath for uint256; /** * @dev this constant represents the utilization rate at which the pool aims to obtain most competitive borrow rates * expressed in ray **/ uint256 public constant OPTIMAL_UTILIZATION_RATE = 0.8 * 1e27; /** * @dev this constant represents the excess utilization rate above the optimal. It's always equal to * 1-optimal utilization rate. Added as a constant here for gas optimizations * expressed in ray **/ uint256 public constant EXCESS_UTILIZATION_RATE = 0.2 * 1e27; using WadRayMath for uint256; using SafeMath for uint256; LendingPoolAddressesProvider public immutable addressesProvider; //base variable borrow rate when Utilization rate = 0. Expressed in ray uint256 internal immutable baseVariableBorrowRate; //slope of the variable interest curve when utilization rate > 0 and <= OPTIMAL_UTILIZATION_RATE. Expressed in ray uint256 internal immutable variableRateSlope1; //slope of the variable interest curve when utilization rate > OPTIMAL_UTILIZATION_RATE. Expressed in ray uint256 internal immutable variableRateSlope2; //slope of the stable interest curve when utilization rate > 0 and <= OPTIMAL_UTILIZATION_RATE. Expressed in ray uint256 internal immutable stableRateSlope1; //slope of the stable interest curve when utilization rate > OPTIMAL_UTILIZATION_RATE. Expressed in ray uint256 internal immutable stableRateSlope2; constructor( LendingPoolAddressesProvider _provider, uint256 _baseVariableBorrowRate, uint256 _variableRateSlope1, uint256 _variableRateSlope2, uint256 _stableRateSlope1, uint256 _stableRateSlope2 ) public { addressesProvider = _provider; baseVariableBorrowRate = _baseVariableBorrowRate; variableRateSlope1 = _variableRateSlope1; variableRateSlope2 = _variableRateSlope2; stableRateSlope1 = _stableRateSlope1; stableRateSlope2 = _stableRateSlope2; } /** * @dev accessors */ function getVariableRateSlope1() external view returns (uint256) { return variableRateSlope1; } function getVariableRateSlope2() external view returns (uint256) { return variableRateSlope2; } function getStableRateSlope1() external view returns (uint256) { return stableRateSlope1; } function getStableRateSlope2() external view returns (uint256) { return stableRateSlope2; } function getBaseVariableBorrowRate() external override view returns (uint256) { return baseVariableBorrowRate; } /** * @dev calculates the interest rates depending on the available liquidity and the total borrowed. * @param _reserve the address of the reserve * @param _availableLiquidity the liquidity available in the reserve * @param _totalBorrowsStable the total borrowed from the reserve a stable rate * @param _totalBorrowsVariable the total borrowed from the reserve at a variable rate * @param _averageStableBorrowRate the weighted average of all the stable rate borrows * @return currentLiquidityRate the liquidity rate * @return currentStableBorrowRate stable borrow rate * @return currentVariableBorrowRate variable borrow rate **/ function calculateInterestRates( address _reserve, uint256 _availableLiquidity, uint256 _totalBorrowsStable, uint256 _totalBorrowsVariable, uint256 _averageStableBorrowRate ) external override view returns ( uint256 currentLiquidityRate, uint256 currentStableBorrowRate, uint256 currentVariableBorrowRate ) { uint256 totalBorrows = _totalBorrowsStable.add(_totalBorrowsVariable); uint256 utilizationRate = (totalBorrows == 0 && _availableLiquidity == 0) ? 0 : totalBorrows.rayDiv(_availableLiquidity.add(totalBorrows)); currentStableBorrowRate = ILendingRateOracle(addressesProvider.getLendingRateOracle()) .getMarketBorrowRate(_reserve); if (utilizationRate > OPTIMAL_UTILIZATION_RATE) { uint256 excessUtilizationRateRatio = utilizationRate.sub(OPTIMAL_UTILIZATION_RATE).rayDiv( EXCESS_UTILIZATION_RATE ); currentStableBorrowRate = currentStableBorrowRate.add(stableRateSlope1).add( stableRateSlope2.rayMul(excessUtilizationRateRatio) ); currentVariableBorrowRate = baseVariableBorrowRate.add(variableRateSlope1).add( variableRateSlope2.rayMul(excessUtilizationRateRatio) ); } else { currentStableBorrowRate = currentStableBorrowRate.add( stableRateSlope1.rayMul(utilizationRate.rayDiv(OPTIMAL_UTILIZATION_RATE)) ); currentVariableBorrowRate = baseVariableBorrowRate.add( utilizationRate.rayDiv(OPTIMAL_UTILIZATION_RATE).rayMul(variableRateSlope1) ); } currentLiquidityRate = getOverallBorrowRateInternal( _totalBorrowsStable, _totalBorrowsVariable, currentVariableBorrowRate, _averageStableBorrowRate ) .rayMul(utilizationRate); } /** * @dev calculates the overall borrow rate as the weighted average between the total variable borrows and total stable borrows. * @param _totalBorrowsStable the total borrowed from the reserve a stable rate * @param _totalBorrowsVariable the total borrowed from the reserve at a variable rate * @param _currentVariableBorrowRate the current variable borrow rate * @param _currentAverageStableBorrowRate the weighted average of all the stable rate borrows * @return the weighted averaged borrow rate **/ function getOverallBorrowRateInternal( uint256 _totalBorrowsStable, uint256 _totalBorrowsVariable, uint256 _currentVariableBorrowRate, uint256 _currentAverageStableBorrowRate ) internal pure returns (uint256) { uint256 totalBorrows = _totalBorrowsStable.add(_totalBorrowsVariable); if (totalBorrows == 0) return 0; uint256 weightedVariableRate = _totalBorrowsVariable.wadToRay().rayMul( _currentVariableBorrowRate ); uint256 weightedStableRate = _totalBorrowsStable.wadToRay().rayMul( _currentAverageStableBorrowRate ); uint256 overallBorrowRate = weightedVariableRate.add(weightedStableRate).rayDiv( totalBorrows.wadToRay() ); return overallBorrowRate; } }