aave-protocol-v2/contracts/lendingpool/DefaultReserveInterestRateStrategy.sol

217 lines
7.7 KiB
Solidity
Raw Normal View History

// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.6.8;
2020-08-20 07:51:21 +00:00
import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol';
import {IReserveInterestRateStrategy} from '../interfaces/IReserveInterestRateStrategy.sol';
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
2020-09-10 11:21:50 +00:00
import {PercentageMath} from '../libraries/math/PercentageMath.sol';
2020-08-20 07:51:21 +00:00
import {LendingPoolAddressesProvider} from '../configuration/LendingPoolAddressesProvider.sol';
import {ILendingRateOracle} from '../interfaces/ILendingRateOracle.sol';
/**
2020-06-20 23:40:03 +00:00
* @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 {
2020-06-20 23:40:03 +00:00
using WadRayMath for uint256;
using SafeMath for uint256;
2020-09-10 11:21:50 +00:00
using PercentageMath for uint256;
2020-06-20 23:40:03 +00:00
/**
* @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;
2020-06-27 02:13:32 +00:00
LendingPoolAddressesProvider public immutable addressesProvider;
2020-06-20 23:40:03 +00:00
//base variable borrow rate when Utilization rate = 0. Expressed in ray
uint256 internal immutable _baseVariableBorrowRate;
2020-06-20 23:40:03 +00:00
//slope of the variable interest curve when utilization rate > 0 and <= OPTIMAL_UTILIZATION_RATE. Expressed in ray
uint256 internal immutable _variableRateSlope1;
2020-06-20 23:40:03 +00:00
//slope of the variable interest curve when utilization rate > OPTIMAL_UTILIZATION_RATE. Expressed in ray
uint256 internal immutable _variableRateSlope2;
2020-06-20 23:40:03 +00:00
//slope of the stable interest curve when utilization rate > 0 and <= OPTIMAL_UTILIZATION_RATE. Expressed in ray
uint256 internal immutable _stableRateSlope1;
2020-06-20 23:40:03 +00:00
//slope of the stable interest curve when utilization rate > OPTIMAL_UTILIZATION_RATE. Expressed in ray
uint256 internal immutable _stableRateSlope2;
2020-06-20 23:40:03 +00:00
2020-09-10 10:51:52 +00:00
2020-06-20 23:40:03 +00:00
constructor(
LendingPoolAddressesProvider provider,
uint256 baseVariableBorrowRate,
uint256 variableRateSlope1,
uint256 variableRateSlope2,
uint256 stableRateSlope1,
uint256 stableRateSlope2
2020-06-20 23:40:03 +00:00
) public {
addressesProvider = provider;
_baseVariableBorrowRate = baseVariableBorrowRate;
_variableRateSlope1 = variableRateSlope1;
_variableRateSlope2 = variableRateSlope2;
_stableRateSlope1 = stableRateSlope1;
_stableRateSlope2 = stableRateSlope2;
2020-06-20 23:40:03 +00:00
}
/**
* @dev accessors
*/
function variableRateSlope1() external view returns (uint256) {
return _variableRateSlope1;
2020-06-20 23:40:03 +00:00
}
function variableRateSlope2() external view returns (uint256) {
return _variableRateSlope2;
2020-06-20 23:40:03 +00:00
}
function stableRateSlope1() external view returns (uint256) {
return _stableRateSlope1;
2020-06-20 23:40:03 +00:00
}
function stableRateSlope2() external view returns (uint256) {
return _stableRateSlope2;
2020-06-20 23:40:03 +00:00
}
function baseVariableBorrowRate() external override view returns (uint256) {
return _baseVariableBorrowRate;
2020-06-20 23:40:03 +00:00
}
2020-09-21 17:52:22 +00:00
function getMaxVariableBorrowRate() external override view returns (uint256) {
return _baseVariableBorrowRate.add(_variableRateSlope1).add(_variableRateSlope2);
}
2020-09-21 18:19:28 +00:00
2020-09-10 10:51:52 +00:00
struct CalcInterestRatesLocalVars {
uint256 totalBorrows;
uint256 currentVariableBorrowRate;
uint256 currentStableBorrowRate;
uint256 currentLiquidityRate;
uint256 utilizationRate;
}
2020-09-21 17:52:22 +00:00
2020-06-20 23:40:03 +00:00
/**
* @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 totalStableDebt the total borrowed from the reserve a stable rate
* @param totalVariableDebt the total borrowed from the reserve at a variable rate
* @param averageStableBorrowRate the weighted average of all the stable rate borrows
2020-09-10 10:51:52 +00:00
* @param reserveFactor the reserve portion of the interest to redirect to the reserve treasury
2020-06-20 23:40:03 +00:00
* @return currentLiquidityRate the liquidity rate
* @return currentStableBorrowRate stable borrow rate
* @return currentVariableBorrowRate variable borrow rate
**/
function calculateInterestRates(
address reserve,
uint256 availableLiquidity,
uint256 totalStableDebt,
uint256 totalVariableDebt,
2020-09-10 10:51:52 +00:00
uint256 averageStableBorrowRate,
uint256 reserveFactor
2020-06-20 23:40:03 +00:00
)
external
override
view
returns (
uint256,
uint256,
uint256
)
2020-06-20 23:40:03 +00:00
{
2020-09-10 10:51:52 +00:00
CalcInterestRatesLocalVars memory vars;
vars.totalBorrows = totalStableDebt.add(totalVariableDebt);
2020-09-10 10:51:52 +00:00
vars.currentVariableBorrowRate = 0;
vars.currentStableBorrowRate = 0;
vars.currentLiquidityRate = 0;
uint256 utilizationRate = vars.totalBorrows == 0
2020-06-20 23:40:03 +00:00
? 0
2020-09-10 10:51:52 +00:00
: vars.totalBorrows.rayDiv(availableLiquidity.add(vars.totalBorrows));
2020-06-20 23:40:03 +00:00
2020-09-10 10:51:52 +00:00
vars.currentStableBorrowRate = ILendingRateOracle(addressesProvider.getLendingRateOracle())
.getMarketBorrowRate(reserve);
2020-06-20 23:40:03 +00:00
if (utilizationRate > OPTIMAL_UTILIZATION_RATE) {
uint256 excessUtilizationRateRatio = utilizationRate.sub(OPTIMAL_UTILIZATION_RATE).rayDiv(
EXCESS_UTILIZATION_RATE
);
2020-09-10 10:51:52 +00:00
vars.currentStableBorrowRate = vars.currentStableBorrowRate.add(_stableRateSlope1).add(
_stableRateSlope2.rayMul(excessUtilizationRateRatio)
2020-06-20 23:40:03 +00:00
);
2020-09-10 10:51:52 +00:00
vars.currentVariableBorrowRate = _baseVariableBorrowRate.add(_variableRateSlope1).add(
_variableRateSlope2.rayMul(excessUtilizationRateRatio)
2020-06-20 23:40:03 +00:00
);
} else {
2020-09-10 10:51:52 +00:00
vars.currentStableBorrowRate = vars.currentStableBorrowRate.add(
_stableRateSlope1.rayMul(utilizationRate.rayDiv(OPTIMAL_UTILIZATION_RATE))
2020-06-20 23:40:03 +00:00
);
2020-09-10 10:51:52 +00:00
vars.currentVariableBorrowRate = _baseVariableBorrowRate.add(
utilizationRate.rayDiv(OPTIMAL_UTILIZATION_RATE).rayMul(_variableRateSlope1)
2020-06-20 23:40:03 +00:00
);
}
2020-09-10 10:51:52 +00:00
vars.currentLiquidityRate = _getOverallBorrowRate(
totalStableDebt,
totalVariableDebt,
2020-09-10 10:51:52 +00:00
vars.currentVariableBorrowRate,
averageStableBorrowRate
2020-06-20 23:40:03 +00:00
)
2020-09-10 10:51:52 +00:00
.rayMul(utilizationRate)
2020-09-10 11:21:50 +00:00
.percentMul(PercentageMath.PERCENTAGE_FACTOR.sub(reserveFactor));
2020-09-10 10:51:52 +00:00
return (vars.currentLiquidityRate, vars.currentStableBorrowRate, vars.currentVariableBorrowRate);
2020-06-20 23:40:03 +00:00
}
/**
* @dev calculates the overall borrow rate as the weighted average between the total variable borrows and total stable borrows.
* @param totalStableDebt the total borrowed from the reserve a stable rate
* @param totalVariableDebt 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
2020-06-20 23:40:03 +00:00
* @return the weighted averaged borrow rate
**/
function _getOverallBorrowRate(
uint256 totalStableDebt,
uint256 totalVariableDebt,
uint256 currentVariableBorrowRate,
uint256 currentAverageStableBorrowRate
2020-06-20 23:40:03 +00:00
) internal pure returns (uint256) {
uint256 totalBorrows = totalStableDebt.add(totalVariableDebt);
2020-06-20 23:40:03 +00:00
if (totalBorrows == 0) return 0;
uint256 weightedVariableRate = totalVariableDebt.wadToRay().rayMul(
currentVariableBorrowRate
2020-06-20 23:40:03 +00:00
);
uint256 weightedStableRate = totalStableDebt.wadToRay().rayMul(
currentAverageStableBorrowRate
2020-06-20 23:40:03 +00:00
);
uint256 overallBorrowRate = weightedVariableRate.add(weightedStableRate).rayDiv(
totalBorrows.wadToRay()
);
return overallBorrowRate;
}
}