refactor: further refactored cache, changed linkage behavior of GenericLogic

This commit is contained in:
emilio 2021-06-11 11:27:19 +02:00
parent 666c6a0666
commit 760be1cb42
7 changed files with 145 additions and 110 deletions

View File

@ -20,8 +20,8 @@ import {Errors} from '../libraries/helpers/Errors.sol';
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
import {PercentageMath} from '../libraries/math/PercentageMath.sol';
import {ReserveLogic} from '../libraries/logic/ReserveLogic.sol';
import {GenericLogic} from '../libraries/logic/GenericLogic.sol';
import {ValidationLogic} from '../libraries/logic/ValidationLogic.sol';
import {GenericLogic} from '../libraries/logic/GenericLogic.sol';
import {ReserveConfiguration} from '../libraries/configuration/ReserveConfiguration.sol';
import {UserConfiguration} from '../libraries/configuration/UserConfiguration.sol';
import {DataTypes} from '../libraries/types/DataTypes.sol';
@ -190,7 +190,6 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
uint16 referralCode,
address onBehalfOf
) external override whenNotPaused {
DataTypes.ReserveData storage reserve = _reserves[asset];
_executeBorrow(
ExecuteBorrowParams(
asset,
@ -372,7 +371,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
DataTypes.ReserveData storage reserve = _reserves[asset];
DataTypes.ReserveCache memory reserveCache = reserve.cache();
ValidationLogic.validateSetUseReserveAsCollateral(reserve, reserveCache);
ValidationLogic.validateSetUseReserveAsCollateral(reserveCache);
_usersConfig[msg.sender].setUsingAsCollateral(reserve.id, useAsCollateral);
@ -619,7 +618,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
ltv,
currentLiquidationThreshold,
healthFactor
) = GenericLogic.calculateUserAccountData(
) = GenericLogic.getUserAccountData(
user,
_reserves,
_usersConfig[user],
@ -990,7 +989,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
reserve.updateState(reserveCache);
ValidationLogic.validateDeposit(reserve, reserveCache, amount);
ValidationLogic.validateDeposit(reserveCache, amount);
reserve.updateInterestRates(reserveCache, asset, amount, 0);
@ -1029,7 +1028,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
amountToWithdraw = userBalance;
}
ValidationLogic.validateWithdraw(reserve, reserveCache, amountToWithdraw, userBalance);
ValidationLogic.validateWithdraw(reserveCache, amountToWithdraw, userBalance);
reserve.updateInterestRates(reserveCache, asset, 0, amountToWithdraw);
@ -1077,7 +1076,6 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
DataTypes.InterestRateMode interestRateMode = DataTypes.InterestRateMode(rateMode);
ValidationLogic.validateRepay(
reserve,
reserveCache,
amount,
interestRateMode,

View File

@ -1,6 +1,8 @@
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import {SafeMath} from '../../dependencies/openzeppelin/contracts//SafeMath.sol';
import {IERC20} from '../../dependencies/openzeppelin/contracts//IERC20.sol';
import {IAToken} from '../../interfaces/IAToken.sol';
@ -9,7 +11,6 @@ import {IVariableDebtToken} from '../../interfaces/IVariableDebtToken.sol';
import {IPriceOracleGetter} from '../../interfaces/IPriceOracleGetter.sol';
import {ILendingPoolCollateralManager} from '../../interfaces/ILendingPoolCollateralManager.sol';
import {VersionedInitializable} from '../libraries/aave-upgradeability/VersionedInitializable.sol';
import {GenericLogic} from '../libraries/logic/GenericLogic.sol';
import {ReserveLogic} from '../libraries/logic/ReserveLogic.sol';
import {Helpers} from '../libraries/helpers/Helpers.sol';
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
@ -54,6 +55,7 @@ contract LendingPoolCollateralManager is
uint256 healthFactor;
uint256 liquidatorPreviousATokenBalance;
IAToken collateralAtoken;
IPriceOracleGetter oracle;
bool isCollateralEnabled;
DataTypes.InterestRateMode borrowRateMode;
uint256 errorCode;
@ -89,33 +91,25 @@ contract LendingPoolCollateralManager is
) external override returns (uint256, string memory) {
DataTypes.ReserveData storage collateralReserve = _reserves[collateralAsset];
DataTypes.ReserveData storage debtReserve = _reserves[debtAsset];
DataTypes.ReserveCache memory debtReserveCache = debtReserve.cache();
DataTypes.UserConfigurationMap storage userConfig = _usersConfig[user];
LiquidationCallLocalVars memory vars;
(, , , , vars.healthFactor) = GenericLogic.calculateUserAccountData(
(vars.userStableDebt, vars.userVariableDebt) = Helpers.getUserCurrentDebt(user, debtReserve);
vars.oracle = IPriceOracleGetter(_addressesProvider.getPriceOracle());
(vars.errorCode, vars.errorMsg) = ValidationLogic.validateLiquidationCall(
collateralReserve,
debtReserveCache,
vars.userStableDebt.add(vars.userVariableDebt),
user,
_reserves,
userConfig,
_reservesList,
_reservesCount,
_addressesProvider.getPriceOracle()
);
DataTypes.ReserveCache memory debtReserveCache = debtReserve.cache();
DataTypes.ReserveCache memory collateralReserveCache = collateralReserve.cache();
(vars.userStableDebt, vars.userVariableDebt) = Helpers.getUserCurrentDebt(user, debtReserve);
(vars.errorCode, vars.errorMsg) = ValidationLogic.validateLiquidationCall(
collateralReserve,
debtReserve,
debtReserveCache,
collateralReserveCache,
userConfig,
vars.healthFactor,
vars.userStableDebt,
vars.userVariableDebt
address(vars.oracle)
);
if (Errors.CollateralManagerErrors(vars.errorCode) != Errors.CollateralManagerErrors.NO_ERROR) {
@ -139,11 +133,12 @@ contract LendingPoolCollateralManager is
vars.debtAmountNeeded
) = _calculateAvailableCollateralToLiquidate(
collateralReserve,
debtReserve,
debtReserveCache,
collateralAsset,
debtAsset,
vars.actualDebtToLiquidate,
vars.userCollateralBalance
vars.userCollateralBalance,
vars.oracle
);
// If debtAmountNeeded < actualDebtToLiquidate, there isn't enough
@ -210,6 +205,7 @@ contract LendingPoolCollateralManager is
emit ReserveUsedAsCollateralEnabled(collateralAsset, msg.sender);
}
} else {
DataTypes.ReserveCache memory collateralReserveCache = collateralReserve.cache();
collateralReserve.updateState(collateralReserveCache);
collateralReserve.updateInterestRates(
collateralReserveCache,
@ -223,7 +219,7 @@ contract LendingPoolCollateralManager is
user,
msg.sender,
vars.maxCollateralToLiquidate,
collateralReserve.liquidityIndex
collateralReserveCache.nextLiquidityIndex
);
}
@ -237,7 +233,7 @@ contract LendingPoolCollateralManager is
// Transfers the debt asset being repaid to the aToken, where the liquidity is kept
IERC20(debtAsset).safeTransferFrom(
msg.sender,
debtReserve.aTokenAddress,
debtReserveCache.aTokenAddress,
vars.actualDebtToLiquidate
);
@ -270,7 +266,7 @@ contract LendingPoolCollateralManager is
* - This function needs to be called after all the checks to validate the liquidation have been performed,
* otherwise it might fail.
* @param collateralReserve The data of the collateral reserve
* @param debtReserve The data of the debt reserve
* @param debtReserveCache The cached data of the debt reserve
* @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
* @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
* @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
@ -281,15 +277,15 @@ contract LendingPoolCollateralManager is
**/
function _calculateAvailableCollateralToLiquidate(
DataTypes.ReserveData storage collateralReserve,
DataTypes.ReserveData storage debtReserve,
DataTypes.ReserveCache memory debtReserveCache,
address collateralAsset,
address debtAsset,
uint256 debtToCover,
uint256 userCollateralBalance
uint256 userCollateralBalance,
IPriceOracleGetter oracle
) internal view returns (uint256, uint256) {
uint256 collateralAmount = 0;
uint256 debtAmountNeeded = 0;
IPriceOracleGetter oracle = IPriceOracleGetter(_addressesProvider.getPriceOracle());
AvailableCollateralToLiquidateLocalVars memory vars;
@ -299,7 +295,7 @@ contract LendingPoolCollateralManager is
(, , vars.liquidationBonus, vars.collateralDecimals, ) = collateralReserve
.configuration
.getParams();
vars.debtAssetDecimals = debtReserve.configuration.getDecimals();
vars.debtAssetDecimals = debtReserveCache.reserveConfiguration.getDecimalsMemory();
// This is the maximum possible amount of the selected collateral that can be liquidated, given the
// max amount of liquidatable debt

View File

@ -70,7 +70,7 @@ library ReserveConfiguration {
* @param self The reserve configuration
* @return The loan to value
**/
function getLtvMemory(DataTypes.ReserveConfigurationMap memory self) internal view returns (uint256) {
function getLtvMemory(DataTypes.ReserveConfigurationMap memory self) internal pure returns (uint256) {
return self.data & ~LTV_MASK;
}
@ -104,18 +104,6 @@ library ReserveConfiguration {
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
* @param self The reserve configuration
@ -172,7 +160,6 @@ library ReserveConfiguration {
return (self.data & ~DECIMALS_MASK) >> RESERVE_DECIMALS_START_BIT_POSITION;
}
/**
* @dev Gets the decimals of the underlying asset of the reserve
* @param self The reserve configuration
@ -180,7 +167,7 @@ library ReserveConfiguration {
**/
function getDecimalsMemory(DataTypes.ReserveConfigurationMap memory self)
internal
view
pure
returns (uint256)
{
return (self.data & ~DECIMALS_MASK) >> RESERVE_DECIMALS_START_BIT_POSITION;
@ -336,7 +323,7 @@ library ReserveConfiguration {
**/
function getReserveFactorMemory(DataTypes.ReserveConfigurationMap memory self)
internal
view
pure
returns (uint256)
{
return (self.data & ~RESERVE_FACTOR_MASK) >> RESERVE_FACTOR_START_BIT_POSITION;

View File

@ -198,4 +198,36 @@ library GenericLogic {
availableBorrowsETH = availableBorrowsETH.sub(totalDebtInETH);
return availableBorrowsETH;
}
/**
* @dev proxy call for calculateUserAccountData as external function.
* Used in LendingPool to work around contract size limit issues
* @param user The address of the user
* @param reservesData Data of all the reserves
* @param userConfig The configuration of the user
* @param reserves The list of the available reserves
* @param oracle The price oracle address
* @return The total collateral and total debt of the user in ETH, the avg ltv, liquidation threshold and the HF
**/
function getUserAccountData(
address user,
mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap memory userConfig,
mapping(uint256 => address) storage reserves,
uint256 reservesCount,
address oracle
)
external
view
returns (
uint256,
uint256,
uint256,
uint256,
uint256
)
{
return
calculateUserAccountData(user, reservesData, userConfig, reserves, reservesCount, oracle);
}
}

View File

@ -186,7 +186,6 @@ library ReserveLogic {
) internal {
UpdateInterestRatesLocalVars memory vars;
reserveCache.nextTotalVariableDebt = reserveCache.nextScaledVariableDebt.rayMul(
reserveCache.nextVariableBorrowIndex
);
@ -386,25 +385,29 @@ library ReserveLogic {
uint256 stableDebtBurned,
uint256 variableDebtMinted,
uint256 variableDebtBurned
) internal {
uint256 scaledVariableDebtMinted = variableDebtMinted.rayDiv(cache.nextVariableBorrowIndex);
uint256 scaledVariableDebtBurned = variableDebtBurned.rayDiv(cache.nextVariableBorrowIndex);
if (cache.currTotalStableDebt.add(stableDebtMinted) > stableDebtBurned) {
cache.nextPrincipalStableDebt = cache.nextTotalStableDebt = cache
.currTotalStableDebt
.add(stableDebtMinted)
.sub(stableDebtBurned);
if (stableDebtMinted != 0 || stableDebtBurned != 0) {
cache.nextAvgStableBorrowRate = IStableDebtToken(cache.stableDebtTokenAddress)
.getAverageStableRate();
) internal view {
if (stableDebtMinted != 0 || stableDebtBurned != 0) {
if (cache.currTotalStableDebt.add(stableDebtMinted) > stableDebtBurned) {
cache.nextPrincipalStableDebt = cache.nextTotalStableDebt = cache
.currTotalStableDebt
.add(stableDebtMinted)
.sub(stableDebtBurned);
if (stableDebtMinted != 0 || stableDebtBurned != 0) {
cache.nextAvgStableBorrowRate = IStableDebtToken(cache.stableDebtTokenAddress)
.getAverageStableRate();
}
} else {
cache.nextPrincipalStableDebt = cache.nextTotalStableDebt = cache
.nextAvgStableBorrowRate = 0;
}
} else {
cache.nextPrincipalStableDebt = cache.nextTotalStableDebt = cache.nextAvgStableBorrowRate = 0;
}
cache.nextScaledVariableDebt = cache.currScaledVariableDebt.add(scaledVariableDebtMinted).sub(
scaledVariableDebtBurned
);
if (variableDebtMinted != 0 || variableDebtBurned != 0) {
uint256 scaledVariableDebtMinted = variableDebtMinted.rayDiv(cache.nextVariableBorrowIndex);
uint256 scaledVariableDebtBurned = variableDebtBurned.rayDiv(cache.nextVariableBorrowIndex);
cache.nextScaledVariableDebt = cache.currScaledVariableDebt.add(scaledVariableDebtMinted).sub(
scaledVariableDebtBurned
);
}
}
}

View File

@ -16,6 +16,7 @@ import {Helpers} from '../helpers/Helpers.sol';
import {IReserveInterestRateStrategy} from '../../../interfaces/IReserveInterestRateStrategy.sol';
import {IVariableDebtToken} from '../../../interfaces/IVariableDebtToken.sol';
import {IStableDebtToken} from '../../../interfaces/IStableDebtToken.sol';
import {IScaledBalanceToken} from '../../../interfaces/IScaledBalanceToken.sol';
import {IAToken} from '../../../interfaces/IAToken.sol';
import {DataTypes} from '../types/DataTypes.sol';
import {IPriceOracleGetter} from '../../../interfaces/IPriceOracleGetter.sol';
@ -39,14 +40,13 @@ library ValidationLogic {
/**
* @dev Validates a deposit action
* @param reserve The reserve object on which the user is depositing
* @param reserveCache The cached data of the reserve
* @param amount The amount to be deposited
*/
function validateDeposit(
DataTypes.ReserveData storage reserve,
DataTypes.ReserveCache memory reserveCache,
uint256 amount
) internal view {
function validateDeposit(DataTypes.ReserveCache memory reserveCache, uint256 amount)
internal
view
{
(bool isActive, bool isFrozen, , , bool isPaused) =
reserveCache.reserveConfiguration.getFlagsMemory();
(, , , uint256 reserveDecimals, ) = reserveCache.reserveConfiguration.getParamsMemory();
@ -70,16 +70,15 @@ library ValidationLogic {
/**
* @dev Validates a withdraw action
* @param reserve The reserve object
* @param reserveCache The cached data of the reserve
* @param amount The amount to be withdrawn
* @param userBalance The balance of the user
*/
function validateWithdraw(
DataTypes.ReserveData storage reserve,
DataTypes.ReserveCache memory reserveCache,
uint256 amount,
uint256 userBalance
) internal view {
) internal pure {
require(amount != 0, Errors.VL_INVALID_AMOUNT);
require(amount <= userBalance, Errors.VL_NOT_ENOUGH_AVAILABLE_USER_BALANCE);
@ -245,21 +244,20 @@ library ValidationLogic {
/**
* @dev Validates a repay action
* @param reserve The reserve state from which the user is repaying
* @param reserveCache The cached data of the reserve
* @param amountSent The amount sent for the repayment. Can be an actual value or uint(-1)
* @param onBehalfOf The address of the user msg.sender is repaying for
* @param stableDebt The borrow balance of the user
* @param variableDebt The borrow balance of the user
*/
function validateRepay(
DataTypes.ReserveData storage reserve,
DataTypes.ReserveCache memory reserveCache,
uint256 amountSent,
DataTypes.InterestRateMode rateMode,
address onBehalfOf,
uint256 stableDebt,
uint256 variableDebt
) external view {
) internal view {
(bool isActive, , , , bool isPaused) = reserveCache.reserveConfiguration.getFlagsMemory();
require(isActive, Errors.VL_NO_ACTIVE_RESERVE);
require(!isPaused, Errors.VL_RESERVE_PAUSED);
@ -371,12 +369,12 @@ library ValidationLogic {
/**
* @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 reserveCache The cached data of the reserve
*/
function validateSetUseReserveAsCollateral(
DataTypes.ReserveData storage reserve,
DataTypes.ReserveCache memory reserveCache
) external view {
function validateSetUseReserveAsCollateral(DataTypes.ReserveCache memory reserveCache)
external
view
{
uint256 underlyingBalance = IERC20(reserveCache.aTokenAddress).balanceOf(msg.sender);
(bool isActive, , , , bool isPaused) = reserveCache.reserveConfiguration.getFlagsMemory();
@ -395,68 +393,88 @@ library ValidationLogic {
address[] memory assets,
uint256[] memory amounts,
mapping(address => DataTypes.ReserveData) storage reservesData
) external view {
) internal view {
for (uint256 i = 0; i < assets.length; i++) {
require(!reservesData[assets[i]].configuration.getPaused(), Errors.VL_RESERVE_PAUSED);
}
require(assets.length == amounts.length, Errors.VL_INCONSISTENT_FLASHLOAN_PARAMS);
}
struct ValidateLiquidationCallLocalVars {
uint256 healthFactor;
bool collateralReserveActive;
bool collateralReservePaused;
bool principalReserveActive;
bool principalReservePaused;
bool isCollateralEnabled;
}
/**
* @dev Validates the liquidation action
* @param collateralReserve The reserve data of the collateral
* @param principalReserve The reserve data of the principal
* @param userConfig The user configuration
* @param userHealthFactor The user's health factor
* @param userStableDebt Total stable debt balance of the user
* @param userVariableDebt Total variable debt balance of the user
* @param totalDebt Total debt balance of the user
**/
function validateLiquidationCall(
DataTypes.ReserveData storage collateralReserve,
DataTypes.ReserveData storage principalReserve,
DataTypes.ReserveCache memory collateralReserveCache,
DataTypes.ReserveCache memory principalReserveCache,
uint256 totalDebt,
address user,
mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap storage userConfig,
uint256 userHealthFactor,
uint256 userStableDebt,
uint256 userVariableDebt
mapping(uint256 => address) storage reserves,
uint256 reservesCount,
address oracle
) internal view returns (uint256, string memory) {
(bool collateralReserveActive, , , , bool collateralReservePaused) =
collateralReserveCache.reserveConfiguration.getFlagsMemory();
ValidateLiquidationCallLocalVars memory vars;
(bool principalReserveActive, , , , bool principalReservePaused) =
collateralReserveCache.reserveConfiguration.getFlagsMemory();
(vars.collateralReserveActive, , , , vars.collateralReservePaused) = collateralReserve
.configuration
.getFlagsMemory();
if (!collateralReserveActive || !principalReserveActive) {
(vars.principalReserveActive, , , , vars.principalReservePaused) = principalReserveCache
.reserveConfiguration
.getFlagsMemory();
if (!vars.collateralReserveActive || !vars.principalReserveActive) {
return (
uint256(Errors.CollateralManagerErrors.NO_ACTIVE_RESERVE),
Errors.VL_NO_ACTIVE_RESERVE
);
}
if (collateralReservePaused || principalReservePaused) {
if (vars.collateralReservePaused || vars.principalReservePaused) {
return (uint256(Errors.CollateralManagerErrors.PAUSED_RESERVE), Errors.VL_RESERVE_PAUSED);
}
if (userHealthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD) {
(, , , , vars.healthFactor) = GenericLogic.calculateUserAccountData(
user,
reservesData,
userConfig,
reserves,
reservesCount,
oracle
);
if (vars.healthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD) {
return (
uint256(Errors.CollateralManagerErrors.HEALTH_FACTOR_ABOVE_THRESHOLD),
Errors.LPCM_HEALTH_FACTOR_NOT_BELOW_THRESHOLD
);
}
bool isCollateralEnabled =
collateralReserveCache.reserveConfiguration.getLiquidationThresholdMemory() > 0 &&
userConfig.isUsingAsCollateral(collateralReserve.id);
vars.isCollateralEnabled =
collateralReserve.configuration.getLiquidationThreshold() > 0 &&
userConfig.isUsingAsCollateral(collateralReserve.id);
//if collateral isn't enabled as collateral by user, it cannot be liquidated
if (!isCollateralEnabled) {
if (!vars.isCollateralEnabled) {
return (
uint256(Errors.CollateralManagerErrors.COLLATERAL_CANNOT_BE_LIQUIDATED),
Errors.LPCM_COLLATERAL_CANNOT_BE_LIQUIDATED
);
}
if (userStableDebt == 0 && userVariableDebt == 0) {
if (totalDebt == 0) {
return (
uint256(Errors.CollateralManagerErrors.CURRRENCY_NOT_BORROWED),
Errors.LPCM_SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER
@ -482,7 +500,7 @@ library ValidationLogic {
mapping(uint256 => address) storage reserves,
uint256 reservesCount,
address oracle
) internal view {
) external view {
(, , , , uint256 healthFactor) =
GenericLogic.calculateUserAccountData(
from,

View File

@ -188,7 +188,8 @@ export const deployAaveLibraries = async (
return {
['__$de8c0cf1a7d7c36c802af9a64fb9d86036$__']: validationLogic.address,
['__$22cd43a9dda9ce44e9b92ba393b88fb9ac$__']: reserveLogic.address,
};
["__$52a8a86ab43135662ff256bbc95497e8e3$__"]: genericLogic.address,
}
};
export const deployLendingPool = async (verify?: boolean) => {