mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
- Refactor validation of swapLiquidity() to ValidationLogic.
- Added extra check on active reserves on swapLiquidity().
This commit is contained in:
parent
8d391b9ab5
commit
59996e1ece
|
@ -110,6 +110,26 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
|
||||||
string errorMsg;
|
string errorMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SwapLiquidityLocalVars {
|
||||||
|
uint256 healthFactor;
|
||||||
|
uint256 amountToReceive;
|
||||||
|
uint256 userBalanceBefore;
|
||||||
|
IAToken fromReserveAToken;
|
||||||
|
IAToken toReserveAToken;
|
||||||
|
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
|
* @dev as the contract extends the VersionedInitializable contract to match the state
|
||||||
* of the LendingPool contract, the getRevision() function is needed.
|
* of the LendingPool contract, the getRevision() function is needed.
|
||||||
|
@ -253,7 +273,12 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
|
||||||
);
|
);
|
||||||
|
|
||||||
//burn the equivalent amount of atoken
|
//burn the equivalent amount of atoken
|
||||||
vars.collateralAtoken.burn(user, msg.sender, vars.maxCollateralToLiquidate, collateralReserve.liquidityIndex);
|
vars.collateralAtoken.burn(
|
||||||
|
user,
|
||||||
|
msg.sender,
|
||||||
|
vars.maxCollateralToLiquidate,
|
||||||
|
collateralReserve.liquidityIndex
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//transfers the principal currency to the aToken
|
//transfers the principal currency to the aToken
|
||||||
|
@ -356,7 +381,12 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
|
||||||
//updating collateral reserve indexes
|
//updating collateral reserve indexes
|
||||||
collateralReserve.updateCumulativeIndexesAndTimestamp();
|
collateralReserve.updateCumulativeIndexesAndTimestamp();
|
||||||
|
|
||||||
vars.collateralAtoken.burn(user, receiver, vars.maxCollateralToLiquidate, collateralReserve.liquidityIndex);
|
vars.collateralAtoken.burn(
|
||||||
|
user,
|
||||||
|
receiver,
|
||||||
|
vars.maxCollateralToLiquidate,
|
||||||
|
collateralReserve.liquidityIndex
|
||||||
|
);
|
||||||
|
|
||||||
if (vars.userCollateralBalance == vars.maxCollateralToLiquidate) {
|
if (vars.userCollateralBalance == vars.maxCollateralToLiquidate) {
|
||||||
usersConfig[user].setUsingAsCollateral(collateralReserve.id, false);
|
usersConfig[user].setUsingAsCollateral(collateralReserve.id, false);
|
||||||
|
@ -375,7 +405,12 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
|
||||||
|
|
||||||
//updating debt reserve
|
//updating debt reserve
|
||||||
debtReserve.updateCumulativeIndexesAndTimestamp();
|
debtReserve.updateCumulativeIndexesAndTimestamp();
|
||||||
debtReserve.updateInterestRates(principal, vars.principalAToken, vars.actualAmountToLiquidate, 0);
|
debtReserve.updateInterestRates(
|
||||||
|
principal,
|
||||||
|
vars.principalAToken,
|
||||||
|
vars.actualAmountToLiquidate,
|
||||||
|
0
|
||||||
|
);
|
||||||
IERC20(principal).transferFrom(receiver, vars.principalAToken, vars.actualAmountToLiquidate);
|
IERC20(principal).transferFrom(receiver, vars.principalAToken, vars.actualAmountToLiquidate);
|
||||||
|
|
||||||
if (vars.userVariableDebt >= vars.actualAmountToLiquidate) {
|
if (vars.userVariableDebt >= vars.actualAmountToLiquidate) {
|
||||||
|
@ -411,14 +446,83 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
|
||||||
return (uint256(Errors.LiquidationErrors.NO_ERROR), Errors.NO_ERRORS);
|
return (uint256(Errors.LiquidationErrors.NO_ERROR), Errors.NO_ERRORS);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AvailableCollateralToLiquidateLocalVars {
|
/**
|
||||||
uint256 userCompoundedBorrowBalance;
|
* @dev Allows an user to release one of his assets deposited in the protocol, even if it is used as collateral.
|
||||||
uint256 liquidationBonus;
|
* - It's not possible to release one asset to swap for the same
|
||||||
uint256 collateralPrice;
|
* @param receiverAddress The address of the contract receiving the funds. The receiver should implement the ISwapAdapter interface
|
||||||
uint256 principalCurrencyPrice;
|
* @param fromAsset Asset to swap from
|
||||||
uint256 maxAmountCollateralToLiquidate;
|
* @param toAsset Asset to swap to
|
||||||
uint256 principalDecimals;
|
* @param params a bytes array to be sent (if needed) to the receiver contract with extra data
|
||||||
uint256 collateralDecimals;
|
**/
|
||||||
|
function swapLiquidity(
|
||||||
|
address receiverAddress,
|
||||||
|
address fromAsset,
|
||||||
|
address toAsset,
|
||||||
|
uint256 amountToSwap,
|
||||||
|
bytes calldata params
|
||||||
|
) external returns (uint256, string memory) {
|
||||||
|
ReserveLogic.ReserveData storage fromReserve = reserves[fromAsset];
|
||||||
|
ReserveLogic.ReserveData storage toReserve = reserves[toAsset];
|
||||||
|
|
||||||
|
// Usage of a memory struct of vars to avoid "Stack too deep" errors due to local variables
|
||||||
|
SwapLiquidityLocalVars memory vars;
|
||||||
|
|
||||||
|
(vars.errorCode, vars.errorMsg) = ValidationLogic.validateSwapLiquidity(
|
||||||
|
fromReserve,
|
||||||
|
toReserve,
|
||||||
|
fromAsset,
|
||||||
|
toAsset
|
||||||
|
);
|
||||||
|
|
||||||
|
if (Errors.LiquidationErrors(vars.errorCode) != Errors.LiquidationErrors.NO_ERROR) {
|
||||||
|
return (vars.errorCode, vars.errorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
vars.fromReserveAToken = IAToken(fromReserve.aTokenAddress);
|
||||||
|
vars.toReserveAToken = IAToken(toReserve.aTokenAddress);
|
||||||
|
|
||||||
|
fromReserve.updateCumulativeIndexesAndTimestamp();
|
||||||
|
toReserve.updateCumulativeIndexesAndTimestamp();
|
||||||
|
|
||||||
|
if (vars.fromReserveAToken.balanceOf(msg.sender) == amountToSwap) {
|
||||||
|
usersConfig[msg.sender].setUsingAsCollateral(fromReserve.id, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fromReserve.updateInterestRates(fromAsset, address(vars.fromReserveAToken), 0, amountToSwap);
|
||||||
|
|
||||||
|
vars.fromReserveAToken.burn(msg.sender, receiverAddress, amountToSwap, fromReserve.liquidityIndex);
|
||||||
|
// Notifies the receiver to proceed, sending as param the underlying already transferred
|
||||||
|
ISwapAdapter(receiverAddress).executeOperation(
|
||||||
|
fromAsset,
|
||||||
|
toAsset,
|
||||||
|
amountToSwap,
|
||||||
|
address(this),
|
||||||
|
params
|
||||||
|
);
|
||||||
|
|
||||||
|
vars.amountToReceive = IERC20(toAsset).balanceOf(receiverAddress);
|
||||||
|
if (vars.amountToReceive != 0) {
|
||||||
|
IERC20(toAsset).transferFrom(receiverAddress, address(vars.toReserveAToken), vars.amountToReceive);
|
||||||
|
vars.toReserveAToken.mint(msg.sender, vars.amountToReceive, toReserve.liquidityIndex);
|
||||||
|
toReserve.updateInterestRates(toAsset, address(vars.toReserveAToken), vars.amountToReceive, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
(, , , , vars.healthFactor) = GenericLogic.calculateUserAccountData(
|
||||||
|
msg.sender,
|
||||||
|
reserves,
|
||||||
|
usersConfig[msg.sender],
|
||||||
|
reservesList,
|
||||||
|
addressesProvider.getPriceOracle()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (vars.healthFactor < GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD) {
|
||||||
|
return (
|
||||||
|
uint256(Errors.LiquidationErrors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD),
|
||||||
|
Errors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (uint256(Errors.LiquidationErrors.NO_ERROR), Errors.NO_ERRORS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -479,73 +583,4 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
|
||||||
return (collateralAmount, principalAmountNeeded);
|
return (collateralAmount, principalAmountNeeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Allows an user to release one of his assets deposited in the protocol, even if it is used as collateral.
|
|
||||||
* - It's not possible to release one asset to swap for the same
|
|
||||||
* @param receiverAddress The address of the contract receiving the funds. The receiver should implement the ISwapAdapter interface
|
|
||||||
* @param fromAsset Asset to swap from
|
|
||||||
* @param toAsset Asset to swap to
|
|
||||||
* @param params a bytes array to be sent (if needed) to the receiver contract with extra data
|
|
||||||
**/
|
|
||||||
function swapLiquidity(
|
|
||||||
address receiverAddress,
|
|
||||||
address fromAsset,
|
|
||||||
address toAsset,
|
|
||||||
uint256 amountToSwap,
|
|
||||||
bytes calldata params
|
|
||||||
) external returns (uint256, string memory) {
|
|
||||||
if (fromAsset == toAsset) {
|
|
||||||
return (uint256(Errors.LiquidationErrors.INVALID_EQUAL_ASSETS_TO_SWAP), Errors.INVALID_EQUAL_ASSETS_TO_SWAP);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReserveLogic.ReserveData storage fromReserve = reserves[fromAsset];
|
|
||||||
ReserveLogic.ReserveData storage toReserve = reserves[toAsset];
|
|
||||||
IAToken fromReserveAToken = IAToken(fromReserve.aTokenAddress);
|
|
||||||
IAToken toReserveAToken = IAToken(toReserve.aTokenAddress);
|
|
||||||
|
|
||||||
fromReserve.updateCumulativeIndexesAndTimestamp();
|
|
||||||
toReserve.updateCumulativeIndexesAndTimestamp();
|
|
||||||
|
|
||||||
// get user position
|
|
||||||
uint256 userBalance = fromReserveAToken.balanceOf(msg.sender);
|
|
||||||
if (userBalance == amountToSwap) {
|
|
||||||
usersConfig[msg.sender].setUsingAsCollateral(fromReserve.id, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
fromReserve.updateInterestRates(fromAsset, address(fromReserveAToken), 0, amountToSwap);
|
|
||||||
|
|
||||||
fromReserveAToken.burn(msg.sender, receiverAddress, amountToSwap, fromReserve.liquidityIndex);
|
|
||||||
// Notifies the receiver to proceed, sending as param the underlying already transferred
|
|
||||||
ISwapAdapter(receiverAddress).executeOperation(
|
|
||||||
fromAsset,
|
|
||||||
toAsset,
|
|
||||||
amountToSwap,
|
|
||||||
address(this),
|
|
||||||
params
|
|
||||||
);
|
|
||||||
|
|
||||||
uint256 amountToReceive = IERC20(toAsset).balanceOf(receiverAddress);
|
|
||||||
if (amountToReceive != 0) {
|
|
||||||
IERC20(toAsset).transferFrom(receiverAddress, address(toReserveAToken), amountToReceive);
|
|
||||||
toReserveAToken.mint(msg.sender, amountToReceive, toReserve.liquidityIndex);
|
|
||||||
toReserve.updateInterestRates(toAsset, address(toReserveAToken), amountToReceive, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
(, , , , uint256 healthFactor) = GenericLogic.calculateUserAccountData(
|
|
||||||
msg.sender,
|
|
||||||
reserves,
|
|
||||||
usersConfig[msg.sender],
|
|
||||||
reservesList,
|
|
||||||
addressesProvider.getPriceOracle()
|
|
||||||
);
|
|
||||||
|
|
||||||
if (healthFactor < GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD) {
|
|
||||||
return (
|
|
||||||
uint256(Errors.LiquidationErrors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD),
|
|
||||||
Errors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (uint256(Errors.LiquidationErrors.NO_ERROR), Errors.NO_ERRORS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -347,12 +347,11 @@ library ValidationLogic {
|
||||||
uint256 userHealthFactor,
|
uint256 userHealthFactor,
|
||||||
uint256 userStableDebt,
|
uint256 userStableDebt,
|
||||||
uint256 userVariableDebt
|
uint256 userVariableDebt
|
||||||
) internal view returns(uint256, string memory) {
|
) internal view returns (uint256, string memory) {
|
||||||
if ( !collateralReserve.configuration.getActive() || !principalReserve.configuration.getActive()) {
|
if (
|
||||||
return (
|
!collateralReserve.configuration.getActive() || !principalReserve.configuration.getActive()
|
||||||
uint256(Errors.LiquidationErrors.NO_ACTIVE_RESERVE),
|
) {
|
||||||
Errors.NO_ACTIVE_RESERVE
|
return (uint256(Errors.LiquidationErrors.NO_ACTIVE_RESERVE), Errors.NO_ACTIVE_RESERVE);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userHealthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD) {
|
if (userHealthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD) {
|
||||||
|
@ -362,8 +361,7 @@ library ValidationLogic {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isCollateralEnabled =
|
bool isCollateralEnabled = collateralReserve.configuration.getLiquidationThreshold() > 0 &&
|
||||||
collateralReserve.configuration.getLiquidationThreshold() > 0 &&
|
|
||||||
userConfig.isUsingAsCollateral(collateralReserve.id);
|
userConfig.isUsingAsCollateral(collateralReserve.id);
|
||||||
|
|
||||||
//if collateral isn't enabled as collateral by user, it cannot be liquidated
|
//if collateral isn't enabled as collateral by user, it cannot be liquidated
|
||||||
|
@ -402,12 +400,11 @@ library ValidationLogic {
|
||||||
uint256 userHealthFactor,
|
uint256 userHealthFactor,
|
||||||
uint256 userStableDebt,
|
uint256 userStableDebt,
|
||||||
uint256 userVariableDebt
|
uint256 userVariableDebt
|
||||||
) internal view returns(uint256, string memory) {
|
) internal view returns (uint256, string memory) {
|
||||||
if ( !collateralReserve.configuration.getActive() || !principalReserve.configuration.getActive()) {
|
if (
|
||||||
return (
|
!collateralReserve.configuration.getActive() || !principalReserve.configuration.getActive()
|
||||||
uint256(Errors.LiquidationErrors.NO_ACTIVE_RESERVE),
|
) {
|
||||||
Errors.NO_ACTIVE_RESERVE
|
return (uint256(Errors.LiquidationErrors.NO_ACTIVE_RESERVE), Errors.NO_ACTIVE_RESERVE);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -420,8 +417,7 @@ library ValidationLogic {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.sender != user) {
|
if (msg.sender != user) {
|
||||||
bool isCollateralEnabled =
|
bool isCollateralEnabled = collateralReserve.configuration.getLiquidationThreshold() > 0 &&
|
||||||
collateralReserve.configuration.getLiquidationThreshold() > 0 &&
|
|
||||||
userConfig.isUsingAsCollateral(collateralReserve.id);
|
userConfig.isUsingAsCollateral(collateralReserve.id);
|
||||||
|
|
||||||
//if collateral isn't enabled as collateral by user, it cannot be liquidated
|
//if collateral isn't enabled as collateral by user, it cannot be liquidated
|
||||||
|
@ -442,4 +438,31 @@ library ValidationLogic {
|
||||||
|
|
||||||
return (uint256(Errors.LiquidationErrors.NO_ERROR), Errors.NO_ERRORS);
|
return (uint256(Errors.LiquidationErrors.NO_ERROR), Errors.NO_ERRORS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Validates the swapLiquidity() action
|
||||||
|
* @param fromReserve The reserve data of the asset to swap from
|
||||||
|
* @param toReserve The reserve data of the asset to swap to
|
||||||
|
* @param fromAsset Address of the asset to swap from
|
||||||
|
* @param toAsset Address of the asset to swap to
|
||||||
|
**/
|
||||||
|
function validateSwapLiquidity(
|
||||||
|
ReserveLogic.ReserveData storage fromReserve,
|
||||||
|
ReserveLogic.ReserveData storage toReserve,
|
||||||
|
address fromAsset,
|
||||||
|
address toAsset
|
||||||
|
) internal view returns (uint256, string memory) {
|
||||||
|
if (!fromReserve.configuration.getActive() || !toReserve.configuration.getActive()) {
|
||||||
|
return (uint256(Errors.LiquidationErrors.NO_ACTIVE_RESERVE), Errors.NO_ACTIVE_RESERVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fromAsset == toAsset) {
|
||||||
|
return (
|
||||||
|
uint256(Errors.LiquidationErrors.INVALID_EQUAL_ASSETS_TO_SWAP),
|
||||||
|
Errors.INVALID_EQUAL_ASSETS_TO_SWAP
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (uint256(Errors.LiquidationErrors.NO_ERROR), Errors.NO_ERRORS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user