From 7ddf18b823fcdb37f9c3688cf097d31e5f78d3e1 Mon Sep 17 00:00:00 2001 From: The3D Date: Tue, 20 Oct 2020 12:19:07 +0200 Subject: [PATCH 1/2] Updated migration scripts to add custom proxy price providers --- config/commons.ts | 7 +++++ deployed-contracts.json | 32 ++++++++++++++++++----- helpers/types.ts | 1 + package.json | 2 +- tasks/full/1_address_provider_registry.ts | 7 +++++ 5 files changed, 42 insertions(+), 7 deletions(-) diff --git a/config/commons.ts b/config/commons.ts index 83c9c25c..71c60c66 100644 --- a/config/commons.ts +++ b/config/commons.ts @@ -258,4 +258,11 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '', }, + ProxyPriceProvider: { + [eEthereumNetwork.coverage]: '', + [eEthereumNetwork.buidlerevm]: '', + [eEthereumNetwork.kovan]: '0x276C4793F2EE3D5Bf18C5b879529dD4270BA4814', + [eEthereumNetwork.ropsten]: '', + [eEthereumNetwork.main]: '', + }, }; diff --git a/deployed-contracts.json b/deployed-contracts.json index f0208be5..033a9c6c 100644 --- a/deployed-contracts.json +++ b/deployed-contracts.json @@ -27,8 +27,8 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "kovan": { - "address": "0x20e080B395341B3b617E893c281c7E999C942276", - "deployer": "0x85e4A467343c0dc4aDAB74Af84448D9c45D8ae6F" + "address": "0xd7e3C4b2CE495066dE1923c268D68A844bD7Ae13", + "deployer": "0x6b40a028d2Ab94e5f6d3793F32D326CDf724Bb1D" } }, "LendingPoolAddressesProviderRegistry": { @@ -45,8 +45,8 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "kovan": { - "address": "0x00219a2958f758122106Bb8A801AFc1B70897663", - "deployer": "0x85e4A467343c0dc4aDAB74Af84448D9c45D8ae6F" + "address": "0x83c7A0E78e8eee2108a87d7a6770f22BAcb68b5A", + "deployer": "0x6b40a028d2Ab94e5f6d3793F32D326CDf724Bb1D" } }, "FeeProvider": { @@ -76,7 +76,7 @@ "address": "0x65e0Cd5B8904A02f2e00BC6f58bf881998D54BDe" }, "kovan": { - "address": "0x50C9d3aD9399c1EEf6DDeadF8e57fF69994F552e" + "address": "0x1339f3c1FfF00D0FD8946187fdC61F0ef0fFe786" } }, "LendingPoolDataProvider": { @@ -92,7 +92,7 @@ "address": "0x5d12dDe3286D94E0d85F9D3B01B7099cfA0aBCf1" }, "kovan": { - "address": "0x6d1e69bB0578699dd955Eefbf23aAC65c0DA5cE7" + "address": "0xB43CCfF1148bb5ab2104E2ee68A7c30cDEBb9A9C" } }, "PriceOracle": { @@ -171,6 +171,10 @@ "coverage": { "address": "0x626FdE749F9d499d3777320CAf29484B624ab84a", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" + }, + "kovan": { + "address": "0xc4e3d83AEd3D3c60Cf4b238F634014cE103F6fa1", + "deployer": "0x6b40a028d2Ab94e5f6d3793F32D326CDf724Bb1D" } }, "LendingPoolLiquidationManager": { @@ -574,6 +578,10 @@ }, "coverage": { "address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4" + }, + "kovan": { + "address": "0xE4566ce19626826360f4faD941418e2849fC3685", + "deployer": "0x6b40a028d2Ab94e5f6d3793F32D326CDf724Bb1D" } }, "StableDebtToken": { @@ -588,6 +596,10 @@ "coverage": { "address": "0xB660Fdd109a95718cB9d20E3A89EE6cE342aDcB6", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" + }, + "kovan": { + "address": "0x0043967C1Cf13c4Ff3Bc38109054D5a97C147B4A", + "deployer": "0x6b40a028d2Ab94e5f6d3793F32D326CDf724Bb1D" } }, "VariableDebtToken": { @@ -602,6 +614,10 @@ "coverage": { "address": "0x830bceA96E56DBC1F8578f75fBaC0AF16B32A07d", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" + }, + "kovan": { + "address": "0xdF75B68c75c30D177f4Dbd47cBcb5E2E4f3cf8F9", + "deployer": "0x6b40a028d2Ab94e5f6d3793F32D326CDf724Bb1D" } }, "AToken": { @@ -616,6 +632,10 @@ "coverage": { "address": "0xA0AB1cB92A4AF81f84dCd258155B5c25D247b54E", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" + }, + "kovan": { + "address": "0x1A23ADa7218e0a66b7368E12E379Ea88d7a68a27", + "deployer": "0x6b40a028d2Ab94e5f6d3793F32D326CDf724Bb1D" } }, "MockAToken": { diff --git a/helpers/types.ts b/helpers/types.ts index 0b5e4a33..26644896 100644 --- a/helpers/types.ts +++ b/helpers/types.ts @@ -344,6 +344,7 @@ export interface ICommonConfiguration { ReserveAssets: iParamsPerNetwork>; ReservesConfig: iMultiPoolsAssets; ATokenDomainSeparator: iParamsPerNetwork; + ProxyPriceProvider: iParamsPerNetwork; } export interface IAaveConfiguration extends ICommonConfiguration { diff --git a/package.json b/package.json index abce7ae4..1c0bfb5b 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "aave:evm:dev:migration": "buidler aave:dev", "aave:evm:full:migration": "buidler aave:full", "aave:kovan:dev:migration": "npm run buidler:kovan -- aave:dev --verify", - "aave:kovan:full:migration": "npm run buidler:kovan -- aave:full --verify", + "aave:kovan:full:migration": "npm run buidler:kovan -- aave:full", "aave:ropsten:dev:migration": "npm run buidler:ropsten -- aave:dev --verify", "aave:ropsten:full:migration": "npm run buidler:ropsten -- aave:full --verify", "aave:main:dev:migration": "npm run buidler:main -- aave:dev --verify", diff --git a/tasks/full/1_address_provider_registry.ts b/tasks/full/1_address_provider_registry.ts index ef579579..85ead901 100644 --- a/tasks/full/1_address_provider_registry.ts +++ b/tasks/full/1_address_provider_registry.ts @@ -37,4 +37,11 @@ task( ProviderId ) ); + + //register the proxy price provider on the addressesProvider + const proxyProvider = getParamPerNetwork(poolConfig.ProxyPriceProvider, network); + + if (proxyProvider && proxyProvider !== '') { + await waitForTx(await addressesProvider.setPriceOracle(proxyProvider)); + } }); From b7efa920ca21c4f5c67c471c3ea6e27921bfb013 Mon Sep 17 00:00:00 2001 From: The3D Date: Thu, 22 Oct 2020 11:50:04 +0200 Subject: [PATCH 2/2] Remove swapLiquidity/repayWithCollateral --- contracts/interfaces/ILendingPool.sol | 37 - contracts/lendingpool/LendingPool.sol | 87 -- .../LendingPoolCollateralManager.sol | 285 +----- contracts/libraries/logic/ValidationLogic.sol | 91 -- contracts/mocks/flashloan/MockSwapAdapter.sol | 59 -- deployed-contracts.json | 96 +- test/collateral-swap.spec.ts | 258 ----- .../flash-liquidation-with-collateral.spec.ts | 932 ------------------ test/pausable-functions.spec.ts | 42 - test/repay-with-collateral.spec.ts | 682 ------------- 10 files changed, 50 insertions(+), 2519 deletions(-) delete mode 100644 contracts/mocks/flashloan/MockSwapAdapter.sol delete mode 100644 test/collateral-swap.spec.ts delete mode 100644 test/flash-liquidation-with-collateral.spec.ts delete mode 100644 test/repay-with-collateral.spec.ts diff --git a/contracts/interfaces/ILendingPool.sol b/contracts/interfaces/ILendingPool.sol index 8396d35f..2b4ead37 100644 --- a/contracts/interfaces/ILendingPool.sol +++ b/contracts/interfaces/ILendingPool.sol @@ -259,27 +259,6 @@ interface ILendingPool { bool receiveAToken ) external; - /** - * @dev flashes the underlying collateral on an user to swap for the owed asset and repay - * - Both the owner of the position and other liquidators can execute it - * - The owner can repay with his collateral at any point, no matter the health factor - * - Other liquidators can only use this function below 1 HF. To liquidate 50% of the debt > HF 0.98 or the whole below - * @param collateral The address of the collateral asset - * @param principal The address of the owed asset - * @param user Address of the borrower - * @param principalAmount Amount of the debt to repay. type(uint256).max to repay the maximum possible - * @param receiver Address of the contract receiving the collateral to swap - * @param params Variadic bytes param to pass with extra information to the receiver - **/ - function repayWithCollateral( - address collateral, - address principal, - address user, - uint256 principalAmount, - address receiver, - bytes calldata params - ) external; - /** * @dev allows smartcontracts to access the liquidity of the pool within one transaction, * as long as the amount taken plus a fee is returned. NOTE There are security concerns for developers of flashloan receiver contracts @@ -299,22 +278,6 @@ interface ILendingPool { uint16 referralCode ) external; - /** - * @dev Allows an user to release one of his assets deposited in the protocol, even if it is used as collateral, to swap for another. - * - 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; - function getUserAccountData(address user) external view diff --git a/contracts/lendingpool/LendingPool.sol b/contracts/lendingpool/LendingPool.sol index ac052e33..c1ff20bb 100644 --- a/contracts/lendingpool/LendingPool.sol +++ b/contracts/lendingpool/LendingPool.sol @@ -482,55 +482,6 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage } } - /** - * @dev flashes the underlying collateral on an user to swap for the owed asset and repay - * - Both the owner of the position and other liquidators can execute it - * - The owner can repay with his collateral at any point, no matter the health factor - * - Other liquidators can only use this function below 1 HF. To liquidate 50% of the debt > HF 0.98 or the whole below - * @param collateral The address of the collateral asset - * @param principal The address of the owed asset - * @param user Address of the borrower - * @param principalAmount Amount of the debt to repay. type(uint256).max to repay the maximum possible - * @param receiver Address of the contract receiving the collateral to swap - * @param params Variadic bytes param to pass with extra information to the receiver - **/ - function repayWithCollateral( - address collateral, - address principal, - address user, - uint256 principalAmount, - address receiver, - bytes calldata params - ) external override { - _whenNotPaused(); - require(!_flashLiquidationLocked, Errors.REENTRANCY_NOT_ALLOWED); - _flashLiquidationLocked = true; - - address collateralManager = _addressesProvider.getLendingPoolCollateralManager(); - - //solium-disable-next-line - (bool success, bytes memory result) = collateralManager.delegatecall( - abi.encodeWithSignature( - 'repayWithCollateral(address,address,address,uint256,address,bytes)', - collateral, - principal, - user, - principalAmount, - receiver, - params - ) - ); - require(success, Errors.FAILED_REPAY_WITH_COLLATERAL); - - (uint256 returnCode, string memory returnMessage) = abi.decode(result, (uint256, string)); - - if (returnCode != 0) { - revert(string(abi.encodePacked(returnMessage))); - } - - _flashLiquidationLocked = false; - } - struct FlashLoanLocalVars { uint256 premium; uint256 amountPlusPremium; @@ -609,44 +560,6 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage } } - /** - * @dev Allows an user to release one of his assets deposited in the protocol, even if it is used as collateral, to swap for another. - * - 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 override { - _whenNotPaused(); - address collateralManager = _addressesProvider.getLendingPoolCollateralManager(); - - //solium-disable-next-line - (bool success, bytes memory result) = collateralManager.delegatecall( - abi.encodeWithSignature( - 'swapLiquidity(address,address,address,uint256,bytes)', - receiverAddress, - fromAsset, - toAsset, - amountToSwap, - params - ) - ); - require(success, Errors.FAILED_COLLATERAL_SWAP); - - (uint256 returnCode, string memory returnMessage) = abi.decode(result, (uint256, string)); - - if (returnCode != 0) { - revert(string(abi.encodePacked(returnMessage))); - } - } - /** * @dev returns the state and configuration of the reserve * @param asset the address of the reserve diff --git a/contracts/lendingpool/LendingPoolCollateralManager.sol b/contracts/lendingpool/LendingPoolCollateralManager.sol index 736eadf9..0341748e 100644 --- a/contracts/lendingpool/LendingPoolCollateralManager.sol +++ b/contracts/lendingpool/LendingPoolCollateralManager.sol @@ -58,24 +58,6 @@ contract LendingPoolCollateralManager is VersionedInitializable, LendingPoolStor bool receiveAToken ); - /** - @dev emitted when a borrower/liquidator repays with the borrower's collateral - @param collateral the address of the collateral being swapped to repay - @param principal the address of the reserve of the debt - @param user the borrower's address - @param liquidator the address of the liquidator, same as the one of the borrower on self-repayment - @param principalAmount the amount of the debt finally covered - @param swappedCollateralAmount the amount of collateral finally swapped - */ - event RepaidWithCollateral( - address indexed collateral, - address indexed principal, - address indexed user, - address liquidator, - uint256 principalAmount, - uint256 swappedCollateralAmount - ); - struct LiquidationCallLocalVars { uint256 userCollateralBalance; uint256 userStableDebt; @@ -96,16 +78,6 @@ contract LendingPoolCollateralManager is VersionedInitializable, LendingPoolStor string errorMsg; } - struct SwapLiquidityLocalVars { - uint256 healthFactor; - uint256 amountToReceive; - uint256 userBalanceBefore; - IAToken fromReserveAToken; - IAToken toReserveAToken; - uint256 errorCode; - string errorMsg; - } - struct AvailableCollateralToLiquidateLocalVars { uint256 userCompoundedBorrowBalance; uint256 liquidationBonus; @@ -189,7 +161,7 @@ contract LendingPoolCollateralManager is VersionedInitializable, LendingPoolStor ( vars.maxCollateralToLiquidate, vars.principalAmountNeeded - ) = calculateAvailableCollateralToLiquidate( + ) = _calculateAvailableCollateralToLiquidate( collateralReserve, principalReserve, collateral, @@ -295,259 +267,6 @@ contract LendingPoolCollateralManager is VersionedInitializable, LendingPoolStor return (uint256(Errors.CollateralManagerErrors.NO_ERROR), Errors.NO_ERRORS); } - /** - * @dev flashes the underlying collateral on an user to swap for the owed asset and repay - * - Both the owner of the position and other liquidators can execute it. - * - The owner can repay with his collateral at any point, no matter the health factor. - * - Other liquidators can only use this function below 1 HF. To liquidate 50% of the debt > HF 0.98 or the whole below. - * @param collateral The address of the collateral asset. - * @param principal The address of the owed asset. - * @param user Address of the borrower. - * @param principalAmount Amount of the debt to repay. - * @param receiver Address of the contract receiving the collateral to swap. - * @param params Variadic bytes param to pass with extra information to the receiver - **/ - function repayWithCollateral( - address collateral, - address principal, - address user, - uint256 principalAmount, - address receiver, - bytes calldata params - ) external returns (uint256, string memory) { - ReserveLogic.ReserveData storage collateralReserve = _reserves[collateral]; - ReserveLogic.ReserveData storage debtReserve = _reserves[principal]; - UserConfiguration.Map storage userConfig = _usersConfig[user]; - - LiquidationCallLocalVars memory vars; - - (, , , , vars.healthFactor) = GenericLogic.calculateUserAccountData( - user, - _reserves, - _usersConfig[user], - _reservesList, - _reservesCount, - _addressesProvider.getPriceOracle() - ); - - (vars.userStableDebt, vars.userVariableDebt) = Helpers.getUserCurrentDebt(user, debtReserve); - - (vars.errorCode, vars.errorMsg) = ValidationLogic.validateRepayWithCollateral( - collateralReserve, - debtReserve, - userConfig, - user, - vars.healthFactor, - vars.userStableDebt, - vars.userVariableDebt - ); - - if (Errors.CollateralManagerErrors(vars.errorCode) != Errors.CollateralManagerErrors.NO_ERROR) { - return (vars.errorCode, vars.errorMsg); - } - - vars.maxPrincipalAmountToLiquidate = vars.userStableDebt.add(vars.userVariableDebt); - - vars.actualAmountToLiquidate = principalAmount > vars.maxPrincipalAmountToLiquidate - ? vars.maxPrincipalAmountToLiquidate - : principalAmount; - - vars.collateralAtoken = IAToken(collateralReserve.aTokenAddress); - vars.userCollateralBalance = vars.collateralAtoken.balanceOf(user); - - ( - vars.maxCollateralToLiquidate, - vars.principalAmountNeeded - ) = calculateAvailableCollateralToLiquidate( - collateralReserve, - debtReserve, - collateral, - principal, - vars.actualAmountToLiquidate, - 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 (vars.principalAmountNeeded < vars.actualAmountToLiquidate) { - vars.actualAmountToLiquidate = vars.principalAmountNeeded; - } - //updating collateral reserve indexes - collateralReserve.updateState(); - - //updating collateral reserve interest rates - collateralReserve.updateInterestRates( - collateral, - address(vars.collateralAtoken), - 0, - vars.maxCollateralToLiquidate - ); - - vars.collateralAtoken.burn( - user, - receiver, - vars.maxCollateralToLiquidate, - collateralReserve.liquidityIndex - ); - - if (vars.userCollateralBalance == vars.maxCollateralToLiquidate) { - _usersConfig[user].setUsingAsCollateral(collateralReserve.id, false); - } - - vars.principalAToken = debtReserve.aTokenAddress; - - // Notifies the receiver to proceed, sending as param the underlying already transferred - ISwapAdapter(receiver).executeOperation( - collateral, - principal, - vars.maxCollateralToLiquidate, - address(this), - params - ); - - //updating debt reserve - debtReserve.updateState(); - debtReserve.updateInterestRates( - principal, - vars.principalAToken, - vars.actualAmountToLiquidate, - 0 - ); - IERC20(principal).safeTransferFrom( - receiver, - vars.principalAToken, - vars.actualAmountToLiquidate - ); - - if (vars.userVariableDebt >= vars.actualAmountToLiquidate) { - IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn( - user, - vars.actualAmountToLiquidate, - debtReserve.variableBorrowIndex - ); - } else { - IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn( - user, - vars.userVariableDebt, - debtReserve.variableBorrowIndex - ); - IStableDebtToken(debtReserve.stableDebtTokenAddress).burn( - user, - vars.actualAmountToLiquidate.sub(vars.userVariableDebt) - ); - } - - emit RepaidWithCollateral( - collateral, - principal, - user, - msg.sender, - vars.actualAmountToLiquidate, - vars.maxCollateralToLiquidate - ); - - return (uint256(Errors.CollateralManagerErrors.NO_ERROR), Errors.NO_ERRORS); - } - - /** - * @dev Allows an user to release one of his assets deposited in the protocol, even if it is used as collateral, to swap for another. - * - 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) { - ReserveLogic.ReserveData storage fromReserve = _reserves[fromAsset]; - ReserveLogic.ReserveData storage toReserve = _reserves[toAsset]; - - SwapLiquidityLocalVars memory vars; - - (vars.errorCode, vars.errorMsg) = ValidationLogic.validateSwapLiquidity( - fromReserve, - toReserve, - fromAsset, - toAsset - ); - - if (Errors.CollateralManagerErrors(vars.errorCode) != Errors.CollateralManagerErrors.NO_ERROR) { - return (vars.errorCode, vars.errorMsg); - } - - vars.fromReserveAToken = IAToken(fromReserve.aTokenAddress); - vars.toReserveAToken = IAToken(toReserve.aTokenAddress); - - fromReserve.updateState(); - toReserve.updateState(); - - 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).safeTransferFrom( - receiverAddress, - address(vars.toReserveAToken), - vars.amountToReceive - ); - - if (vars.toReserveAToken.balanceOf(msg.sender) == 0) { - _usersConfig[msg.sender].setUsingAsCollateral(toReserve.id, true); - } - - 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, - _reservesCount, - _addressesProvider.getPriceOracle() - ); - - if (vars.healthFactor < GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD) { - return ( - uint256(Errors.CollateralManagerErrors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD), - Errors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD - ); - } - - return (uint256(Errors.CollateralManagerErrors.NO_ERROR), Errors.NO_ERRORS); - } - /** * @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 @@ -559,7 +278,7 @@ contract LendingPoolCollateralManager is VersionedInitializable, LendingPoolStor * @return collateralAmount the maximum amount that is possible to liquidated given all the liquidation constraints (user balance, close factor) * @return principalAmountNeeded the purchase amount **/ - function calculateAvailableCollateralToLiquidate( + function _calculateAvailableCollateralToLiquidate( ReserveLogic.ReserveData storage collateralReserve, ReserveLogic.ReserveData storage principalReserve, address collateralAddress, diff --git a/contracts/libraries/logic/ValidationLogic.sol b/contracts/libraries/logic/ValidationLogic.sol index e5691fda..93219ce8 100644 --- a/contracts/libraries/logic/ValidationLogic.sol +++ b/contracts/libraries/logic/ValidationLogic.sol @@ -384,95 +384,4 @@ library ValidationLogic { return (uint256(Errors.CollateralManagerErrors.NO_ERROR), Errors.NO_ERRORS); } - - /** - * @dev Validates the repayWithCollateral() action - * @param collateralReserve The reserve data of the collateral - * @param principalReserve The reserve data of the principal - * @param userConfig The user configuration - * @param user The address of the user - * @param userHealthFactor The user's health factor - * @param userStableDebt Total stable debt balance of the user - * @param userVariableDebt Total variable debt balance of the user - **/ - function validateRepayWithCollateral( - ReserveLogic.ReserveData storage collateralReserve, - ReserveLogic.ReserveData storage principalReserve, - UserConfiguration.Map storage userConfig, - address user, - uint256 userHealthFactor, - uint256 userStableDebt, - uint256 userVariableDebt - ) internal view returns (uint256, string memory) { - if ( - !collateralReserve.configuration.getActive() || !principalReserve.configuration.getActive() - ) { - return (uint256(Errors.CollateralManagerErrors.NO_ACTIVE_RESERVE), Errors.NO_ACTIVE_RESERVE); - } - - if ( - msg.sender != user && userHealthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD - ) { - return ( - uint256(Errors.CollateralManagerErrors.HEALTH_FACTOR_ABOVE_THRESHOLD), - Errors.HEALTH_FACTOR_NOT_BELOW_THRESHOLD - ); - } - - if (msg.sender != user) { - bool isCollateralEnabled = collateralReserve.configuration.getLiquidationThreshold() > 0 && - userConfig.isUsingAsCollateral(collateralReserve.id); - - //if collateral isn't enabled as collateral by user, it cannot be liquidated - if (!isCollateralEnabled) { - return ( - uint256(Errors.CollateralManagerErrors.COLLATERAL_CANNOT_BE_LIQUIDATED), - Errors.COLLATERAL_CANNOT_BE_LIQUIDATED - ); - } - } - - if (userStableDebt == 0 && userVariableDebt == 0) { - return ( - uint256(Errors.CollateralManagerErrors.CURRRENCY_NOT_BORROWED), - Errors.SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER - ); - } - - return (uint256(Errors.CollateralManagerErrors.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 (fromAsset == toAsset) { - return ( - uint256(Errors.CollateralManagerErrors.INVALID_EQUAL_ASSETS_TO_SWAP), - Errors.INVALID_EQUAL_ASSETS_TO_SWAP - ); - } - - (bool isToActive, bool isToFreezed, , ) = toReserve.configuration.getFlags(); - if (!fromReserve.configuration.getActive() || !isToActive) { - return (uint256(Errors.CollateralManagerErrors.NO_ACTIVE_RESERVE), Errors.NO_ACTIVE_RESERVE); - } - if (isToFreezed) { - return ( - uint256(Errors.CollateralManagerErrors.NO_UNFREEZED_RESERVE), - Errors.NO_UNFREEZED_RESERVE - ); - } - - return (uint256(Errors.CollateralManagerErrors.NO_ERROR), Errors.NO_ERRORS); - } } diff --git a/contracts/mocks/flashloan/MockSwapAdapter.sol b/contracts/mocks/flashloan/MockSwapAdapter.sol deleted file mode 100644 index 1e8bca38..00000000 --- a/contracts/mocks/flashloan/MockSwapAdapter.sol +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-License-Identifier: agpl-3.0 -pragma solidity ^0.6.8; - -import {MintableERC20} from '../tokens/MintableERC20.sol'; -import {ILendingPoolAddressesProvider} from '../../interfaces/ILendingPoolAddressesProvider.sol'; -import {ISwapAdapter} from '../../interfaces/ISwapAdapter.sol'; -import {ILendingPool} from '../../interfaces/ILendingPool.sol'; -import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol'; - -contract MockSwapAdapter is ISwapAdapter { - uint256 internal _amountToReturn; - bool internal _tryReentrancy; - ILendingPoolAddressesProvider public addressesProvider; - - event Swapped(address fromAsset, address toAsset, uint256 fromAmount, uint256 receivedAmount); - - constructor(ILendingPoolAddressesProvider provider) public { - addressesProvider = provider; - } - - function setAmountToReturn(uint256 amount) public { - _amountToReturn = amount; - } - - function setTryReentrancy(bool tryReentrancy) public { - _tryReentrancy = tryReentrancy; - } - - function executeOperation( - address assetToSwapFrom, - address assetToSwapTo, - uint256 amountToSwap, - address fundsDestination, - bytes calldata params - ) external override { - params; - IERC20(assetToSwapFrom).transfer(address(1), amountToSwap); // We don't want to keep funds here - MintableERC20(assetToSwapTo).mint(_amountToReturn); - IERC20(assetToSwapTo).approve(fundsDestination, _amountToReturn); - - if (_tryReentrancy) { - ILendingPool(fundsDestination).repayWithCollateral( - assetToSwapFrom, - assetToSwapTo, - address(1), // Doesn't matter, we just want to test the reentrancy - 1 ether, // Same - address(1), // Same - '0x' - ); - } - - emit Swapped(assetToSwapFrom, assetToSwapTo, amountToSwap, _amountToReturn); - } - - function burnAsset(IERC20 asset, uint256 amount) public { - uint256 amountToBurn = (amount == type(uint256).max) ? asset.balanceOf(address(this)) : amount; - asset.transfer(address(0), amountToBurn); - } -} diff --git a/deployed-contracts.json b/deployed-contracts.json index 033a9c6c..04e8014b 100644 --- a/deployed-contracts.json +++ b/deployed-contracts.json @@ -5,7 +5,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x58F132FBB86E21545A4Bace3C19f1C05d86d7A22", + "address": "0xDFbeeed692AA81E7f86E72F7ACbEA2A1C4d63544", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -19,7 +19,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xa4bcDF64Cdd5451b6ac3743B414124A6299B65FF", + "address": "0x5191aA68c7dB195181Dd2441dBE23A48EA24b040", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -37,7 +37,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x5A0773Ff307Bf7C71a832dBB5312237fD3437f9F", + "address": "0xa89E20284Bd638F31b0011D0fC754Fc9d2fa73e3", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -73,7 +73,7 @@ "address": "0x6642B57e4265BAD868C17Fc1d1F4F88DBBA04Aa8" }, "localhost": { - "address": "0x65e0Cd5B8904A02f2e00BC6f58bf881998D54BDe" + "address": "0x9Ec55627757348b322c8dD0865D704649bFa0c7b" }, "kovan": { "address": "0x1339f3c1FfF00D0FD8946187fdC61F0ef0fFe786" @@ -89,7 +89,7 @@ "address": "0xD9273d497eDBC967F39d419461CfcF382a0A822e" }, "localhost": { - "address": "0x5d12dDe3286D94E0d85F9D3B01B7099cfA0aBCf1" + "address": "0x3EE716e38f21e5FC16BFDB773db24D63C637A5d8" }, "kovan": { "address": "0xB43CCfF1148bb5ab2104E2ee68A7c30cDEBb9A9C" @@ -101,7 +101,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x1750499D05Ed1674d822430FB960d5F6731fDf64", + "address": "0x5889354f21A1C8D8D2f82669d778f6Dab778B519", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -115,7 +115,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xEC1C93A9f6a9e18E97784c76aC52053587FcDB89", + "address": "0xC452C5244F701108B4e8E8BCe693160046b30332", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -129,7 +129,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x7B6C3e5486D9e6959441ab554A889099eed76290", + "address": "0x0B63c002cb44B2e5e580C3B3560a27F4101D95c0", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -147,7 +147,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xD83D2773a7873ae2b5f8Fb92097e20a8C64F691E", + "address": "0xCeB290A2C6614BF23B2faa0f0B8067F29C48DB0F", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -165,7 +165,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x626FdE749F9d499d3777320CAf29484B624ab84a", + "address": "0x7C95b1ad025F0C9aB14192f87bF2aD53889bE4F7", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -227,7 +227,7 @@ "address": "0xBEF0d4b9c089a5883741fC14cbA352055f35DDA2" }, "localhost": { - "address": "0x2B681757d757fbB80cc51c6094cEF5eE75bF55aA" + "address": "0x9c91aEaD98b1354C7B0EAfb8ff539d0796c79894" }, "coverage": { "address": "0x2B681757d757fbB80cc51c6094cEF5eE75bF55aA" @@ -235,11 +235,11 @@ }, "WalletBalanceProvider": { "buidlerevm": { - "address": "0xC6bA6049F86d528698B5924B8fC2FE7289D38578", + "address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xDf73fC454FA018051D4a1509e63D11530A59DE10", + "address": "0x145b7B6368Df63e7F3497b0A948B30fC1A4d5E55", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -253,7 +253,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x7c2C195CD6D34B8F845992d380aADB2730bB9C6F", + "address": "0x010e948B9B7D30771E23346C0B17a4D5Ff04e300", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -267,7 +267,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x8858eeB3DfffA017D4BCE9801D340D36Cf895CCf", + "address": "0x79094eDB848047e87a4B8a64ab5Ee2f527791bC0", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -281,7 +281,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x0078371BDeDE8aAc7DeBfFf451B74c5EDB385Af7", + "address": "0xEE0A69d0Bb1312685870Dd7E20AcAD66b6f6264F", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -295,7 +295,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xf4e77E5Da47AC3125140c470c71cBca77B5c638c", + "address": "0x631B367fBE1dbB934bC039aAA0C9eC2EE5943fd5", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -309,7 +309,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x3619DbE27d7c1e7E91aA738697Ae7Bc5FC3eACA5", + "address": "0xf55Af78B3f3059fACF166Aa338FFe059A14e75F6", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -323,7 +323,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x038B86d9d8FAFdd0a02ebd1A476432877b0107C8", + "address": "0xD5A0587aAEB195028909E98930B391dFB3f9F589", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -337,7 +337,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x1A1FEe7EeD918BD762173e4dc5EfDB8a78C924A8", + "address": "0xaD3AdbC18E4AD090034A6C74Eda61f4310dce313", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -351,7 +351,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x500D1d6A4c7D8Ae28240b47c8FCde034D827fD5e", + "address": "0x25a88BbA9c8D2a46e3Ff4bFe98712DF7A1044fB6", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -365,7 +365,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xc4905364b78a742ccce7B890A89514061E47068D", + "address": "0x16d1802cd7cfcb67955BBBa26bAae1cE559B5F5B", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -379,7 +379,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xD6C850aeBFDC46D7F4c207e445cC0d6B0919BDBe", + "address": "0xE58d8c88f5A670f16BE8F7864707170F43e943A6", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -393,7 +393,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x8B5B7a6055E54a36fF574bbE40cf2eA68d5554b3", + "address": "0xfdAF4f6e47e854c05bE158993d32872e784F0502", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -407,7 +407,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xEcc0a6dbC0bb4D51E4F84A315a9e5B0438cAD4f0", + "address": "0x92edC13A10036A3C50396f2B63148a3e9a8D589e", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -421,7 +421,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x20Ce94F404343aD2752A2D01b43fa407db9E0D00", + "address": "0xE5C277cDb7E10372918Ac54Ce54022910A24FE88", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -435,7 +435,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x1d80315fac6aBd3EfeEbE97dEc44461ba7556160", + "address": "0xF5742a599a0F4520089cbf2EBBa66Bb4F471B85F", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -449,7 +449,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x2D8553F9ddA85A9B3259F6Bf26911364B85556F5", + "address": "0x380EF388e13D8cAdeACef6eF682C7B7D85865076", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -463,7 +463,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x52d3b94181f8654db2530b0fEe1B19173f519C52", + "address": "0xC89577DED8441e52C17C13D527b85b225C5c8311", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -477,7 +477,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xd15468525c35BDBC1eD8F2e09A00F8a173437f2f", + "address": "0xD4b06774A717Ff5A7c20c8712e31c6BbfFcb1F01", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -491,7 +491,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x7e35Eaf7e8FBd7887ad538D4A38Df5BbD073814a", + "address": "0xbe66dC9DFEe580ED968403e35dF7b5159f873df8", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -505,7 +505,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x5bcb88A0d20426e451332eE6C4324b0e663c50E0", + "address": "0x93AfC6Df4bB8F62F2493B19e577f8382c0BA9EBC", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -519,7 +519,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x3521eF8AaB0323004A6dD8b03CE890F4Ea3A13f5", + "address": "0x75Ded61646B5945BdDd0CD9a9Db7c8288DA6F810", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -533,7 +533,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x53369fd4680FfE3DfF39Fc6DDa9CfbfD43daeA2E", + "address": "0xdE7c40e675bF1aA45c18cCbaEb9662B16b0Ddf7E", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -547,7 +547,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xB00cC45B4a7d3e1FEE684cFc4417998A1c183e6d", + "address": "0xEcb928A3c079a1696Aa5244779eEc3dE1717fACd", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -561,7 +561,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x58F132FBB86E21545A4Bace3C19f1C05d86d7A22", + "address": "0xDFbeeed692AA81E7f86E72F7ACbEA2A1C4d63544", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -574,7 +574,7 @@ "address": "0xe7536f450378748E1BD4645D3c77ec38e0F3ba28" }, "localhost": { - "address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4" + "address": "0x987223924D2DD6c6efB601756850f3886ECbceF6" }, "coverage": { "address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4" @@ -590,7 +590,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xB660Fdd109a95718cB9d20E3A89EE6cE342aDcB6", + "address": "0xaca5aCeB6f44845d07Fd339a51F0bd52Bb3D8D1A", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -608,7 +608,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x830bceA96E56DBC1F8578f75fBaC0AF16B32A07d", + "address": "0x9bD0Bec44106D8Ea8fFb6296d7A84742a290E064", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -622,7 +622,7 @@ }, "AToken": { "localhost": { - "address": "0xA0AB1cB92A4AF81f84dCd258155B5c25D247b54E", + "address": "0x00f126cCA2266bFb634Ed6DB17c4C74fb8cA5177", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "buidlerevm": { @@ -640,11 +640,11 @@ }, "MockAToken": { "buidlerevm": { - "address": "0x3b050AFb4ac4ACE646b31fF3639C1CD43aC31460", + "address": "0x392E5355a0e88Bd394F717227c752670fb3a8020", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xa89E20284Bd638F31b0011D0fC754Fc9d2fa73e3", + "address": "0xbF538F34cb100bAeEE55aa1F036D33F03b03d900", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -658,7 +658,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xf784709d2317D872237C4bC22f867d1BAe2913AB", + "address": "0xff1B1B810F5DCe853a9b1819DE220D532D1CFeF2", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -668,11 +668,11 @@ }, "MockStableDebtToken": { "buidlerevm": { - "address": "0xEBAB67ee3ef604D5c250A53b4b8fcbBC6ec3007C", + "address": "0x3b050AFb4ac4ACE646b31fF3639C1CD43aC31460", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xaA935993065F2dDB1d13623B1941C7AEE3A60F23", + "address": "0x7436d6adaA697413F00cb63E1A2A854bF2Aec5A1", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -682,11 +682,11 @@ }, "MockVariableDebtToken": { "buidlerevm": { - "address": "0xBE36BE5680244Ae1A6F983E4A6f6E1c142cdAbe3", + "address": "0xEBAB67ee3ef604D5c250A53b4b8fcbBC6ec3007C", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x35A2624888e207e4B3434E9a9E250bF6Ee68FeA3", + "address": "0x2A7BE996B8801ED21f2f45148791D402811A2106", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "coverage": { @@ -702,7 +702,7 @@ "address": "0xBEF0d4b9c089a5883741fC14cbA352055f35DDA2" }, "localhost": { - "address": "0xBEF0d4b9c089a5883741fC14cbA352055f35DDA2" + "address": "0x48FAde2E719B770E1783d03466dAEe98b5183538" } }, "MockFlashRepayAdapter": { diff --git a/test/collateral-swap.spec.ts b/test/collateral-swap.spec.ts deleted file mode 100644 index b85e1dd3..00000000 --- a/test/collateral-swap.spec.ts +++ /dev/null @@ -1,258 +0,0 @@ -import {makeSuite, TestEnv} from './helpers/make-suite'; -import {MockSwapAdapter} from '../types/MockSwapAdapter'; -import {getMockSwapAdapter} from '../helpers/contracts-helpers'; -import {ProtocolErrors} from '../helpers/types'; -import {ethers} from 'ethers'; -import {APPROVAL_AMOUNT_LENDING_POOL} from '../helpers/constants'; -import {getContractsData, getTxCostAndTimestamp} from './helpers/actions'; -import {calcExpectedATokenBalance} from './helpers/utils/calculations'; -import {waitForTx} from '../helpers/misc-utils'; -import {advanceBlock, timeLatest} from '../helpers/misc-utils'; - -const {expect} = require('chai'); - -makeSuite('LendingPool SwapDeposit function', (testEnv: TestEnv) => { - let _mockSwapAdapter = {} as MockSwapAdapter; - const { - HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD, - NO_UNFREEZED_RESERVE, - NO_ACTIVE_RESERVE, - INVALID_EQUAL_ASSETS_TO_SWAP, - } = ProtocolErrors; - - before(async () => { - _mockSwapAdapter = await getMockSwapAdapter(); - }); - - it('Should not allow to swap if from equal to', async () => { - const {pool, weth} = testEnv; - - await expect( - pool.swapLiquidity( - _mockSwapAdapter.address, - weth.address, - weth.address, - '1'.toString(), - '0x10' - ) - ).to.be.revertedWith(INVALID_EQUAL_ASSETS_TO_SWAP); - }); - - it('Should not allow to swap if from or to reserves are not active', async () => { - const {pool, weth, dai, configurator} = testEnv; - - await configurator.deactivateReserve(weth.address); - - await expect( - pool.swapLiquidity( - _mockSwapAdapter.address, - weth.address, - dai.address, - '1'.toString(), - '0x10' - ) - ).to.be.revertedWith(NO_ACTIVE_RESERVE); - await configurator.activateReserve(weth.address); - - await configurator.deactivateReserve(dai.address); - - await expect( - pool.swapLiquidity( - _mockSwapAdapter.address, - weth.address, - dai.address, - '1'.toString(), - '0x10' - ) - ).to.be.revertedWith(NO_ACTIVE_RESERVE); - - //cleanup state - await configurator.activateReserve(dai.address); - }); - - it('Deposits WETH into the reserve', async () => { - const {pool, weth, users} = testEnv; - const amountToDeposit = ethers.utils.parseEther('1'); - - for (const signer of [weth.signer, users[2].signer]) { - const connectedWETH = weth.connect(signer); - await connectedWETH.mint(amountToDeposit); - await connectedWETH.approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - await pool - .connect(signer) - .deposit(weth.address, amountToDeposit, await signer.getAddress(), '0'); - } - }); - - it('User tries to swap more then he can, revert expected', async () => { - const {pool, weth, dai} = testEnv; - await expect( - pool.swapLiquidity( - _mockSwapAdapter.address, - weth.address, - dai.address, - ethers.utils.parseEther('1.1'), - '0x10' - ) - ).to.be.revertedWith('55'); - }); - - it('User tries to swap more then available on the reserve', async () => { - const {pool, weth, dai, users, aEth, deployer} = testEnv; - - await pool.borrow(weth.address, ethers.utils.parseEther('0.1'), 1, 0, deployer.address); - await pool.connect(users[2].signer).withdraw(weth.address, ethers.utils.parseEther('1')); - - await expect( - pool.swapLiquidity( - _mockSwapAdapter.address, - weth.address, - dai.address, - ethers.utils.parseEther('1'), - '0x10' - ) - ).to.be.revertedWith('55'); - }); - - it('User tries to swap correct amount', async () => { - const {pool, weth, dai, aEth, aDai, helpersContract} = testEnv; - const userAddress = await pool.signer.getAddress(); - const amountToSwap = ethers.utils.parseEther('0.25'); - - const amountToReturn = ethers.utils.parseEther('0.5'); - await _mockSwapAdapter.setAmountToReturn(amountToReturn); - - const { - reserveData: wethReserveDataBefore, - userData: wethUserDataBefore, - } = await getContractsData(weth.address, userAddress, testEnv); - - const {reserveData: daiReserveDataBefore, userData: daiUserDataBefore} = await getContractsData( - dai.address, - userAddress, - testEnv - ); - - const reserveBalanceWETHBefore = await weth.balanceOf(aEth.address); - const reserveBalanceDAIBefore = await dai.balanceOf(aDai.address); - - const txReceipt = await waitForTx( - await pool.swapLiquidity( - _mockSwapAdapter.address, - weth.address, - dai.address, - amountToSwap, - '0x10' - ) - ); - const {txTimestamp} = await getTxCostAndTimestamp(txReceipt); - const userATokenBalanceWETHAfter = await aEth.balanceOf(userAddress); - const userATokenBalanceDAIAfter = await aDai.balanceOf(userAddress); - - const reserveBalanceWETHAfter = await weth.balanceOf(aEth.address); - const reserveBalanceDAIAfter = await dai.balanceOf(aDai.address); - - expect(userATokenBalanceWETHAfter.toString()).to.be.equal( - calcExpectedATokenBalance(wethReserveDataBefore, wethUserDataBefore, txTimestamp) - .minus(amountToSwap.toString()) - .toString(), - 'was burned incorrect amount of user funds' - ); - expect(userATokenBalanceDAIAfter.toString()).to.be.equal( - calcExpectedATokenBalance(daiReserveDataBefore, daiUserDataBefore, txTimestamp) - .plus(amountToReturn.toString()) - .toString(), - 'was minted incorrect amount of user funds' - ); - - expect(reserveBalanceWETHAfter.toString()).to.be.equal( - reserveBalanceWETHBefore.sub(amountToSwap).toString(), - 'was sent incorrect amount if reserve funds' - ); - expect(reserveBalanceDAIAfter.toString()).to.be.equal( - reserveBalanceDAIBefore.add(amountToReturn).toString(), - 'was received incorrect amount if reserve funds' - ); - expect( - (await helpersContract.getUserReserveData(dai.address, userAddress)).usageAsCollateralEnabled - ).to.be.equal(true, 'usage as collateral was not enabled on destination reserve for the user'); - }); - - it('User tries to drop HF below one', async () => { - const {pool, weth, dai, deployer} = testEnv; - const amountToSwap = ethers.utils.parseEther('0.3'); - - const amountToReturn = ethers.utils.parseEther('0.5'); - await _mockSwapAdapter.setAmountToReturn(amountToReturn); - - await pool.borrow(weth.address, ethers.utils.parseEther('0.3'), 1, 0, deployer.address); - - await expect( - pool.swapLiquidity(_mockSwapAdapter.address, weth.address, dai.address, amountToSwap, '0x10') - ).to.be.revertedWith(HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD); - }); - - it('Should set usage as collateral to false if no leftovers after swap', async () => { - const {pool, weth, dai, users} = testEnv; - const userAddress = await pool.signer.getAddress(); - - // add more liquidity to allow user 0 to swap everything he has - await weth.connect(users[2].signer).mint(ethers.utils.parseEther('1')); - await pool - .connect(users[2].signer) - .deposit(weth.address, ethers.utils.parseEther('1'), users[2].address, '0'); - - // cleanup borrowings, to be abe to swap whole weth - const amountToRepay = ethers.utils.parseEther('0.5'); - await weth.mint(amountToRepay); - await pool.repay(weth.address, amountToRepay, '1', userAddress); - const txTimestamp = (await timeLatest()).plus(100); - - const { - reserveData: wethReserveDataBefore, - userData: wethUserDataBefore, - } = await getContractsData(weth.address, userAddress, testEnv); - const amountToSwap = calcExpectedATokenBalance( - wethReserveDataBefore, - wethUserDataBefore, - txTimestamp.plus('1') - ); - - await advanceBlock(txTimestamp.toNumber()); - - await pool.swapLiquidity( - _mockSwapAdapter.address, - weth.address, - dai.address, - amountToSwap.toString(), - '0x10' - ); - const {userData: wethUserDataAfter} = await getContractsData( - weth.address, - userAddress, - testEnv - ); - expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.equal( - false, - 'usageAsCollateralEnabled are not set to false' - ); - }); - it('Should not allow to swap if to reserve are freezed', async () => { - const {pool, weth, dai, configurator} = testEnv; - - await configurator.freezeReserve(dai.address); - - await expect( - pool.swapLiquidity( - _mockSwapAdapter.address, - weth.address, - dai.address, - '1'.toString(), - '0x10' - ) - ).to.be.revertedWith(NO_UNFREEZED_RESERVE); - - //cleanup state - await configurator.unfreezeReserve(dai.address); - }); -}); diff --git a/test/flash-liquidation-with-collateral.spec.ts b/test/flash-liquidation-with-collateral.spec.ts deleted file mode 100644 index 91bfe38f..00000000 --- a/test/flash-liquidation-with-collateral.spec.ts +++ /dev/null @@ -1,932 +0,0 @@ -import {TestEnv, makeSuite} from './helpers/make-suite'; -import {APPROVAL_AMOUNT_LENDING_POOL, oneEther} from '../helpers/constants'; -import {ethers} from 'ethers'; -import BigNumber from 'bignumber.js'; -import { - calcExpectedVariableDebtTokenBalance, - calcExpectedStableDebtTokenBalance, -} from './helpers/utils/calculations'; -import {getContractsData} from './helpers/actions'; -import {timeLatest, BRE, increaseTime, waitForTx} from '../helpers/misc-utils'; -import {ProtocolErrors} from '../helpers/types'; -import {convertToCurrencyDecimals} from '../helpers/contracts-helpers'; -import {expectRepayWithCollateralEvent} from './repay-with-collateral.spec'; - -const {expect} = require('chai'); -const {parseUnits, parseEther} = ethers.utils; - -makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEnv) => { - const {INVALID_HF, COLLATERAL_CANNOT_BE_LIQUIDATED, IS_PAUSED} = ProtocolErrors; - - it('User 1 provides some liquidity for others to borrow', async () => { - const {pool, weth, dai, usdc, deployer} = testEnv; - - await weth.mint(parseEther('200')); - await weth.approve(pool.address, parseEther('200')); - await pool.deposit(weth.address, parseEther('200'), deployer.address, 0); - await dai.mint(parseEther('20000')); - await dai.approve(pool.address, parseEther('20000')); - await pool.deposit(dai.address, parseEther('20000'), deployer.address, 0); - await usdc.mint(parseEther('20000')); - await usdc.approve(pool.address, parseEther('20000')); - await pool.deposit(usdc.address, parseEther('20000'), deployer.address, 0); - }); - - it('User 5 liquidate User 3 collateral, all his variable debt and part of the stable', async () => { - const {pool, weth, usdc, users, mockSwapAdapter, oracle, helpersContract} = testEnv; - const user = users[2]; - const liquidator = users[4]; - const amountToDeposit = parseEther('20'); - const amountToBorrow = parseUnits('40', 6); - - await weth.connect(user.signer).mint(amountToDeposit); - - await weth.connect(user.signer).approve(pool.address, amountToDeposit); - await pool.connect(user.signer).deposit(weth.address, amountToDeposit, user.address, '0'); - - const usdcPrice = await oracle.getAssetPrice(usdc.address); - - await pool.connect(user.signer).borrow(usdc.address, amountToBorrow, 2, 0, user.address); - - await pool.connect(user.signer).borrow(usdc.address, amountToBorrow, 1, 0, user.address); - - const {userData: wethUserDataBefore} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const { - reserveData: usdcReserveDataBefore, - userData: usdcUserDataBefore, - } = await getContractsData(usdc.address, user.address, testEnv); - - // Set HF below 1 - await oracle.setAssetPrice( - usdc.address, - new BigNumber(usdcPrice.toString()).multipliedBy(60).toFixed(0) - ); - const userGlobalDataPrior = await pool.getUserAccountData(user.address); - expect(userGlobalDataPrior.healthFactor.toString()).to.be.bignumber.lt(oneEther, INVALID_HF); - - const amountToRepay = parseUnits('80', 6); - - await mockSwapAdapter.setAmountToReturn(amountToRepay); - const txReceipt = await waitForTx( - await pool - .connect(liquidator.signer) - .repayWithCollateral( - weth.address, - usdc.address, - user.address, - amountToRepay, - mockSwapAdapter.address, - '0x' - ) - ); - const repayWithCollateralTimestamp = await timeLatest(); - - const {userData: wethUserDataAfter} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const {userData: usdcUserDataAfter} = await getContractsData( - usdc.address, - user.address, - testEnv - ); - - const collateralPrice = await oracle.getAssetPrice(weth.address); - const principalPrice = await oracle.getAssetPrice(usdc.address); - - const collateralDecimals = ( - await helpersContract.getReserveConfigurationData(weth.address) - ).decimals.toString(); - const principalDecimals = ( - await helpersContract.getReserveConfigurationData(usdc.address) - ).decimals.toString(); - - const expectedCollateralLiquidated = new BigNumber(principalPrice.toString()) - .times(new BigNumber(amountToRepay.toString()).times(105)) - .times(new BigNumber(10).pow(collateralDecimals)) - .div( - new BigNumber(collateralPrice.toString()).times(new BigNumber(10).pow(principalDecimals)) - ) - .div(100) - .decimalPlaces(0, BigNumber.ROUND_DOWN); - - const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance( - usdcReserveDataBefore, - usdcUserDataBefore, - new BigNumber(repayWithCollateralTimestamp) - ).minus(usdcUserDataBefore.currentVariableDebt); - - const expectedStableDebtIncrease = calcExpectedStableDebtTokenBalance( - usdcUserDataBefore.principalStableDebt, - usdcUserDataBefore.stableBorrowRate, - usdcUserDataBefore.stableRateLastUpdated, - new BigNumber(repayWithCollateralTimestamp) - ).minus(usdcUserDataBefore.currentStableDebt); - - expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.equal( - new BigNumber(usdcUserDataBefore.currentVariableDebt) - .minus(amountToRepay.toString()) - .plus(expectedVariableDebtIncrease) - .gte(0) - ? new BigNumber(usdcUserDataBefore.currentVariableDebt) - .minus(amountToRepay.toString()) - .plus(expectedVariableDebtIncrease) - .toString() - : '0', - 'INVALID_VARIABLE_DEBT_POSITION' - ); - - const stableDebtRepaid = new BigNumber(usdcUserDataBefore.currentVariableDebt) - .minus(amountToRepay.toString()) - .plus(expectedVariableDebtIncrease) - .abs(); - - expect(usdcUserDataAfter.currentStableDebt).to.be.bignumber.equal( - new BigNumber(usdcUserDataBefore.currentStableDebt) - .minus(stableDebtRepaid) - .plus(expectedStableDebtIncrease) - .gte(0) - ? new BigNumber(usdcUserDataBefore.currentStableDebt) - .minus(stableDebtRepaid) - .plus(expectedStableDebtIncrease) - .toString() - : '0', - 'INVALID_STABLE_DEBT_POSITION' - ); - - expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal( - new BigNumber(wethUserDataBefore.currentATokenBalance).minus( - expectedCollateralLiquidated.toString() - ), - 'INVALID_COLLATERAL_POSITION' - ); - - const eventsEmitted = txReceipt.events || []; - - expectRepayWithCollateralEvent( - eventsEmitted, - pool.address, - weth.address, - usdc.address, - user.address - ); - // Resets USDC Price - await oracle.setAssetPrice(usdc.address, usdcPrice); - }); - - it('User 3 deposits WETH and borrows USDC at Variable', async () => { - const {pool, weth, usdc, users, oracle} = testEnv; - const user = users[2]; - const amountToDeposit = parseEther('10'); - - await weth.connect(user.signer).mint(amountToDeposit); - - await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - - await pool.connect(user.signer).deposit(weth.address, amountToDeposit, user.address, '0'); - - const userGlobalData = await pool.getUserAccountData(user.address); - - const usdcPrice = await oracle.getAssetPrice(usdc.address); - - const amountUSDCToBorrow = await convertToCurrencyDecimals( - usdc.address, - new BigNumber(userGlobalData.availableBorrowsETH.toString()) - .div(usdcPrice.toString()) - .multipliedBy(0.95) - .toFixed(0) - ); - - await pool.connect(user.signer).borrow(usdc.address, amountUSDCToBorrow, 2, 0, user.address); - }); - - it('User 5 liquidates half the USDC loan of User 3 by swapping his WETH collateral', async () => { - const {pool, weth, usdc, users, mockSwapAdapter, oracle, helpersContract} = testEnv; - const user = users[2]; - const liquidator = users[4]; - // Sets USDC Price higher to decrease health factor below 1 - const usdcPrice = await oracle.getAssetPrice(usdc.address); - - await oracle.setAssetPrice( - usdc.address, - new BigNumber(usdcPrice.toString()).multipliedBy(1.15).toFixed(0) - ); - - const userGlobalData = await pool.getUserAccountData(user.address); - - expect(userGlobalData.healthFactor.toString()).to.be.bignumber.lt(oneEther, INVALID_HF); - - const {userData: wethUserDataBefore} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const { - reserveData: usdcReserveDataBefore, - userData: usdcUserDataBefore, - } = await getContractsData(usdc.address, user.address, testEnv); - - const amountToRepay = usdcReserveDataBefore.totalVariableDebt.dividedBy(2).toFixed(0); - - await mockSwapAdapter.setAmountToReturn(amountToRepay); - await waitForTx( - await pool - .connect(liquidator.signer) - .repayWithCollateral( - weth.address, - usdc.address, - user.address, - amountToRepay, - mockSwapAdapter.address, - '0x' - ) - ); - const repayWithCollateralTimestamp = await timeLatest(); - - const {userData: wethUserDataAfter} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const {userData: usdcUserDataAfter} = await getContractsData( - usdc.address, - user.address, - testEnv - ); - - const collateralPrice = await oracle.getAssetPrice(weth.address); - const principalPrice = await oracle.getAssetPrice(usdc.address); - - const collateralDecimals = ( - await helpersContract.getReserveConfigurationData(weth.address) - ).decimals.toString(); - const principalDecimals = ( - await helpersContract.getReserveConfigurationData(usdc.address) - ).decimals.toString(); - - const expectedCollateralLiquidated = new BigNumber(principalPrice.toString()) - .times(new BigNumber(amountToRepay.toString()).times(105)) - .times(new BigNumber(10).pow(collateralDecimals)) - .div( - new BigNumber(collateralPrice.toString()).times(new BigNumber(10).pow(principalDecimals)) - ) - .div(100) - .decimalPlaces(0, BigNumber.ROUND_DOWN); - - const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance( - usdcReserveDataBefore, - usdcUserDataBefore, - new BigNumber(repayWithCollateralTimestamp) - ).minus(usdcUserDataBefore.currentVariableDebt); - - expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual( - new BigNumber(usdcUserDataBefore.currentVariableDebt) - .minus(amountToRepay.toString()) - .plus(expectedVariableDebtIncrease) - .toString(), - 'INVALID_DEBT_POSITION' - ); - - expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.almostEqual( - new BigNumber(wethUserDataBefore.currentATokenBalance).minus( - expectedCollateralLiquidated.toString() - ), - 'INVALID_COLLATERAL_POSITION' - ); - expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.true; - - // Resets USDC Price - await oracle.setAssetPrice(usdc.address, usdcPrice); - }); - - it('Revert expected. User 5 tries to liquidate an User 3 collateral a currency he havent borrow', async () => { - const {pool, weth, dai, users, oracle, mockSwapAdapter, usdc} = testEnv; - const user = users[2]; - const liquidator = users[4]; - - const amountToRepay = parseUnits('10', 6); - - // Sets USDC Price higher to decrease health factor below 1 - const usdcPrice = await oracle.getAssetPrice(usdc.address); - - await oracle.setAssetPrice( - usdc.address, - new BigNumber(usdcPrice.toString()).multipliedBy(6.4).toFixed(0) - ); - const userGlobalData = await pool.getUserAccountData(user.address); - - expect(userGlobalData.healthFactor.toString()).to.be.bignumber.lt(oneEther, INVALID_HF); - - await expect( - pool - .connect(liquidator.signer) - .repayWithCollateral( - weth.address, - dai.address, - user.address, - amountToRepay, - mockSwapAdapter.address, - '0x' - ) - ).to.be.revertedWith('40'); - - await oracle.setAssetPrice(usdc.address, usdcPrice); - }); - - it('User 5 liquidates all the USDC loan of User 3 by swapping his WETH collateral', async () => { - const {pool, weth, usdc, users, mockSwapAdapter, oracle, helpersContract} = testEnv; - const user = users[2]; - const liquidator = users[4]; - // Sets USDC Price higher to decrease health factor below 1 - const usdcPrice = await oracle.getAssetPrice(usdc.address); - - await oracle.setAssetPrice( - usdc.address, - new BigNumber(usdcPrice.toString()).multipliedBy(1.35).toFixed(0) - ); - - const userGlobalData = await pool.getUserAccountData(user.address); - - expect(userGlobalData.healthFactor.toString()).to.be.bignumber.lt(oneEther, INVALID_HF); - - const {userData: wethUserDataBefore} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const { - reserveData: usdcReserveDataBefore, - userData: usdcUserDataBefore, - } = await getContractsData(usdc.address, user.address, testEnv); - - const amountToRepay = usdcReserveDataBefore.totalVariableDebt.toFixed(0); - - await mockSwapAdapter.setAmountToReturn(amountToRepay); - await waitForTx( - await pool - .connect(liquidator.signer) - .repayWithCollateral( - weth.address, - usdc.address, - user.address, - amountToRepay, - mockSwapAdapter.address, - '0x' - ) - ); - const repayWithCollateralTimestamp = await timeLatest(); - - const {userData: wethUserDataAfter} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const {userData: usdcUserDataAfter} = await getContractsData( - usdc.address, - user.address, - testEnv - ); - - const collateralPrice = await oracle.getAssetPrice(weth.address); - const principalPrice = await oracle.getAssetPrice(usdc.address); - - const collateralDecimals = ( - await helpersContract.getReserveConfigurationData(weth.address) - ).decimals.toString(); - const principalDecimals = ( - await helpersContract.getReserveConfigurationData(usdc.address) - ).decimals.toString(); - - const expectedCollateralLiquidated = new BigNumber(principalPrice.toString()) - .times(new BigNumber(amountToRepay.toString()).times(105)) - .times(new BigNumber(10).pow(collateralDecimals)) - .div( - new BigNumber(collateralPrice.toString()).times(new BigNumber(10).pow(principalDecimals)) - ) - .div(100) - .decimalPlaces(0, BigNumber.ROUND_DOWN); - - const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance( - usdcReserveDataBefore, - usdcUserDataBefore, - new BigNumber(repayWithCollateralTimestamp) - ).minus(usdcUserDataBefore.currentVariableDebt); - - expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual( - new BigNumber(usdcUserDataBefore.currentVariableDebt) - .minus(amountToRepay.toString()) - .plus(expectedVariableDebtIncrease) - .toString(), - 'INVALID_DEBT_POSITION' - ); - - expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal( - new BigNumber(wethUserDataBefore.currentATokenBalance).minus( - expectedCollateralLiquidated.toString() - ), - 'INVALID_COLLATERAL_POSITION' - ); - - // Resets USDC Price - await oracle.setAssetPrice(usdc.address, usdcPrice); - }); - - it('User 2 deposit WETH and borrows DAI at Variable', async () => { - const {pool, weth, dai, users, oracle} = testEnv; - const user = users[1]; - const amountToDeposit = ethers.utils.parseEther('2'); - - await weth.connect(user.signer).mint(amountToDeposit); - - await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - - await pool.connect(user.signer).deposit(weth.address, amountToDeposit, user.address, '0'); - - const userGlobalData = await pool.getUserAccountData(user.address); - - const daiPrice = await oracle.getAssetPrice(dai.address); - - const amountDAIToBorrow = await convertToCurrencyDecimals( - dai.address, - new BigNumber(userGlobalData.availableBorrowsETH.toString()) - .div(daiPrice.toString()) - .multipliedBy(0.9) - .toFixed(0) - ); - - await pool.connect(user.signer).borrow(dai.address, amountDAIToBorrow, 2, 0, user.address); - }); - - it('It is not possible to do reentrancy on repayWithCollateral()', async () => { - const {pool, weth, dai, users, mockSwapAdapter, oracle} = testEnv; - const user = users[1]; - const liquidator = users[4]; - - // Sets DAI Price higher to decrease health factor below 1 - const daiPrice = await oracle.getAssetPrice(dai.address); - - await oracle.setAssetPrice( - dai.address, - new BigNumber(daiPrice.toString()).multipliedBy(1.4).toFixed(0) - ); - - const {reserveData: daiReserveDataBefore} = await getContractsData( - dai.address, - user.address, - testEnv - ); - - const amountToRepay = daiReserveDataBefore.totalVariableDebt.toString(); - - await waitForTx(await mockSwapAdapter.setTryReentrancy(true)); - - await mockSwapAdapter.setAmountToReturn(amountToRepay); - await expect( - pool - .connect(liquidator.signer) - .repayWithCollateral( - weth.address, - dai.address, - user.address, - amountToRepay, - mockSwapAdapter.address, - '0x' - ) - ).to.be.revertedWith('53'); - - // Resets DAI Price - await oracle.setAssetPrice(dai.address, daiPrice); - // Resets mock - await waitForTx(await mockSwapAdapter.setTryReentrancy(false)); - }); - - it('User 5 tries to liquidate User 2 DAI Variable loan using his WETH collateral, with good HF', async () => { - const {pool, weth, dai, users, mockSwapAdapter} = testEnv; - const user = users[1]; - const liquidator = users[4]; - - const {reserveData: daiReserveDataBefore} = await getContractsData( - dai.address, - user.address, - testEnv - ); - - // First half - const amountToRepay = daiReserveDataBefore.totalVariableDebt.dividedBy(2).toString(); - - await mockSwapAdapter.setAmountToReturn(amountToRepay); - await expect( - pool - .connect(liquidator.signer) - .repayWithCollateral( - weth.address, - dai.address, - user.address, - amountToRepay, - mockSwapAdapter.address, - '0x' - ) - ).to.be.revertedWith('38'); - }); - it('User 5 liquidates User 2 DAI Variable loan using his WETH collateral, half the amount', async () => { - const {pool, weth, dai, users, mockSwapAdapter, oracle, helpersContract} = testEnv; - const user = users[1]; - const liquidator = users[4]; - - // Sets DAI Price higher to decrease health factor below 1 - const daiPrice = await oracle.getAssetPrice(dai.address); - - await oracle.setAssetPrice( - dai.address, - new BigNumber(daiPrice.toString()).multipliedBy(1.4).toFixed(0) - ); - - const userGlobalData = await pool.getUserAccountData(user.address); - - expect(userGlobalData.healthFactor.toString()).to.be.bignumber.lt(oneEther, INVALID_HF); - - const {userData: wethUserDataBefore} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const {reserveData: daiReserveDataBefore, userData: daiUserDataBefore} = await getContractsData( - dai.address, - user.address, - testEnv - ); - - // First half - const amountToRepay = daiReserveDataBefore.totalVariableDebt - .multipliedBy(0.6) - .toFixed(0) - .toString(); - - await mockSwapAdapter.setAmountToReturn(amountToRepay); - await waitForTx( - await pool - .connect(liquidator.signer) - .repayWithCollateral( - weth.address, - dai.address, - user.address, - amountToRepay, - mockSwapAdapter.address, - '0x' - ) - ); - const repayWithCollateralTimestamp = await timeLatest(); - - const {userData: wethUserDataAfter} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const {userData: daiUserDataAfter} = await getContractsData(dai.address, user.address, testEnv); - - const collateralPrice = await oracle.getAssetPrice(weth.address); - const principalPrice = await oracle.getAssetPrice(dai.address); - - const collateralDecimals = ( - await helpersContract.getReserveConfigurationData(weth.address) - ).decimals.toString(); - const principalDecimals = ( - await helpersContract.getReserveConfigurationData(dai.address) - ).decimals.toString(); - - const expectedCollateralLiquidated = new BigNumber(principalPrice.toString()) - .times(new BigNumber(amountToRepay.toString()).times(105)) - .times(new BigNumber(10).pow(collateralDecimals)) - .div( - new BigNumber(collateralPrice.toString()).times(new BigNumber(10).pow(principalDecimals)) - ) - .div(100) - .decimalPlaces(0, BigNumber.ROUND_DOWN); - - const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance( - daiReserveDataBefore, - daiUserDataBefore, - new BigNumber(repayWithCollateralTimestamp) - ).minus(daiUserDataBefore.currentVariableDebt); - - expect(daiUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual( - new BigNumber(daiUserDataBefore.currentVariableDebt) - .minus(amountToRepay.toString()) - .plus(expectedVariableDebtIncrease) - .toString() - ); - - expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal( - new BigNumber(wethUserDataBefore.currentATokenBalance).minus( - expectedCollateralLiquidated.toString() - ) - ); - expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.true; - - // Resets DAI price - await oracle.setAssetPrice(dai.address, daiPrice); - }); - - it('User 2 tries to repay remaining DAI Variable loan using his WETH collateral', async () => { - const {pool, weth, dai, users, mockSwapAdapter, oracle, helpersContract} = testEnv; - const user = users[1]; - - const {userData: wethUserDataBefore} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const {reserveData: daiReserveDataBefore, userData: daiUserDataBefore} = await getContractsData( - dai.address, - user.address, - testEnv - ); - - await increaseTime(1000); - // Repay the remaining DAI - const amountToRepay = daiReserveDataBefore.totalVariableDebt.toString(); - - await mockSwapAdapter.setAmountToReturn(amountToRepay); - const receipt = await waitForTx( - await pool - .connect(user.signer) - .repayWithCollateral( - weth.address, - dai.address, - user.address, - amountToRepay, - mockSwapAdapter.address, - '0x' - ) - ); - const repayWithCollateralTimestamp = (await BRE.ethers.provider.getBlock(receipt.blockNumber)) - .timestamp; - - const {userData: wethUserDataAfter} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const {userData: daiUserDataAfter} = await getContractsData(dai.address, user.address, testEnv); - - const collateralPrice = await oracle.getAssetPrice(weth.address); - const principalPrice = await oracle.getAssetPrice(dai.address); - - const collateralDecimals = ( - await helpersContract.getReserveConfigurationData(weth.address) - ).decimals.toString(); - const principalDecimals = ( - await helpersContract.getReserveConfigurationData(dai.address) - ).decimals.toString(); - - const expectedCollateralLiquidated = new BigNumber(principalPrice.toString()) - .times(new BigNumber(amountToRepay.toString()).times(105)) - .times(new BigNumber(10).pow(collateralDecimals)) - .div( - new BigNumber(collateralPrice.toString()).times(new BigNumber(10).pow(principalDecimals)) - ) - .div(100) - .decimalPlaces(0, BigNumber.ROUND_DOWN); - - const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance( - daiReserveDataBefore, - daiUserDataBefore, - new BigNumber(repayWithCollateralTimestamp) - ).minus(daiUserDataBefore.currentVariableDebt); - - expect(daiUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual( - new BigNumber(daiUserDataBefore.currentVariableDebt) - .minus(amountToRepay.toString()) - .plus(expectedVariableDebtIncrease) - .toString() - ); - - expect( - new BigNumber(wethUserDataBefore.currentATokenBalance).minus( - expectedCollateralLiquidated.toString() - ) - ).to.be.bignumber.equal(wethUserDataAfter.currentATokenBalance); - }); - - it('Liquidator tries to repay 4 user a bigger amount that what can be swapped of a particular collateral, repaying only the maximum allowed by that collateral', async () => { - const {pool, weth, dai, usdc, users, mockSwapAdapter, oracle, helpersContract} = testEnv; - const user = users[3]; - const liquidator = users[5]; - - const amountToDepositWeth = parseEther('0.1'); - const amountToDepositDAI = parseEther('500'); - const amountToBorrowVariable = parseUnits('80', '6'); - - await weth.connect(user.signer).mint(amountToDepositWeth); - await dai.connect(user.signer).mint(amountToDepositDAI); - await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - await dai.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - - await pool.connect(user.signer).deposit(weth.address, amountToDepositWeth, user.address, '0'); - await pool.connect(user.signer).deposit(dai.address, amountToDepositDAI, user.address, '0'); - - await pool - .connect(user.signer) - .borrow(usdc.address, amountToBorrowVariable, 2, 0, user.address); - - const amountToRepay = amountToBorrowVariable; - - const {userData: wethUserDataBefore} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const { - reserveData: usdcReserveDataBefore, - userData: usdcUserDataBefore, - } = await getContractsData(usdc.address, user.address, testEnv); - - // Set HF below 1 - const daiPrice = await oracle.getAssetPrice(dai.address); - await oracle.setAssetPrice( - dai.address, - new BigNumber(daiPrice.toString()).multipliedBy(0.1).toFixed(0) - ); - const userGlobalDataPrior = await pool.getUserAccountData(user.address); - expect(userGlobalDataPrior.healthFactor.toString()).to.be.bignumber.lt(oneEther, INVALID_HF); - - // Execute liquidation - await mockSwapAdapter.setAmountToReturn(amountToRepay); - await waitForTx( - await pool - .connect(liquidator.signer) - .repayWithCollateral( - weth.address, - usdc.address, - user.address, - amountToRepay, - mockSwapAdapter.address, - '0x' - ) - ); - const repayWithCollateralTimestamp = await timeLatest(); - - const {userData: wethUserDataAfter} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const {userData: usdcUserDataAfter} = await getContractsData( - usdc.address, - user.address, - testEnv - ); - - const collateralPrice = await oracle.getAssetPrice(weth.address); - const principalPrice = await oracle.getAssetPrice(usdc.address); - - const collateralConfig = await helpersContract.getReserveConfigurationData(weth.address); - - const collateralDecimals = collateralConfig.decimals.toString(); - const principalDecimals = ( - await helpersContract.getReserveConfigurationData(usdc.address) - ).decimals.toString(); - const collateralLiquidationBonus = collateralConfig.liquidationBonus.toString(); - - const expectedDebtCovered = new BigNumber(collateralPrice.toString()) - .times(new BigNumber(wethUserDataBefore.currentATokenBalance.toString())) - .times(new BigNumber(10).pow(principalDecimals)) - .div( - new BigNumber(principalPrice.toString()).times(new BigNumber(10).pow(collateralDecimals)) - ) - .div(new BigNumber(collateralLiquidationBonus).div(10000).toString()) - .decimalPlaces(0, BigNumber.ROUND_DOWN); - - const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance( - usdcReserveDataBefore, - usdcUserDataBefore, - new BigNumber(repayWithCollateralTimestamp) - ).minus(usdcUserDataBefore.currentVariableDebt); - - expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual( - new BigNumber(usdcUserDataBefore.currentVariableDebt) - .minus(expectedDebtCovered.toString()) - .plus(expectedVariableDebtIncrease), - 'INVALID_VARIABLE_DEBT_POSITION' - ); - - expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.false; - - expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal(0); - - // Resets DAI Price - await oracle.setAssetPrice(dai.address, daiPrice); - }); - - it('User 4 deposits WETH, LEND and DAI, then borrows USDC at Variable, then disables WETH as collateral', async () => { - const {pool, weth, dai, usdc, users} = testEnv; - const user = users[4]; - const amountWETHToDeposit = parseEther('10'); - const amountDAIToDeposit = parseEther('100'); - - const amountToBorrow = parseUnits('75', 6); - - await weth.connect(user.signer).mint(amountWETHToDeposit); - await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - await pool.connect(user.signer).deposit(weth.address, amountWETHToDeposit, user.address, '0'); - - await dai.connect(user.signer).mint(amountDAIToDeposit); - await dai.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - await pool.connect(user.signer).deposit(dai.address, amountDAIToDeposit, user.address, '0'); - - await pool.connect(user.signer).borrow(usdc.address, amountToBorrow, 2, 0, user.address); - }); - - it('Liquidator tries to liquidate User 5 USDC loan by swapping his WETH collateral, should revert due WETH collateral disabled', async () => { - const {pool, weth, dai, usdc, users, mockSwapAdapter, oracle} = testEnv; - const user = users[4]; - const liquidator = users[5]; - - const amountToRepay = parseUnits('65', 6); - - // User 5 Disable WETH as collateral - await pool.connect(user.signer).setUserUseReserveAsCollateral(weth.address, false); - - const {userData: wethUserDataBefore} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const { - reserveData: usdcReserveDataBefore, - userData: usdcUserDataBefore, - } = await getContractsData(usdc.address, user.address, testEnv); - - expect(wethUserDataBefore.usageAsCollateralEnabled).to.be.false; - - //drop the price to set the HF below 1 - const daiPrice = await oracle.getAssetPrice(dai.address); - - await oracle.setAssetPrice( - dai.address, - new BigNumber(daiPrice.toString()).multipliedBy(0.9).toFixed(0) - ); - - // Liquidator should NOT be able to liquidate himself with WETH, even if is disabled - await mockSwapAdapter.setAmountToReturn(amountToRepay); - await expect( - pool - .connect(liquidator.signer) - .repayWithCollateral( - weth.address, - usdc.address, - user.address, - amountToRepay, - mockSwapAdapter.address, - '0x' - ) - ).to.be.revertedWith(COLLATERAL_CANNOT_BE_LIQUIDATED); - - const repayWithCollateralTimestamp = await timeLatest(); - - const {userData: wethUserDataAfter} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const {userData: usdcUserDataAfter} = await getContractsData( - usdc.address, - user.address, - testEnv - ); - - const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance( - usdcReserveDataBefore, - usdcUserDataBefore, - new BigNumber(repayWithCollateralTimestamp) - ).minus(usdcUserDataBefore.currentVariableDebt); - - expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual( - new BigNumber(usdcUserDataBefore.currentVariableDebt) - .plus(expectedVariableDebtIncrease) - .toString(), - 'INVALID_DEBT_POSITION' - ); - - expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.false; - }); -}); diff --git a/test/pausable-functions.spec.ts b/test/pausable-functions.spec.ts index d5e321e3..8e7cc2a7 100644 --- a/test/pausable-functions.spec.ts +++ b/test/pausable-functions.spec.ts @@ -155,22 +155,6 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { await configurator.setPoolPause(false); }); - it('Swap liquidity', async () => { - const {pool, dai, weth, users, configurator} = testEnv; - - const user = users[1]; - // Pause the pool - await configurator.setPoolPause(true); - - // Try to execute liquidation - await expect( - pool.connect(user.signer).swapLiquidity(user.address, dai.address, weth.address, '1', '0x') - ).revertedWith(IS_PAUSED); - - // Unpause the pool - await configurator.setPoolPause(false); - }); - it('Repay', async () => { const {pool, dai, users, configurator} = testEnv; @@ -187,32 +171,6 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { await configurator.setPoolPause(false); }); - it('Repay with collateral', async () => { - const {pool, weth, dai, usdc, users, mockSwapAdapter, oracle, configurator} = testEnv; - const user = users[6]; - const liquidator = users[5]; - - // Pause the pool - await configurator.setPoolPause(true); - - // Try to execute liquidation - await expect( - pool - .connect(liquidator.signer) - .repayWithCollateral( - weth.address, - usdc.address, - user.address, - '1', - mockSwapAdapter.address, - '0x' - ) - ).revertedWith(IS_PAUSED); - - // Unpause the pool - await configurator.setPoolPause(false); - }); - it('Flash loan', async () => { const {dai, pool, weth, users, configurator} = testEnv; diff --git a/test/repay-with-collateral.spec.ts b/test/repay-with-collateral.spec.ts deleted file mode 100644 index 282cddb3..00000000 --- a/test/repay-with-collateral.spec.ts +++ /dev/null @@ -1,682 +0,0 @@ -import {TestEnv, makeSuite} from './helpers/make-suite'; -import {APPROVAL_AMOUNT_LENDING_POOL} from '../helpers/constants'; -import {ethers} from 'ethers'; -import BigNumber from 'bignumber.js'; -import { - calcExpectedVariableDebtTokenBalance, - calcExpectedStableDebtTokenBalance, -} from './helpers/utils/calculations'; -import {getContractsData} from './helpers/actions'; -import {timeLatest, waitForTx} from '../helpers/misc-utils'; -import {ProtocolErrors, tEthereumAddress} from '../helpers/types'; - -const {expect} = require('chai'); -const {parseUnits, parseEther} = ethers.utils; - -export const expectRepayWithCollateralEvent = ( - events: ethers.Event[], - pool: tEthereumAddress, - collateral: tEthereumAddress, - borrowing: tEthereumAddress, - user: tEthereumAddress -) => { - if (!events || events.length < 16) { - expect(false, 'INVALID_EVENTS_LENGTH_ON_REPAY_COLLATERAL'); - } - - const repayWithCollateralEvent = events[15]; - - expect(repayWithCollateralEvent.address).to.be.equal(pool); - expect(`0x${repayWithCollateralEvent.topics[1].slice(26)}`.toLowerCase()).to.be.equal( - collateral.toLowerCase() - ); - expect(`0x${repayWithCollateralEvent.topics[2].slice(26)}`).to.be.equal(borrowing.toLowerCase()); - expect(`0x${repayWithCollateralEvent.topics[3].slice(26)}`.toLowerCase()).to.be.equal( - user.toLowerCase() - ); -}; - -makeSuite('LendingPool. repayWithCollateral()', (testEnv: TestEnv) => { - const {IS_PAUSED} = ProtocolErrors; - it("It's not possible to repayWithCollateral() on a non-active collateral or a non active principal", async () => { - const {configurator, weth, pool, users, dai, mockSwapAdapter} = testEnv; - const user = users[1]; - await configurator.deactivateReserve(weth.address); - - await expect( - pool - .connect(user.signer) - .repayWithCollateral( - weth.address, - dai.address, - user.address, - parseEther('100'), - mockSwapAdapter.address, - '0x' - ) - ).to.be.revertedWith('2'); - - await configurator.activateReserve(weth.address); - - await configurator.deactivateReserve(dai.address); - - await expect( - pool - .connect(user.signer) - .repayWithCollateral( - weth.address, - dai.address, - user.address, - parseEther('100'), - mockSwapAdapter.address, - '0x' - ) - ).to.be.revertedWith('2'); - - await configurator.activateReserve(dai.address); - }); - - it('User 1 provides some liquidity for others to borrow', async () => { - const {pool, weth, dai, usdc, deployer} = testEnv; - - await weth.mint(parseEther('200')); - await weth.approve(pool.address, parseEther('200')); - await pool.deposit(weth.address, parseEther('200'), deployer.address, 0); - await dai.mint(parseEther('20000')); - await dai.approve(pool.address, parseEther('20000')); - await pool.deposit(dai.address, parseEther('20000'), deployer.address, 0); - await usdc.mint(parseEther('20000')); - await usdc.approve(pool.address, parseEther('20000')); - await pool.deposit(usdc.address, parseEther('20000'), deployer.address, 0); - }); - - it('User 2 deposit WETH and borrows DAI at Variable', async () => { - const {pool, weth, dai, users} = testEnv; - const user = users[1]; - const amountToDeposit = ethers.utils.parseEther('1'); - const amountToBorrow = ethers.utils.parseEther('20'); - - await weth.connect(user.signer).mint(amountToDeposit); - - await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - - await pool.connect(user.signer).deposit(weth.address, amountToDeposit, user.address, '0'); - - await pool.connect(user.signer).borrow(dai.address, amountToBorrow, 2, 0, user.address); - }); - - it('It is not possible to do reentrancy on repayWithCollateral()', async () => { - const {pool, weth, dai, users, mockSwapAdapter, oracle} = testEnv; - const user = users[1]; - - const amountToRepay = parseEther('10'); - - await waitForTx(await mockSwapAdapter.setTryReentrancy(true)); - - await mockSwapAdapter.setAmountToReturn(amountToRepay); - await expect( - pool - .connect(user.signer) - .repayWithCollateral( - weth.address, - dai.address, - user.address, - amountToRepay, - mockSwapAdapter.address, - '0x' - ) - ).to.be.revertedWith('53'); - }); - - it('User 2 tries to repay his DAI Variable loan using his WETH collateral. First half the amount, after that, the rest', async () => { - const {pool, weth, dai, users, mockSwapAdapter, oracle, helpersContract} = testEnv; - const user = users[1]; - - const amountToRepay = parseEther('10'); - - await waitForTx(await mockSwapAdapter.setTryReentrancy(false)); - - const {userData: wethUserDataBefore} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const {reserveData: daiReserveDataBefore, userData: daiUserDataBefore} = await getContractsData( - dai.address, - user.address, - testEnv - ); - - await mockSwapAdapter.setAmountToReturn(amountToRepay); - await waitForTx( - await pool - .connect(user.signer) - .repayWithCollateral( - weth.address, - dai.address, - user.address, - amountToRepay, - mockSwapAdapter.address, - '0x' - ) - ); - const repayWithCollateralTimestamp = await timeLatest(); - - const {userData: wethUserDataAfter} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const {userData: daiUserDataAfter} = await getContractsData(dai.address, user.address, testEnv); - - const collateralPrice = await oracle.getAssetPrice(weth.address); - const principalPrice = await oracle.getAssetPrice(dai.address); - - const collateralDecimals = ( - await helpersContract.getReserveConfigurationData(weth.address) - ).decimals.toString(); - const principalDecimals = ( - await helpersContract.getReserveConfigurationData(dai.address) - ).decimals.toString(); - - const expectedCollateralLiquidated = new BigNumber(principalPrice.toString()) - .times(new BigNumber(amountToRepay.toString()).times(105)) - .times(new BigNumber(10).pow(collateralDecimals)) - .div( - new BigNumber(collateralPrice.toString()).times(new BigNumber(10).pow(principalDecimals)) - ) - .div(100) - .decimalPlaces(0, BigNumber.ROUND_DOWN); - - const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance( - daiReserveDataBefore, - daiUserDataBefore, - new BigNumber(repayWithCollateralTimestamp) - ).minus(daiUserDataBefore.currentVariableDebt); - - expect(daiUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual( - new BigNumber(daiUserDataBefore.currentVariableDebt) - .minus(amountToRepay.toString()) - .plus(expectedVariableDebtIncrease) - .toString() - ); - - expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal( - new BigNumber(wethUserDataBefore.currentATokenBalance).minus( - expectedCollateralLiquidated.toString() - ) - ); - - expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.true; - }); - - it('User 3 deposits WETH and borrows USDC at Variable', async () => { - const {pool, weth, usdc, users} = testEnv; - const user = users[2]; - const amountToDeposit = parseEther('10'); - const amountToBorrow = parseUnits('40', 6); - - await weth.connect(user.signer).mint(amountToDeposit); - - await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - - await pool.connect(user.signer).deposit(weth.address, amountToDeposit, user.address, '0'); - - await pool.connect(user.signer).borrow(usdc.address, amountToBorrow, 2, 0, user.address); - }); - - it('User 3 repays completely his USDC loan by swapping his WETH collateral', async () => { - const {pool, weth, usdc, users, mockSwapAdapter, oracle, helpersContract} = testEnv; - const user = users[2]; - - const amountToRepay = parseUnits('10', 6); - - const {userData: wethUserDataBefore} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const { - reserveData: usdcReserveDataBefore, - userData: usdcUserDataBefore, - } = await getContractsData(usdc.address, user.address, testEnv); - - await mockSwapAdapter.setAmountToReturn(amountToRepay); - await waitForTx( - await pool - .connect(user.signer) - .repayWithCollateral( - weth.address, - usdc.address, - user.address, - amountToRepay, - mockSwapAdapter.address, - '0x' - ) - ); - const repayWithCollateralTimestamp = await timeLatest(); - - const {userData: wethUserDataAfter} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const {userData: usdcUserDataAfter} = await getContractsData( - usdc.address, - user.address, - testEnv - ); - - const collateralPrice = await oracle.getAssetPrice(weth.address); - const principalPrice = await oracle.getAssetPrice(usdc.address); - - const collateralDecimals = ( - await helpersContract.getReserveConfigurationData(weth.address) - ).decimals.toString(); - const principalDecimals = ( - await helpersContract.getReserveConfigurationData(usdc.address) - ).decimals.toString(); - - const expectedCollateralLiquidated = new BigNumber(principalPrice.toString()) - .times(new BigNumber(amountToRepay.toString()).times(105)) - .times(new BigNumber(10).pow(collateralDecimals)) - .div( - new BigNumber(collateralPrice.toString()).times(new BigNumber(10).pow(principalDecimals)) - ) - .div(100) - .decimalPlaces(0, BigNumber.ROUND_DOWN); - - const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance( - usdcReserveDataBefore, - usdcUserDataBefore, - new BigNumber(repayWithCollateralTimestamp) - ).minus(usdcUserDataBefore.currentVariableDebt); - - expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual( - new BigNumber(usdcUserDataBefore.currentVariableDebt) - .minus(amountToRepay.toString()) - .plus(expectedVariableDebtIncrease) - .toString(), - 'INVALID_DEBT_POSITION' - ); - - expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal( - new BigNumber(wethUserDataBefore.currentATokenBalance).minus( - expectedCollateralLiquidated.toString() - ), - 'INVALID_COLLATERAL_POSITION' - ); - - expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.true; - }); - - it('Revert expected. User 3 tries to repay with his collateral a currency he havent borrow', async () => { - const {pool, weth, dai, users, mockSwapAdapter} = testEnv; - const user = users[2]; - - const amountToRepay = parseUnits('10', 6); - - await expect( - pool - .connect(user.signer) - .repayWithCollateral( - weth.address, - dai.address, - user.address, - amountToRepay, - mockSwapAdapter.address, - '0x' - ) - ).to.be.revertedWith('40'); - }); - - it('User 3 tries to repay with his collateral all his variable debt and part of the stable', async () => { - const {pool, weth, usdc, users, mockSwapAdapter, oracle, helpersContract} = testEnv; - const user = users[2]; - - const amountToDeposit = parseEther('20'); - const amountToBorrowStable = parseUnits('40', 6); - const amountToBorrowVariable = parseUnits('40', 6); - - await weth.connect(user.signer).mint(amountToDeposit); - - await pool.connect(user.signer).deposit(weth.address, amountToDeposit, user.address, '0'); - - await pool - .connect(user.signer) - .borrow(usdc.address, amountToBorrowVariable, 2, 0, user.address); - - await pool.connect(user.signer).borrow(usdc.address, amountToBorrowStable, 1, 0, user.address); - - const amountToRepay = parseUnits('80', 6); - - const {userData: wethUserDataBefore} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const { - reserveData: usdcReserveDataBefore, - userData: usdcUserDataBefore, - } = await getContractsData(usdc.address, user.address, testEnv); - - await mockSwapAdapter.setAmountToReturn(amountToRepay); - const txReceipt = await waitForTx( - await pool - .connect(user.signer) - .repayWithCollateral( - weth.address, - usdc.address, - user.address, - amountToRepay, - mockSwapAdapter.address, - '0x' - ) - ); - const repayWithCollateralTimestamp = await timeLatest(); - - const {userData: wethUserDataAfter} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const {userData: usdcUserDataAfter} = await getContractsData( - usdc.address, - user.address, - testEnv - ); - - const collateralPrice = await oracle.getAssetPrice(weth.address); - const principalPrice = await oracle.getAssetPrice(usdc.address); - - const collateralDecimals = ( - await helpersContract.getReserveConfigurationData(weth.address) - ).decimals.toString(); - const principalDecimals = ( - await helpersContract.getReserveConfigurationData(usdc.address) - ).decimals.toString(); - - const expectedCollateralLiquidated = new BigNumber(principalPrice.toString()) - .times(new BigNumber(amountToRepay.toString()).times(105)) - .times(new BigNumber(10).pow(collateralDecimals)) - .div( - new BigNumber(collateralPrice.toString()).times(new BigNumber(10).pow(principalDecimals)) - ) - .div(100) - .decimalPlaces(0, BigNumber.ROUND_DOWN); - - const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance( - usdcReserveDataBefore, - usdcUserDataBefore, - new BigNumber(repayWithCollateralTimestamp) - ).minus(usdcUserDataBefore.currentVariableDebt); - - const expectedStableDebtIncrease = calcExpectedStableDebtTokenBalance( - usdcUserDataBefore.principalStableDebt, - usdcUserDataBefore.stableBorrowRate, - usdcUserDataBefore.stableRateLastUpdated, - new BigNumber(repayWithCollateralTimestamp) - ).minus(usdcUserDataBefore.currentStableDebt); - - expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.equal( - new BigNumber(usdcUserDataBefore.currentVariableDebt) - .minus(amountToRepay.toString()) - .plus(expectedVariableDebtIncrease) - .gte(0) - ? new BigNumber(usdcUserDataBefore.currentVariableDebt) - .minus(amountToRepay.toString()) - .plus(expectedVariableDebtIncrease) - .toString() - : '0', - 'INVALID_VARIABLE_DEBT_POSITION' - ); - - const stableDebtRepaid = new BigNumber(usdcUserDataBefore.currentVariableDebt) - .minus(amountToRepay.toString()) - .plus(expectedVariableDebtIncrease) - .abs(); - - expect(usdcUserDataAfter.currentStableDebt).to.be.bignumber.equal( - new BigNumber(usdcUserDataBefore.currentStableDebt) - .minus(stableDebtRepaid) - .plus(expectedStableDebtIncrease) - .gte(0) - ? new BigNumber(usdcUserDataBefore.currentStableDebt) - .minus(stableDebtRepaid) - .plus(expectedStableDebtIncrease) - .toString() - : '0', - 'INVALID_STABLE_DEBT_POSITION' - ); - - expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal( - new BigNumber(wethUserDataBefore.currentATokenBalance).minus( - expectedCollateralLiquidated.toString() - ), - 'INVALID_COLLATERAL_POSITION' - ); - - const eventsEmitted = txReceipt.events || []; - - expectRepayWithCollateralEvent( - eventsEmitted, - pool.address, - weth.address, - usdc.address, - user.address - ); - - expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.true; - }); - - it('User 4 tries to repay a bigger amount that what can be swapped of a particular collateral, repaying only the maximum allowed by that collateral', async () => { - const {pool, weth, dai, users, mockSwapAdapter, oracle, helpersContract} = testEnv; - const user = users[3]; - - const amountToDepositWeth = parseEther('0.1'); - const amountToDepositDAI = parseEther('500'); - const amountToBorrowVariable = parseEther('80'); - - await weth.connect(user.signer).mint(amountToDepositWeth); - await dai.connect(user.signer).mint(amountToDepositDAI); - await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - await dai.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - - await pool.connect(user.signer).deposit(weth.address, amountToDepositWeth, user.address, '0'); - await pool.connect(user.signer).deposit(dai.address, amountToDepositDAI, user.address, '0'); - - await pool.connect(user.signer).borrow(dai.address, amountToBorrowVariable, 2, 0, user.address); - - const amountToRepay = parseEther('80'); - - const {userData: wethUserDataBefore} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const {reserveData: daiReserveDataBefore, userData: daiUserDataBefore} = await getContractsData( - dai.address, - user.address, - testEnv - ); - - await mockSwapAdapter.setAmountToReturn(amountToRepay); - await waitForTx( - await pool - .connect(user.signer) - .repayWithCollateral( - weth.address, - dai.address, - user.address, - amountToRepay, - mockSwapAdapter.address, - '0x' - ) - ); - const repayWithCollateralTimestamp = await timeLatest(); - - const {userData: wethUserDataAfter} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const {userData: daiUserDataAfter} = await getContractsData(dai.address, user.address, testEnv); - - const collateralPrice = await oracle.getAssetPrice(weth.address); - const principalPrice = await oracle.getAssetPrice(dai.address); - - const collateralConfig = await helpersContract.getReserveConfigurationData(weth.address); - - const collateralDecimals = collateralConfig.decimals.toString(); - const collateralLiquidationBonus = collateralConfig.liquidationBonus.toString(); - - const principalDecimals = ( - await helpersContract.getReserveConfigurationData(dai.address) - ).decimals.toString(); - - const expectedDebtCovered = new BigNumber(collateralPrice.toString()) - .times(new BigNumber(wethUserDataBefore.currentATokenBalance.toString())) - .times(new BigNumber(10).pow(principalDecimals)) - .div( - new BigNumber(principalPrice.toString()).times(new BigNumber(10).pow(collateralDecimals)) - ) - .div(new BigNumber(collateralLiquidationBonus).div(10000).toString()) - .decimalPlaces(0, BigNumber.ROUND_DOWN); - - const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance( - daiReserveDataBefore, - daiUserDataBefore, - new BigNumber(repayWithCollateralTimestamp) - ).minus(daiUserDataBefore.currentVariableDebt); - - expect(daiUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual( - new BigNumber(daiUserDataBefore.currentVariableDebt) - .minus(expectedDebtCovered.toString()) - .plus(expectedVariableDebtIncrease), - 'INVALID_VARIABLE_DEBT_POSITION' - ); - - expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.almostEqual(0); - - expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.false; - }); - - it('User 5 deposits WETH and DAI, then borrows USDC at Variable, then disables WETH as collateral', async () => { - const {pool, weth, dai, usdc, users} = testEnv; - const user = users[4]; - const amountWETHToDeposit = parseEther('10'); - const amountDAIToDeposit = parseEther('120'); - const amountToBorrow = parseUnits('65', 6); - - await weth.connect(user.signer).mint(amountWETHToDeposit); - await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - await pool.connect(user.signer).deposit(weth.address, amountWETHToDeposit, user.address, '0'); - - await dai.connect(user.signer).mint(amountDAIToDeposit); - await dai.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - await pool.connect(user.signer).deposit(dai.address, amountDAIToDeposit, user.address, '0'); - - await pool.connect(user.signer).borrow(usdc.address, amountToBorrow, 2, 0, user.address); - }); - - it('User 5 tries to repay his USDC loan by swapping his WETH collateral, should not revert even with WETH collateral disabled', async () => { - const {pool, weth, usdc, users, mockSwapAdapter, oracle, helpersContract} = testEnv; - const user = users[4]; - - const amountToRepay = parseUnits('65', 6); - - // Disable WETH as collateral - await pool.connect(user.signer).setUserUseReserveAsCollateral(weth.address, false); - - const {userData: wethUserDataBefore} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const { - reserveData: usdcReserveDataBefore, - userData: usdcUserDataBefore, - } = await getContractsData(usdc.address, user.address, testEnv); - - expect(wethUserDataBefore.usageAsCollateralEnabled).to.be.false; - - // User 5 should be able to liquidate himself with WETH, even if is disabled - await mockSwapAdapter.setAmountToReturn(amountToRepay); - expect( - await pool - .connect(user.signer) - .repayWithCollateral( - weth.address, - usdc.address, - user.address, - amountToRepay, - mockSwapAdapter.address, - '0x' - ) - ); - const repayWithCollateralTimestamp = await timeLatest(); - - const {userData: wethUserDataAfter} = await getContractsData( - weth.address, - user.address, - testEnv - ); - - const {userData: usdcUserDataAfter} = await getContractsData( - usdc.address, - user.address, - testEnv - ); - - const collateralPrice = await oracle.getAssetPrice(weth.address); - const principalPrice = await oracle.getAssetPrice(usdc.address); - - const collateralDecimals = ( - await helpersContract.getReserveConfigurationData(weth.address) - ).decimals.toString(); - const principalDecimals = ( - await helpersContract.getReserveConfigurationData(usdc.address) - ).decimals.toString(); - - const expectedCollateralLiquidated = new BigNumber(principalPrice.toString()) - .times(new BigNumber(amountToRepay.toString()).times(105)) - .times(new BigNumber(10).pow(collateralDecimals)) - .div( - new BigNumber(collateralPrice.toString()).times(new BigNumber(10).pow(principalDecimals)) - ) - .div(100) - .decimalPlaces(0, BigNumber.ROUND_DOWN); - - const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance( - usdcReserveDataBefore, - usdcUserDataBefore, - new BigNumber(repayWithCollateralTimestamp) - ).minus(usdcUserDataBefore.currentVariableDebt); - - expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual( - new BigNumber(usdcUserDataBefore.currentVariableDebt) - .minus(amountToRepay.toString()) - .plus(expectedVariableDebtIncrease) - .toString(), - 'INVALID_DEBT_POSITION' - ); - - expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal( - new BigNumber(wethUserDataBefore.currentATokenBalance).minus( - expectedCollateralLiquidated.toString() - ), - 'INVALID_COLLATERAL_POSITION' - ); - - expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.false; - }); -});