Merge branch 'master' into 'certora/integrationStep2'

# Conflicts:
#   specs/harness/LendingPoolHarnessForVariableDebtToken.sol
This commit is contained in:
pistiner 2020-11-25 16:20:07 +00:00
commit 513c7c09f1
21 changed files with 467 additions and 460 deletions

2
.gitignore vendored
View File

@ -7,7 +7,7 @@ dist/
build/
.vscode
.idea
types
/types
deployed-contracts.json

View File

@ -2,10 +2,9 @@
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import {ReserveConfiguration} from '../protocol/libraries/configuration/ReserveConfiguration.sol';
import {UserConfiguration} from '../protocol/libraries/configuration/UserConfiguration.sol';
import {ReserveLogic} from '../protocol/libraries/logic/ReserveLogic.sol';
import {ILendingPoolAddressesProvider} from './ILendingPoolAddressesProvider.sol';
import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
interface ILendingPool {
/**
@ -355,14 +354,20 @@ interface ILendingPool {
* @param asset The address of the underlying asset of the reserve
* @return The configuration of the reserve
**/
function getConfiguration(address asset) external view returns (ReserveConfiguration.Map memory);
function getConfiguration(address asset)
external
view
returns (DataTypes.ReserveConfigurationMap memory);
/**
* @dev Returns the configuration of the user across all the reserves
* @param user The user address
* @return The configuration of the user
**/
function getUserConfiguration(address user) external view returns (UserConfiguration.Map memory);
function getUserConfiguration(address user)
external
view
returns (DataTypes.UserConfigurationMap memory);
/**
* @dev Returns the normalized income normalized income of the reserve
@ -383,7 +388,7 @@ interface ILendingPool {
* @param asset The address of the underlying asset of the reserve
* @return The state of the reserve
**/
function getReserveData(address asset) external view returns (ReserveLogic.ReserveData memory);
function getReserveData(address asset) external view returns (DataTypes.ReserveData memory);
function finalizeTransfer(
address asset,

View File

@ -49,5 +49,5 @@ interface ILendingPoolCollateralManager {
address user,
uint256 debtToCover,
bool receiveAToken
) external virtual returns (uint256, string memory);
) external returns (uint256, string memory);
}

View File

@ -5,15 +5,15 @@ pragma experimental ABIEncoderV2;
import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol';
import {ILendingPool} from '../interfaces/ILendingPool.sol';
import {ReserveLogic} from '../protocol/libraries/logic/ReserveLogic.sol';
import {ReserveConfiguration} from '../protocol/libraries/configuration/ReserveConfiguration.sol';
import {UserConfiguration} from '../protocol/libraries/configuration/UserConfiguration.sol';
import {IStableDebtToken} from '../protocol/tokenization/interfaces/IStableDebtToken.sol';
import {IVariableDebtToken} from '../protocol/tokenization/interfaces/IVariableDebtToken.sol';
import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
contract AaveProtocolDataProvider {
using ReserveConfiguration for ReserveConfiguration.Map;
using UserConfiguration for UserConfiguration.Map;
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
using UserConfiguration for DataTypes.UserConfigurationMap;
address constant MKR = 0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2;
address constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
@ -55,7 +55,7 @@ contract AaveProtocolDataProvider {
address[] memory reserves = pool.getReservesList();
TokenData[] memory aTokens = new TokenData[](reserves.length);
for (uint256 i = 0; i < reserves.length; i++) {
ReserveLogic.ReserveData memory reserveData = pool.getReserveData(reserves[i]);
DataTypes.ReserveData memory reserveData = pool.getReserveData(reserves[i]);
aTokens[i] = TokenData({
symbol: IERC20Detailed(reserveData.aTokenAddress).symbol(),
tokenAddress: reserveData.aTokenAddress
@ -80,7 +80,7 @@ contract AaveProtocolDataProvider {
bool isFrozen
)
{
ReserveConfiguration.Map memory configuration =
DataTypes.ReserveConfigurationMap memory configuration =
ILendingPool(ADDRESSES_PROVIDER.getLendingPool()).getConfiguration(asset);
(ltv, liquidationThreshold, liquidationBonus, decimals, reserveFactor) = configuration
@ -108,7 +108,7 @@ contract AaveProtocolDataProvider {
uint40 lastUpdateTimestamp
)
{
ReserveLogic.ReserveData memory reserve =
DataTypes.ReserveData memory reserve =
ILendingPool(ADDRESSES_PROVIDER.getLendingPool()).getReserveData(asset);
return (
@ -140,10 +140,10 @@ contract AaveProtocolDataProvider {
bool usageAsCollateralEnabled
)
{
ReserveLogic.ReserveData memory reserve =
DataTypes.ReserveData memory reserve =
ILendingPool(ADDRESSES_PROVIDER.getLendingPool()).getReserveData(asset);
UserConfiguration.Map memory userConfig =
DataTypes.UserConfigurationMap memory userConfig =
ILendingPool(ADDRESSES_PROVIDER.getLendingPool()).getUserConfiguration(user);
currentATokenBalance = IERC20Detailed(reserve.aTokenAddress).balanceOf(user);
@ -168,7 +168,7 @@ contract AaveProtocolDataProvider {
address variableDebtTokenAddress
)
{
ReserveLogic.ReserveData memory reserve =
DataTypes.ReserveData memory reserve =
ILendingPool(ADDRESSES_PROVIDER.getLendingPool()).getReserveData(asset);
return (

View File

@ -12,17 +12,17 @@ import {IVariableDebtToken} from '../protocol/tokenization/interfaces/IVariableD
import {IStableDebtToken} from '../protocol/tokenization/interfaces/IStableDebtToken.sol';
import {WadRayMath} from '../protocol/libraries/math/WadRayMath.sol';
import {ReserveLogic} from '../protocol/libraries/logic/ReserveLogic.sol';
import {ReserveConfiguration} from '../protocol/libraries/configuration/ReserveConfiguration.sol';
import {UserConfiguration} from '../protocol/libraries/configuration/UserConfiguration.sol';
import {
DefaultReserveInterestRateStrategy
} from '../protocol/lendingpool/DefaultReserveInterestRateStrategy.sol';
import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
contract UiPoolDataProvider is IUiPoolDataProvider {
using WadRayMath for uint256;
using ReserveConfiguration for ReserveConfiguration.Map;
using UserConfiguration for UserConfiguration.Map;
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
using UserConfiguration for DataTypes.UserConfigurationMap;
address public constant MOCK_USD_ADDRESS = 0x10F7Fc1F91Ba351f9C629c5947AD69bD03C05b96;
@ -57,7 +57,7 @@ contract UiPoolDataProvider is IUiPoolDataProvider {
ILendingPool lendingPool = ILendingPool(provider.getLendingPool());
IPriceOracleGetter oracle = IPriceOracleGetter(provider.getPriceOracle());
address[] memory reserves = lendingPool.getReservesList();
UserConfiguration.Map memory userConfig = lendingPool.getUserConfiguration(user);
DataTypes.UserConfigurationMap memory userConfig = lendingPool.getUserConfiguration(user);
AggregatedReserveData[] memory reservesData = new AggregatedReserveData[](reserves.length);
UserReserveData[] memory userReservesData =
@ -68,7 +68,7 @@ contract UiPoolDataProvider is IUiPoolDataProvider {
reserveData.underlyingAsset = reserves[i];
// reserve current state
ReserveLogic.ReserveData memory baseData =
DataTypes.ReserveData memory baseData =
lendingPool.getReserveData(reserveData.underlyingAsset);
reserveData.liquidityIndex = baseData.liquidityIndex;
reserveData.variableBorrowIndex = baseData.variableBorrowIndex;

View File

@ -6,16 +6,16 @@ import {IWETH} from './interfaces/IWETH.sol';
import {IWETHGateway} from './interfaces/IWETHGateway.sol';
import {ILendingPool} from '../interfaces/ILendingPool.sol';
import {IAToken} from '../protocol/tokenization/interfaces/IAToken.sol';
import {ReserveLogic} from '../protocol/libraries/logic/ReserveLogic.sol';
import {ReserveConfiguration} from '../protocol/libraries/configuration/ReserveConfiguration.sol';
import {UserConfiguration} from '../protocol/libraries/configuration/UserConfiguration.sol';
import {Helpers} from '../protocol/libraries/helpers/Helpers.sol';
import {Ownable} from '../dependencies/openzeppelin/contracts/Ownable.sol';
import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
contract WETHGateway is IWETHGateway, Ownable {
using ReserveConfiguration for ReserveConfiguration.Map;
using UserConfiguration for UserConfiguration.Map;
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
using UserConfiguration for DataTypes.UserConfigurationMap;
IWETH internal immutable WETH;
ILendingPool internal immutable POOL;
@ -79,7 +79,7 @@ contract WETHGateway is IWETHGateway, Ownable {
Helpers.getUserCurrentDebtMemory(onBehalfOf, POOL.getReserveData(address(WETH)));
uint256 paybackAmount =
ReserveLogic.InterestRateMode(rateMode) == ReserveLogic.InterestRateMode.STABLE
DataTypes.InterestRateMode(rateMode) == DataTypes.InterestRateMode.STABLE
? stableDebt
: variableDebt;

View File

@ -10,6 +10,7 @@ import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddresses
import {ILendingPool} from '../interfaces/ILendingPool.sol';
import {SafeERC20} from '../dependencies/openzeppelin/contracts/SafeERC20.sol';
import {ReserveConfiguration} from '../protocol/libraries/configuration/ReserveConfiguration.sol';
import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
/**
* @title WalletBalanceProvider contract
@ -22,7 +23,7 @@ contract WalletBalanceProvider {
using Address for address payable;
using Address for address;
using SafeERC20 for IERC20;
using ReserveConfiguration for ReserveConfiguration.Map;
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
address constant MOCK_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
@ -92,7 +93,7 @@ contract WalletBalanceProvider {
uint256[] memory balances = new uint256[](reservesWithEth.length);
for (uint256 j = 0; j < reserves.length; j++) {
ReserveConfiguration.Map memory configuration = pool.getConfiguration(reservesWithEth[j]);
DataTypes.ReserveConfigurationMap memory configuration = pool.getConfiguration(reservesWithEth[j]);
(bool isActive, , , ) = configuration.getFlagsMemory();

View File

@ -3,7 +3,6 @@ pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import {ILendingPoolAddressesProvider} from '../../interfaces/ILendingPoolAddressesProvider.sol';
import {ReserveLogic} from '../../protocol/libraries/logic/ReserveLogic.sol';
interface IUiPoolDataProvider {
struct AggregatedReserveData {

View File

@ -24,6 +24,7 @@ import {SafeERC20} from '../../dependencies/openzeppelin/contracts/SafeERC20.sol
import {ILendingPool} from '../../interfaces/ILendingPool.sol';
import {LendingPoolStorage} from './LendingPoolStorage.sol';
import {Address} from '../../dependencies/openzeppelin/contracts/Address.sol';
import {DataTypes} from '../libraries/types/DataTypes.sol';
/**
* @title LendingPool contract
@ -107,7 +108,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
address onBehalfOf,
uint16 referralCode
) external override whenNotPaused {
ReserveLogic.ReserveData storage reserve = _reserves[asset];
DataTypes.ReserveData storage reserve = _reserves[asset];
ValidationLogic.validateDeposit(reserve, amount);
@ -143,7 +144,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
uint256 amount,
address to
) external override whenNotPaused {
ReserveLogic.ReserveData storage reserve = _reserves[asset];
DataTypes.ReserveData storage reserve = _reserves[asset];
address aToken = reserve.aTokenAddress;
@ -202,7 +203,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
uint16 referralCode,
address onBehalfOf
) external override whenNotPaused {
ReserveLogic.ReserveData storage reserve = _reserves[asset];
DataTypes.ReserveData storage reserve = _reserves[asset];
_executeBorrow(
ExecuteBorrowParams(
@ -235,11 +236,11 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
uint256 rateMode,
address onBehalfOf
) external override whenNotPaused {
ReserveLogic.ReserveData storage reserve = _reserves[asset];
DataTypes.ReserveData storage reserve = _reserves[asset];
(uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(onBehalfOf, reserve);
ReserveLogic.InterestRateMode interestRateMode = ReserveLogic.InterestRateMode(rateMode);
DataTypes.InterestRateMode interestRateMode = DataTypes.InterestRateMode(rateMode);
ValidationLogic.validateRepay(
reserve,
@ -250,7 +251,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
variableDebt
);
uint256 paybackAmount = interestRateMode == ReserveLogic.InterestRateMode.STABLE
uint256 paybackAmount = interestRateMode == DataTypes.InterestRateMode.STABLE
? stableDebt
: variableDebt;
@ -260,7 +261,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
reserve.updateState();
if (interestRateMode == ReserveLogic.InterestRateMode.STABLE) {
if (interestRateMode == DataTypes.InterestRateMode.STABLE) {
IStableDebtToken(reserve.stableDebtTokenAddress).burn(onBehalfOf, paybackAmount);
} else {
IVariableDebtToken(reserve.variableDebtTokenAddress).burn(
@ -288,11 +289,11 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
* @param rateMode The rate mode that the user wants to swap to
**/
function swapBorrowRateMode(address asset, uint256 rateMode) external override whenNotPaused {
ReserveLogic.ReserveData storage reserve = _reserves[asset];
DataTypes.ReserveData storage reserve = _reserves[asset];
(uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(msg.sender, reserve);
ReserveLogic.InterestRateMode interestRateMode = ReserveLogic.InterestRateMode(rateMode);
DataTypes.InterestRateMode interestRateMode = DataTypes.InterestRateMode(rateMode);
ValidationLogic.validateSwapRateMode(
reserve,
@ -304,7 +305,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
reserve.updateState();
if (interestRateMode == ReserveLogic.InterestRateMode.STABLE) {
if (interestRateMode == DataTypes.InterestRateMode.STABLE) {
IStableDebtToken(reserve.stableDebtTokenAddress).burn(msg.sender, stableDebt);
IVariableDebtToken(reserve.variableDebtTokenAddress).mint(
msg.sender,
@ -341,7 +342,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
* @param user The address of the user to be rebalanced
**/
function rebalanceStableBorrowRate(address asset, address user) external override whenNotPaused {
ReserveLogic.ReserveData storage reserve = _reserves[asset];
DataTypes.ReserveData storage reserve = _reserves[asset];
IERC20 stableDebtToken = IERC20(reserve.stableDebtTokenAddress);
IERC20 variableDebtToken = IERC20(reserve.variableDebtTokenAddress);
@ -382,7 +383,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
override
whenNotPaused
{
ReserveLogic.ReserveData storage reserve = _reserves[asset];
DataTypes.ReserveData storage reserve = _reserves[asset];
ValidationLogic.validateSetUseReserveAsCollateral(
reserve,
@ -509,7 +510,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
vars.currentATokenAddress = aTokenAddresses[vars.i];
vars.currentAmountPlusPremium = vars.currentAmount.add(vars.currentPremium);
if (ReserveLogic.InterestRateMode(modes[vars.i]) == ReserveLogic.InterestRateMode.NONE) {
if (DataTypes.InterestRateMode(modes[vars.i]) == DataTypes.InterestRateMode.NONE) {
_reserves[vars.currentAsset].updateState();
_reserves[vars.currentAsset].cumulateToLiquidityIndex(
IERC20(vars.currentATokenAddress).totalSupply(),
@ -563,7 +564,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
external
view
override
returns (ReserveLogic.ReserveData memory)
returns (DataTypes.ReserveData memory)
{
return _reserves[asset];
}
@ -622,7 +623,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
external
view
override
returns (ReserveConfiguration.Map memory)
returns (DataTypes.ReserveConfigurationMap memory)
{
return _reserves[asset].configuration;
}
@ -636,7 +637,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
external
view
override
returns (UserConfiguration.Map memory)
returns (DataTypes.UserConfigurationMap memory)
{
return _usersConfig[user];
}
@ -729,13 +730,13 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
if (from != to) {
if (balanceFromBefore.sub(amount) == 0) {
UserConfiguration.Map storage fromConfig = _usersConfig[from];
DataTypes.UserConfigurationMap storage fromConfig = _usersConfig[from];
fromConfig.setUsingAsCollateral(reserveId, false);
emit ReserveUsedAsCollateralDisabled(asset, from);
}
if (balanceToBefore == 0 && amount != 0) {
UserConfiguration.Map storage toConfig = _usersConfig[to];
DataTypes.UserConfigurationMap storage toConfig = _usersConfig[to];
toConfig.setUsingAsCollateral(reserveId, true);
emit ReserveUsedAsCollateralEnabled(asset, to);
}
@ -823,8 +824,8 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
}
function _executeBorrow(ExecuteBorrowParams memory vars) internal {
ReserveLogic.ReserveData storage reserve = _reserves[vars.asset];
UserConfiguration.Map storage userConfig = _usersConfig[vars.onBehalfOf];
DataTypes.ReserveData storage reserve = _reserves[vars.asset];
DataTypes.UserConfigurationMap storage userConfig = _usersConfig[vars.onBehalfOf];
address oracle = _addressesProvider.getPriceOracle();
@ -854,7 +855,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
bool isFirstBorrowing = false;
if (
ReserveLogic.InterestRateMode(vars.interestRateMode) == ReserveLogic.InterestRateMode.STABLE
DataTypes.InterestRateMode(vars.interestRateMode) == DataTypes.InterestRateMode.STABLE
) {
currentStableRate = reserve.currentStableBorrowRate;
@ -894,7 +895,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
vars.onBehalfOf,
vars.amount,
vars.interestRateMode,
ReserveLogic.InterestRateMode(vars.interestRateMode) == ReserveLogic.InterestRateMode.STABLE
DataTypes.InterestRateMode(vars.interestRateMode) == DataTypes.InterestRateMode.STABLE
? currentStableRate
: reserve.currentVariableBorrowRate,
vars.referralCode

View File

@ -10,8 +10,6 @@ import {IVariableDebtToken} from '../tokenization/interfaces/IVariableDebtToken.
import {IPriceOracleGetter} from '../../interfaces/IPriceOracleGetter.sol';
import {ILendingPoolCollateralManager} from '../../interfaces/ILendingPoolCollateralManager.sol';
import {GenericLogic} from '../libraries/logic/GenericLogic.sol';
import {ReserveLogic} from '../libraries/logic/ReserveLogic.sol';
import {UserConfiguration} from '../libraries/configuration/UserConfiguration.sol';
import {Helpers} from '../libraries/helpers/Helpers.sol';
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
import {PercentageMath} from '../libraries/math/PercentageMath.sol';
@ -19,82 +17,76 @@ import {SafeERC20} from '../../dependencies/openzeppelin/contracts/SafeERC20.sol
import {Errors} from '../libraries/helpers/Errors.sol';
import {ValidationLogic} from '../libraries/logic/ValidationLogic.sol';
import {LendingPoolStorage} from './LendingPoolStorage.sol';
import {DataTypes} from '../libraries/types/DataTypes.sol';
/**
* @title LendingPoolCollateralManager contract
* @author Aave
* @notice Implements actions involving management of collateral in the protocol.
* @notice this contract will be ran always through delegatecall
* @dev LendingPoolCollateralManager inherits VersionedInitializable from OpenZeppelin to have the same storage layout as LendingPool
* @dev Implements actions involving management of collateral in the protocol, the main one being the liquidations
* IMPORTANT This contract will run always via DELEGATECALL, through the LendingPool, so the chain of inheritance
* is the same as the LendingPool, to have compatible storage layouts
**/
contract LendingPoolCollateralManager is ILendingPoolCollateralManager, VersionedInitializable, LendingPoolStorage {
contract LendingPoolCollateralManager is
ILendingPoolCollateralManager,
VersionedInitializable,
LendingPoolStorage
{
using SafeERC20 for IERC20;
using SafeMath for uint256;
using WadRayMath for uint256;
using PercentageMath for uint256;
// IMPORTANT The storage layout of the LendingPool is reproduced here because this contract
// is gonna be used through DELEGATECALL
uint256 internal constant LIQUIDATION_CLOSE_FACTOR_PERCENT = 5000;
struct LiquidationCallLocalVars {
uint256 userCollateralBalance;
uint256 userStableDebt;
uint256 userVariableDebt;
uint256 maxPrincipalAmountToLiquidate;
uint256 actualAmountToLiquidate;
uint256 maxLiquidatableDebt;
uint256 actualDebtToLiquidate;
uint256 liquidationRatio;
uint256 maxAmountCollateralToLiquidate;
uint256 userStableRate;
uint256 maxCollateralToLiquidate;
uint256 principalAmountNeeded;
uint256 debtAmountNeeded;
uint256 healthFactor;
IAToken collateralAtoken;
bool isCollateralEnabled;
ReserveLogic.InterestRateMode borrowRateMode;
address principalAToken;
DataTypes.InterestRateMode borrowRateMode;
uint256 errorCode;
string errorMsg;
}
struct AvailableCollateralToLiquidateLocalVars {
uint256 userCompoundedBorrowBalance;
uint256 liquidationBonus;
uint256 collateralPrice;
uint256 principalCurrencyPrice;
uint256 maxAmountCollateralToLiquidate;
uint256 principalDecimals;
uint256 collateralDecimals;
}
/**
* @dev as the contract extends the VersionedInitializable contract to match the state
* of the LendingPool contract, the getRevision() function is needed.
* @dev As thIS contract extends the VersionedInitializable contract to match the state
* of the LendingPool contract, the getRevision() function is needed, but the value is not
* important, as the initialize() function will never be called here
*/
function getRevision() internal pure override returns (uint256) {
return 0;
}
/**
* @dev users can invoke this function to liquidate an undercollateralized position.
* @param collateral the address of the collateral to liquidated
* @param principal the address of the principal reserve
* @param user the address of the borrower
* @param debtToCover the amount of principal that the liquidator wants to repay
* @param receiveAToken true if the liquidators wants to receive the aTokens, false if
* he wants to receive the underlying asset directly
* @dev Function to liquidate a position if its Health Factor drops below 1
* - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives
* a proportionally amount of the `collateralAsset` plus a bonus to cover market risk
* @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 user The address of the borrower getting liquidated
* @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
* @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants
* to receive the underlying collateral asset directly
**/
function liquidationCall(
address collateral,
address principal,
address collateralAsset,
address debtAsset,
address user,
uint256 debtToCover,
bool receiveAToken
) external override returns (uint256, string memory) {
ReserveLogic.ReserveData storage collateralReserve = _reserves[collateral];
ReserveLogic.ReserveData storage principalReserve = _reserves[principal];
UserConfiguration.Map storage userConfig = _usersConfig[user];
DataTypes.ReserveData storage collateralReserve = _reserves[collateralAsset];
DataTypes.ReserveData storage debtReserve = _reserves[debtAsset];
DataTypes.UserConfigurationMap storage userConfig = _usersConfig[user];
LiquidationCallLocalVars memory vars;
@ -107,15 +99,11 @@ contract LendingPoolCollateralManager is ILendingPoolCollateralManager, Versione
_addressesProvider.getPriceOracle()
);
//if the user hasn't borrowed the specific currency defined by asset, it cannot be liquidated
(vars.userStableDebt, vars.userVariableDebt) = Helpers.getUserCurrentDebt(
user,
principalReserve
);
(vars.userStableDebt, vars.userVariableDebt) = Helpers.getUserCurrentDebt(user, debtReserve);
(vars.errorCode, vars.errorMsg) = ValidationLogic.validateLiquidationCall(
collateralReserve,
principalReserve,
debtReserve,
userConfig,
vars.healthFactor,
vars.userStableDebt,
@ -130,38 +118,39 @@ contract LendingPoolCollateralManager is ILendingPoolCollateralManager, Versione
vars.userCollateralBalance = vars.collateralAtoken.balanceOf(user);
vars.maxPrincipalAmountToLiquidate = vars.userStableDebt.add(vars.userVariableDebt).percentMul(
vars.maxLiquidatableDebt = vars.userStableDebt.add(vars.userVariableDebt).percentMul(
LIQUIDATION_CLOSE_FACTOR_PERCENT
);
vars.actualAmountToLiquidate = debtToCover > vars.maxPrincipalAmountToLiquidate
? vars.maxPrincipalAmountToLiquidate
vars.actualDebtToLiquidate = debtToCover > vars.maxLiquidatableDebt
? vars.maxLiquidatableDebt
: debtToCover;
(
vars.maxCollateralToLiquidate,
vars.principalAmountNeeded
vars.debtAmountNeeded
) = _calculateAvailableCollateralToLiquidate(
collateralReserve,
principalReserve,
collateral,
principal,
vars.actualAmountToLiquidate,
debtReserve,
collateralAsset,
debtAsset,
vars.actualDebtToLiquidate,
vars.userCollateralBalance
);
//if principalAmountNeeded < vars.ActualAmountToLiquidate, there isn't enough
//of collateral to cover the actual amount that is being liquidated, hence we liquidate
//a smaller amount
// If debtAmountNeeded < actualDebtToLiquidate, there isn't enough
// collateral to cover the actual amount that is being liquidated, hence we liquidate
// a smaller amount
if (vars.principalAmountNeeded < vars.actualAmountToLiquidate) {
vars.actualAmountToLiquidate = vars.principalAmountNeeded;
if (vars.debtAmountNeeded < vars.actualDebtToLiquidate) {
vars.actualDebtToLiquidate = vars.debtAmountNeeded;
}
//if liquidator reclaims the underlying asset, we make sure there is enough available collateral in the reserve
// If the liquidator reclaims the underlying asset, we make sure there is enough available liquidity in the
// collateral reserve
if (!receiveAToken) {
uint256 currentAvailableCollateral =
IERC20(collateral).balanceOf(address(vars.collateralAtoken));
IERC20(collateralAsset).balanceOf(address(vars.collateralAtoken));
if (currentAvailableCollateral < vars.maxCollateralToLiquidate) {
return (
uint256(Errors.CollateralManagerErrors.NOT_ENOUGH_LIQUIDITY),
@ -170,54 +159,48 @@ contract LendingPoolCollateralManager is ILendingPoolCollateralManager, Versione
}
}
//update the principal reserve
principalReserve.updateState();
debtReserve.updateState();
if (vars.userVariableDebt >= vars.actualAmountToLiquidate) {
IVariableDebtToken(principalReserve.variableDebtTokenAddress).burn(
if (vars.userVariableDebt >= vars.actualDebtToLiquidate) {
IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn(
user,
vars.actualAmountToLiquidate,
principalReserve.variableBorrowIndex
vars.actualDebtToLiquidate,
debtReserve.variableBorrowIndex
);
} else {
//if the user does not 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) {
IVariableDebtToken(principalReserve.variableDebtTokenAddress).burn(
IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn(
user,
vars.userVariableDebt,
principalReserve.variableBorrowIndex
debtReserve.variableBorrowIndex
);
}
IStableDebtToken(principalReserve.stableDebtTokenAddress).burn(
IStableDebtToken(debtReserve.stableDebtTokenAddress).burn(
user,
vars.actualAmountToLiquidate.sub(vars.userVariableDebt)
vars.actualDebtToLiquidate.sub(vars.userVariableDebt)
);
}
principalReserve.updateInterestRates(
principal,
principalReserve.aTokenAddress,
vars.actualAmountToLiquidate,
debtReserve.updateInterestRates(
debtAsset,
debtReserve.aTokenAddress,
vars.actualDebtToLiquidate,
0
);
//if liquidator reclaims the aToken, he receives the equivalent atoken amount
if (receiveAToken) {
vars.collateralAtoken.transferOnLiquidation(user, msg.sender, vars.maxCollateralToLiquidate);
} else {
//otherwise receives the underlying asset
//updating collateral reserve
collateralReserve.updateState();
collateralReserve.updateInterestRates(
collateral,
collateralAsset,
address(vars.collateralAtoken),
0,
vars.maxCollateralToLiquidate
);
//burn the equivalent amount of atoken
// Burn the equivalent amount of aToken, sending the underlying to the liquidator
vars.collateralAtoken.burn(
user,
msg.sender,
@ -226,26 +209,25 @@ contract LendingPoolCollateralManager is ILendingPoolCollateralManager, Versione
);
}
//if the collateral being liquidated is equal to the user balance,
//we set the currency as not being used as collateral anymore
// If the collateral being liquidated is equal to the user balance,
// we set the currency as not being used as collateral anymore
if (vars.maxCollateralToLiquidate == vars.userCollateralBalance) {
userConfig.setUsingAsCollateral(collateralReserve.id, false);
emit ReserveUsedAsCollateralDisabled(collateral, user);
emit ReserveUsedAsCollateralDisabled(collateralAsset, user);
}
//transfers the principal currency to the aToken
IERC20(principal).safeTransferFrom(
// Transfers the debt asset being repaid to the aToken, where the liquidity is kept
IERC20(debtAsset).safeTransferFrom(
msg.sender,
principalReserve.aTokenAddress,
vars.actualAmountToLiquidate
debtReserve.aTokenAddress,
vars.actualDebtToLiquidate
);
emit LiquidationCall(
collateral,
principal,
collateralAsset,
debtAsset,
user,
vars.actualAmountToLiquidate,
vars.actualDebtToLiquidate,
vars.maxCollateralToLiquidate,
msg.sender,
receiveAToken
@ -254,60 +236,74 @@ contract LendingPoolCollateralManager is ILendingPoolCollateralManager, Versione
return (uint256(Errors.CollateralManagerErrors.NO_ERROR), Errors.LPCM_NO_ERRORS);
}
struct AvailableCollateralToLiquidateLocalVars {
uint256 userCompoundedBorrowBalance;
uint256 liquidationBonus;
uint256 collateralPrice;
uint256 debtAssetPrice;
uint256 maxAmountCollateralToLiquidate;
uint256 debtAssetDecimals;
uint256 collateralDecimals;
}
/**
* @dev calculates how much of a specific collateral can be liquidated, given
* a certain amount of principal currency. This function needs to be called after
* all the checks to validate the liquidation have been performed, otherwise it might fail.
* @param collateralAddress the collateral to be liquidated
* @param principalAddress the principal currency to be liquidated
* @param debtToCover the amount of principal being liquidated
* @param userCollateralBalance the collatera balance for the specific collateral asset of the user being liquidated
* @return collateralAmount the maximum amount that is possible to liquidated given all the liquidation constraints (user balance, close factor)
* @return principalAmountNeeded the purchase amount
* @dev Calculates how much of a specific collateral can be liquidated, given
* a certain amount of debt asset.
* - 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 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
* @param userCollateralBalance The collateral balance for the specific `collateralAsset` of the user being liquidated
* @return collateralAmount: The maximum amount that is possible to liquidate given all the liquidation constraints
* (user balance, close factor)
* debtAmountNeeded: The amount to repay with the liquidation
**/
function _calculateAvailableCollateralToLiquidate(
ReserveLogic.ReserveData storage collateralReserve,
ReserveLogic.ReserveData storage principalReserve,
address collateralAddress,
address principalAddress,
DataTypes.ReserveData storage collateralReserve,
DataTypes.ReserveData storage debtReserve,
address collateralAsset,
address debtAsset,
uint256 debtToCover,
uint256 userCollateralBalance
) internal view returns (uint256, uint256) {
uint256 collateralAmount = 0;
uint256 principalAmountNeeded = 0;
uint256 debtAmountNeeded = 0;
IPriceOracleGetter oracle = IPriceOracleGetter(_addressesProvider.getPriceOracle());
AvailableCollateralToLiquidateLocalVars memory vars;
vars.collateralPrice = oracle.getAssetPrice(collateralAddress);
vars.principalCurrencyPrice = oracle.getAssetPrice(principalAddress);
vars.collateralPrice = oracle.getAssetPrice(collateralAsset);
vars.debtAssetPrice = oracle.getAssetPrice(debtAsset);
(, , vars.liquidationBonus, vars.collateralDecimals, ) = collateralReserve
.configuration
.getParams();
vars.principalDecimals = principalReserve.configuration.getDecimals();
vars.debtAssetDecimals = debtReserve.configuration.getDecimals();
//this is the maximum possible amount of the selected collateral that can be liquidated, given the
//max amount of principal currency that is available for liquidation.
// This is the maximum possible amount of the selected collateral that can be liquidated, given the
// max amount of liquidatable debt
vars.maxAmountCollateralToLiquidate = vars
.principalCurrencyPrice
.debtAssetPrice
.mul(debtToCover)
.mul(10**vars.collateralDecimals)
.percentMul(vars.liquidationBonus)
.div(vars.collateralPrice.mul(10**vars.principalDecimals));
.div(vars.collateralPrice.mul(10**vars.debtAssetDecimals));
if (vars.maxAmountCollateralToLiquidate > userCollateralBalance) {
collateralAmount = userCollateralBalance;
principalAmountNeeded = vars
debtAmountNeeded = vars
.collateralPrice
.mul(collateralAmount)
.mul(10**vars.principalDecimals)
.div(vars.principalCurrencyPrice.mul(10**vars.collateralDecimals))
.mul(10**vars.debtAssetDecimals)
.div(vars.debtAssetPrice.mul(10**vars.collateralDecimals))
.percentDiv(vars.liquidationBonus);
} else {
collateralAmount = vars.maxAmountCollateralToLiquidate;
principalAmountNeeded = debtToCover;
debtAmountNeeded = debtToCover;
}
return (collateralAmount, principalAmountNeeded);
return (collateralAmount, debtAmountNeeded);
}
}

View File

@ -14,26 +14,26 @@ import {ITokenConfiguration} from '../tokenization/interfaces/ITokenConfiguratio
import {IERC20Detailed} from '../../dependencies/openzeppelin/contracts/IERC20Detailed.sol';
import {Errors} from '../libraries/helpers/Errors.sol';
import {PercentageMath} from '../libraries/math/PercentageMath.sol';
import {ReserveLogic} from '../libraries/logic/ReserveLogic.sol';
import {DataTypes} from '../libraries/types/DataTypes.sol';
/**
* @title LendingPoolConfigurator contract
* @author Aave
* @notice Executes configuration methods on the LendingPoolCore contract. Allows to enable/disable reserves
* and set different protocol parameters.
* @dev Implements the configuration methods for the Aave protocol
**/
contract LendingPoolConfigurator is VersionedInitializable {
using SafeMath for uint256;
using ReserveConfiguration for ReserveConfiguration.Map;
using PercentageMath for uint256;
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
/**
* @dev emitted when a reserve is initialized.
* @param asset the address of the reserve
* @param aToken the address of the overlying aToken contract
* @param stableDebtToken the address of the associated stable rate debt token
* @param variableDebtToken the address of the associated variable rate debt token
* @param interestRateStrategyAddress the address of the interest rate strategy for the reserve
* @dev Emitted when a reserve is initialized.
* @param asset The address of the underlying asset of the reserve
* @param aToken The address of the associated aToken contract
* @param stableDebtToken The address of the associated stable rate debt token
* @param variableDebtToken The address of the associated variable rate debt token
* @param interestRateStrategyAddress The address of the interest rate strategy for the reserve
**/
event ReserveInitialized(
address indexed asset,
@ -44,24 +44,24 @@ contract LendingPoolConfigurator is VersionedInitializable {
);
/**
* @dev emitted when borrowing is enabled on a reserve
* @param asset the address of the reserve
* @param stableRateEnabled true if stable rate borrowing is enabled, false otherwise
* @dev Emitted when borrowing is enabled on a reserve
* @param asset The address of the underlying asset of the reserve
* @param stableRateEnabled True if stable rate borrowing is enabled, false otherwise
**/
event BorrowingEnabledOnReserve(address indexed asset, bool stableRateEnabled);
/**
* @dev emitted when borrowing is disabled on a reserve
* @param asset the address of the reserve
* @dev Emitted when borrowing is disabled on a reserve
* @param asset The address of the underlying asset of the reserve
**/
event BorrowingDisabledOnReserve(address indexed asset);
/**
* @dev emitted when a a reserve collateralization risk parameters are updated.
* @param asset the address of the reserve
* @param ltv the loan to value of the asset when used as collateral
* @param liquidationThreshold the threshold at which loans using this asset as collateral will be considered undercollateralized
* @param liquidationBonus the bonus liquidators receive to liquidate this asset
* @dev Emitted when the collateralization risk parameters for the specified asset are updated.
* @param asset The address of the underlying asset of the reserve
* @param ltv The loan to value of the asset when used as collateral
* @param liquidationThreshold The threshold at which loans using this asset as collateral will be considered undercollateralized
* @param liquidationBonus The bonus liquidators receive to liquidate this asset
**/
event CollateralConfigurationChanged(
address indexed asset,
@ -71,67 +71,67 @@ contract LendingPoolConfigurator is VersionedInitializable {
);
/**
* @dev emitted when stable rate borrowing is enabled on a reserve
* @param asset the address of the reserve
* @dev Emitted when stable rate borrowing is enabled on a reserve
* @param asset The address of the underlying asset of the reserve
**/
event StableRateEnabledOnReserve(address indexed asset);
/**
* @dev emitted when stable rate borrowing is disabled on a reserve
* @param asset the address of the reserve
* @dev Emitted when stable rate borrowing is disabled on a reserve
* @param asset The address of the underlying asset of the reserve
**/
event StableRateDisabledOnReserve(address indexed asset);
/**
* @dev emitted when a reserve is activated
* @param asset the address of the reserve
* @dev Emitted when a reserve is activated
* @param asset The address of the underlying asset of the reserve
**/
event ReserveActivated(address indexed asset);
/**
* @dev emitted when a reserve is deactivated
* @param asset the address of the reserve
* @dev Emitted when a reserve is deactivated
* @param asset The address of the underlying asset of the reserve
**/
event ReserveDeactivated(address indexed asset);
/**
* @dev emitted when a reserve is frozen
* @param asset the address of the reserve
* @dev Emitted when a reserve is frozen
* @param asset The address of the underlying asset of the reserve
**/
event ReserveFrozen(address indexed asset);
/**
* @dev emitted when a reserve is unfrozen
* @param asset the address of the reserve
* @dev Emitted when a reserve is unfrozen
* @param asset The address of the underlying asset of the reserve
**/
event ReserveUnfrozen(address indexed asset);
/**
* @dev emitted when a reserve factor is updated
* @param asset the address of the reserve
* @param factor the new reserve factor
* @dev Emitted when a reserve factor is updated
* @param asset The address of the underlying asset of the reserve
* @param factor The new reserve factor
**/
event ReserveFactorChanged(address indexed asset, uint256 factor);
/**
* @dev emitted when the reserve decimals are updated
* @param asset the address of the reserve
* @param decimals the new decimals
* @dev Emitted when the reserve decimals are updated
* @param asset The address of the underlying asset of the reserve
* @param decimals The new decimals
**/
event ReserveDecimalsChanged(address indexed asset, uint256 decimals);
/**
* @dev emitted when a reserve interest strategy contract is updated
* @param asset the address of the reserve
* @param strategy the new address of the interest strategy contract
* @dev Emitted when a reserve interest strategy contract is updated
* @param asset The address of the underlying asset of the reserve
* @param strategy The new address of the interest strategy contract
**/
event ReserveInterestRateStrategyChanged(address indexed asset, address strategy);
/**
* @dev emitted when an aToken implementation is upgraded
* @param asset the address of the reserve
* @param proxy the aToken proxy address
* @param implementation the new aToken implementation
* @dev Emitted when an aToken implementation is upgraded
* @param asset The address of the underlying asset of the reserve
* @param proxy The aToken proxy address
* @param implementation The new aToken implementation
**/
event ATokenUpgraded(
address indexed asset,
@ -140,10 +140,10 @@ contract LendingPoolConfigurator is VersionedInitializable {
);
/**
* @dev emitted when the implementation of a stable debt token is upgraded
* @param asset the address of the reserve
* @param proxy the stable debt token proxy address
* @param implementation the new aToken implementation
* @dev Emitted when the implementation of a stable debt token is upgraded
* @param asset The address of the underlying asset of the reserve
* @param proxy The stable debt token proxy address
* @param implementation The new aToken implementation
**/
event StableDebtTokenUpgraded(
address indexed asset,
@ -152,10 +152,10 @@ contract LendingPoolConfigurator is VersionedInitializable {
);
/**
* @dev emitted when the implementation of a variable debt token is upgraded
* @param asset the address of the reserve
* @param proxy the variable debt token proxy address
* @param implementation the new aToken implementation
* @dev Emitted when the implementation of a variable debt token is upgraded
* @param asset The address of the underlying asset of the reserve
* @param proxy The variable debt token proxy address
* @param implementation The new aToken implementation
**/
event VariableDebtTokenUpgraded(
address indexed asset,
@ -166,17 +166,11 @@ contract LendingPoolConfigurator is VersionedInitializable {
ILendingPoolAddressesProvider internal addressesProvider;
ILendingPool internal pool;
/**
* @dev only the pool admin can call functions affected by this modifier
**/
modifier onlyPoolAdmin {
require(addressesProvider.getPoolAdmin() == msg.sender, Errors.CALLER_NOT_POOL_ADMIN);
_;
}
/**
* @dev only the emergency admin can call functions affected by this modifier
**/
modifier onlyEmergencyAdmin {
require(
addressesProvider.getEmergencyAdmin() == msg.sender,
@ -185,7 +179,7 @@ contract LendingPoolConfigurator is VersionedInitializable {
_;
}
uint256 internal constant CONFIGURATOR_REVISION = 0x3;
uint256 internal constant CONFIGURATOR_REVISION = 0x1;
function getRevision() internal pure override returns (uint256) {
return CONFIGURATOR_REVISION;
@ -197,12 +191,12 @@ contract LendingPoolConfigurator is VersionedInitializable {
}
/**
* @dev initializes a reserve
* @param aTokenImpl the address of the aToken contract implementation
* @param stableDebtTokenImpl the address of the stable debt token contract
* @param variableDebtTokenImpl the address of the variable debt token contract
* @param underlyingAssetDecimals the decimals of the reserve underlying asset
* @param interestRateStrategyAddress the address of the interest rate strategy contract for this reserve
* @dev Initializes a reserve
* @param aTokenImpl The address of the aToken contract implementation
* @param stableDebtTokenImpl The address of the stable debt token contract
* @param variableDebtTokenImpl The address of the variable debt token contract
* @param underlyingAssetDecimals The decimals of the reserve underlying asset
* @param interestRateStrategyAddress The address of the interest rate strategy contract for this reserve
**/
function initReserve(
address aTokenImpl,
@ -250,7 +244,7 @@ contract LendingPoolConfigurator is VersionedInitializable {
interestRateStrategyAddress
);
ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset);
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
currentConfig.setDecimals(underlyingAssetDecimals);
@ -269,12 +263,12 @@ contract LendingPoolConfigurator is VersionedInitializable {
}
/**
* @dev updates the aToken implementation for the asset
* @param asset the address of the reserve to be updated
* @param implementation the address of the new aToken implementation
* @dev Updates the aToken implementation for the reserve
* @param asset The address of the underlying asset of the reserve to be updated
* @param implementation The address of the new aToken implementation
**/
function updateAToken(address asset, address implementation) external onlyPoolAdmin {
ReserveLogic.ReserveData memory reserveData = pool.getReserveData(asset);
DataTypes.ReserveData memory reserveData = pool.getReserveData(asset);
_upgradeTokenImplementation(asset, reserveData.aTokenAddress, implementation);
@ -282,12 +276,12 @@ contract LendingPoolConfigurator is VersionedInitializable {
}
/**
* @dev updates the stable debt token implementation for the asset
* @param asset the address of the reserve to be updated
* @param implementation the address of the new aToken implementation
* @dev Updates the stable debt token implementation for the reserve
* @param asset The address of the underlying asset of the reserve to be updated
* @param implementation The address of the new aToken implementation
**/
function updateStableDebtToken(address asset, address implementation) external onlyPoolAdmin {
ReserveLogic.ReserveData memory reserveData = pool.getReserveData(asset);
DataTypes.ReserveData memory reserveData = pool.getReserveData(asset);
_upgradeTokenImplementation(asset, reserveData.stableDebtTokenAddress, implementation);
@ -295,12 +289,12 @@ contract LendingPoolConfigurator is VersionedInitializable {
}
/**
* @dev updates the variable debt token implementation for the asset
* @param asset the address of the reserve to be updated
* @param implementation the address of the new aToken implementation
* @dev Updates the variable debt token implementation for the asset
* @param asset The address of the underlying asset of the reserve to be updated
* @param implementation The address of the new aToken implementation
**/
function updateVariableDebtToken(address asset, address implementation) external onlyPoolAdmin {
ReserveLogic.ReserveData memory reserveData = pool.getReserveData(asset);
DataTypes.ReserveData memory reserveData = pool.getReserveData(asset);
_upgradeTokenImplementation(asset, reserveData.variableDebtTokenAddress, implementation);
@ -308,15 +302,15 @@ contract LendingPoolConfigurator is VersionedInitializable {
}
/**
* @dev enables borrowing on a reserve
* @param asset the address of the reserve
* @param stableBorrowRateEnabled true if stable borrow rate needs to be enabled by default on this reserve
* @dev Enables borrowing on a reserve
* @param asset The address of the underlying asset of the reserve
* @param stableBorrowRateEnabled True if stable borrow rate needs to be enabled by default on this reserve
**/
function enableBorrowingOnReserve(address asset, bool stableBorrowRateEnabled)
external
onlyPoolAdmin
{
ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset);
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
currentConfig.setBorrowingEnabled(true);
currentConfig.setStableRateBorrowingEnabled(stableBorrowRateEnabled);
@ -327,11 +321,11 @@ contract LendingPoolConfigurator is VersionedInitializable {
}
/**
* @dev disables borrowing on a reserve
* @param asset the address of the reserve
* @dev Disables borrowing on a reserve
* @param asset The address of the underlying asset of the reserve
**/
function disableBorrowingOnReserve(address asset) external onlyPoolAdmin {
ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset);
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
currentConfig.setBorrowingEnabled(false);
@ -340,12 +334,12 @@ contract LendingPoolConfigurator is VersionedInitializable {
}
/**
* @dev configures the reserve collateralization parameters.
* @dev Configures the reserve collateralization parameters
* all the values are expressed in percentages with two decimals of precision. A valid value is 10000, which means 100.00%
* @param asset the address of the reserve
* @param ltv the loan to value of the asset when used as collateral
* @param liquidationThreshold the threshold at which loans using this asset as collateral will be considered undercollateralized
* @param liquidationBonus the bonus liquidators receive to liquidate this asset. The values is always above 100%. A value of 105%
* @param asset The address of the underlying asset of the reserve
* @param ltv The loan to value of the asset when used as collateral
* @param liquidationThreshold The threshold at which loans using this asset as collateral will be considered undercollateralized
* @param liquidationBonus The bonus liquidators receive to liquidate this asset. The values is always above 100%. A value of 105%
* means the liquidator will receive a 5% bonus
**/
function configureReserveAsCollateral(
@ -354,7 +348,7 @@ contract LendingPoolConfigurator is VersionedInitializable {
uint256 liquidationThreshold,
uint256 liquidationBonus
) external onlyPoolAdmin {
ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset);
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
//validation of the parameters: the LTV can
//only be lower or equal than the liquidation threshold
@ -363,15 +357,16 @@ contract LendingPoolConfigurator is VersionedInitializable {
if (liquidationThreshold != 0) {
//liquidation bonus must be bigger than 100.00%, otherwise the liquidator would receive less
//collateral than needed to cover the debt.
uint256 absoluteBonus =
liquidationBonus.sub(PercentageMath.PERCENTAGE_FACTOR, Errors.LPC_INVALID_CONFIGURATION);
require(absoluteBonus > 0, Errors.LPC_INVALID_CONFIGURATION);
//we also need to require that the liq threshold is lower or equal than the liquidation bonus, to ensure that
//there is always enough margin for liquidators to receive the bonus.
//collateral than needed to cover the debt
require(
liquidationThreshold.add(absoluteBonus) <= PercentageMath.PERCENTAGE_FACTOR,
liquidationBonus > PercentageMath.PERCENTAGE_FACTOR,
Errors.LPC_INVALID_CONFIGURATION
);
//if threshold * bonus is less than PERCENTAGE_FACTOR, it's guaranteed that at the moment
//a loan is taken there is enough collateral available to cover the liquidation bonus
require(
liquidationThreshold.percentMul(liquidationBonus) <= PercentageMath.PERCENTAGE_FACTOR,
Errors.LPC_INVALID_CONFIGURATION
);
} else {
@ -392,11 +387,11 @@ contract LendingPoolConfigurator is VersionedInitializable {
}
/**
* @dev enable stable rate borrowing on a reserve
* @param asset the address of the reserve
* @dev Enable stable rate borrowing on a reserve
* @param asset The address of the underlying asset of the reserve
**/
function enableReserveStableRate(address asset) external onlyPoolAdmin {
ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset);
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
currentConfig.setStableRateBorrowingEnabled(true);
@ -406,11 +401,11 @@ contract LendingPoolConfigurator is VersionedInitializable {
}
/**
* @dev disable stable rate borrowing on a reserve
* @param asset the address of the reserve
* @dev Disable stable rate borrowing on a reserve
* @param asset The address of the underlying asset of the reserve
**/
function disableReserveStableRate(address asset) external onlyPoolAdmin {
ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset);
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
currentConfig.setStableRateBorrowingEnabled(false);
@ -420,11 +415,11 @@ contract LendingPoolConfigurator is VersionedInitializable {
}
/**
* @dev activates a reserve
* @param asset the address of the reserve
* @dev Activates a reserve
* @param asset The address of the underlying asset of the reserve
**/
function activateReserve(address asset) external onlyPoolAdmin {
ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset);
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
currentConfig.setActive(true);
@ -434,13 +429,13 @@ contract LendingPoolConfigurator is VersionedInitializable {
}
/**
* @dev deactivates a reserve
* @param asset the address of the reserve
* @dev Deactivates a reserve
* @param asset The address of the underlying asset of the reserve
**/
function deactivateReserve(address asset) external onlyPoolAdmin {
_checkNoLiquidity(asset);
ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset);
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
currentConfig.setActive(false);
@ -450,11 +445,12 @@ contract LendingPoolConfigurator is VersionedInitializable {
}
/**
* @dev freezes a reserve. A frozen reserve doesn't accept any new deposit, borrow or rate swap, but can accept repayments, liquidations, rate rebalances and redeems
* @param asset the address of the reserve
* @dev Freezes a reserve. A frozen reserve doesn't allow any new deposit, borrow or rate swap
* but allows repayments, liquidations, rate rebalances and withdrawals
* @param asset The address of the underlying asset of the reserve
**/
function freezeReserve(address asset) external onlyPoolAdmin {
ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset);
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
currentConfig.setFrozen(true);
@ -464,11 +460,11 @@ contract LendingPoolConfigurator is VersionedInitializable {
}
/**
* @dev unfreezes a reserve
* @param asset the address of the reserve
* @dev Unfreezes a reserve
* @param asset The address of the underlying asset of the reserve
**/
function unfreezeReserve(address asset) external onlyPoolAdmin {
ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset);
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
currentConfig.setFrozen(false);
@ -478,12 +474,12 @@ contract LendingPoolConfigurator is VersionedInitializable {
}
/**
* @dev updates the reserve factor of a reserve
* @param asset the address of the reserve
* @param reserveFactor the new reserve factor of the reserve
* @dev Updates the reserve factor of a reserve
* @param asset The address of the underlying asset of the reserve
* @param reserveFactor The new reserve factor of the reserve
**/
function setReserveFactor(address asset, uint256 reserveFactor) external onlyPoolAdmin {
ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset);
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
currentConfig.setReserveFactor(reserveFactor);
@ -493,9 +489,9 @@ contract LendingPoolConfigurator is VersionedInitializable {
}
/**
* @dev sets the interest rate strategy of a reserve
* @param asset the address of the reserve
* @param rateStrategyAddress the new address of the interest strategy contract
* @dev Sets the interest rate strategy of a reserve
* @param asset The address of the underlying asset of the reserve
* @param rateStrategyAddress The new address of the interest strategy contract
**/
function setReserveInterestRateStrategyAddress(address asset, address rateStrategyAddress)
external
@ -506,10 +502,13 @@ contract LendingPoolConfigurator is VersionedInitializable {
}
/**
* @dev initializes a token with a proxy and a specific implementation
* @param implementation the address of the implementation
* @param decimals the decimals of the token
* @dev pauses or unpauses all the actions of the protocol, including aToken transfers
* @param val true if protocol needs to be paused, false otherwise
**/
function setPoolPause(bool val) external onlyEmergencyAdmin {
pool.setPause(val);
}
function _initTokenWithProxy(address implementation, uint8 decimals) internal returns (address) {
InitializableImmutableAdminUpgradeabilityProxy proxy =
new InitializableImmutableAdminUpgradeabilityProxy(address(this));
@ -535,7 +534,7 @@ contract LendingPoolConfigurator is VersionedInitializable {
InitializableImmutableAdminUpgradeabilityProxy proxy =
InitializableImmutableAdminUpgradeabilityProxy(payable(proxyAddress));
ReserveConfiguration.Map memory configuration = pool.getConfiguration(asset);
DataTypes.ReserveConfigurationMap memory configuration = pool.getConfiguration(asset);
(, , , uint256 decimals, ) = configuration.getParamsMemory();
@ -550,16 +549,8 @@ contract LendingPoolConfigurator is VersionedInitializable {
proxy.upgradeToAndCall(implementation, params);
}
/**
* @dev pauses or unpauses LendingPool actions
* @param val the boolean value to set the current pause state of LendingPool
**/
function setPoolPause(bool val) external onlyEmergencyAdmin {
pool.setPause(val);
}
function _checkNoLiquidity(address asset) internal view {
ReserveLogic.ReserveData memory reserveData = pool.getReserveData(asset);
DataTypes.ReserveData memory reserveData = pool.getReserveData(asset);
uint256 availableLiquidity = IERC20Detailed(asset).balanceOf(reserveData.aTokenAddress);

View File

@ -5,16 +5,17 @@ import {UserConfiguration} from '../libraries/configuration/UserConfiguration.so
import {ReserveConfiguration} from '../libraries/configuration/ReserveConfiguration.sol';
import {ReserveLogic} from '../libraries/logic/ReserveLogic.sol';
import {ILendingPoolAddressesProvider} from '../../interfaces/ILendingPoolAddressesProvider.sol';
import {DataTypes} from '../libraries/types/DataTypes.sol';
contract LendingPoolStorage {
using ReserveLogic for ReserveLogic.ReserveData;
using ReserveConfiguration for ReserveConfiguration.Map;
using UserConfiguration for UserConfiguration.Map;
using ReserveLogic for DataTypes.ReserveData;
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
using UserConfiguration for DataTypes.UserConfigurationMap;
ILendingPoolAddressesProvider internal _addressesProvider;
mapping(address => ReserveLogic.ReserveData) internal _reserves;
mapping(address => UserConfiguration.Map) internal _usersConfig;
mapping(address => DataTypes.ReserveData) internal _reserves;
mapping(address => DataTypes.UserConfigurationMap) internal _usersConfig;
// the list of the available reserves, structured as a mapping for gas savings reasons
mapping(uint256 => address) internal _reservesList;

View File

@ -2,6 +2,7 @@
pragma solidity 0.6.12;
import {Errors} from '../helpers/Errors.sol';
import {DataTypes} from '../types/DataTypes.sol';
/**
* @title ReserveConfiguration library
@ -35,26 +36,12 @@ library ReserveConfiguration {
uint256 constant MAX_VALID_DECIMALS = 255;
uint256 constant MAX_VALID_RESERVE_FACTOR = 65535;
struct Map {
//bit 0-15: LTV
//bit 16-31: Liq. threshold
//bit 32-47: Liq. bonus
//bit 48-55: Decimals
//bit 56: Reserve is active
//bit 57: reserve is frozen
//bit 58: borrowing is enabled
//bit 59: stable rate borrowing enabled
//bit 60-63: reserved
//bit 64-79: reserve factor
uint256 data;
}
/**
* @dev sets the Loan to Value of the reserve
* @param self the reserve configuration
* @param ltv the new ltv
**/
function setLtv(ReserveConfiguration.Map memory self, uint256 ltv) internal pure {
function setLtv(DataTypes.ReserveConfigurationMap memory self, uint256 ltv) internal pure {
require(ltv <= MAX_VALID_LTV, Errors.RC_INVALID_LTV);
self.data = (self.data & LTV_MASK) | ltv;
@ -65,7 +52,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @return the loan to value
**/
function getLtv(ReserveConfiguration.Map storage self) internal view returns (uint256) {
function getLtv(DataTypes.ReserveConfigurationMap storage self) internal view returns (uint256) {
return self.data & ~LTV_MASK;
}
@ -74,7 +61,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @param threshold the new liquidation threshold
**/
function setLiquidationThreshold(ReserveConfiguration.Map memory self, uint256 threshold)
function setLiquidationThreshold(DataTypes.ReserveConfigurationMap memory self, uint256 threshold)
internal
pure
{
@ -90,7 +77,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @return the liquidation threshold
**/
function getLiquidationThreshold(ReserveConfiguration.Map storage self)
function getLiquidationThreshold(DataTypes.ReserveConfigurationMap storage self)
internal
view
returns (uint256)
@ -103,7 +90,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @param bonus the new liquidation bonus
**/
function setLiquidationBonus(ReserveConfiguration.Map memory self, uint256 bonus) internal pure {
function setLiquidationBonus(DataTypes.ReserveConfigurationMap memory self, uint256 bonus) internal pure {
require(bonus <= MAX_VALID_LIQUIDATION_BONUS, Errors.RC_INVALID_LIQ_BONUS);
self.data =
@ -116,7 +103,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @return the liquidation bonus
**/
function getLiquidationBonus(ReserveConfiguration.Map storage self)
function getLiquidationBonus(DataTypes.ReserveConfigurationMap storage self)
internal
view
returns (uint256)
@ -129,7 +116,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @param decimals the decimals
**/
function setDecimals(ReserveConfiguration.Map memory self, uint256 decimals) internal pure {
function setDecimals(DataTypes.ReserveConfigurationMap memory self, uint256 decimals) internal pure {
require(decimals <= MAX_VALID_DECIMALS, Errors.RC_INVALID_DECIMALS);
self.data = (self.data & DECIMALS_MASK) | (decimals << RESERVE_DECIMALS_START_BIT_POSITION);
@ -140,7 +127,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @return the decimals of the asset
**/
function getDecimals(ReserveConfiguration.Map storage self) internal view returns (uint256) {
function getDecimals(DataTypes.ReserveConfigurationMap storage self) internal view returns (uint256) {
return (self.data & ~DECIMALS_MASK) >> RESERVE_DECIMALS_START_BIT_POSITION;
}
@ -149,7 +136,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @param active the active state
**/
function setActive(ReserveConfiguration.Map memory self, bool active) internal pure {
function setActive(DataTypes.ReserveConfigurationMap memory self, bool active) internal pure {
self.data =
(self.data & ACTIVE_MASK) |
(uint256(active ? 1 : 0) << IS_ACTIVE_START_BIT_POSITION);
@ -160,7 +147,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @return the active state
**/
function getActive(ReserveConfiguration.Map storage self) internal view returns (bool) {
function getActive(DataTypes.ReserveConfigurationMap storage self) internal view returns (bool) {
return (self.data & ~ACTIVE_MASK) != 0;
}
@ -169,7 +156,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @param frozen the frozen state
**/
function setFrozen(ReserveConfiguration.Map memory self, bool frozen) internal pure {
function setFrozen(DataTypes.ReserveConfigurationMap memory self, bool frozen) internal pure {
self.data =
(self.data & FROZEN_MASK) |
(uint256(frozen ? 1 : 0) << IS_FROZEN_START_BIT_POSITION);
@ -180,7 +167,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @return the frozen state
**/
function getFrozen(ReserveConfiguration.Map storage self) internal view returns (bool) {
function getFrozen(DataTypes.ReserveConfigurationMap storage self) internal view returns (bool) {
return (self.data & ~FROZEN_MASK) != 0;
}
@ -189,7 +176,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @param enabled true if the borrowing needs to be enabled, false otherwise
**/
function setBorrowingEnabled(ReserveConfiguration.Map memory self, bool enabled) internal pure {
function setBorrowingEnabled(DataTypes.ReserveConfigurationMap memory self, bool enabled) internal pure {
self.data =
(self.data & BORROWING_MASK) |
(uint256(enabled ? 1 : 0) << BORROWING_ENABLED_START_BIT_POSITION);
@ -200,7 +187,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @return the borrowing state
**/
function getBorrowingEnabled(ReserveConfiguration.Map storage self) internal view returns (bool) {
function getBorrowingEnabled(DataTypes.ReserveConfigurationMap storage self) internal view returns (bool) {
return (self.data & ~BORROWING_MASK) != 0;
}
@ -209,7 +196,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @param enabled true if the stable rate borrowing needs to be enabled, false otherwise
**/
function setStableRateBorrowingEnabled(ReserveConfiguration.Map memory self, bool enabled)
function setStableRateBorrowingEnabled(DataTypes.ReserveConfigurationMap memory self, bool enabled)
internal
pure
{
@ -223,7 +210,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @return the stable rate borrowing state
**/
function getStableRateBorrowingEnabled(ReserveConfiguration.Map storage self)
function getStableRateBorrowingEnabled(DataTypes.ReserveConfigurationMap storage self)
internal
view
returns (bool)
@ -236,7 +223,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @param reserveFactor the reserve factor
**/
function setReserveFactor(ReserveConfiguration.Map memory self, uint256 reserveFactor)
function setReserveFactor(DataTypes.ReserveConfigurationMap memory self, uint256 reserveFactor)
internal
pure
{
@ -252,7 +239,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @return the reserve factor
**/
function getReserveFactor(ReserveConfiguration.Map storage self) internal view returns (uint256) {
function getReserveFactor(DataTypes.ReserveConfigurationMap storage self) internal view returns (uint256) {
return (self.data & ~RESERVE_FACTOR_MASK) >> RESERVE_FACTOR_START_BIT_POSITION;
}
@ -261,7 +248,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @return the state flags representing active, frozen, borrowing enabled, stableRateBorrowing enabled
**/
function getFlags(ReserveConfiguration.Map storage self)
function getFlags(DataTypes.ReserveConfigurationMap storage self)
internal
view
returns (
@ -286,7 +273,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @return the state params representing ltv, liquidation threshold, liquidation bonus, the reserve decimals
**/
function getParams(ReserveConfiguration.Map storage self)
function getParams(DataTypes.ReserveConfigurationMap storage self)
internal
view
returns (
@ -313,7 +300,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @return the state params representing ltv, liquidation threshold, liquidation bonus, the reserve decimals
**/
function getParamsMemory(ReserveConfiguration.Map memory self)
function getParamsMemory(DataTypes.ReserveConfigurationMap memory self)
internal
pure
returns (
@ -338,7 +325,7 @@ library ReserveConfiguration {
* @param self the reserve configuration
* @return the state flags representing active, frozen, borrowing enabled, stableRateBorrowing enabled
**/
function getFlagsMemory(ReserveConfiguration.Map memory self)
function getFlagsMemory(DataTypes.ReserveConfigurationMap memory self)
internal
pure
returns (

View File

@ -2,6 +2,7 @@
pragma solidity 0.6.12;
import {Errors} from '../helpers/Errors.sol';
import {DataTypes} from '../types/DataTypes.sol';
/**
* @title UserConfiguration library
@ -12,10 +13,6 @@ library UserConfiguration {
uint256 internal constant BORROWING_MASK =
0x5555555555555555555555555555555555555555555555555555555555555555;
struct Map {
uint256 data;
}
/**
* @dev sets if the user is borrowing the reserve identified by reserveIndex
* @param self the configuration object
@ -23,7 +20,7 @@ library UserConfiguration {
* @param borrowing true if the user is borrowing the reserve, false otherwise
**/
function setBorrowing(
UserConfiguration.Map storage self,
DataTypes.UserConfigurationMap storage self,
uint256 reserveIndex,
bool borrowing
) internal {
@ -40,7 +37,7 @@ library UserConfiguration {
* @param _usingAsCollateral true if the user is usin the reserve as collateral, false otherwise
**/
function setUsingAsCollateral(
UserConfiguration.Map storage self,
DataTypes.UserConfigurationMap storage self,
uint256 reserveIndex,
bool _usingAsCollateral
) internal {
@ -56,7 +53,7 @@ library UserConfiguration {
* @param reserveIndex the index of the reserve in the bitmap
* @return true if the user has been using a reserve for borrowing or as collateral, false otherwise
**/
function isUsingAsCollateralOrBorrowing(UserConfiguration.Map memory self, uint256 reserveIndex)
function isUsingAsCollateralOrBorrowing(DataTypes.UserConfigurationMap memory self, uint256 reserveIndex)
internal
pure
returns (bool)
@ -71,7 +68,7 @@ library UserConfiguration {
* @param reserveIndex the index of the reserve in the bitmap
* @return true if the user has been using a reserve for borrowing, false otherwise
**/
function isBorrowing(UserConfiguration.Map memory self, uint256 reserveIndex)
function isBorrowing(DataTypes.UserConfigurationMap memory self, uint256 reserveIndex)
internal
pure
returns (bool)
@ -86,7 +83,7 @@ library UserConfiguration {
* @param reserveIndex the index of the reserve in the bitmap
* @return true if the user has been using a reserve as collateral, false otherwise
**/
function isUsingAsCollateral(UserConfiguration.Map memory self, uint256 reserveIndex)
function isUsingAsCollateral(DataTypes.UserConfigurationMap memory self, uint256 reserveIndex)
internal
pure
returns (bool)
@ -100,7 +97,7 @@ library UserConfiguration {
* @param self the configuration object
* @return true if the user has been borrowing any reserve, false otherwise
**/
function isBorrowingAny(UserConfiguration.Map memory self) internal pure returns (bool) {
function isBorrowingAny(DataTypes.UserConfigurationMap memory self) internal pure returns (bool) {
return self.data & BORROWING_MASK != 0;
}
@ -109,7 +106,7 @@ library UserConfiguration {
* @param self the configuration object
* @return true if the user has been borrowing any reserve, false otherwise
**/
function isEmpty(UserConfiguration.Map memory self) internal pure returns (bool) {
function isEmpty(DataTypes.UserConfigurationMap memory self) internal pure returns (bool) {
return self.data == 0;
}
}

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.12;
import {DebtTokenBase} from '../../tokenization/base/DebtTokenBase.sol';
import {ReserveLogic} from '../logic/ReserveLogic.sol';
import {IERC20} from '../../../dependencies/openzeppelin/contracts/IERC20.sol';
import {DataTypes} from '../types/DataTypes.sol';
/**
* @title Helpers library
@ -16,25 +16,25 @@ library Helpers {
* @param reserve the reserve object
* @return the stable and variable debt balance
**/
function getUserCurrentDebt(address user, ReserveLogic.ReserveData storage reserve)
function getUserCurrentDebt(address user, DataTypes.ReserveData storage reserve)
internal
view
returns (uint256, uint256)
{
return (
DebtTokenBase(reserve.stableDebtTokenAddress).balanceOf(user),
DebtTokenBase(reserve.variableDebtTokenAddress).balanceOf(user)
IERC20(reserve.stableDebtTokenAddress).balanceOf(user),
IERC20(reserve.variableDebtTokenAddress).balanceOf(user)
);
}
function getUserCurrentDebtMemory(address user, ReserveLogic.ReserveData memory reserve)
function getUserCurrentDebtMemory(address user, DataTypes.ReserveData memory reserve)
internal
view
returns (uint256, uint256)
{
return (
DebtTokenBase(reserve.stableDebtTokenAddress).balanceOf(user),
DebtTokenBase(reserve.variableDebtTokenAddress).balanceOf(user)
IERC20(reserve.stableDebtTokenAddress).balanceOf(user),
IERC20(reserve.variableDebtTokenAddress).balanceOf(user)
);
}
}

View File

@ -10,6 +10,7 @@ import {UserConfiguration} from '../configuration/UserConfiguration.sol';
import {WadRayMath} from '../math/WadRayMath.sol';
import {PercentageMath} from '../math/PercentageMath.sol';
import {IPriceOracleGetter} from '../../../interfaces/IPriceOracleGetter.sol';
import {DataTypes} from '../types/DataTypes.sol';
/**
* @title GenericLogic library
@ -17,12 +18,12 @@ import {IPriceOracleGetter} from '../../../interfaces/IPriceOracleGetter.sol';
* @title Implements protocol-level logic to check the status of the user across all the reserves
*/
library GenericLogic {
using ReserveLogic for ReserveLogic.ReserveData;
using ReserveLogic for DataTypes.ReserveData;
using SafeMath for uint256;
using WadRayMath for uint256;
using PercentageMath for uint256;
using ReserveConfiguration for ReserveConfiguration.Map;
using UserConfiguration for UserConfiguration.Map;
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
using UserConfiguration for DataTypes.UserConfigurationMap;
uint256 public constant HEALTH_FACTOR_LIQUIDATION_THRESHOLD = 1 ether;
@ -55,8 +56,8 @@ library GenericLogic {
address asset,
address user,
uint256 amount,
mapping(address => ReserveLogic.ReserveData) storage reservesData,
UserConfiguration.Map calldata userConfig,
mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap calldata userConfig,
mapping(uint256 => address) storage reserves,
uint256 reservesCount,
address oracle
@ -150,8 +151,8 @@ library GenericLogic {
**/
function calculateUserAccountData(
address user,
mapping(address => ReserveLogic.ReserveData) storage reservesData,
UserConfiguration.Map memory userConfig,
mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap memory userConfig,
mapping(uint256 => address) storage reserves,
uint256 reservesCount,
address oracle
@ -177,7 +178,7 @@ library GenericLogic {
}
vars.currentReserveAddress = reserves[vars.i];
ReserveLogic.ReserveData storage currentReserve = reservesData[vars.currentReserveAddress];
DataTypes.ReserveData storage currentReserve = reservesData[vars.currentReserveAddress];
(vars.ltv, vars.liquidationThreshold, , vars.decimals, ) = currentReserve
.configuration

View File

@ -13,6 +13,7 @@ import {IReserveInterestRateStrategy} from '../../../interfaces/IReserveInterest
import {WadRayMath} from '../math/WadRayMath.sol';
import {PercentageMath} from '../math/PercentageMath.sol';
import {Errors} from '../helpers/Errors.sol';
import {DataTypes} from '../types/DataTypes.sol';
/**
* @title ReserveLogic library
@ -43,35 +44,8 @@ library ReserveLogic {
uint256 variableBorrowIndex
);
using ReserveLogic for ReserveLogic.ReserveData;
using ReserveConfiguration for ReserveConfiguration.Map;
enum InterestRateMode {NONE, STABLE, VARIABLE}
// refer to the whitepaper, section 1.1 basic concepts for a formal description of these properties.
struct ReserveData {
//stores the reserve configuration
ReserveConfiguration.Map configuration;
//the liquidity index. Expressed in ray
uint128 liquidityIndex;
//variable borrow index. Expressed in ray
uint128 variableBorrowIndex;
//the current supply rate. Expressed in ray
uint128 currentLiquidityRate;
//the current variable borrow rate. Expressed in ray
uint128 currentVariableBorrowRate;
//the current stable borrow rate. Expressed in ray
uint128 currentStableBorrowRate;
uint40 lastUpdateTimestamp;
//tokens addresses
address aTokenAddress;
address stableDebtTokenAddress;
address variableDebtTokenAddress;
//address of the interest rate strategy
address interestRateStrategyAddress;
//the id of the reserve. Represents the position in the list of the active reserves
uint8 id;
}
using ReserveLogic for DataTypes.ReserveData;
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
/**
* @dev returns the ongoing normalized income for the reserve.
@ -80,7 +54,11 @@ library ReserveLogic {
* @param reserve the reserve object
* @return the normalized income. expressed in ray
**/
function getNormalizedIncome(ReserveData storage reserve) internal view returns (uint256) {
function getNormalizedIncome(DataTypes.ReserveData storage reserve)
internal
view
returns (uint256)
{
uint40 timestamp = reserve.lastUpdateTimestamp;
//solium-disable-next-line
@ -104,7 +82,11 @@ library ReserveLogic {
* @param reserve the reserve object
* @return the normalized variable debt. expressed in ray
**/
function getNormalizedDebt(ReserveData storage reserve) internal view returns (uint256) {
function getNormalizedDebt(DataTypes.ReserveData storage reserve)
internal
view
returns (uint256)
{
uint40 timestamp = reserve.lastUpdateTimestamp;
//solium-disable-next-line
@ -126,7 +108,7 @@ library ReserveLogic {
* a formal specification.
* @param reserve the reserve object
**/
function updateState(ReserveData storage reserve) internal {
function updateState(DataTypes.ReserveData storage reserve) internal {
uint256 scaledVariableDebt =
IVariableDebtToken(reserve.variableDebtTokenAddress).scaledTotalSupply();
uint256 previousVariableBorrowIndex = reserve.variableBorrowIndex;
@ -160,7 +142,7 @@ library ReserveLogic {
* @param amount the amount to accomulate
**/
function cumulateToLiquidityIndex(
ReserveData storage reserve,
DataTypes.ReserveData storage reserve,
uint256 totalLiquidity,
uint256 amount
) internal {
@ -181,7 +163,7 @@ library ReserveLogic {
* @param interestRateStrategyAddress the address of the interest rate strategy contract
**/
function init(
ReserveData storage reserve,
DataTypes.ReserveData storage reserve,
address aTokenAddress,
address stableDebtTokenAddress,
address variableDebtTokenAddress,
@ -216,7 +198,7 @@ library ReserveLogic {
* @param liquidityTaken the amount of liquidity taken from the protocol (redeem or borrow)
**/
function updateInterestRates(
ReserveData storage reserve,
DataTypes.ReserveData storage reserve,
address reserveAddress,
address aTokenAddress,
uint256 liquidityAdded,
@ -292,7 +274,7 @@ library ReserveLogic {
* @param newVariableBorrowIndex the variable borrow index after the last accumulation of the interest
**/
function _mintToTreasury(
ReserveData storage reserve,
DataTypes.ReserveData storage reserve,
uint256 scaledVariableDebt,
uint256 previousVariableBorrowIndex,
uint256 newLiquidityIndex,
@ -352,7 +334,7 @@ library ReserveLogic {
* @param variableBorrowIndex the last stored variable borrow index
**/
function _updateIndexes(
ReserveData storage reserve,
DataTypes.ReserveData storage reserve,
uint256 scaledVariableDebt,
uint256 liquidityIndex,
uint256 variableBorrowIndex,

View File

@ -14,6 +14,7 @@ import {UserConfiguration} from '../configuration/UserConfiguration.sol';
import {Errors} from '../helpers/Errors.sol';
import {Helpers} from '../helpers/Helpers.sol';
import {IReserveInterestRateStrategy} from '../../../interfaces/IReserveInterestRateStrategy.sol';
import {DataTypes} from '../types/DataTypes.sol';
/**
* @title ReserveLogic library
@ -21,13 +22,13 @@ import {IReserveInterestRateStrategy} from '../../../interfaces/IReserveInterest
* @notice Implements functions to validate specific action on the protocol.
*/
library ValidationLogic {
using ReserveLogic for ReserveLogic.ReserveData;
using ReserveLogic for DataTypes.ReserveData;
using SafeMath for uint256;
using WadRayMath for uint256;
using PercentageMath for uint256;
using SafeERC20 for IERC20;
using ReserveConfiguration for ReserveConfiguration.Map;
using UserConfiguration for UserConfiguration.Map;
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
using UserConfiguration for DataTypes.UserConfigurationMap;
uint256 public constant REBALANCE_UP_LIQUIDITY_RATE_THRESHOLD = 4000;
uint256 public constant REBALANCE_UP_USAGE_RATIO_THRESHOLD = 0.95 * 1e27; //usage ratio of 95%
@ -37,7 +38,7 @@ library ValidationLogic {
* @param reserve the reserve state on which the user is depositing
* @param amount the amount to be deposited
*/
function validateDeposit(ReserveLogic.ReserveData storage reserve, uint256 amount) external view {
function validateDeposit(DataTypes.ReserveData storage reserve, uint256 amount) external view {
(bool isActive, bool isFrozen, , ) = reserve.configuration.getFlags();
require(amount != 0, Errors.VL_INVALID_AMOUNT);
@ -60,8 +61,8 @@ library ValidationLogic {
address reserveAddress,
uint256 amount,
uint256 userBalance,
mapping(address => ReserveLogic.ReserveData) storage reservesData,
UserConfiguration.Map storage userConfig,
mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap storage userConfig,
mapping(uint256 => address) storage reserves,
uint256 reservesCount,
address oracle
@ -100,7 +101,7 @@ library ValidationLogic {
uint256 availableLiquidity;
uint256 finalUserBorrowRate;
uint256 healthFactor;
ReserveLogic.InterestRateMode rateMode;
DataTypes.InterestRateMode rateMode;
bool healthFactorBelowThreshold;
bool isActive;
bool isFrozen;
@ -125,14 +126,14 @@ library ValidationLogic {
function validateBorrow(
address asset,
ReserveLogic.ReserveData storage reserve,
DataTypes.ReserveData storage reserve,
address userAddress,
uint256 amount,
uint256 amountInETH,
uint256 interestRateMode,
uint256 maxStableLoanPercent,
mapping(address => ReserveLogic.ReserveData) storage reservesData,
UserConfiguration.Map storage userConfig,
mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap storage userConfig,
mapping(uint256 => address) storage reserves,
uint256 reservesCount,
address oracle
@ -151,8 +152,8 @@ library ValidationLogic {
//validate interest rate mode
require(
uint256(ReserveLogic.InterestRateMode.VARIABLE) == interestRateMode ||
uint256(ReserveLogic.InterestRateMode.STABLE) == interestRateMode,
uint256(DataTypes.InterestRateMode.VARIABLE) == interestRateMode ||
uint256(DataTypes.InterestRateMode.STABLE) == interestRateMode,
Errors.VL_INVALID_INTEREST_RATE_MODE_SELECTED
);
@ -197,7 +198,7 @@ library ValidationLogic {
* liquidity
**/
if (vars.rateMode == ReserveLogic.InterestRateMode.STABLE) {
if (vars.rateMode == DataTypes.InterestRateMode.STABLE) {
//check if the borrow mode is stable and if stable rate borrowing is enabled on this reserve
require(vars.stableRateBorrowingEnabled, Errors.VL_STABLE_BORROWING_NOT_ENABLED);
@ -228,9 +229,9 @@ library ValidationLogic {
* @param variableDebt the borrow balance of the user
*/
function validateRepay(
ReserveLogic.ReserveData storage reserve,
DataTypes.ReserveData storage reserve,
uint256 amountSent,
ReserveLogic.InterestRateMode rateMode,
DataTypes.InterestRateMode rateMode,
address onBehalfOf,
uint256 stableDebt,
uint256 variableDebt
@ -243,9 +244,9 @@ library ValidationLogic {
require(
(stableDebt > 0 &&
ReserveLogic.InterestRateMode(rateMode) == ReserveLogic.InterestRateMode.STABLE) ||
DataTypes.InterestRateMode(rateMode) == DataTypes.InterestRateMode.STABLE) ||
(variableDebt > 0 &&
ReserveLogic.InterestRateMode(rateMode) == ReserveLogic.InterestRateMode.VARIABLE),
DataTypes.InterestRateMode(rateMode) == DataTypes.InterestRateMode.VARIABLE),
Errors.VL_NO_DEBT_OF_SELECTED_TYPE
);
@ -264,20 +265,20 @@ library ValidationLogic {
* @param currentRateMode the rate mode of the borrow
*/
function validateSwapRateMode(
ReserveLogic.ReserveData storage reserve,
UserConfiguration.Map storage userConfig,
DataTypes.ReserveData storage reserve,
DataTypes.UserConfigurationMap storage userConfig,
uint256 stableDebt,
uint256 variableDebt,
ReserveLogic.InterestRateMode currentRateMode
DataTypes.InterestRateMode currentRateMode
) external view {
(bool isActive, bool isFrozen, , bool stableRateEnabled) = reserve.configuration.getFlags();
require(isActive, Errors.VL_NO_ACTIVE_RESERVE);
require(!isFrozen, Errors.VL_RESERVE_FROZEN);
if (currentRateMode == ReserveLogic.InterestRateMode.STABLE) {
if (currentRateMode == DataTypes.InterestRateMode.STABLE) {
require(stableDebt > 0, Errors.VL_NO_STABLE_RATE_LOAN_IN_RESERVE);
} else if (currentRateMode == ReserveLogic.InterestRateMode.VARIABLE) {
} else if (currentRateMode == DataTypes.InterestRateMode.VARIABLE) {
require(variableDebt > 0, Errors.VL_NO_VARIABLE_RATE_LOAN_IN_RESERVE);
/**
* user wants to swap to stable, before swapping we need to ensure that
@ -308,7 +309,7 @@ library ValidationLogic {
* @param aTokenAddress the address of the aToken contract
*/
function validateRebalanceStableBorrowRate(
ReserveLogic.ReserveData storage reserve,
DataTypes.ReserveData storage reserve,
address reserveAddress,
IERC20 stableDebtToken,
IERC20 variableDebtToken,
@ -349,11 +350,11 @@ library ValidationLogic {
* @param oracle the price oracle
*/
function validateSetUseReserveAsCollateral(
ReserveLogic.ReserveData storage reserve,
DataTypes.ReserveData storage reserve,
address reserveAddress,
bool useAsCollateral,
mapping(address => ReserveLogic.ReserveData) storage reservesData,
UserConfiguration.Map storage userConfig,
mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap storage userConfig,
mapping(uint256 => address) storage reserves,
uint256 reservesCount,
address oracle
@ -397,9 +398,9 @@ library ValidationLogic {
* @param userVariableDebt Total variable debt balance of the user
**/
function validateLiquidationCall(
ReserveLogic.ReserveData storage collateralReserve,
ReserveLogic.ReserveData storage principalReserve,
UserConfiguration.Map storage userConfig,
DataTypes.ReserveData storage collateralReserve,
DataTypes.ReserveData storage principalReserve,
DataTypes.UserConfigurationMap storage userConfig,
uint256 userHealthFactor,
uint256 userStableDebt,
uint256 userVariableDebt
@ -452,8 +453,8 @@ library ValidationLogic {
*/
function validateTransfer(
address from,
mapping(address => ReserveLogic.ReserveData) storage reservesData,
UserConfiguration.Map storage userConfig,
mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap storage userConfig,
mapping(uint256 => address) storage reserves,
uint256 reservesCount,
address oracle

View File

@ -0,0 +1,49 @@
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.12;
library DataTypes {
// refer to the whitepaper, section 1.1 basic concepts for a formal description of these properties.
struct ReserveData {
//stores the reserve configuration
ReserveConfigurationMap configuration;
//the liquidity index. Expressed in ray
uint128 liquidityIndex;
//variable borrow index. Expressed in ray
uint128 variableBorrowIndex;
//the current supply rate. Expressed in ray
uint128 currentLiquidityRate;
//the current variable borrow rate. Expressed in ray
uint128 currentVariableBorrowRate;
//the current stable borrow rate. Expressed in ray
uint128 currentStableBorrowRate;
uint40 lastUpdateTimestamp;
//tokens addresses
address aTokenAddress;
address stableDebtTokenAddress;
address variableDebtTokenAddress;
//address of the interest rate strategy
address interestRateStrategyAddress;
//the id of the reserve. Represents the position in the list of the active reserves
uint8 id;
}
struct ReserveConfigurationMap {
//bit 0-15: LTV
//bit 16-31: Liq. threshold
//bit 32-47: Liq. bonus
//bit 48-55: Decimals
//bit 56: Reserve is active
//bit 57: reserve is frozen
//bit 58: borrowing is enabled
//bit 59: stable rate borrowing enabled
//bit 60-63: reserved
//bit 64-79: reserve factor
uint256 data;
}
struct UserConfigurationMap {
uint256 data;
}
enum InterestRateMode {NONE, STABLE, VARIABLE}
}

View File

@ -1,16 +1,12 @@
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import {
ReserveConfiguration
} from '../../contracts/protocol/libraries/configuration/ReserveConfiguration.sol';
import {UserConfiguration} from '../../contracts/protocol/libraries/configuration/UserConfiguration.sol';
import {ReserveLogic} from '../../contracts/protocol/libraries/logic/ReserveLogic.sol';
import {ILendingPool} from '../../contracts/interfaces/ILendingPool.sol';
import {LendingPool} from '../../contracts/protocol/lendingpool/LendingPool.sol';
import {
ILendingPoolAddressesProvider
} from '../../contracts/interfaces/ILendingPoolAddressesProvider.sol';
import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
/*
Certora: Harness that delegates calls to the original LendingPool.
@ -77,24 +73,24 @@ contract LendingPoolHarnessForVariableDebtToken is ILendingPool {
originalPool.liquidationCall(collateral, asset, user, debtToCover, receiveAToken);
}
function getReservesList() external override view returns (address[] memory) {
function getReservesList() external view override returns (address[] memory) {
return originalPool.getReservesList();
}
function getReserveData(address asset)
external
override
view
returns (ReserveLogic.ReserveData memory)
override
returns (DataTypes.ReserveData memory)
{
return originalPool.getReserveData(asset);
}
function getUserConfiguration(address user)
external
override
view
returns (UserConfiguration.Map memory)
override
returns (DataTypes.UserConfigurationMap memory)
{
return originalPool.getUserConfiguration(user);
}
@ -144,16 +140,16 @@ contract LendingPoolHarnessForVariableDebtToken is ILendingPool {
function getConfiguration(address asset)
external
override
view
returns (ReserveConfiguration.Map memory)
override
returns (DataTypes.ReserveConfigurationMap memory)
{
return originalPool.getConfiguration(asset);
}
mapping(uint256 => uint256) private reserveNormalizedIncome;
function getReserveNormalizedIncome(address asset) external override view returns (uint256) {
function getReserveNormalizedIncome(address asset) external view override returns (uint256) {
require(reserveNormalizedIncome[block.timestamp] == 1e27);
return reserveNormalizedIncome[block.timestamp];
}
@ -162,8 +158,8 @@ contract LendingPoolHarnessForVariableDebtToken is ILendingPool {
function getReserveNormalizedVariableDebt(address asset)
external
override
view
override
returns (uint256)
{
require(reserveNormalizedVariableDebt[block.timestamp] == 1e27);
@ -174,7 +170,7 @@ contract LendingPoolHarnessForVariableDebtToken is ILendingPool {
originalPool.setPause(val);
}
function paused() external override view returns (bool) {
function paused() external view override returns (bool) {
return originalPool.paused();
}
@ -201,7 +197,7 @@ contract LendingPoolHarnessForVariableDebtToken is ILendingPool {
originalPool.finalizeTransfer(asset, from, to, amount, balanceFromAfter, balanceToBefore);
}
function getAddressesProvider() external override view returns (ILendingPoolAddressesProvider) {
function getAddressesProvider() external view override returns (ILendingPoolAddressesProvider) {
return originalPool.getAddressesProvider();
}
}

View File

@ -7,7 +7,7 @@ import {UserConfiguration} from '../../contracts/protocol/libraries/configuratio
A wrapper contract for calling functions from the library UserConfiguration.
*/
contract UserConfigurationHarness {
UserConfiguration.Map internal usersConfig;
DataTypes.UserConfigurationMap internal usersConfig;
function setBorrowing(
address user,