refactor: further refactored the cache helper functions

This commit is contained in:
The3D 2021-06-07 18:02:13 +02:00
parent c794a697a7
commit 86686ef3be
8 changed files with 260 additions and 245 deletions

View File

@ -26,7 +26,6 @@ import {ReserveConfiguration} from '../libraries/configuration/ReserveConfigurat
import {UserConfiguration} from '../libraries/configuration/UserConfiguration.sol'; import {UserConfiguration} from '../libraries/configuration/UserConfiguration.sol';
import {DataTypes} from '../libraries/types/DataTypes.sol'; import {DataTypes} from '../libraries/types/DataTypes.sol';
import {LendingPoolStorage} from './LendingPoolStorage.sol'; import {LendingPoolStorage} from './LendingPoolStorage.sol';
import {CachingHelper} from '../libraries/helpers/CachingHelper.sol';
/** /**
* @title LendingPool contract * @title LendingPool contract
@ -270,7 +269,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
**/ **/
function swapBorrowRateMode(address asset, uint256 rateMode) external override whenNotPaused { function swapBorrowRateMode(address asset, uint256 rateMode) external override whenNotPaused {
DataTypes.ReserveData storage reserve = _reserves[asset]; DataTypes.ReserveData storage reserve = _reserves[asset];
CachingHelper.CachedData memory cachedData = CachingHelper.fetchData(reserve); DataTypes.ReserveCache memory reserveCache = reserve.cache();
(uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(msg.sender, reserve); (uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(msg.sender, reserve);
@ -278,53 +277,54 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
ValidationLogic.validateSwapRateMode( ValidationLogic.validateSwapRateMode(
reserve, reserve,
reserveCache,
_usersConfig[msg.sender], _usersConfig[msg.sender],
stableDebt, stableDebt,
variableDebt, variableDebt,
interestRateMode interestRateMode
); );
reserve.updateState(cachedData); reserve.updateState(reserveCache);
if (interestRateMode == DataTypes.InterestRateMode.STABLE) { if (interestRateMode == DataTypes.InterestRateMode.STABLE) {
IStableDebtToken(cachedData.stableDebtTokenAddress).burn(msg.sender, stableDebt); IStableDebtToken(reserveCache.stableDebtTokenAddress).burn(msg.sender, stableDebt);
cachedData.newPrincipalStableDebt = cachedData.newTotalStableDebt = cachedData reserveCache.newPrincipalStableDebt = reserveCache.newTotalStableDebt = reserveCache
.oldTotalStableDebt .oldTotalStableDebt
.sub(stableDebt); .sub(stableDebt);
IVariableDebtToken(cachedData.variableDebtTokenAddress).mint( IVariableDebtToken(reserveCache.variableDebtTokenAddress).mint(
msg.sender, msg.sender,
msg.sender, msg.sender,
stableDebt, stableDebt,
cachedData.newVariableBorrowIndex reserveCache.newVariableBorrowIndex
); );
cachedData.newScaledVariableDebt = cachedData.oldScaledVariableDebt.add( reserveCache.newScaledVariableDebt = reserveCache.oldScaledVariableDebt.add(
stableDebt.rayDiv(cachedData.newVariableBorrowIndex) stableDebt.rayDiv(reserveCache.newVariableBorrowIndex)
); );
} else { } else {
IVariableDebtToken(cachedData.variableDebtTokenAddress).burn( IVariableDebtToken(reserveCache.variableDebtTokenAddress).burn(
msg.sender, msg.sender,
variableDebt, variableDebt,
cachedData.newVariableBorrowIndex reserveCache.newVariableBorrowIndex
); );
cachedData.newScaledVariableDebt = cachedData.oldScaledVariableDebt.sub( reserveCache.newScaledVariableDebt = reserveCache.oldScaledVariableDebt.sub(
variableDebt.rayDiv(cachedData.newVariableBorrowIndex) variableDebt.rayDiv(reserveCache.newVariableBorrowIndex)
); );
IStableDebtToken(cachedData.stableDebtTokenAddress).mint( IStableDebtToken(reserveCache.stableDebtTokenAddress).mint(
msg.sender, msg.sender,
msg.sender, msg.sender,
variableDebt, variableDebt,
reserve.currentStableBorrowRate reserve.currentStableBorrowRate
); );
cachedData.newPrincipalStableDebt = cachedData.newTotalStableDebt = cachedData reserveCache.newPrincipalStableDebt = reserveCache.newTotalStableDebt = reserveCache
.oldTotalStableDebt .oldTotalStableDebt
.add(stableDebt); .add(stableDebt);
} }
reserve.updateInterestRates(cachedData, asset, 0, 0); reserve.updateInterestRates(reserveCache, asset, 0, 0);
emit Swap(asset, msg.sender, rateMode); emit Swap(asset, msg.sender, rateMode);
} }
@ -340,21 +340,22 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
**/ **/
function rebalanceStableBorrowRate(address asset, address user) external override whenNotPaused { function rebalanceStableBorrowRate(address asset, address user) external override whenNotPaused {
DataTypes.ReserveData storage reserve = _reserves[asset]; DataTypes.ReserveData storage reserve = _reserves[asset];
CachingHelper.CachedData memory cachedData = CachingHelper.fetchData(reserve); DataTypes.ReserveCache memory reserveCache = reserve.cache();
IERC20 stableDebtToken = IERC20(cachedData.stableDebtTokenAddress); IERC20 stableDebtToken = IERC20(reserveCache.stableDebtTokenAddress);
IERC20 variableDebtToken = IERC20(cachedData.variableDebtTokenAddress); IERC20 variableDebtToken = IERC20(reserveCache.variableDebtTokenAddress);
uint256 stableDebt = IERC20(stableDebtToken).balanceOf(user); uint256 stableDebt = IERC20(stableDebtToken).balanceOf(user);
ValidationLogic.validateRebalanceStableBorrowRate( ValidationLogic.validateRebalanceStableBorrowRate(
reserve, reserve,
reserveCache,
asset, asset,
stableDebtToken, stableDebtToken,
variableDebtToken, variableDebtToken,
cachedData.aTokenAddress reserveCache.aTokenAddress
); );
reserve.updateState(cachedData); reserve.updateState(reserveCache);
IStableDebtToken(address(stableDebtToken)).burn(user, stableDebt); IStableDebtToken(address(stableDebtToken)).burn(user, stableDebt);
IStableDebtToken(address(stableDebtToken)).mint( IStableDebtToken(address(stableDebtToken)).mint(
@ -364,7 +365,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
reserve.currentStableBorrowRate reserve.currentStableBorrowRate
); );
reserve.updateInterestRates(cachedData, asset, 0, 0); reserve.updateInterestRates(reserveCache, asset, 0, 0);
emit RebalanceStableBorrowRate(asset, user); emit RebalanceStableBorrowRate(asset, user);
} }
@ -380,8 +381,9 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
whenNotPaused whenNotPaused
{ {
DataTypes.ReserveData storage reserve = _reserves[asset]; DataTypes.ReserveData storage reserve = _reserves[asset];
DataTypes.ReserveCache memory reserveCache = reserve.cache();
ValidationLogic.validateSetUseReserveAsCollateral(reserve); ValidationLogic.validateSetUseReserveAsCollateral(reserve, reserveCache);
_usersConfig[msg.sender].setUsingAsCollateral(reserve.id, useAsCollateral); _usersConfig[msg.sender].setUsingAsCollateral(reserve.id, useAsCollateral);
@ -512,15 +514,15 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
if (DataTypes.InterestRateMode(modes[vars.i]) == DataTypes.InterestRateMode.NONE) { if (DataTypes.InterestRateMode(modes[vars.i]) == DataTypes.InterestRateMode.NONE) {
DataTypes.ReserveData storage reserve = _reserves[vars.currentAsset]; DataTypes.ReserveData storage reserve = _reserves[vars.currentAsset];
CachingHelper.CachedData memory cachedData = CachingHelper.fetchData(reserve); DataTypes.ReserveCache memory reserveCache = reserve.cache();
reserve.updateState(cachedData); reserve.updateState(reserveCache);
reserve.cumulateToLiquidityIndex( reserve.cumulateToLiquidityIndex(
IERC20(vars.currentATokenAddress).totalSupply(), IERC20(vars.currentATokenAddress).totalSupply(),
vars.currentPremium vars.currentPremium
); );
reserve.updateInterestRates( reserve.updateInterestRates(
cachedData, reserveCache,
vars.currentAsset, vars.currentAsset,
vars.currentAmountPlusPremium, vars.currentAmountPlusPremium,
0 0
@ -894,12 +896,12 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
function _executeBorrow(ExecuteBorrowParams memory vars) internal { function _executeBorrow(ExecuteBorrowParams memory vars) internal {
DataTypes.ReserveData storage reserve = _reserves[vars.asset]; DataTypes.ReserveData storage reserve = _reserves[vars.asset];
DataTypes.UserConfigurationMap storage userConfig = _usersConfig[vars.onBehalfOf]; DataTypes.UserConfigurationMap storage userConfig = _usersConfig[vars.onBehalfOf];
CachingHelper.CachedData memory cachedData = CachingHelper.fetchData(reserve); DataTypes.ReserveCache memory reserveCache = reserve.cache();
reserve.updateState(cachedData); reserve.updateState(reserveCache);
ValidationLogic.validateBorrow( ValidationLogic.validateBorrow(
cachedData, reserveCache,
vars.asset, vars.asset,
vars.onBehalfOf, vars.onBehalfOf,
vars.amount, vars.amount,
@ -918,27 +920,27 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
if (DataTypes.InterestRateMode(vars.interestRateMode) == DataTypes.InterestRateMode.STABLE) { if (DataTypes.InterestRateMode(vars.interestRateMode) == DataTypes.InterestRateMode.STABLE) {
currentStableRate = reserve.currentStableBorrowRate; currentStableRate = reserve.currentStableBorrowRate;
isFirstBorrowing = IStableDebtToken(cachedData.stableDebtTokenAddress).mint( isFirstBorrowing = IStableDebtToken(reserveCache.stableDebtTokenAddress).mint(
vars.user, vars.user,
vars.onBehalfOf, vars.onBehalfOf,
vars.amount, vars.amount,
currentStableRate currentStableRate
); );
cachedData.newPrincipalStableDebt = cachedData.newTotalStableDebt = cachedData reserveCache.newPrincipalStableDebt = reserveCache.newTotalStableDebt = reserveCache
.oldTotalStableDebt .oldTotalStableDebt
.add(vars.amount); .add(vars.amount);
} else { } else {
isFirstBorrowing = IVariableDebtToken(cachedData.variableDebtTokenAddress).mint( isFirstBorrowing = IVariableDebtToken(reserveCache.variableDebtTokenAddress).mint(
vars.user, vars.user,
vars.onBehalfOf, vars.onBehalfOf,
vars.amount, vars.amount,
cachedData.newVariableBorrowIndex reserveCache.newVariableBorrowIndex
); );
cachedData.newScaledVariableDebt = cachedData.newScaledVariableDebt.add( reserveCache.newScaledVariableDebt = reserveCache.newScaledVariableDebt.add(
vars.amount.rayDiv(cachedData.newVariableBorrowIndex) vars.amount.rayDiv(reserveCache.newVariableBorrowIndex)
); );
} }
@ -947,14 +949,14 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
} }
reserve.updateInterestRates( reserve.updateInterestRates(
cachedData, reserveCache,
vars.asset, vars.asset,
0, 0,
vars.releaseUnderlying ? vars.amount : 0 vars.releaseUnderlying ? vars.amount : 0
); );
if (vars.releaseUnderlying) { if (vars.releaseUnderlying) {
IAToken(cachedData.aTokenAddress).transferUnderlyingTo(vars.user, vars.amount); IAToken(reserveCache.aTokenAddress).transferUnderlyingTo(vars.user, vars.amount);
} }
emit Borrow( emit Borrow(
@ -977,18 +979,18 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
uint16 referralCode uint16 referralCode
) internal { ) internal {
DataTypes.ReserveData storage reserve = _reserves[asset]; DataTypes.ReserveData storage reserve = _reserves[asset];
CachingHelper.CachedData memory cachedData = CachingHelper.fetchData(reserve); DataTypes.ReserveCache memory reserveCache = reserve.cache();
reserve.updateState(cachedData); reserve.updateState(reserveCache);
ValidationLogic.validateDeposit(reserve, cachedData, amount); ValidationLogic.validateDeposit(reserve, reserveCache, amount);
reserve.updateInterestRates(cachedData, asset, amount, 0); reserve.updateInterestRates(reserveCache, asset, amount, 0);
IERC20(asset).safeTransferFrom(msg.sender, cachedData.aTokenAddress, amount); IERC20(asset).safeTransferFrom(msg.sender, reserveCache.aTokenAddress, amount);
bool isFirstDeposit = bool isFirstDeposit =
IAToken(cachedData.aTokenAddress).mint(onBehalfOf, amount, cachedData.newLiquidityIndex); IAToken(reserveCache.aTokenAddress).mint(onBehalfOf, amount, reserveCache.newLiquidityIndex);
if (isFirstDeposit) { if (isFirstDeposit) {
_usersConfig[onBehalfOf].setUsingAsCollateral(reserve.id, true); _usersConfig[onBehalfOf].setUsingAsCollateral(reserve.id, true);
@ -1005,13 +1007,13 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
) internal returns (uint256) { ) internal returns (uint256) {
DataTypes.ReserveData storage reserve = _reserves[asset]; DataTypes.ReserveData storage reserve = _reserves[asset];
DataTypes.UserConfigurationMap storage userConfig = _usersConfig[msg.sender]; DataTypes.UserConfigurationMap storage userConfig = _usersConfig[msg.sender];
CachingHelper.CachedData memory cachedData = CachingHelper.fetchData(reserve); DataTypes.ReserveCache memory reserveCache = reserve.cache();
reserve.updateState(cachedData); reserve.updateState(reserveCache);
uint256 userBalance = uint256 userBalance =
IAToken(cachedData.aTokenAddress).scaledBalanceOf(msg.sender).rayMul( IAToken(reserveCache.aTokenAddress).scaledBalanceOf(msg.sender).rayMul(
cachedData.newLiquidityIndex reserveCache.newLiquidityIndex
); );
uint256 amountToWithdraw = amount; uint256 amountToWithdraw = amount;
@ -1020,15 +1022,15 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
amountToWithdraw = userBalance; amountToWithdraw = userBalance;
} }
ValidationLogic.validateWithdraw(reserve, amountToWithdraw, userBalance); ValidationLogic.validateWithdraw(reserve, reserveCache, amountToWithdraw, userBalance);
reserve.updateInterestRates(cachedData, asset, 0, amountToWithdraw); reserve.updateInterestRates(reserveCache, asset, 0, amountToWithdraw);
IAToken(cachedData.aTokenAddress).burn( IAToken(reserveCache.aTokenAddress).burn(
msg.sender, msg.sender,
to, to,
amountToWithdraw, amountToWithdraw,
cachedData.newLiquidityIndex reserveCache.newLiquidityIndex
); );
if (userConfig.isUsingAsCollateral(reserve.id)) { if (userConfig.isUsingAsCollateral(reserve.id)) {
@ -1061,7 +1063,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
address onBehalfOf address onBehalfOf
) internal returns (uint256) { ) internal returns (uint256) {
DataTypes.ReserveData storage reserve = _reserves[asset]; DataTypes.ReserveData storage reserve = _reserves[asset];
CachingHelper.CachedData memory cachedData = CachingHelper.fetchData(reserve); DataTypes.ReserveCache memory reserveCache = reserve.cache();
(uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(onBehalfOf, reserve); (uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(onBehalfOf, reserve);
@ -1069,6 +1071,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
ValidationLogic.validateRepay( ValidationLogic.validateRepay(
reserve, reserve,
reserveCache,
amount, amount,
interestRateMode, interestRateMode,
onBehalfOf, onBehalfOf,
@ -1083,33 +1086,33 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
paybackAmount = amount; paybackAmount = amount;
} }
reserve.updateState(cachedData); reserve.updateState(reserveCache);
if (interestRateMode == DataTypes.InterestRateMode.STABLE) { if (interestRateMode == DataTypes.InterestRateMode.STABLE) {
IStableDebtToken(cachedData.stableDebtTokenAddress).burn(onBehalfOf, paybackAmount); IStableDebtToken(reserveCache.stableDebtTokenAddress).burn(onBehalfOf, paybackAmount);
cachedData.newPrincipalStableDebt = cachedData.newTotalStableDebt = cachedData reserveCache.newPrincipalStableDebt = reserveCache.newTotalStableDebt = reserveCache
.oldTotalStableDebt .oldTotalStableDebt
.sub(paybackAmount); .sub(paybackAmount);
} else { } else {
IVariableDebtToken(cachedData.variableDebtTokenAddress).burn( IVariableDebtToken(reserveCache.variableDebtTokenAddress).burn(
onBehalfOf, onBehalfOf,
paybackAmount, paybackAmount,
cachedData.newVariableBorrowIndex reserveCache.newVariableBorrowIndex
); );
cachedData.newScaledVariableDebt = cachedData.oldScaledVariableDebt.sub( reserveCache.newScaledVariableDebt = reserveCache.oldScaledVariableDebt.sub(
paybackAmount.rayDiv(cachedData.newVariableBorrowIndex) paybackAmount.rayDiv(reserveCache.newVariableBorrowIndex)
); );
} }
reserve.updateInterestRates(cachedData, asset, paybackAmount, 0); reserve.updateInterestRates(reserveCache, asset, paybackAmount, 0);
if (stableDebt.add(variableDebt).sub(paybackAmount) == 0) { if (stableDebt.add(variableDebt).sub(paybackAmount) == 0) {
_usersConfig[onBehalfOf].setBorrowing(reserve.id, false); _usersConfig[onBehalfOf].setBorrowing(reserve.id, false);
} }
IERC20(asset).safeTransferFrom(msg.sender, cachedData.aTokenAddress, paybackAmount); IERC20(asset).safeTransferFrom(msg.sender, reserveCache.aTokenAddress, paybackAmount);
IAToken(cachedData.aTokenAddress).handleRepayment(msg.sender, paybackAmount); IAToken(reserveCache.aTokenAddress).handleRepayment(msg.sender, paybackAmount);
emit Repay(asset, onBehalfOf, msg.sender, paybackAmount); emit Repay(asset, onBehalfOf, msg.sender, paybackAmount);

View File

@ -18,7 +18,6 @@ import {Errors} from '../libraries/helpers/Errors.sol';
import {ValidationLogic} from '../libraries/logic/ValidationLogic.sol'; import {ValidationLogic} from '../libraries/logic/ValidationLogic.sol';
import {DataTypes} from '../libraries/types/DataTypes.sol'; import {DataTypes} from '../libraries/types/DataTypes.sol';
import {LendingPoolStorage} from './LendingPoolStorage.sol'; import {LendingPoolStorage} from './LendingPoolStorage.sol';
import {CachingHelper} from '../libraries/helpers/CachingHelper.sol';
/** /**
* @title LendingPoolCollateralManager contract * @title LendingPoolCollateralManager contract
@ -101,11 +100,16 @@ contract LendingPoolCollateralManager is
_addressesProvider.getPriceOracle() _addressesProvider.getPriceOracle()
); );
DataTypes.ReserveCache memory debtReserveCache = debtReserve.cache();
DataTypes.ReserveCache memory collateralReserveCache = collateralReserve.cache();
(vars.userStableDebt, vars.userVariableDebt) = Helpers.getUserCurrentDebt(user, debtReserve); (vars.userStableDebt, vars.userVariableDebt) = Helpers.getUserCurrentDebt(user, debtReserve);
(vars.errorCode, vars.errorMsg) = ValidationLogic.validateLiquidationCall( (vars.errorCode, vars.errorMsg) = ValidationLogic.validateLiquidationCall(
collateralReserve, collateralReserve,
debtReserve, debtReserve,
debtReserveCache,
collateralReserveCache,
userConfig, userConfig,
vars.healthFactor, vars.healthFactor,
vars.userStableDebt, vars.userStableDebt,
@ -161,44 +165,42 @@ contract LendingPoolCollateralManager is
} }
} }
CachingHelper.CachedData memory debtReserveCachedData = CachingHelper.fetchData(debtReserve); debtReserve.updateState(debtReserveCache);
debtReserve.updateState(debtReserveCachedData);
if (vars.userVariableDebt >= vars.actualDebtToLiquidate) { if (vars.userVariableDebt >= vars.actualDebtToLiquidate) {
IVariableDebtToken(debtReserveCachedData.variableDebtTokenAddress).burn( IVariableDebtToken(debtReserveCache.variableDebtTokenAddress).burn(
user, user,
vars.actualDebtToLiquidate, vars.actualDebtToLiquidate,
debtReserveCachedData.newVariableBorrowIndex debtReserveCache.newVariableBorrowIndex
); );
debtReserveCachedData.newScaledVariableDebt = debtReserveCachedData.oldScaledVariableDebt.sub( debtReserveCache.newScaledVariableDebt = debtReserveCache.oldScaledVariableDebt.sub(
vars.actualDebtToLiquidate.rayDiv(debtReserveCachedData.newVariableBorrowIndex) vars.actualDebtToLiquidate.rayDiv(debtReserveCache.newVariableBorrowIndex)
); );
} else { } else {
// If the user doesn't have variable debt, no need to try to burn variable debt tokens // If the user doesn't have variable debt, no need to try to burn variable debt tokens
if (vars.userVariableDebt > 0) { if (vars.userVariableDebt > 0) {
IVariableDebtToken(debtReserveCachedData.variableDebtTokenAddress).burn( IVariableDebtToken(debtReserveCache.variableDebtTokenAddress).burn(
user, user,
vars.userVariableDebt, vars.userVariableDebt,
debtReserveCachedData.newVariableBorrowIndex debtReserveCache.newVariableBorrowIndex
); );
debtReserveCachedData.newScaledVariableDebt = debtReserveCachedData debtReserveCache.newScaledVariableDebt = debtReserveCache
.oldScaledVariableDebt .oldScaledVariableDebt
.sub(vars.userVariableDebt.rayDiv(debtReserveCachedData.newVariableBorrowIndex)); .sub(vars.userVariableDebt.rayDiv(debtReserveCache.newVariableBorrowIndex));
} }
IStableDebtToken(debtReserveCachedData.stableDebtTokenAddress).burn( IStableDebtToken(debtReserveCache.stableDebtTokenAddress).burn(
user, user,
vars.actualDebtToLiquidate.sub(vars.userVariableDebt) vars.actualDebtToLiquidate.sub(vars.userVariableDebt)
); );
debtReserveCachedData.newPrincipalStableDebt = debtReserveCachedData debtReserveCache.newPrincipalStableDebt = debtReserveCache
.newTotalStableDebt = debtReserveCachedData.oldTotalStableDebt.sub( .newTotalStableDebt = debtReserveCache.oldTotalStableDebt.sub(
vars.actualDebtToLiquidate.sub(vars.userVariableDebt) vars.actualDebtToLiquidate.sub(vars.userVariableDebt)
); );
} }
debtReserve.updateInterestRates( debtReserve.updateInterestRates(
debtReserveCachedData, debtReserveCache,
debtAsset, debtAsset,
vars.actualDebtToLiquidate, vars.actualDebtToLiquidate,
0 0
@ -214,12 +216,9 @@ contract LendingPoolCollateralManager is
emit ReserveUsedAsCollateralEnabled(collateralAsset, msg.sender); emit ReserveUsedAsCollateralEnabled(collateralAsset, msg.sender);
} }
} else { } else {
CachingHelper.CachedData memory collateralReserveCachedData = collateralReserve.updateState(collateralReserveCache);
CachingHelper.fetchData(collateralReserve);
collateralReserve.updateState(collateralReserveCachedData);
collateralReserve.updateInterestRates( collateralReserve.updateInterestRates(
collateralReserveCachedData, collateralReserveCache,
collateralAsset, collateralAsset,
0, 0,
vars.maxCollateralToLiquidate vars.maxCollateralToLiquidate

View File

@ -104,6 +104,18 @@ library ReserveConfiguration {
return (self.data & ~LIQUIDATION_THRESHOLD_MASK) >> LIQUIDATION_THRESHOLD_START_BIT_POSITION; return (self.data & ~LIQUIDATION_THRESHOLD_MASK) >> LIQUIDATION_THRESHOLD_START_BIT_POSITION;
} }
/**
* @dev Gets the liquidation threshold of the reserve
* @param self The reserve configuration
* @return The liquidation threshold
**/
function getLiquidationThresholdMemory(DataTypes.ReserveConfigurationMap memory self)
internal
view
returns (uint256)
{
return (self.data & ~LIQUIDATION_THRESHOLD_MASK) >> LIQUIDATION_THRESHOLD_START_BIT_POSITION;
}
/** /**
* @dev Sets the liquidation bonus of the reserve * @dev Sets the liquidation bonus of the reserve
* @param self The reserve configuration * @param self The reserve configuration

View File

@ -1,73 +0,0 @@
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import {DataTypes} from '../types/DataTypes.sol';
import {IVariableDebtToken} from '../../../interfaces/IVariableDebtToken.sol';
import {IStableDebtToken} from '../../../interfaces/IStableDebtToken.sol';
library CachingHelper {
struct CachedData {
uint256 oldScaledVariableDebt;
uint256 oldTotalVariableDebt;
uint256 newScaledVariableDebt;
uint256 newTotalVariableDebt;
uint256 oldPrincipalStableDebt;
uint256 oldAvgStableBorrowRate;
uint256 oldTotalStableDebt;
uint256 newPrincipalStableDebt;
uint256 newAvgStableBorrowRate;
uint256 newTotalStableDebt;
uint256 oldLiquidityIndex;
uint256 newLiquidityIndex;
uint256 oldVariableBorrowIndex;
uint256 newVariableBorrowIndex;
uint256 oldLiquidityRate;
uint256 oldVariableBorrowRate;
DataTypes.ReserveConfigurationMap reserveConfiguration;
address aTokenAddress;
address stableDebtTokenAddress;
address variableDebtTokenAddress;
uint40 reserveLastUpdateTimestamp;
uint40 stableDebtLastUpdateTimestamp;
}
function fetchData(DataTypes.ReserveData storage reserveData)
internal
view
returns (CachingHelper.CachedData memory)
{
CachedData memory cachedData;
cachedData.reserveConfiguration = reserveData.configuration;
cachedData.oldLiquidityIndex = reserveData.liquidityIndex;
cachedData.oldVariableBorrowIndex = reserveData.variableBorrowIndex;
cachedData.oldLiquidityRate = reserveData.currentLiquidityRate;
cachedData.oldVariableBorrowRate = reserveData.currentVariableBorrowRate;
cachedData.aTokenAddress = reserveData.aTokenAddress;
cachedData.stableDebtTokenAddress = reserveData.stableDebtTokenAddress;
cachedData.variableDebtTokenAddress = reserveData.variableDebtTokenAddress;
cachedData.reserveLastUpdateTimestamp = reserveData.lastUpdateTimestamp;
cachedData.oldScaledVariableDebt = cachedData.newScaledVariableDebt = IVariableDebtToken(
cachedData
.variableDebtTokenAddress
)
.scaledTotalSupply();
(
cachedData.oldPrincipalStableDebt,
cachedData.oldTotalStableDebt,
cachedData.oldAvgStableBorrowRate,
cachedData.stableDebtLastUpdateTimestamp
) = IStableDebtToken(cachedData.stableDebtTokenAddress).getSupplyData();
cachedData.newPrincipalStableDebt = cachedData.oldPrincipalStableDebt;
cachedData.newTotalStableDebt = cachedData.oldTotalStableDebt;
cachedData.newAvgStableBorrowRate = cachedData.oldAvgStableBorrowRate;
return cachedData;
}
}

View File

@ -14,7 +14,6 @@ import {WadRayMath} from '../math/WadRayMath.sol';
import {PercentageMath} from '../math/PercentageMath.sol'; import {PercentageMath} from '../math/PercentageMath.sol';
import {Errors} from '../helpers/Errors.sol'; import {Errors} from '../helpers/Errors.sol';
import {DataTypes} from '../types/DataTypes.sol'; import {DataTypes} from '../types/DataTypes.sol';
import {CachingHelper} from '../helpers/CachingHelper.sol';
/** /**
* @title ReserveLogic library * @title ReserveLogic library
@ -110,11 +109,10 @@ library ReserveLogic {
**/ **/
function updateState( function updateState(
DataTypes.ReserveData storage reserve, DataTypes.ReserveData storage reserve,
CachingHelper.CachedData memory cachedData DataTypes.ReserveCache memory reserveCache
) internal { ) internal {
_updateIndexes(reserve, cachedData); _updateIndexes(reserve, reserveCache);
_accrueToTreasury(reserve, reserveCache);
_accrueToTreasury(reserve, cachedData);
} }
/** /**
@ -181,20 +179,20 @@ library ReserveLogic {
**/ **/
function updateInterestRates( function updateInterestRates(
DataTypes.ReserveData storage reserve, DataTypes.ReserveData storage reserve,
CachingHelper.CachedData memory cachedData, DataTypes.ReserveCache memory reserveCache,
address reserveAddress, address reserveAddress,
uint256 liquidityAdded, uint256 liquidityAdded,
uint256 liquidityTaken uint256 liquidityTaken
) internal { ) internal {
UpdateInterestRatesLocalVars memory vars; UpdateInterestRatesLocalVars memory vars;
if (cachedData.oldTotalStableDebt != cachedData.newTotalStableDebt) { if (reserveCache.oldTotalStableDebt != reserveCache.newTotalStableDebt) {
cachedData.newAvgStableBorrowRate = IStableDebtToken(cachedData.stableDebtTokenAddress) reserveCache.newAvgStableBorrowRate = IStableDebtToken(reserveCache.stableDebtTokenAddress)
.getAverageStableRate(); .getAverageStableRate();
} }
cachedData.newTotalVariableDebt = cachedData.newScaledVariableDebt.rayMul( reserveCache.newTotalVariableDebt = reserveCache.newScaledVariableDebt.rayMul(
cachedData.newVariableBorrowIndex reserveCache.newVariableBorrowIndex
); );
( (
@ -203,13 +201,13 @@ library ReserveLogic {
vars.newVariableRate vars.newVariableRate
) = IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).calculateInterestRates( ) = IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).calculateInterestRates(
reserveAddress, reserveAddress,
cachedData.aTokenAddress, reserveCache.aTokenAddress,
liquidityAdded, liquidityAdded,
liquidityTaken, liquidityTaken,
cachedData.newTotalStableDebt, reserveCache.newTotalStableDebt,
cachedData.newTotalVariableDebt, reserveCache.newTotalVariableDebt,
cachedData.newAvgStableBorrowRate, reserveCache.newAvgStableBorrowRate,
cachedData.reserveConfiguration.getReserveFactorMemory() reserveCache.reserveConfiguration.getReserveFactorMemory()
); );
require(vars.newLiquidityRate <= type(uint128).max, Errors.RL_LIQUIDITY_RATE_OVERFLOW); require(vars.newLiquidityRate <= type(uint128).max, Errors.RL_LIQUIDITY_RATE_OVERFLOW);
require(vars.newStableRate <= type(uint128).max, Errors.RL_STABLE_BORROW_RATE_OVERFLOW); require(vars.newStableRate <= type(uint128).max, Errors.RL_STABLE_BORROW_RATE_OVERFLOW);
@ -224,8 +222,8 @@ library ReserveLogic {
vars.newLiquidityRate, vars.newLiquidityRate,
vars.newStableRate, vars.newStableRate,
vars.newVariableRate, vars.newVariableRate,
cachedData.newLiquidityIndex, reserveCache.newLiquidityIndex,
cachedData.newVariableBorrowIndex reserveCache.newVariableBorrowIndex
); );
} }
@ -247,43 +245,45 @@ library ReserveLogic {
* @dev Mints part of the repaid interest to the reserve treasury as a function of the reserveFactor for the * @dev Mints part of the repaid interest to the reserve treasury as a function of the reserveFactor for the
* specific asset. * specific asset.
* @param reserve The reserve reserve to be updated * @param reserve The reserve reserve to be updated
* @param cachedData The caching layer for the reserve data * @param reserveCache The caching layer for the reserve data
**/ **/
function _accrueToTreasury( function _accrueToTreasury(
DataTypes.ReserveData storage reserve, DataTypes.ReserveData storage reserve,
CachingHelper.CachedData memory cachedData DataTypes.ReserveCache memory reserveCache
) internal { ) internal {
MintToTreasuryLocalVars memory vars; MintToTreasuryLocalVars memory vars;
vars.reserveFactor = cachedData.reserveConfiguration.getReserveFactorMemory(); vars.reserveFactor = reserveCache.reserveConfiguration.getReserveFactorMemory();
if (vars.reserveFactor == 0) { if (vars.reserveFactor == 0) {
return; return;
} }
//calculate the last principal variable debt //calculate the last principal variable debt
vars.previousVariableDebt = cachedData.oldScaledVariableDebt.rayMul( vars.previousVariableDebt = reserveCache.oldScaledVariableDebt.rayMul(
cachedData.oldVariableBorrowIndex reserveCache.oldVariableBorrowIndex
); );
//calculate the new total supply after accumulation of the index //calculate the new total supply after accumulation of the index
vars.currentVariableDebt = cachedData.oldScaledVariableDebt.rayMul( vars.currentVariableDebt = reserveCache.oldScaledVariableDebt.rayMul(
cachedData.newVariableBorrowIndex reserveCache.newVariableBorrowIndex
); );
//calculate the stable debt until the last timestamp update //calculate the stable debt until the last timestamp update
vars.cumulatedStableInterest = MathUtils.calculateCompoundedInterest( vars.cumulatedStableInterest = MathUtils.calculateCompoundedInterest(
cachedData.oldAvgStableBorrowRate, reserveCache.oldAvgStableBorrowRate,
cachedData.stableDebtLastUpdateTimestamp, reserveCache.stableDebtLastUpdateTimestamp,
cachedData.reserveLastUpdateTimestamp reserveCache.reserveLastUpdateTimestamp
); );
vars.previousStableDebt = cachedData.oldPrincipalStableDebt.rayMul(vars.cumulatedStableInterest); vars.previousStableDebt = reserveCache.oldPrincipalStableDebt.rayMul(
vars.cumulatedStableInterest
);
//debt accrued is the sum of the current debt minus the sum of the debt at the last update //debt accrued is the sum of the current debt minus the sum of the debt at the last update
vars.totalDebtAccrued = vars vars.totalDebtAccrued = vars
.currentVariableDebt .currentVariableDebt
.add(cachedData.oldTotalStableDebt) .add(reserveCache.oldTotalStableDebt)
.sub(vars.previousVariableDebt) .sub(vars.previousVariableDebt)
.sub(vars.previousStableDebt); .sub(vars.previousStableDebt);
@ -291,7 +291,7 @@ library ReserveLogic {
if (vars.amountToMint != 0) { if (vars.amountToMint != 0) {
reserve.accruedToTreasury = reserve.accruedToTreasury.add( reserve.accruedToTreasury = reserve.accruedToTreasury.add(
vars.amountToMint.rayDiv(cachedData.newLiquidityIndex) vars.amountToMint.rayDiv(reserveCache.newLiquidityIndex)
); );
} }
} }
@ -299,52 +299,90 @@ library ReserveLogic {
/** /**
* @dev Updates the reserve indexes and the timestamp of the update * @dev Updates the reserve indexes and the timestamp of the update
* @param reserve The reserve reserve to be updated * @param reserve The reserve reserve to be updated
* @param cachedData The cache layer holding the cached protocol data * @param reserveCache The cache layer holding the cached protocol data
**/ **/
function _updateIndexes( function _updateIndexes(
DataTypes.ReserveData storage reserve, DataTypes.ReserveData storage reserve,
CachingHelper.CachedData memory cachedData DataTypes.ReserveCache memory reserveCache
) internal { ) internal {
cachedData.newLiquidityIndex = cachedData.oldLiquidityIndex; reserveCache.newLiquidityIndex = reserveCache.oldLiquidityIndex;
cachedData.newVariableBorrowIndex = cachedData.oldVariableBorrowIndex; reserveCache.newVariableBorrowIndex = reserveCache.oldVariableBorrowIndex;
//only cumulating if there is any income being produced //only cumulating if there is any income being produced
if (cachedData.oldLiquidityRate > 0) { if (reserveCache.oldLiquidityRate > 0) {
uint256 cumulatedLiquidityInterest = uint256 cumulatedLiquidityInterest =
MathUtils.calculateLinearInterest( MathUtils.calculateLinearInterest(
cachedData.oldLiquidityRate, reserveCache.oldLiquidityRate,
cachedData.reserveLastUpdateTimestamp reserveCache.reserveLastUpdateTimestamp
); );
cachedData.newLiquidityIndex = cumulatedLiquidityInterest.rayMul( reserveCache.newLiquidityIndex = cumulatedLiquidityInterest.rayMul(
cachedData.oldLiquidityIndex reserveCache.oldLiquidityIndex
); );
require( require(
cachedData.newLiquidityIndex <= type(uint128).max, reserveCache.newLiquidityIndex <= type(uint128).max,
Errors.RL_LIQUIDITY_INDEX_OVERFLOW Errors.RL_LIQUIDITY_INDEX_OVERFLOW
); );
reserve.liquidityIndex = uint128(reserveCache.newLiquidityIndex);
reserve.liquidityIndex = uint128(cachedData.newLiquidityIndex);
//as the liquidity rate might come only from stable rate loans, we need to ensure //as the liquidity rate might come only from stable rate loans, we need to ensure
//that there is actual variable debt before accumulating //that there is actual variable debt before accumulating
if (cachedData.oldScaledVariableDebt != 0) { if (reserveCache.oldScaledVariableDebt != 0) {
uint256 cumulatedVariableBorrowInterest = uint256 cumulatedVariableBorrowInterest =
MathUtils.calculateCompoundedInterest( MathUtils.calculateCompoundedInterest(
cachedData.oldVariableBorrowRate, reserveCache.oldVariableBorrowRate,
cachedData.reserveLastUpdateTimestamp reserveCache.reserveLastUpdateTimestamp
); );
cachedData.newVariableBorrowIndex = cumulatedVariableBorrowInterest.rayMul( reserveCache.newVariableBorrowIndex = cumulatedVariableBorrowInterest.rayMul(
cachedData.oldVariableBorrowIndex reserveCache.oldVariableBorrowIndex
); );
require( require(
cachedData.newVariableBorrowIndex <= type(uint128).max, reserveCache.newVariableBorrowIndex <= type(uint128).max,
Errors.RL_VARIABLE_BORROW_INDEX_OVERFLOW Errors.RL_VARIABLE_BORROW_INDEX_OVERFLOW
); );
reserve.variableBorrowIndex = uint128(cachedData.newVariableBorrowIndex); reserve.variableBorrowIndex = uint128(reserveCache.newVariableBorrowIndex);
} }
} }
//solium-disable-next-line //solium-disable-next-line
reserve.lastUpdateTimestamp = uint40(block.timestamp); reserve.lastUpdateTimestamp = uint40(block.timestamp);
} }
function cache(DataTypes.ReserveData storage reserve)
internal
view
returns (DataTypes.ReserveCache memory)
{
DataTypes.ReserveCache memory reserveCache;
reserveCache.reserveConfiguration = reserve.configuration;
reserveCache.oldLiquidityIndex = reserve.liquidityIndex;
reserveCache.oldVariableBorrowIndex = reserve.variableBorrowIndex;
reserveCache.oldLiquidityRate = reserve.currentLiquidityRate;
reserveCache.oldVariableBorrowRate = reserve.currentVariableBorrowRate;
reserveCache.aTokenAddress = reserve.aTokenAddress;
reserveCache.stableDebtTokenAddress = reserve.stableDebtTokenAddress;
reserveCache.variableDebtTokenAddress = reserve.variableDebtTokenAddress;
reserveCache.reserveLastUpdateTimestamp = reserve.lastUpdateTimestamp;
reserveCache.oldScaledVariableDebt = reserveCache.newScaledVariableDebt = IVariableDebtToken(
reserveCache
.variableDebtTokenAddress
)
.scaledTotalSupply();
(
reserveCache.oldPrincipalStableDebt,
reserveCache.oldTotalStableDebt,
reserveCache.oldAvgStableBorrowRate,
reserveCache.stableDebtLastUpdateTimestamp
) = IStableDebtToken(reserveCache.stableDebtTokenAddress).getSupplyData();
reserveCache.newPrincipalStableDebt = reserveCache.oldPrincipalStableDebt;
reserveCache.newTotalStableDebt = reserveCache.oldTotalStableDebt;
reserveCache.newAvgStableBorrowRate = reserveCache.oldAvgStableBorrowRate;
return reserveCache;
}
} }

View File

@ -12,7 +12,6 @@ import {SafeERC20} from '../../../dependencies/openzeppelin/contracts/SafeERC20.
import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol'; import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol';
import {UserConfiguration} from '../configuration/UserConfiguration.sol'; import {UserConfiguration} from '../configuration/UserConfiguration.sol';
import {Errors} from '../helpers/Errors.sol'; import {Errors} from '../helpers/Errors.sol';
import {CachingHelper} from '../helpers/CachingHelper.sol';
import {Helpers} from '../helpers/Helpers.sol'; import {Helpers} from '../helpers/Helpers.sol';
import {IReserveInterestRateStrategy} from '../../../interfaces/IReserveInterestRateStrategy.sol'; import {IReserveInterestRateStrategy} from '../../../interfaces/IReserveInterestRateStrategy.sol';
import {IVariableDebtToken} from '../../../interfaces/IVariableDebtToken.sol'; import {IVariableDebtToken} from '../../../interfaces/IVariableDebtToken.sol';
@ -45,13 +44,13 @@ library ValidationLogic {
*/ */
function validateDeposit( function validateDeposit(
DataTypes.ReserveData storage reserve, DataTypes.ReserveData storage reserve,
CachingHelper.CachedData memory cachedData, DataTypes.ReserveCache memory reserveCache,
uint256 amount uint256 amount
) internal view { ) internal view {
(bool isActive, bool isFrozen, , , bool isPaused) = (bool isActive, bool isFrozen, , , bool isPaused) =
cachedData.reserveConfiguration.getFlagsMemory(); reserveCache.reserveConfiguration.getFlagsMemory();
(, , , uint256 reserveDecimals, ) = cachedData.reserveConfiguration.getParamsMemory(); (, , , uint256 reserveDecimals, ) = reserveCache.reserveConfiguration.getParamsMemory();
uint256 supplyCap = cachedData.reserveConfiguration.getSupplyCapMemory(); uint256 supplyCap = reserveCache.reserveConfiguration.getSupplyCapMemory();
require(amount != 0, Errors.VL_INVALID_AMOUNT); require(amount != 0, Errors.VL_INVALID_AMOUNT);
require(isActive, Errors.VL_NO_ACTIVE_RESERVE); require(isActive, Errors.VL_NO_ACTIVE_RESERVE);
@ -59,9 +58,9 @@ library ValidationLogic {
require(!isFrozen, Errors.VL_RESERVE_FROZEN); require(!isFrozen, Errors.VL_RESERVE_FROZEN);
require( require(
supplyCap == 0 || supplyCap == 0 ||
IAToken(cachedData.aTokenAddress) IAToken(reserveCache.aTokenAddress)
.scaledTotalSupply() .scaledTotalSupply()
.rayMul(cachedData.newLiquidityIndex) .rayMul(reserveCache.newLiquidityIndex)
.add(amount) .add(amount)
.div(10**reserveDecimals) < .div(10**reserveDecimals) <
supplyCap, supplyCap,
@ -77,13 +76,14 @@ library ValidationLogic {
*/ */
function validateWithdraw( function validateWithdraw(
DataTypes.ReserveData storage reserve, DataTypes.ReserveData storage reserve,
DataTypes.ReserveCache memory reserveCache,
uint256 amount, uint256 amount,
uint256 userBalance uint256 userBalance
) external view { ) external view {
require(amount != 0, Errors.VL_INVALID_AMOUNT); require(amount != 0, Errors.VL_INVALID_AMOUNT);
require(amount <= userBalance, Errors.VL_NOT_ENOUGH_AVAILABLE_USER_BALANCE); require(amount <= userBalance, Errors.VL_NOT_ENOUGH_AVAILABLE_USER_BALANCE);
(bool isActive, , , , bool isPaused) = reserve.configuration.getFlags(); (bool isActive, , , , bool isPaused) = reserveCache.reserveConfiguration.getFlagsMemory();
require(isActive, Errors.VL_NO_ACTIVE_RESERVE); require(isActive, Errors.VL_NO_ACTIVE_RESERVE);
require(!isPaused, Errors.VL_RESERVE_PAUSED); require(!isPaused, Errors.VL_RESERVE_PAUSED);
} }
@ -122,7 +122,7 @@ library ValidationLogic {
*/ */
function validateBorrow( function validateBorrow(
CachingHelper.CachedData memory cachedData, DataTypes.ReserveCache memory reserveCache,
address asset, address asset,
address userAddress, address userAddress,
uint256 amount, uint256 amount,
@ -136,7 +136,7 @@ library ValidationLogic {
) external view { ) external view {
ValidateBorrowLocalVars memory vars; ValidateBorrowLocalVars memory vars;
(, , , vars.reserveDecimals, ) = cachedData.reserveConfiguration.getParamsMemory(); (, , , vars.reserveDecimals, ) = reserveCache.reserveConfiguration.getParamsMemory();
( (
vars.isActive, vars.isActive,
@ -144,7 +144,7 @@ library ValidationLogic {
vars.borrowingEnabled, vars.borrowingEnabled,
vars.stableRateBorrowingEnabled, vars.stableRateBorrowingEnabled,
vars.isPaused vars.isPaused
) = cachedData.reserveConfiguration.getFlagsMemory(); ) = reserveCache.reserveConfiguration.getFlagsMemory();
require(vars.isActive, Errors.VL_NO_ACTIVE_RESERVE); require(vars.isActive, Errors.VL_NO_ACTIVE_RESERVE);
require(!vars.isPaused, Errors.VL_RESERVE_PAUSED); require(!vars.isPaused, Errors.VL_RESERVE_PAUSED);
@ -160,15 +160,15 @@ library ValidationLogic {
Errors.VL_INVALID_INTEREST_RATE_MODE_SELECTED Errors.VL_INVALID_INTEREST_RATE_MODE_SELECTED
); );
vars.borrowCap = cachedData.reserveConfiguration.getBorrowCapMemory(); vars.borrowCap = reserveCache.reserveConfiguration.getBorrowCapMemory();
if (vars.borrowCap > 0) { if (vars.borrowCap > 0) {
{ {
vars.totalSupplyVariableDebt = cachedData.oldScaledVariableDebt.rayMul( vars.totalSupplyVariableDebt = reserveCache.oldScaledVariableDebt.rayMul(
cachedData.newVariableBorrowIndex reserveCache.newVariableBorrowIndex
); );
vars.totalDebt = cachedData.oldTotalStableDebt.add(vars.totalSupplyVariableDebt).add( vars.totalDebt = reserveCache.oldTotalStableDebt.add(vars.totalSupplyVariableDebt).add(
amount amount
); );
require( require(
@ -228,12 +228,12 @@ library ValidationLogic {
require( require(
!userConfig.isUsingAsCollateral(reservesData[asset].id) || !userConfig.isUsingAsCollateral(reservesData[asset].id) ||
cachedData.reserveConfiguration.getLtvMemory() == 0 || reserveCache.reserveConfiguration.getLtvMemory() == 0 ||
amount > IERC20(cachedData.aTokenAddress).balanceOf(userAddress), amount > IERC20(reserveCache.aTokenAddress).balanceOf(userAddress),
Errors.VL_COLLATERAL_SAME_AS_BORROWING_CURRENCY Errors.VL_COLLATERAL_SAME_AS_BORROWING_CURRENCY
); );
vars.availableLiquidity = IERC20(asset).balanceOf(cachedData.aTokenAddress); vars.availableLiquidity = IERC20(asset).balanceOf(reserveCache.aTokenAddress);
//calculate the max available loan size in stable rate mode as a percentage of the //calculate the max available loan size in stable rate mode as a percentage of the
//available liquidity //available liquidity
@ -253,13 +253,14 @@ library ValidationLogic {
*/ */
function validateRepay( function validateRepay(
DataTypes.ReserveData storage reserve, DataTypes.ReserveData storage reserve,
DataTypes.ReserveCache memory reserveCache,
uint256 amountSent, uint256 amountSent,
DataTypes.InterestRateMode rateMode, DataTypes.InterestRateMode rateMode,
address onBehalfOf, address onBehalfOf,
uint256 stableDebt, uint256 stableDebt,
uint256 variableDebt uint256 variableDebt
) external view { ) external view {
(bool isActive, , , , bool isPaused) = reserve.configuration.getFlags(); (bool isActive, , , , bool isPaused) = reserveCache.reserveConfiguration.getFlagsMemory();
require(isActive, Errors.VL_NO_ACTIVE_RESERVE); require(isActive, Errors.VL_NO_ACTIVE_RESERVE);
require(!isPaused, Errors.VL_RESERVE_PAUSED); require(!isPaused, Errors.VL_RESERVE_PAUSED);
@ -289,13 +290,14 @@ library ValidationLogic {
*/ */
function validateSwapRateMode( function validateSwapRateMode(
DataTypes.ReserveData storage reserve, DataTypes.ReserveData storage reserve,
DataTypes.ReserveCache memory reserveCache,
DataTypes.UserConfigurationMap storage userConfig, DataTypes.UserConfigurationMap storage userConfig,
uint256 stableDebt, uint256 stableDebt,
uint256 variableDebt, uint256 variableDebt,
DataTypes.InterestRateMode currentRateMode DataTypes.InterestRateMode currentRateMode
) external view { ) external view {
(bool isActive, bool isFrozen, , bool stableRateEnabled, bool isPaused) = (bool isActive, bool isFrozen, , bool stableRateEnabled, bool isPaused) =
reserve.configuration.getFlags(); reserveCache.reserveConfiguration.getFlagsMemory();
require(isActive, Errors.VL_NO_ACTIVE_RESERVE); require(isActive, Errors.VL_NO_ACTIVE_RESERVE);
require(!isPaused, Errors.VL_RESERVE_PAUSED); require(!isPaused, Errors.VL_RESERVE_PAUSED);
@ -316,8 +318,8 @@ library ValidationLogic {
require( require(
!userConfig.isUsingAsCollateral(reserve.id) || !userConfig.isUsingAsCollateral(reserve.id) ||
reserve.configuration.getLtv() == 0 || reserveCache.reserveConfiguration.getLtvMemory() == 0 ||
stableDebt.add(variableDebt) > IERC20(reserve.aTokenAddress).balanceOf(msg.sender), stableDebt.add(variableDebt) > IERC20(reserveCache.aTokenAddress).balanceOf(msg.sender),
Errors.VL_COLLATERAL_SAME_AS_BORROWING_CURRENCY Errors.VL_COLLATERAL_SAME_AS_BORROWING_CURRENCY
); );
} else { } else {
@ -335,12 +337,13 @@ library ValidationLogic {
*/ */
function validateRebalanceStableBorrowRate( function validateRebalanceStableBorrowRate(
DataTypes.ReserveData storage reserve, DataTypes.ReserveData storage reserve,
DataTypes.ReserveCache memory reserveCache,
address reserveAddress, address reserveAddress,
IERC20 stableDebtToken, IERC20 stableDebtToken,
IERC20 variableDebtToken, IERC20 variableDebtToken,
address aTokenAddress address aTokenAddress
) external view { ) external view {
(bool isActive, , , , bool isPaused) = reserve.configuration.getFlags(); (bool isActive, , , , bool isPaused) = reserveCache.reserveConfiguration.getFlagsMemory();
require(isActive, Errors.VL_NO_ACTIVE_RESERVE); require(isActive, Errors.VL_NO_ACTIVE_RESERVE);
require(!isPaused, Errors.VL_RESERVE_PAUSED); require(!isPaused, Errors.VL_RESERVE_PAUSED);
@ -354,7 +357,7 @@ library ValidationLogic {
//if the liquidity rate is below REBALANCE_UP_THRESHOLD of the max variable APR at 95% usage, //if the liquidity rate is below REBALANCE_UP_THRESHOLD of the max variable APR at 95% usage,
//then we allow rebalancing of the stable rate positions. //then we allow rebalancing of the stable rate positions.
uint256 currentLiquidityRate = reserve.currentLiquidityRate; uint256 currentLiquidityRate = reserveCache.oldLiquidityRate;
uint256 maxVariableBorrowRate = uint256 maxVariableBorrowRate =
IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).getMaxVariableBorrowRate(); IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).getMaxVariableBorrowRate();
@ -370,10 +373,14 @@ library ValidationLogic {
* @dev Validates the action of setting an asset as collateral * @dev Validates the action of setting an asset as collateral
* @param reserve The state of the reserve that the user is enabling or disabling as collateral * @param reserve The state of the reserve that the user is enabling or disabling as collateral
*/ */
function validateSetUseReserveAsCollateral(DataTypes.ReserveData storage reserve) external view { function validateSetUseReserveAsCollateral(
uint256 underlyingBalance = IERC20(reserve.aTokenAddress).balanceOf(msg.sender); DataTypes.ReserveData storage reserve,
bool isPaused = reserve.configuration.getPaused(); DataTypes.ReserveCache memory reserveCache
) external view {
uint256 underlyingBalance = IERC20(reserveCache.aTokenAddress).balanceOf(msg.sender);
(bool isActive, , , , bool isPaused) = reserveCache.reserveConfiguration.getFlagsMemory();
require(isActive, Errors.VL_NO_ACTIVE_RESERVE);
require(!isPaused, Errors.VL_RESERVE_PAUSED); require(!isPaused, Errors.VL_RESERVE_PAUSED);
require(underlyingBalance > 0, Errors.VL_UNDERLYING_BALANCE_NOT_GREATER_THAN_0); require(underlyingBalance > 0, Errors.VL_UNDERLYING_BALANCE_NOT_GREATER_THAN_0);
@ -407,20 +414,26 @@ library ValidationLogic {
function validateLiquidationCall( function validateLiquidationCall(
DataTypes.ReserveData storage collateralReserve, DataTypes.ReserveData storage collateralReserve,
DataTypes.ReserveData storage principalReserve, DataTypes.ReserveData storage principalReserve,
DataTypes.ReserveCache memory collateralReserveCache,
DataTypes.ReserveCache memory principalReserveCache,
DataTypes.UserConfigurationMap storage userConfig, DataTypes.UserConfigurationMap storage userConfig,
uint256 userHealthFactor, uint256 userHealthFactor,
uint256 userStableDebt, uint256 userStableDebt,
uint256 userVariableDebt uint256 userVariableDebt
) internal view returns (uint256, string memory) { ) internal view returns (uint256, string memory) {
if ( (bool collateralReserveActive, , , , bool collateralReservePaused) =
!collateralReserve.configuration.getActive() || !principalReserve.configuration.getActive() collateralReserveCache.reserveConfiguration.getFlagsMemory();
) {
(bool principalReserveActive, , , , bool principalReservePaused) =
collateralReserveCache.reserveConfiguration.getFlagsMemory();
if (!collateralReserveActive || !principalReserveActive) {
return ( return (
uint256(Errors.CollateralManagerErrors.NO_ACTIVE_RESERVE), uint256(Errors.CollateralManagerErrors.NO_ACTIVE_RESERVE),
Errors.VL_NO_ACTIVE_RESERVE Errors.VL_NO_ACTIVE_RESERVE
); );
} }
if (collateralReserve.configuration.getPaused() || principalReserve.configuration.getPaused()) { if (collateralReservePaused || principalReservePaused) {
return (uint256(Errors.CollateralManagerErrors.PAUSED_RESERVE), Errors.VL_RESERVE_PAUSED); return (uint256(Errors.CollateralManagerErrors.PAUSED_RESERVE), Errors.VL_RESERVE_PAUSED);
} }
@ -432,7 +445,7 @@ library ValidationLogic {
} }
bool isCollateralEnabled = bool isCollateralEnabled =
collateralReserve.configuration.getLiquidationThreshold() > 0 && collateralReserveCache.reserveConfiguration.getLiquidationThresholdMemory() > 0 &&
userConfig.isUsingAsCollateral(collateralReserve.id); userConfig.isUsingAsCollateral(collateralReserve.id);
//if collateral isn't enabled as collateral by user, it cannot be liquidated //if collateral isn't enabled as collateral by user, it cannot be liquidated

View File

@ -51,4 +51,29 @@ library DataTypes {
} }
enum InterestRateMode {NONE, STABLE, VARIABLE} enum InterestRateMode {NONE, STABLE, VARIABLE}
struct ReserveCache {
uint256 oldScaledVariableDebt;
uint256 oldTotalVariableDebt;
uint256 newScaledVariableDebt;
uint256 newTotalVariableDebt;
uint256 oldPrincipalStableDebt;
uint256 oldAvgStableBorrowRate;
uint256 oldTotalStableDebt;
uint256 newPrincipalStableDebt;
uint256 newAvgStableBorrowRate;
uint256 newTotalStableDebt;
uint256 oldLiquidityIndex;
uint256 newLiquidityIndex;
uint256 oldVariableBorrowIndex;
uint256 newVariableBorrowIndex;
uint256 oldLiquidityRate;
uint256 oldVariableBorrowRate;
DataTypes.ReserveConfigurationMap reserveConfiguration;
address aTokenAddress;
address stableDebtTokenAddress;
address variableDebtTokenAddress;
uint40 reserveLastUpdateTimestamp;
uint40 stableDebtLastUpdateTimestamp;
}
} }

14
package-lock.json generated
View File

@ -11142,14 +11142,6 @@
"requires": { "requires": {
"min-document": "^2.19.0", "min-document": "^2.19.0",
"process": "^0.11.10" "process": "^0.11.10"
},
"dependencies": {
"process": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz",
"integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=",
"dev": true
}
} }
}, },
"got": { "got": {
@ -12794,6 +12786,12 @@
"integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==",
"dev": true "dev": true
}, },
"process": {
"version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
"integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
"dev": true
},
"process-nextick-args": { "process-nextick-args": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",