Initial update of ReserveLogic

This commit is contained in:
The3D 2020-08-21 15:13:08 +02:00
parent 86541b3fe5
commit 8fe40b4639
2 changed files with 75 additions and 91 deletions

View File

@ -677,8 +677,18 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable, ILendingPool {
'The actual balance of the protocol is inconsistent' 'The actual balance of the protocol is inconsistent'
); );
reserve.updateStateOnFlashLoan(_reserve, availableLiquidityBefore, amountFee); //compounding the cumulated interest
reserve.updateCumulativeIndexesAndTimestamp();
uint256 totalLiquidityBefore = availableLiquidityBefore
.add(IERC20(reserve.variableDebtTokenAddress).totalSupply())
.add(IERC20(reserve.stableDebtTokenAddress).totalSupply());
//compounding the received fee into the reserve
reserve.cumulateToLiquidityIndex(totalLiquidityBefore, amountFee);
//refresh interest rates
reserve.updateInterestRates(reserve, asset, amountFee, 0);
//solium-disable-next-line //solium-disable-next-line
emit FlashLoan(_receiver, _reserve, _amount, amountFee, block.timestamp); emit FlashLoan(_receiver, _reserve, _amount, amountFee, block.timestamp);
} }

View File

@ -23,7 +23,6 @@ library ReserveLogic {
/** /**
* @dev Emitted when the state of a reserve is updated * @dev Emitted when the state of a reserve is updated
* @dev NOTE: This event replaces the Deprecated ReserveUpdated() event, which didn't emit the average stable borrow rate
* @param reserve the address of the reserve * @param reserve the address of the reserve
* @param liquidityRate the new liquidity rate * @param liquidityRate the new liquidity rate
* @param stableBorrowRate the new stable borrow rate * @param stableBorrowRate the new stable borrow rate
@ -74,21 +73,21 @@ library ReserveLogic {
* @dev returns the ongoing normalized income for the reserve. * @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. * a value of 1e27 means there is no income. As time passes, the income is accrued.
* A value of 2*1e27 means for each unit of assset two units of income have been accrued. * A value of 2*1e27 means for each unit of assset two units of income have been accrued.
* @param _reserve the reserve object * @param reserve the reserve object
* @return the normalized income. expressed in ray * @return the normalized income. expressed in ray
**/ **/
function getNormalizedIncome(ReserveData storage _reserve) internal view returns (uint256) { function getNormalizedIncome(ReserveData storage reserve) internal view returns (uint256) {
uint40 timestamp = _reserve.lastUpdateTimestamp; uint40 timestamp = reserve.lastUpdateTimestamp;
//solium-disable-next-line //solium-disable-next-line
if (timestamp == uint40(block.timestamp)) { if (timestamp == uint40(block.timestamp)) {
//if the index was updated in the same block, no need to perform any calculation //if the index was updated in the same block, no need to perform any calculation
return _reserve.lastLiquidityCumulativeIndex; return reserve.lastLiquidityCumulativeIndex;
} }
uint256 cumulated = MathUtils uint256 cumulated = MathUtils
.calculateLinearInterest(_reserve.currentLiquidityRate, timestamp) .calculateLinearInterest(reserve.currentLiquidityRate, timestamp)
.rayMul(_reserve.lastLiquidityCumulativeIndex); .rayMul(reserve.lastLiquidityCumulativeIndex);
return cumulated; return cumulated;
} }
@ -97,21 +96,21 @@ library ReserveLogic {
* @dev returns the ongoing normalized variable debt for the reserve. * @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 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. * A value of 2*1e27 means that the debt of the reserve is double the initial amount.
* @param _reserve the reserve object * @param reserve the reserve object
* @return the normalized variable debt. expressed in ray * @return the normalized variable debt. expressed in ray
**/ **/
function getNormalizedDebt(ReserveData storage _reserve) internal view returns (uint256) { function getNormalizedDebt(ReserveData storage reserve) internal view returns (uint256) {
uint40 timestamp = _reserve.lastUpdateTimestamp; uint40 timestamp = reserve.lastUpdateTimestamp;
//solium-disable-next-line //solium-disable-next-line
if (timestamp == uint40(block.timestamp)) { if (timestamp == uint40(block.timestamp)) {
//if the index was updated in the same block, no need to perform any calculation //if the index was updated in the same block, no need to perform any calculation
return _reserve.lastVariableBorrowCumulativeIndex; return reserve.lastVariableBorrowCumulativeIndex;
} }
uint256 cumulated = MathUtils uint256 cumulated = MathUtils
.calculateCompoundedInterest(_reserve.currentVariableBorrowRate, timestamp) .calculateCompoundedInterest(reserve.currentVariableBorrowRate, timestamp)
.rayMul(_reserve.lastVariableBorrowCumulativeIndex); .rayMul(reserve.lastVariableBorrowCumulativeIndex);
return cumulated; return cumulated;
} }
@ -119,153 +118,128 @@ library ReserveLogic {
/** /**
* @dev Updates the liquidity cumulative index Ci and variable borrow cumulative index Bvc. Refer to the whitepaper for * @dev Updates the liquidity cumulative index Ci and variable borrow cumulative index Bvc. Refer to the whitepaper for
* a formal specification. * a formal specification.
* @param _self the reserve object * @param reserve the reserve object
**/ **/
function updateCumulativeIndexesAndTimestamp(ReserveData storage _self) internal { function updateCumulativeIndexesAndTimestamp(ReserveData storage reserve) internal {
//only cumulating if there is any income being produced //only cumulating if there is any income being produced
if ( if (
IERC20(_self.variableDebtTokenAddress).totalSupply() > 0 || IERC20(reserve.variableDebtTokenAddress).totalSupply() > 0 ||
IERC20(_self.stableDebtTokenAddress).totalSupply() > 0 IERC20(reserve.stableDebtTokenAddress).totalSupply() > 0
) { ) {
uint256 cumulatedLiquidityInterest = MathUtils.calculateLinearInterest( uint256 cumulatedLiquidityInterest = MathUtils.calculateLinearInterest(
_self.currentLiquidityRate, reserve.currentLiquidityRate,
_self.lastUpdateTimestamp reserve.lastUpdateTimestamp
); );
_self.lastLiquidityCumulativeIndex = cumulatedLiquidityInterest.rayMul( reserve.lastLiquidityCumulativeIndex = cumulatedLiquidityInterest.rayMul(
_self.lastLiquidityCumulativeIndex reserve.lastLiquidityCumulativeIndex
); );
uint256 cumulatedVariableBorrowInterest = MathUtils.calculateCompoundedInterest( uint256 cumulatedVariableBorrowInterest = MathUtils.calculateCompoundedInterest(
_self.currentVariableBorrowRate, reserve.currentVariableBorrowRate,
_self.lastUpdateTimestamp reserve.lastUpdateTimestamp
); );
_self.lastVariableBorrowCumulativeIndex = cumulatedVariableBorrowInterest.rayMul( reserve.lastVariableBorrowCumulativeIndex = cumulatedVariableBorrowInterest.rayMul(
_self.lastVariableBorrowCumulativeIndex reserve.lastVariableBorrowCumulativeIndex
); );
} }
//solium-disable-next-line //solium-disable-next-line
_self.lastUpdateTimestamp = uint40(block.timestamp); reserve.lastUpdateTimestamp = uint40(block.timestamp);
} }
/** /**
* @dev accumulates a predefined amount of asset to the reserve as a fixed, one time income. Used for example to accumulate * @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. * the flashloan fee to the reserve, and spread it through the depositors.
* @param _self the reserve object * @param reserve the reserve object
* @param _totalLiquidity the total liquidity available in the reserve * @param totalLiquidity the total liquidity available in the reserve
* @param _amount the amount to accomulate * @param amount the amount to accomulate
**/ **/
function cumulateToLiquidityIndex( function cumulateToLiquidityIndex(
ReserveData storage _self, ReserveData storage reserve,
uint256 _totalLiquidity, uint256 totalLiquidity,
uint256 _amount uint256 amount
) internal { ) internal {
uint256 amountToLiquidityRatio = _amount.wadToRay().rayDiv(_totalLiquidity.wadToRay()); uint256 amountToLiquidityRatio = amount.wadToRay().rayDiv(totalLiquidity.wadToRay());
uint256 cumulatedLiquidity = amountToLiquidityRatio.add(WadRayMath.ray()); uint256 cumulatedLiquidity = amountToLiquidityRatio.add(WadRayMath.ray());
_self.lastLiquidityCumulativeIndex = cumulatedLiquidity.rayMul( reserve.lastLiquidityCumulativeIndex = cumulatedLiquidity.rayMul(
_self.lastLiquidityCumulativeIndex reserve.lastLiquidityCumulativeIndex
); );
} }
/** /**
* @dev initializes a reserve * @dev initializes a reserve
* @param _self the reserve object * @param reserve the reserve object
* @param _aTokenAddress the address of the overlying atoken contract * @param aTokenAddress the address of the overlying atoken contract
* @param _interestRateStrategyAddress the address of the interest rate strategy contract * @param interestRateStrategyAddress the address of the interest rate strategy contract
**/ **/
function init( function init(
ReserveData storage _self, ReserveData storage reserve,
address _aTokenAddress, address aTokenAddress,
address _stableDebtAddress, address _stableDebtAddress,
address _variableDebtAddress, address _variableDebtAddress,
address _interestRateStrategyAddress address interestRateStrategyAddress
) external { ) external {
require(_self.aTokenAddress == address(0), 'Reserve has already been initialized'); require(reserve.aTokenAddress == address(0), 'Reserve has already been initialized');
if (_self.lastLiquidityCumulativeIndex == 0) { if (reserve.lastLiquidityCumulativeIndex == 0) {
//if the reserve has not been initialized yet //if the reserve has not been initialized yet
_self.lastLiquidityCumulativeIndex = WadRayMath.ray(); reserve.lastLiquidityCumulativeIndex = WadRayMath.ray();
} }
if (_self.lastVariableBorrowCumulativeIndex == 0) { if (reserve.lastVariableBorrowCumulativeIndex == 0) {
_self.lastVariableBorrowCumulativeIndex = WadRayMath.ray(); reserve.lastVariableBorrowCumulativeIndex = WadRayMath.ray();
} }
_self.aTokenAddress = _aTokenAddress; reserve.aTokenAddress = aTokenAddress;
_self.stableDebtTokenAddress = _stableDebtAddress; reserve.stableDebtTokenAddress = _stableDebtAddress;
_self.variableDebtTokenAddress = _variableDebtAddress; reserve.variableDebtTokenAddress = _variableDebtAddress;
_self.interestRateStrategyAddress = _interestRateStrategyAddress; reserve.interestRateStrategyAddress = interestRateStrategyAddress;
}
/**
* @dev updates the state of the core as a result of a flashloan action
* @param _reserve the address of the reserve in which the flashloan is happening
* @param _income the income of the protocol as a result of the action
**/
function updateStateOnFlashLoan(
ReserveData storage _reserve,
address _reserveAddress,
uint256 _availableLiquidityBefore,
uint256 _income
) external {
//compounding the cumulated interest
_reserve.updateCumulativeIndexesAndTimestamp();
uint256 totalLiquidityBefore = _availableLiquidityBefore
.add(IERC20(_reserve.variableDebtTokenAddress).totalSupply())
.add(IERC20(_reserve.stableDebtTokenAddress).totalSupply());
//compounding the received fee into the reserve
_reserve.cumulateToLiquidityIndex(totalLiquidityBefore, _income);
//refresh interest rates
updateInterestRates(_reserve, _reserveAddress, _income, 0);
} }
/** /**
* @dev Updates the reserve current stable borrow rate Rf, the current variable borrow rate Rv and the current liquidity rate Rl. * @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. * Also updates the lastUpdateTimestamp value. Please refer to the whitepaper for further information.
* @param _reserve the address of the reserve to be updated * @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 _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) * @param _liquidityTaken the amount of liquidity taken from the protocol (redeem or borrow)
**/ **/
function updateInterestRates( function updateInterestRates(
ReserveData storage _reserve, ReserveData storage reserve,
address _reserveAddress, address reserveAddress,
uint256 _liquidityAdded, uint256 _liquidityAdded,
uint256 _liquidityTaken uint256 _liquidityTaken
) internal { ) internal {
uint256 currentAvgStableRate = IStableDebtToken(_reserve.stableDebtTokenAddress) uint256 currentAvgStableRate = IStableDebtToken(reserve.stableDebtTokenAddress)
.getAverageStableRate(); .getAverageStableRate();
uint256 balance = IERC20(_reserveAddress).balanceOf(_reserve.aTokenAddress); uint256 balance = IERC20(reserveAddress).balanceOf(reserve.aTokenAddress);
( (
uint256 newLiquidityRate, uint256 newLiquidityRate,
uint256 newStableRate, uint256 newStableRate,
uint256 newVariableRate uint256 newVariableRate
) = IReserveInterestRateStrategy(_reserve.interestRateStrategyAddress).calculateInterestRates( ) = IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).calculateInterestRates(
_reserveAddress, reserveAddress,
balance.add(_liquidityAdded).sub(_liquidityTaken), balance.add(_liquidityAdded).sub(_liquidityTaken),
IERC20(_reserve.stableDebtTokenAddress).totalSupply(), IERC20(reserve.stableDebtTokenAddress).totalSupply(),
IERC20(_reserve.variableDebtTokenAddress).totalSupply(), IERC20(reserve.variableDebtTokenAddress).totalSupply(),
currentAvgStableRate currentAvgStableRate
); );
_reserve.currentLiquidityRate = newLiquidityRate; reserve.currentLiquidityRate = newLiquidityRate;
_reserve.currentStableBorrowRate = newStableRate; reserve.currentStableBorrowRate = newStableRate;
_reserve.currentVariableBorrowRate = newVariableRate; reserve.currentVariableBorrowRate = newVariableRate;
emit ReserveDataUpdated( emit ReserveDataUpdated(
_reserveAddress, reserveAddress,
newLiquidityRate, newLiquidityRate,
newStableRate, newStableRate,
currentAvgStableRate, currentAvgStableRate,
newVariableRate, newVariableRate,
_reserve.lastLiquidityCumulativeIndex, reserve.lastLiquidityCumulativeIndex,
_reserve.lastVariableBorrowCumulativeIndex reserve.lastVariableBorrowCumulativeIndex
); );
} }
} }