mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
Merge branch 'protocol-2.5' into feat/gas-optimization-3
This commit is contained in:
commit
7395363e59
|
@ -1,163 +1,49 @@
|
|||
// SPDX-License-Identifier: agpl-3.0
|
||||
pragma solidity 0.6.12;
|
||||
|
||||
/**
|
||||
* @dev Wrappers over Solidity's arithmetic operations with added overflow
|
||||
* checks.
|
||||
*
|
||||
* Arithmetic operations in Solidity wrap on overflow. This can easily result
|
||||
* in bugs, because programmers usually assume that an overflow raises an
|
||||
* error, which is the standard behavior in high level programming languages.
|
||||
* `SafeMath` restores this intuition by reverting the transaction when an
|
||||
* operation overflows.
|
||||
*
|
||||
* Using this library instead of the unchecked operations eliminates an entire
|
||||
* class of bugs, so it's recommended to use it always.
|
||||
*/
|
||||
/// @title Optimized overflow and underflow safe math operations
|
||||
/// @notice Contains methods for doing math operations that revert on overflow or underflow for minimal gas cost
|
||||
library SafeMath {
|
||||
/**
|
||||
* @dev Returns the addition of two unsigned integers, reverting on
|
||||
* overflow.
|
||||
*
|
||||
* Counterpart to Solidity's `+` operator.
|
||||
*
|
||||
* Requirements:
|
||||
* - Addition cannot overflow.
|
||||
*/
|
||||
function add(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
uint256 c = a + b;
|
||||
require(c >= a, 'SafeMath: addition overflow');
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the subtraction of two unsigned integers, reverting on
|
||||
* overflow (when the result is negative).
|
||||
*
|
||||
* Counterpart to Solidity's `-` operator.
|
||||
*
|
||||
* Requirements:
|
||||
* - Subtraction cannot overflow.
|
||||
*/
|
||||
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
return sub(a, b, 'SafeMath: subtraction overflow');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
|
||||
* overflow (when the result is negative).
|
||||
*
|
||||
* Counterpart to Solidity's `-` operator.
|
||||
*
|
||||
* Requirements:
|
||||
* - Subtraction cannot overflow.
|
||||
*/
|
||||
function sub(
|
||||
uint256 a,
|
||||
uint256 b,
|
||||
string memory errorMessage
|
||||
) internal pure returns (uint256) {
|
||||
require(b <= a, errorMessage);
|
||||
uint256 c = a - b;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the multiplication of two unsigned integers, reverting on
|
||||
* overflow.
|
||||
*
|
||||
* Counterpart to Solidity's `*` operator.
|
||||
*
|
||||
* Requirements:
|
||||
* - Multiplication cannot overflow.
|
||||
*/
|
||||
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
|
||||
// benefit is lost if 'b' is also tested.
|
||||
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
|
||||
if (a == 0) {
|
||||
return 0;
|
||||
/// @notice Returns x + y, reverts if sum overflows uint256
|
||||
/// @param x The augend
|
||||
/// @param y The addend
|
||||
/// @return z The sum of x and y
|
||||
function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
|
||||
require((z = x + y) >= x);
|
||||
}
|
||||
|
||||
uint256 c = a * b;
|
||||
require(c / a == b, 'SafeMath: multiplication overflow');
|
||||
/// @notice Returns x - y, reverts if underflows
|
||||
/// @param x The minuend
|
||||
/// @param y The subtrahend
|
||||
/// @return z The difference of x and y
|
||||
function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
|
||||
require((z = x - y) <= x);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
/// @notice Returns x - y, reverts if underflows
|
||||
/// @param x The minuend
|
||||
/// @param y The subtrahend
|
||||
/// @param message The error msg
|
||||
/// @return z The difference of x and y
|
||||
function sub(uint256 x, uint256 y, string memory message) internal pure returns (uint256 z) {
|
||||
require((z = x - y) <= x, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the integer division of two unsigned integers. Reverts on
|
||||
* division by zero. The result is rounded towards zero.
|
||||
*
|
||||
* Counterpart to Solidity's `/` operator. Note: this function uses a
|
||||
* `revert` opcode (which leaves remaining gas untouched) while Solidity
|
||||
* uses an invalid opcode to revert (consuming all remaining gas).
|
||||
*
|
||||
* Requirements:
|
||||
* - The divisor cannot be zero.
|
||||
*/
|
||||
function div(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
return div(a, b, 'SafeMath: division by zero');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
|
||||
* division by zero. The result is rounded towards zero.
|
||||
*
|
||||
* Counterpart to Solidity's `/` operator. Note: this function uses a
|
||||
* `revert` opcode (which leaves remaining gas untouched) while Solidity
|
||||
* uses an invalid opcode to revert (consuming all remaining gas).
|
||||
*
|
||||
* Requirements:
|
||||
* - The divisor cannot be zero.
|
||||
*/
|
||||
function div(
|
||||
uint256 a,
|
||||
uint256 b,
|
||||
string memory errorMessage
|
||||
) internal pure returns (uint256) {
|
||||
// Solidity only automatically asserts when dividing by 0
|
||||
require(b > 0, errorMessage);
|
||||
uint256 c = a / b;
|
||||
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
|
||||
/// @notice Returns x * y, reverts if overflows
|
||||
/// @param x The multiplicand
|
||||
/// @param y The multiplier
|
||||
/// @return z The product of x and y
|
||||
function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
|
||||
require(x == 0 || (z = x * y) / x == y);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
/// @notice Returns x / y, reverts if overflows - no specific check, solidity reverts on division by 0
|
||||
/// @param x The numerator
|
||||
/// @param y The denominator
|
||||
/// @return z The product of x and y
|
||||
function div(uint256 x, uint256 y) internal pure returns (uint256 z) {
|
||||
return x / y;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
|
||||
* Reverts when dividing by zero.
|
||||
*
|
||||
* Counterpart to Solidity's `%` operator. This function uses a `revert`
|
||||
* opcode (which leaves remaining gas untouched) while Solidity uses an
|
||||
* invalid opcode to revert (consuming all remaining gas).
|
||||
*
|
||||
* Requirements:
|
||||
* - The divisor cannot be zero.
|
||||
*/
|
||||
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
return mod(a, b, 'SafeMath: modulo by zero');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
|
||||
* Reverts with custom message when dividing by zero.
|
||||
*
|
||||
* Counterpart to Solidity's `%` operator. This function uses a `revert`
|
||||
* opcode (which leaves remaining gas untouched) while Solidity uses an
|
||||
* invalid opcode to revert (consuming all remaining gas).
|
||||
*
|
||||
* Requirements:
|
||||
* - The divisor cannot be zero.
|
||||
*/
|
||||
function mod(
|
||||
uint256 a,
|
||||
uint256 b,
|
||||
string memory errorMessage
|
||||
) internal pure returns (uint256) {
|
||||
require(b != 0, errorMessage);
|
||||
return a % b;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -136,7 +136,15 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
bytes32 permitR,
|
||||
bytes32 permitS
|
||||
) external override {
|
||||
IERC20WithPermit(asset).permit(msg.sender, address(this), amount, deadline, permitV, permitR, permitS);
|
||||
IERC20WithPermit(asset).permit(
|
||||
msg.sender,
|
||||
address(this),
|
||||
amount,
|
||||
deadline,
|
||||
permitV,
|
||||
permitR,
|
||||
permitS
|
||||
);
|
||||
_executeDeposit(asset, amount, onBehalfOf, referralCode);
|
||||
}
|
||||
|
||||
|
@ -243,7 +251,15 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
bytes32 permitR,
|
||||
bytes32 permitS
|
||||
) external override returns (uint256) {
|
||||
IERC20WithPermit(asset).permit(msg.sender, address(this), amount, deadline, permitV, permitR, permitS);
|
||||
IERC20WithPermit(asset).permit(
|
||||
msg.sender,
|
||||
address(this),
|
||||
amount,
|
||||
deadline,
|
||||
permitV,
|
||||
permitR,
|
||||
permitS
|
||||
);
|
||||
return _executeRepay(asset, amount, rateMode, onBehalfOf);
|
||||
}
|
||||
|
||||
|
@ -349,22 +365,22 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
{
|
||||
DataTypes.ReserveData storage reserve = _reserves[asset];
|
||||
|
||||
ValidationLogic.validateSetUseReserveAsCollateral(
|
||||
reserve,
|
||||
asset,
|
||||
useAsCollateral,
|
||||
_reserves,
|
||||
_usersConfig[msg.sender],
|
||||
_reservesList,
|
||||
_reservesCount,
|
||||
_addressesProvider.getPriceOracle()
|
||||
);
|
||||
ValidationLogic.validateSetUseReserveAsCollateral(reserve);
|
||||
|
||||
_usersConfig[msg.sender].setUsingAsCollateral(reserve.id, useAsCollateral);
|
||||
|
||||
if (useAsCollateral) {
|
||||
emit ReserveUsedAsCollateralEnabled(asset, msg.sender);
|
||||
} else {
|
||||
ValidationLogic.validateHealthFactor(
|
||||
msg.sender,
|
||||
_reserves,
|
||||
_usersConfig[msg.sender],
|
||||
_reservesList,
|
||||
_reservesCount,
|
||||
_addressesProvider.getPriceOracle()
|
||||
);
|
||||
|
||||
emit ReserveUsedAsCollateralDisabled(asset, msg.sender);
|
||||
}
|
||||
}
|
||||
|
@ -691,7 +707,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the fee on flash loans
|
||||
* @dev Returns the fee on flash loans
|
||||
*/
|
||||
function FLASHLOAN_PREMIUM_TOTAL() public view returns (uint256) {
|
||||
return _flashLoanPremiumTotal;
|
||||
|
@ -724,22 +740,26 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
) external override whenNotPaused {
|
||||
require(msg.sender == _reserves[asset].aTokenAddress, Errors.LP_CALLER_MUST_BE_AN_ATOKEN);
|
||||
|
||||
ValidationLogic.validateTransfer(
|
||||
from,
|
||||
_reserves,
|
||||
_usersConfig[from],
|
||||
_reservesList,
|
||||
_reservesCount,
|
||||
_addressesProvider.getPriceOracle()
|
||||
);
|
||||
|
||||
uint256 reserveId = _reserves[asset].id;
|
||||
|
||||
if (from != to) {
|
||||
if (balanceFromBefore.sub(amount) == 0) {
|
||||
DataTypes.UserConfigurationMap storage fromConfig = _usersConfig[from];
|
||||
fromConfig.setUsingAsCollateral(reserveId, false);
|
||||
emit ReserveUsedAsCollateralDisabled(asset, from);
|
||||
DataTypes.UserConfigurationMap storage fromConfig = _usersConfig[from];
|
||||
|
||||
if (fromConfig.isUsingAsCollateral(reserveId)) {
|
||||
if (fromConfig.isBorrowingAny()) {
|
||||
ValidationLogic.validateHealthFactor(
|
||||
from,
|
||||
_reserves,
|
||||
_usersConfig[from],
|
||||
_reservesList,
|
||||
_reservesCount,
|
||||
_addressesProvider.getPriceOracle()
|
||||
);
|
||||
}
|
||||
if (balanceFromBefore.sub(amount) == 0) {
|
||||
fromConfig.setUsingAsCollateral(reserveId, false);
|
||||
emit ReserveUsedAsCollateralDisabled(asset, from);
|
||||
}
|
||||
}
|
||||
|
||||
if (balanceToBefore == 0 && amount != 0) {
|
||||
|
@ -940,10 +960,15 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
address to
|
||||
) internal returns (uint256) {
|
||||
DataTypes.ReserveData storage reserve = _reserves[asset];
|
||||
DataTypes.UserConfigurationMap storage userConfig = _usersConfig[msg.sender];
|
||||
|
||||
address aToken = reserve.aTokenAddress;
|
||||
|
||||
uint256 userBalance = IAToken(aToken).balanceOf(msg.sender);
|
||||
reserve.updateState();
|
||||
|
||||
uint256 liquidityIndex = reserve.liquidityIndex;
|
||||
|
||||
uint256 userBalance = IAToken(aToken).scaledBalanceOf(msg.sender).rayMul(liquidityIndex);
|
||||
|
||||
uint256 amountToWithdraw = amount;
|
||||
|
||||
|
@ -951,27 +976,29 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
amountToWithdraw = userBalance;
|
||||
}
|
||||
|
||||
ValidationLogic.validateWithdraw(
|
||||
asset,
|
||||
amountToWithdraw,
|
||||
userBalance,
|
||||
_reserves,
|
||||
_usersConfig[msg.sender],
|
||||
_reservesList,
|
||||
_reservesCount,
|
||||
_addressesProvider.getPriceOracle()
|
||||
);
|
||||
|
||||
reserve.updateState();
|
||||
ValidationLogic.validateWithdraw(reserve, amountToWithdraw, userBalance);
|
||||
|
||||
reserve.updateInterestRates(asset, aToken, 0, amountToWithdraw);
|
||||
|
||||
if (amountToWithdraw == userBalance) {
|
||||
_usersConfig[msg.sender].setUsingAsCollateral(reserve.id, false);
|
||||
emit ReserveUsedAsCollateralDisabled(asset, msg.sender);
|
||||
}
|
||||
IAToken(aToken).burn(msg.sender, to, amountToWithdraw, liquidityIndex);
|
||||
|
||||
IAToken(aToken).burn(msg.sender, to, amountToWithdraw, reserve.liquidityIndex);
|
||||
if (userConfig.isUsingAsCollateral(reserve.id)) {
|
||||
if (userConfig.isBorrowingAny()) {
|
||||
ValidationLogic.validateHealthFactor(
|
||||
msg.sender,
|
||||
_reserves,
|
||||
userConfig,
|
||||
_reservesList,
|
||||
_reservesCount,
|
||||
_addressesProvider.getPriceOracle()
|
||||
);
|
||||
}
|
||||
|
||||
if (amountToWithdraw == userBalance) {
|
||||
userConfig.setUsingAsCollateral(reserve.id, false);
|
||||
emit ReserveUsedAsCollateralDisabled(asset, msg.sender);
|
||||
}
|
||||
}
|
||||
|
||||
emit Withdraw(asset, msg.sender, to, amountToWithdraw);
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ library Errors {
|
|||
string public constant VL_RESERVE_FROZEN = '3'; // 'Action cannot be performed because the reserve is frozen'
|
||||
string public constant VL_CURRENT_AVAILABLE_LIQUIDITY_NOT_ENOUGH = '4'; // 'The current liquidity is not enough'
|
||||
string public constant VL_NOT_ENOUGH_AVAILABLE_USER_BALANCE = '5'; // 'User cannot withdraw more than the available balance'
|
||||
string public constant VL_TRANSFER_NOT_ALLOWED = '6'; // 'Transfer cannot be allowed.'
|
||||
string public constant VL_BORROWING_NOT_ENABLED = '7'; // 'Borrowing is not enabled'
|
||||
string public constant VL_INVALID_INTEREST_RATE_MODE_SELECTED = '8'; // 'Invalid interest rate mode selected'
|
||||
string public constant VL_COLLATERAL_BALANCE_IS_0 = '9'; // 'The collateral balance is 0'
|
||||
|
|
|
@ -28,94 +28,6 @@ library GenericLogic {
|
|||
|
||||
uint256 public constant HEALTH_FACTOR_LIQUIDATION_THRESHOLD = 1 ether;
|
||||
|
||||
struct balanceDecreaseAllowedLocalVars {
|
||||
uint256 decimals;
|
||||
uint256 liquidationThreshold;
|
||||
uint256 totalCollateralInETH;
|
||||
uint256 totalDebtInETH;
|
||||
uint256 avgLiquidationThreshold;
|
||||
uint256 amountToDecreaseInETH;
|
||||
uint256 collateralBalanceAfterDecrease;
|
||||
uint256 liquidationThresholdAfterDecrease;
|
||||
uint256 healthFactorAfterDecrease;
|
||||
bool reserveUsageAsCollateralEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Checks if a specific balance decrease is allowed
|
||||
* (i.e. doesn't bring the user borrow position health factor under HEALTH_FACTOR_LIQUIDATION_THRESHOLD)
|
||||
* @param asset The address of the underlying asset of the reserve
|
||||
* @param user The address of the user
|
||||
* @param amount The amount to decrease
|
||||
* @param reservesData The data of all the reserves
|
||||
* @param userConfig The user configuration
|
||||
* @param reserves The list of all the active reserves
|
||||
* @param oracle The address of the oracle contract
|
||||
* @return true if the decrease of the balance is allowed
|
||||
**/
|
||||
function balanceDecreaseAllowed(
|
||||
address asset,
|
||||
address user,
|
||||
uint256 amount,
|
||||
mapping(address => DataTypes.ReserveData) storage reservesData,
|
||||
DataTypes.UserConfigurationMap calldata userConfig,
|
||||
mapping(uint256 => address) storage reserves,
|
||||
uint256 reservesCount,
|
||||
address oracle
|
||||
) external view returns (bool) {
|
||||
if (!userConfig.isBorrowingAny() || !userConfig.isUsingAsCollateral(reservesData[asset].id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
balanceDecreaseAllowedLocalVars memory vars;
|
||||
|
||||
(, vars.liquidationThreshold, , vars.decimals, ) = reservesData[asset]
|
||||
.configuration
|
||||
.getParams();
|
||||
|
||||
if (vars.liquidationThreshold == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
(
|
||||
vars.totalCollateralInETH,
|
||||
vars.totalDebtInETH,
|
||||
,
|
||||
vars.avgLiquidationThreshold,
|
||||
|
||||
) = calculateUserAccountData(user, reservesData, userConfig, reserves, reservesCount, oracle);
|
||||
|
||||
if (vars.totalDebtInETH == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
vars.amountToDecreaseInETH = IPriceOracleGetter(oracle).getAssetPrice(asset).mul(amount).div(
|
||||
10**vars.decimals
|
||||
);
|
||||
|
||||
vars.collateralBalanceAfterDecrease = vars.totalCollateralInETH.sub(vars.amountToDecreaseInETH);
|
||||
|
||||
//if there is a borrow, there can't be 0 collateral
|
||||
if (vars.collateralBalanceAfterDecrease == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vars.liquidationThresholdAfterDecrease = vars
|
||||
.totalCollateralInETH
|
||||
.mul(vars.avgLiquidationThreshold)
|
||||
.sub(vars.amountToDecreaseInETH.mul(vars.liquidationThreshold))
|
||||
.div(vars.collateralBalanceAfterDecrease);
|
||||
|
||||
uint256 healthFactorAfterDecrease =
|
||||
calculateHealthFactorFromBalances(
|
||||
vars.collateralBalanceAfterDecrease,
|
||||
vars.totalDebtInETH,
|
||||
vars.liquidationThresholdAfterDecrease
|
||||
);
|
||||
|
||||
return healthFactorAfterDecrease >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD;
|
||||
}
|
||||
|
||||
struct CalculateUserAccountDataVars {
|
||||
uint256 assetPrice;
|
||||
uint256 assetUnit;
|
||||
|
@ -220,8 +132,7 @@ library GenericLogic {
|
|||
IERC20(currentReserve.stableDebtTokenAddress).balanceOf(user)
|
||||
);
|
||||
vars.userDebtETH = vars.assetPrice.mul(vars.userDebt).div(vars.assetUnit);
|
||||
vars.totalDebtInETH = vars.totalDebtInETH.add(vars.userDebtETH);
|
||||
|
||||
vars.totalDebtInETH = vars.totalDebtInETH.add(vars.userDebtETH);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ library ValidationLogic {
|
|||
* @param reserve The reserve object on which the user is depositing
|
||||
* @param amount The amount to be deposited
|
||||
*/
|
||||
function validateDeposit(DataTypes.ReserveData storage reserve, uint256 amount) external view {
|
||||
function validateDeposit(DataTypes.ReserveData storage reserve, uint256 amount) internal view {
|
||||
(bool isActive, bool isFrozen, , ) = reserve.configuration.getFlags();
|
||||
|
||||
require(amount != 0, Errors.VL_INVALID_AMOUNT);
|
||||
|
@ -46,46 +46,23 @@ library ValidationLogic {
|
|||
require(!isFrozen, Errors.VL_RESERVE_FROZEN);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dev Validates a withdraw action
|
||||
* @param reserveAddress The address of the reserve
|
||||
* @param reserve The reserve object
|
||||
* @param amount The amount to be withdrawn
|
||||
* @param userBalance The balance of the user
|
||||
* @param reservesData The reserves state
|
||||
* @param userConfig The user configuration
|
||||
* @param reserves The addresses of the reserves
|
||||
* @param reservesCount The number of reserves
|
||||
* @param oracle The price oracle
|
||||
*/
|
||||
function validateWithdraw(
|
||||
address reserveAddress,
|
||||
DataTypes.ReserveData storage reserve,
|
||||
uint256 amount,
|
||||
uint256 userBalance,
|
||||
mapping(address => DataTypes.ReserveData) storage reservesData,
|
||||
DataTypes.UserConfigurationMap storage userConfig,
|
||||
mapping(uint256 => address) storage reserves,
|
||||
uint256 reservesCount,
|
||||
address oracle
|
||||
) external view {
|
||||
uint256 userBalance
|
||||
) internal view {
|
||||
require(amount != 0, Errors.VL_INVALID_AMOUNT);
|
||||
require(amount <= userBalance, Errors.VL_NOT_ENOUGH_AVAILABLE_USER_BALANCE);
|
||||
|
||||
(bool isActive, , , ) = reservesData[reserveAddress].configuration.getFlags();
|
||||
(bool isActive, , , ) = reserve.configuration.getFlags();
|
||||
require(isActive, Errors.VL_NO_ACTIVE_RESERVE);
|
||||
|
||||
require(
|
||||
GenericLogic.balanceDecreaseAllowed(
|
||||
reserveAddress,
|
||||
msg.sender,
|
||||
amount,
|
||||
reservesData,
|
||||
userConfig,
|
||||
reserves,
|
||||
reservesCount,
|
||||
oracle
|
||||
),
|
||||
Errors.VL_TRANSFER_NOT_ALLOWED
|
||||
);
|
||||
}
|
||||
|
||||
struct ValidateBorrowLocalVars {
|
||||
|
@ -130,7 +107,7 @@ library ValidationLogic {
|
|||
mapping(uint256 => address) storage reserves,
|
||||
uint256 reservesCount,
|
||||
address oracle
|
||||
) external view {
|
||||
) internal view {
|
||||
ValidateBorrowLocalVars memory vars;
|
||||
|
||||
(vars.isActive, vars.isFrozen, vars.borrowingEnabled, vars.stableRateBorrowingEnabled) = reserve
|
||||
|
@ -227,7 +204,7 @@ library ValidationLogic {
|
|||
address onBehalfOf,
|
||||
uint256 stableDebt,
|
||||
uint256 variableDebt
|
||||
) external view {
|
||||
) internal view {
|
||||
bool isActive = reserve.configuration.getActive();
|
||||
|
||||
require(isActive, Errors.VL_NO_ACTIVE_RESERVE);
|
||||
|
@ -335,40 +312,13 @@ 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 reserveAddress The address of the reserve
|
||||
* @param reservesData The data of all the reserves
|
||||
* @param userConfig The state of the user for the specific reserve
|
||||
* @param reserves The addresses of all the active reserves
|
||||
* @param oracle The price oracle
|
||||
*/
|
||||
function validateSetUseReserveAsCollateral(
|
||||
DataTypes.ReserveData storage reserve,
|
||||
address reserveAddress,
|
||||
bool useAsCollateral,
|
||||
mapping(address => DataTypes.ReserveData) storage reservesData,
|
||||
DataTypes.UserConfigurationMap storage userConfig,
|
||||
mapping(uint256 => address) storage reserves,
|
||||
uint256 reservesCount,
|
||||
address oracle
|
||||
DataTypes.ReserveData storage reserve
|
||||
) external view {
|
||||
uint256 underlyingBalance = IERC20(reserve.aTokenAddress).balanceOf(msg.sender);
|
||||
|
||||
require(underlyingBalance > 0, Errors.VL_UNDERLYING_BALANCE_NOT_GREATER_THAN_0);
|
||||
|
||||
require(
|
||||
useAsCollateral ||
|
||||
GenericLogic.balanceDecreaseAllowed(
|
||||
reserveAddress,
|
||||
msg.sender,
|
||||
underlyingBalance,
|
||||
reservesData,
|
||||
userConfig,
|
||||
reserves,
|
||||
reservesCount,
|
||||
oracle
|
||||
),
|
||||
Errors.VL_DEPOSIT_ALREADY_IN_USE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -436,14 +386,15 @@ library ValidationLogic {
|
|||
}
|
||||
|
||||
/**
|
||||
* @dev Validates an aToken transfer
|
||||
* @dev Validates the health factor of a user
|
||||
* @param from The user from which the aTokens are being transferred
|
||||
* @param reservesData The state of all the reserves
|
||||
* @param userConfig The state of the user for the specific reserve
|
||||
* @param reserves The addresses of all the active reserves
|
||||
* @param reservesCount The number of available reserves
|
||||
* @param oracle The price oracle
|
||||
*/
|
||||
function validateTransfer(
|
||||
function validateHealthFactor(
|
||||
address from,
|
||||
mapping(address => DataTypes.ReserveData) storage reservesData,
|
||||
DataTypes.UserConfigurationMap storage userConfig,
|
||||
|
@ -463,7 +414,7 @@ library ValidationLogic {
|
|||
|
||||
require(
|
||||
healthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
|
||||
Errors.VL_TRANSFER_NOT_ALLOWED
|
||||
Errors.VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,7 +111,6 @@ export enum ProtocolErrors {
|
|||
VL_RESERVE_FROZEN = '3', // 'Action requires an unfrozen reserve'
|
||||
VL_CURRENT_AVAILABLE_LIQUIDITY_NOT_ENOUGH = '4', // 'The current liquidity is not enough'
|
||||
VL_NOT_ENOUGH_AVAILABLE_USER_BALANCE = '5', // 'User cannot withdraw more than the available balance'
|
||||
VL_TRANSFER_NOT_ALLOWED = '6', // 'Transfer cannot be allowed.'
|
||||
VL_BORROWING_NOT_ENABLED = '7', // 'Borrowing is not enabled'
|
||||
VL_INVALID_INTEREST_RATE_MODE_SELECTED = '8', // 'Invalid interest rate mode selected'
|
||||
VL_COLLATERAL_BALANCE_IS_0 = '9', // 'The collateral balance is 0'
|
||||
|
|
|
@ -12,7 +12,7 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => {
|
|||
const {
|
||||
INVALID_FROM_BALANCE_AFTER_TRANSFER,
|
||||
INVALID_TO_BALANCE_AFTER_TRANSFER,
|
||||
VL_TRANSFER_NOT_ALLOWED,
|
||||
VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD,
|
||||
} = ProtocolErrors;
|
||||
|
||||
it('User 0 deposits 1000 DAI, transfers to user 1', async () => {
|
||||
|
@ -81,8 +81,8 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => {
|
|||
|
||||
await expect(
|
||||
aDai.connect(users[1].signer).transfer(users[0].address, aDAItoTransfer),
|
||||
VL_TRANSFER_NOT_ALLOWED
|
||||
).to.be.revertedWith(VL_TRANSFER_NOT_ALLOWED);
|
||||
VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD
|
||||
).to.be.revertedWith(VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD);
|
||||
});
|
||||
|
||||
it('User 1 tries to transfer a small amount of DAI used as collateral back to user 0', async () => {
|
||||
|
|
|
@ -12,7 +12,7 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => {
|
|||
const {
|
||||
INVALID_FROM_BALANCE_AFTER_TRANSFER,
|
||||
INVALID_TO_BALANCE_AFTER_TRANSFER,
|
||||
VL_TRANSFER_NOT_ALLOWED,
|
||||
VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD,
|
||||
} = ProtocolErrors;
|
||||
|
||||
it('User 0 deposits 1000 DAI, transfers to user 1', async () => {
|
||||
|
@ -81,8 +81,8 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => {
|
|||
|
||||
await expect(
|
||||
aDai.connect(users[1].signer).transfer(users[0].address, aDAItoTransfer),
|
||||
VL_TRANSFER_NOT_ALLOWED
|
||||
).to.be.revertedWith(VL_TRANSFER_NOT_ALLOWED);
|
||||
VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD
|
||||
).to.be.revertedWith(VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD);
|
||||
});
|
||||
|
||||
it('User 1 tries to transfer a small amount of DAI used as collateral back to user 0', async () => {
|
||||
|
|
Loading…
Reference in New Issue
Block a user