aave-protocol-v2/contracts/libraries/logic/ReserveLogic.sol

243 lines
9.0 KiB
Solidity
Raw Normal View History

2020-06-20 23:40:03 +00:00
// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.6.8;
2020-07-08 22:16:05 +00:00
import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol';
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
2020-08-20 07:51:21 +00:00
import {MathUtils} from '../math/MathUtils.sol';
import {IPriceOracleGetter} from '../../interfaces/IPriceOracleGetter.sol';
import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/SafeERC20.sol';
2020-08-20 07:51:21 +00:00
import {IStableDebtToken} from '../../tokenization/interfaces/IStableDebtToken.sol';
import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol';
import {IReserveInterestRateStrategy} from '../../interfaces/IReserveInterestRateStrategy.sol';
import {WadRayMath} from '../math/WadRayMath.sol';
2020-06-27 02:13:32 +00:00
/**
2020-07-08 22:16:05 +00:00
* @title ReserveLogic library
* @author Aave
* @notice Implements the logic to update the state of the reserves
*/
2020-06-20 23:40:03 +00:00
library ReserveLogic {
2020-07-08 22:16:05 +00:00
using SafeMath for uint256;
using WadRayMath for uint256;
2020-08-12 17:36:58 +00:00
using SafeERC20 for IERC20;
2020-08-19 14:36:58 +00:00
/**
* @dev Emitted when the state of a reserve is updated
* @param reserve the address of the reserve
* @param liquidityRate the new liquidity rate
* @param stableBorrowRate the new stable borrow rate
* @param averageStableBorrowRate the new average stable borrow rate
* @param variableBorrowRate the new variable borrow rate
* @param liquidityIndex the new liquidity index
* @param variableBorrowIndex the new variable borrow index
**/
event ReserveDataUpdated(
address indexed reserve,
uint256 liquidityRate,
uint256 stableBorrowRate,
uint256 averageStableBorrowRate,
uint256 variableBorrowRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex
);
2020-07-08 22:16:05 +00:00
using ReserveLogic for ReserveLogic.ReserveData;
2020-07-23 15:18:06 +00:00
using ReserveConfiguration for ReserveConfiguration.Map;
2020-06-20 23:40:03 +00:00
2020-07-08 22:16:05 +00:00
enum InterestRateMode {NONE, STABLE, VARIABLE}
2020-06-20 23:40:03 +00:00
2020-08-19 14:36:58 +00:00
// refer to the whitepaper, section 1.1 basic concepts for a formal description of these properties.
2020-07-08 22:16:05 +00:00
struct ReserveData {
//the liquidity index. Expressed in ray
2020-08-21 14:00:51 +00:00
uint256 lastLiquidityIndex;
2020-07-08 22:16:05 +00:00
//the current supply rate. Expressed in ray
uint256 currentLiquidityRate;
//the current variable borrow rate. Expressed in ray
uint256 currentVariableBorrowRate;
//the current stable borrow rate. Expressed in ray
uint256 currentStableBorrowRate;
//variable borrow index. Expressed in ray
2020-08-21 14:00:51 +00:00
uint256 lastVariableBorrowIndex;
2020-08-19 14:36:58 +00:00
//stores the reserve configuration
2020-07-23 15:18:06 +00:00
ReserveConfiguration.Map configuration;
address aTokenAddress;
2020-07-08 22:16:05 +00:00
address stableDebtTokenAddress;
address variableDebtTokenAddress;
address interestRateStrategyAddress;
uint40 lastUpdateTimestamp;
2020-08-19 14:36:58 +00:00
//the index of the reserve in the list of the active reserves
2020-08-05 10:40:24 +00:00
uint8 index;
2020-07-08 22:16:05 +00:00
}
/**
* @dev returns the ongoing normalized income for the reserve.
* a value of 1e27 means there is no income. As time passes, the income is accrued.
2020-08-19 14:36:58 +00:00
* A value of 2*1e27 means for each unit of assset two units of income have been accrued.
2020-08-21 13:13:08 +00:00
* @param reserve the reserve object
2020-07-08 22:16:05 +00:00
* @return the normalized income. expressed in ray
**/
2020-08-21 13:13:08 +00:00
function getNormalizedIncome(ReserveData storage reserve) internal view returns (uint256) {
uint40 timestamp = reserve.lastUpdateTimestamp;
2020-08-10 18:20:08 +00:00
//solium-disable-next-line
if (timestamp == uint40(block.timestamp)) {
//if the index was updated in the same block, no need to perform any calculation
2020-08-21 14:00:51 +00:00
return reserve.lastLiquidityIndex;
}
2020-07-08 22:16:05 +00:00
uint256 cumulated = MathUtils
2020-08-21 13:13:08 +00:00
.calculateLinearInterest(reserve.currentLiquidityRate, timestamp)
2020-08-21 14:00:51 +00:00
.rayMul(reserve.lastLiquidityIndex);
2020-07-08 22:16:05 +00:00
return cumulated;
}
/**
* @dev returns the ongoing normalized variable debt for the reserve.
* a value of 1e27 means there is no debt. As time passes, the income is accrued.
* A value of 2*1e27 means that the debt of the reserve is double the initial amount.
2020-08-21 13:13:08 +00:00
* @param reserve the reserve object
2020-07-08 22:16:05 +00:00
* @return the normalized variable debt. expressed in ray
**/
2020-08-21 13:13:08 +00:00
function getNormalizedDebt(ReserveData storage reserve) internal view returns (uint256) {
uint40 timestamp = reserve.lastUpdateTimestamp;
2020-08-10 18:20:08 +00:00
//solium-disable-next-line
if (timestamp == uint40(block.timestamp)) {
//if the index was updated in the same block, no need to perform any calculation
2020-08-21 14:00:51 +00:00
return reserve.lastVariableBorrowIndex;
}
2020-07-08 22:16:05 +00:00
uint256 cumulated = MathUtils
2020-08-21 13:13:08 +00:00
.calculateCompoundedInterest(reserve.currentVariableBorrowRate, timestamp)
2020-08-21 14:00:51 +00:00
.rayMul(reserve.lastVariableBorrowIndex);
2020-07-08 22:16:05 +00:00
return cumulated;
}
/**
* @dev Updates the liquidity cumulative index Ci and variable borrow cumulative index Bvc. Refer to the whitepaper for
* a formal specification.
2020-08-21 13:13:08 +00:00
* @param reserve the reserve object
2020-07-08 22:16:05 +00:00
**/
2020-08-21 13:13:08 +00:00
function updateCumulativeIndexesAndTimestamp(ReserveData storage reserve) internal {
2020-08-19 14:36:58 +00:00
//only cumulating if there is any income being produced
if (
2020-08-21 13:13:08 +00:00
IERC20(reserve.variableDebtTokenAddress).totalSupply() > 0 ||
IERC20(reserve.stableDebtTokenAddress).totalSupply() > 0
2020-08-19 14:36:58 +00:00
) {
2020-08-25 10:37:38 +00:00
uint40 lastUpdateTimestamp = reserve.lastUpdateTimestamp;
2020-07-08 22:16:05 +00:00
uint256 cumulatedLiquidityInterest = MathUtils.calculateLinearInterest(
2020-08-21 13:13:08 +00:00
reserve.currentLiquidityRate,
2020-08-25 10:37:38 +00:00
lastUpdateTimestamp
2020-07-08 22:16:05 +00:00
);
2020-08-25 10:37:38 +00:00
reserve.lastLiquidityIndex = cumulatedLiquidityInterest.rayMul(reserve.lastLiquidityIndex);
2020-07-08 22:16:05 +00:00
uint256 cumulatedVariableBorrowInterest = MathUtils.calculateCompoundedInterest(
2020-08-21 13:13:08 +00:00
reserve.currentVariableBorrowRate,
2020-08-25 10:37:38 +00:00
lastUpdateTimestamp
2020-07-08 22:16:05 +00:00
);
2020-08-21 14:00:51 +00:00
reserve.lastVariableBorrowIndex = cumulatedVariableBorrowInterest.rayMul(
reserve.lastVariableBorrowIndex
2020-07-08 22:16:05 +00:00
);
2020-06-20 23:40:03 +00:00
}
2020-06-27 02:13:32 +00:00
2020-07-08 22:16:05 +00:00
//solium-disable-next-line
2020-08-21 13:13:08 +00:00
reserve.lastUpdateTimestamp = uint40(block.timestamp);
2020-07-08 22:16:05 +00:00
}
/**
* @dev accumulates a predefined amount of asset to the reserve as a fixed, one time income. Used for example to accumulate
* the flashloan fee to the reserve, and spread it through the depositors.
2020-08-21 13:13:08 +00:00
* @param reserve the reserve object
* @param totalLiquidity the total liquidity available in the reserve
* @param amount the amount to accomulate
2020-07-08 22:16:05 +00:00
**/
function cumulateToLiquidityIndex(
2020-08-21 13:13:08 +00:00
ReserveData storage reserve,
uint256 totalLiquidity,
uint256 amount
2020-07-08 22:16:05 +00:00
) internal {
2020-08-21 13:13:08 +00:00
uint256 amountToLiquidityRatio = amount.wadToRay().rayDiv(totalLiquidity.wadToRay());
2020-06-20 23:40:03 +00:00
2020-07-08 22:16:05 +00:00
uint256 cumulatedLiquidity = amountToLiquidityRatio.add(WadRayMath.ray());
2020-08-25 10:37:38 +00:00
reserve.lastLiquidityIndex = cumulatedLiquidity.rayMul(reserve.lastLiquidityIndex);
2020-07-08 22:16:05 +00:00
}
/**
* @dev initializes a reserve
2020-08-21 13:13:08 +00:00
* @param reserve the reserve object
* @param aTokenAddress the address of the overlying atoken contract
* @param interestRateStrategyAddress the address of the interest rate strategy contract
2020-07-08 22:16:05 +00:00
**/
function init(
2020-08-21 13:13:08 +00:00
ReserveData storage reserve,
address aTokenAddress,
address stableDebtTokenAddress,
address variableDebtTokenAddress,
2020-08-21 13:13:08 +00:00
address interestRateStrategyAddress
2020-07-08 22:16:05 +00:00
) external {
2020-08-21 13:13:08 +00:00
require(reserve.aTokenAddress == address(0), 'Reserve has already been initialized');
2020-08-21 14:00:51 +00:00
if (reserve.lastLiquidityIndex == 0) {
2020-07-08 22:16:05 +00:00
//if the reserve has not been initialized yet
2020-08-21 14:00:51 +00:00
reserve.lastLiquidityIndex = WadRayMath.ray();
2020-06-20 23:40:03 +00:00
}
2020-08-21 14:00:51 +00:00
if (reserve.lastVariableBorrowIndex == 0) {
reserve.lastVariableBorrowIndex = WadRayMath.ray();
2020-06-20 23:40:03 +00:00
}
2020-08-21 13:13:08 +00:00
reserve.aTokenAddress = aTokenAddress;
reserve.stableDebtTokenAddress = stableDebtTokenAddress;
reserve.variableDebtTokenAddress = variableDebtTokenAddress;
2020-08-21 13:13:08 +00:00
reserve.interestRateStrategyAddress = interestRateStrategyAddress;
2020-07-08 22:16:05 +00:00
}
/**
* @dev Updates the reserve current stable borrow rate Rf, the current variable borrow rate Rv and the current liquidity rate Rl.
* Also updates the lastUpdateTimestamp value. Please refer to the whitepaper for further information.
2020-08-21 13:13:08 +00:00
* @param reserve the address of the reserve to be updated
* @param liquidityAdded the amount of liquidity added to the protocol (deposit or repay) in the previous action
* @param liquidityTaken the amount of liquidity taken from the protocol (redeem or borrow)
2020-07-08 22:16:05 +00:00
**/
function updateInterestRates(
2020-08-21 13:13:08 +00:00
ReserveData storage reserve,
address reserveAddress,
2020-08-25 10:37:38 +00:00
address aTokenAddress,
uint256 liquidityAdded,
uint256 liquidityTaken
2020-07-08 22:16:05 +00:00
) internal {
2020-08-21 13:13:08 +00:00
uint256 currentAvgStableRate = IStableDebtToken(reserve.stableDebtTokenAddress)
2020-07-08 22:16:05 +00:00
.getAverageStableRate();
(
uint256 newLiquidityRate,
uint256 newStableRate,
uint256 newVariableRate
2020-08-21 13:13:08 +00:00
) = IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).calculateInterestRates(
reserveAddress,
2020-08-25 10:37:38 +00:00
IERC20(reserveAddress).balanceOf(aTokenAddress).add(liquidityAdded).sub(liquidityTaken),
2020-08-21 13:13:08 +00:00
IERC20(reserve.stableDebtTokenAddress).totalSupply(),
IERC20(reserve.variableDebtTokenAddress).totalSupply(),
2020-07-08 22:16:05 +00:00
currentAvgStableRate
);
2020-08-21 13:13:08 +00:00
reserve.currentLiquidityRate = newLiquidityRate;
reserve.currentStableBorrowRate = newStableRate;
reserve.currentVariableBorrowRate = newVariableRate;
2020-07-08 22:16:05 +00:00
emit ReserveDataUpdated(
2020-08-21 13:13:08 +00:00
reserveAddress,
2020-07-08 22:16:05 +00:00
newLiquidityRate,
newStableRate,
currentAvgStableRate,
newVariableRate,
2020-08-21 14:00:51 +00:00
reserve.lastLiquidityIndex,
reserve.lastVariableBorrowIndex
2020-07-08 22:16:05 +00:00
);
}
2020-06-20 23:40:03 +00:00
}