diff --git a/.solcover.js b/.solcover.js
index b63d9c64..9235302a 100644
--- a/.solcover.js
+++ b/.solcover.js
@@ -2,7 +2,7 @@ const accounts = require(`./test-wallets.js`).accounts;
 
 module.exports = {
   client: require('ganache-cli'),
-  skipFiles: [],
+  skipFiles: ['./mocks', './interfaces'],
   mocha: {
     enableTimeouts: false,
   },
diff --git a/buidler.config.ts b/buidler.config.ts
index d21f5293..be2d98f4 100644
--- a/buidler.config.ts
+++ b/buidler.config.ts
@@ -57,6 +57,9 @@ const config: any = {
     timeout: 0,
   },
   networks: {
+    coverage: {
+      url: 'http://localhost:8555',
+    },
     kovan: getCommonNetworkConfig(eEthereumNetwork.kovan, 42),
     ropsten: getCommonNetworkConfig(eEthereumNetwork.ropsten, 3),
     main: getCommonNetworkConfig(eEthereumNetwork.main, 1),
diff --git a/contracts/flashloan/base/FlashLoanReceiverBase.sol b/contracts/flashloan/base/FlashLoanReceiverBase.sol
index f96609d2..a648508c 100644
--- a/contracts/flashloan/base/FlashLoanReceiverBase.sol
+++ b/contracts/flashloan/base/FlashLoanReceiverBase.sol
@@ -19,5 +19,4 @@ abstract contract FlashLoanReceiverBase is IFlashLoanReceiver {
   }
 
   receive() external payable {}
-
 }
diff --git a/contracts/interfaces/ILendingPool.sol b/contracts/interfaces/ILendingPool.sol
index a7a5e1ca..85290836 100644
--- a/contracts/interfaces/ILendingPool.sol
+++ b/contracts/interfaces/ILendingPool.sol
@@ -218,6 +218,27 @@ 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
diff --git a/contracts/interfaces/ISwapAdapter.sol b/contracts/interfaces/ISwapAdapter.sol
new file mode 100644
index 00000000..c51ee0fd
--- /dev/null
+++ b/contracts/interfaces/ISwapAdapter.sol
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: agpl-3.0
+pragma solidity ^0.6.8;
+
+interface ISwapAdapter {
+
+    /** 
+     * @dev Swaps an `amountToSwap` of an asset to another, approving a `fundsDestination` to pull the funds
+     * @param assetToSwapFrom Origin asset
+     * @param assetToSwapTo Destination asset
+     * @param amountToSwap How much `assetToSwapFrom` needs to be swapped
+     * @param fundsDestination Address that will be pulling the swapped funds
+     * @param params Additional variadic field to include extra params
+     */
+    function executeOperation(
+        address assetToSwapFrom,
+        address assetToSwapTo,
+        uint256 amountToSwap,
+        address fundsDestination,
+        bytes calldata params
+    ) external;
+}
\ No newline at end of file
diff --git a/contracts/lendingpool/LendingPool.sol b/contracts/lendingpool/LendingPool.sol
index 9e4e6707..092e242f 100644
--- a/contracts/lendingpool/LendingPool.sol
+++ b/contracts/lendingpool/LendingPool.sol
@@ -51,6 +51,8 @@ contract LendingPool is VersionedInitializable, ILendingPool {
 
   address[] internal _reservesList;
 
+  bool internal _flashLiquidationLocked;
+
   /**
    * @dev only lending pools configurator can use functions affected by this modifier
    **/
@@ -198,6 +200,16 @@ contract LendingPool is VersionedInitializable, ILendingPool {
     uint256 rateMode,
     address onBehalfOf
   ) external override {
+    _executeRepay(asset, msg.sender, amount, rateMode, onBehalfOf);
+  }
+
+  function _executeRepay(
+    address asset,
+    address user,
+    uint256 amount,
+    uint256 rateMode,
+    address onBehalfOf
+  ) internal {
     ReserveLogic.ReserveData storage reserve = _reserves[asset];
 
     (uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(onBehalfOf, reserve);
@@ -238,9 +250,9 @@ contract LendingPool is VersionedInitializable, ILendingPool {
       _usersConfig[onBehalfOf].setBorrowing(reserve.index, false);
     }
 
-    IERC20(asset).safeTransferFrom(msg.sender, aToken, paybackAmount);
+    IERC20(asset).safeTransferFrom(user, aToken, paybackAmount);
 
-    emit Repay(asset, onBehalfOf, msg.sender, paybackAmount);
+    emit Repay(asset, onBehalfOf, user, paybackAmount);
   }
 
   /**
@@ -410,7 +422,55 @@ contract LendingPool is VersionedInitializable, ILendingPool {
   }
 
   /**
-   * @dev allows smart contracts to access the liquidity of the pool within one transaction,
+   * @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 {
+    require(!_flashLiquidationLocked, Errors.REENTRANCY_NOT_ALLOWED);
+    _flashLiquidationLocked = true;
+
+    address liquidationManager = _addressesProvider.getLendingPoolLiquidationManager();
+
+    //solium-disable-next-line
+    (bool success, bytes memory result) = liquidationManager.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;
+  }
+
+  /**
+   * @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
    * that must be kept into consideration. For further details please visit https://developers.aave.com
    * @param receiverAddress The address of the contract receiving the funds. The receiver should implement the IFlashLoanReceiver interface.
@@ -450,15 +510,13 @@ contract LendingPool is VersionedInitializable, ILendingPool {
     vars.amountPlusPremium = amount.add(vars.premium);
 
     if (debtMode == ReserveLogic.InterestRateMode.NONE) {
-      
       IERC20(asset).transferFrom(receiverAddress, vars.aTokenAddress, vars.amountPlusPremium);
-      
+
       reserve.updateCumulativeIndexesAndTimestamp();
       reserve.cumulateToLiquidityIndex(IERC20(vars.aTokenAddress).totalSupply(), vars.premium);
       reserve.updateInterestRates(asset, vars.aTokenAddress, vars.premium, 0);
-      
-      emit FlashLoan(receiverAddress, asset, amount, vars.premium, referralCode);
 
+      emit FlashLoan(receiverAddress, asset, amount, vars.premium, referralCode);
     } else {
       // If the transfer didn't succeed, the receiver either didn't return the funds, or didn't approve the transfer.
       _executeBorrow(
@@ -728,13 +786,11 @@ contract LendingPool is VersionedInitializable, ILendingPool {
       oracle
     );
 
-
     uint256 reserveIndex = reserve.index;
     if (!userConfig.isBorrowing(reserveIndex)) {
       userConfig.setBorrowing(reserveIndex, true);
     }
 
-
     reserve.updateCumulativeIndexesAndTimestamp();
 
     //caching the current stable borrow rate
@@ -754,13 +810,17 @@ contract LendingPool is VersionedInitializable, ILendingPool {
       IVariableDebtToken(reserve.variableDebtTokenAddress).mint(vars.user, vars.amount);
     }
 
-    reserve.updateInterestRates(vars.asset, vars.aTokenAddress, 0, vars.releaseUnderlying ?  vars.amount : 0);
-  
-    if(vars.releaseUnderlying){
-        IAToken(vars.aTokenAddress).transferUnderlyingTo(msg.sender, vars.amount);
+    reserve.updateInterestRates(
+      vars.asset,
+      vars.aTokenAddress,
+      0,
+      vars.releaseUnderlying ? vars.amount : 0
+    );
+
+    if (vars.releaseUnderlying) {
+      IAToken(vars.aTokenAddress).transferUnderlyingTo(msg.sender, vars.amount);
     }
-  
-  
+
     emit Borrow(
       vars.asset,
       msg.sender,
diff --git a/contracts/lendingpool/LendingPoolLiquidationManager.sol b/contracts/lendingpool/LendingPoolLiquidationManager.sol
index 12ecf777..6c7b340b 100644
--- a/contracts/lendingpool/LendingPoolLiquidationManager.sol
+++ b/contracts/lendingpool/LendingPoolLiquidationManager.sol
@@ -19,6 +19,7 @@ import {Helpers} from '../libraries/helpers/Helpers.sol';
 import {WadRayMath} from '../libraries/math/WadRayMath.sol';
 import {PercentageMath} from '../libraries/math/PercentageMath.sol';
 import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/SafeERC20.sol';
+import {ISwapAdapter} from '../interfaces/ISwapAdapter.sol';
 import {Errors} from '../libraries/helpers/Errors.sol';
 
 /**
@@ -35,6 +36,9 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
   using ReserveConfiguration for ReserveConfiguration.Map;
   using UserConfiguration for UserConfiguration.Map;
 
+  // IMPORTANT The storage layout of the LendingPool is reproduced here because this contract
+  // is gonna be used through DELEGATECALL
+
   LendingPoolAddressesProvider internal addressesProvider;
 
   mapping(address => ReserveLogic.ReserveData) internal reserves;
@@ -42,6 +46,8 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
 
   address[] internal reservesList;
 
+  bool internal _flashLiquidationLocked;
+
   uint256 internal constant LIQUIDATION_CLOSE_FACTOR_PERCENT = 5000;
 
   /**
@@ -64,6 +70,24 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
     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
+  );
+
   enum LiquidationErrors {
     NO_ERROR,
     NO_COLLATERAL_AVAILABLE,
@@ -270,6 +294,157 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
     return (uint256(LiquidationErrors.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 debtReserve = reserves[principal];
+    ReserveLogic.ReserveData storage collateralReserve = reserves[collateral];
+
+    UserConfiguration.Map storage userConfig = usersConfig[user];
+
+    LiquidationCallLocalVars memory vars;
+
+    (, , , , vars.healthFactor) = GenericLogic.calculateUserAccountData(
+      user,
+      reserves,
+      usersConfig[user],
+      reservesList,
+      addressesProvider.getPriceOracle()
+    );
+
+    if (
+      msg.sender != user && vars.healthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD
+    ) {
+      return (
+        uint256(LiquidationErrors.HEALTH_FACTOR_ABOVE_THRESHOLD),
+        Errors.HEALTH_FACTOR_NOT_BELOW_THRESHOLD
+      );
+    }
+
+    if (msg.sender != user) {
+      vars.isCollateralEnabled =
+        collateralReserve.configuration.getLiquidationThreshold() > 0 &&
+        userConfig.isUsingAsCollateral(collateralReserve.index);
+
+      //if collateral isn't enabled as collateral by user, it cannot be liquidated
+      if (!vars.isCollateralEnabled) {
+        return (
+          uint256(LiquidationErrors.COLLATERAL_CANNOT_BE_LIQUIDATED),
+          Errors.COLLATERAL_CANNOT_BE_LIQUIDATED
+        );
+      }
+    }
+
+    (vars.userStableDebt, vars.userVariableDebt) = Helpers.getUserCurrentDebt(user, debtReserve);
+
+    if (vars.userStableDebt == 0 && vars.userVariableDebt == 0) {
+      return (
+        uint256(LiquidationErrors.CURRRENCY_NOT_BORROWED),
+        Errors.SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER
+      );
+    }
+
+    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;
+    }
+
+    vars.collateralAtoken.burn(user, receiver, vars.maxCollateralToLiquidate);
+
+    if (vars.userCollateralBalance == vars.maxCollateralToLiquidate) {
+      usersConfig[user].setUsingAsCollateral(collateralReserve.index, false);
+    }
+
+    address 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.updateCumulativeIndexesAndTimestamp();
+    debtReserve.updateInterestRates(principal, principalAToken, vars.actualAmountToLiquidate, 0);
+    IERC20(principal).transferFrom(receiver, principalAToken, vars.actualAmountToLiquidate);
+
+    if (vars.userVariableDebt >= vars.actualAmountToLiquidate) {
+      IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn(
+        user,
+        vars.actualAmountToLiquidate
+      );
+    } else {
+      IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn(user, vars.userVariableDebt);
+      IStableDebtToken(debtReserve.stableDebtTokenAddress).burn(
+        user,
+        vars.actualAmountToLiquidate.sub(vars.userVariableDebt)
+      );
+    }
+
+    //updating collateral reserve
+    collateralReserve.updateCumulativeIndexesAndTimestamp();
+    collateralReserve.updateInterestRates(
+      collateral,
+      address(vars.collateralAtoken),
+      0,
+      vars.maxCollateralToLiquidate
+    );
+
+    emit RepaidWithCollateral(
+      collateral,
+      principal,
+      user,
+      msg.sender,
+      vars.actualAmountToLiquidate,
+      vars.maxCollateralToLiquidate
+    );
+
+    return (uint256(LiquidationErrors.NO_ERROR), Errors.NO_ERRORS);
+  }
+
   struct AvailableCollateralToLiquidateLocalVars {
     uint256 userCompoundedBorrowBalance;
     uint256 liquidationBonus;
diff --git a/contracts/libraries/helpers/Errors.sol b/contracts/libraries/helpers/Errors.sol
index 974aa5e1..b7598eec 100644
--- a/contracts/libraries/helpers/Errors.sol
+++ b/contracts/libraries/helpers/Errors.sol
@@ -38,6 +38,8 @@ library Errors {
   string public constant INCONSISTENT_PROTOCOL_ACTUAL_BALANCE = '26'; // 'The actual balance of the protocol is inconsistent'
   string public constant CALLER_NOT_LENDING_POOL_CONFIGURATOR = '27'; // 'The actual balance of the protocol is inconsistent'
   string public constant INVALID_FLASHLOAN_MODE = '43'; //Invalid flashloan mode selected
+  string public constant REENTRANCY_NOT_ALLOWED = '52';
+  string public constant FAILED_REPAY_WITH_COLLATERAL = '53';
 
   // require error messages - aToken
   string public constant CALLER_MUST_BE_LENDING_POOL = '28'; // 'The caller of this function must be a lending pool'
@@ -70,7 +72,7 @@ library Errors {
   string public constant NO_ERRORS = '42'; // 'No errors'
 
   //require error messages - Math libraries
-  string public constant MULTIPLICATION_OVERFLOW = '44'; 
-  string public constant ADDITION_OVERFLOW = '45'; 
+  string public constant MULTIPLICATION_OVERFLOW = '44';
+  string public constant ADDITION_OVERFLOW = '45';
   string public constant DIVISION_BY_ZERO = '46';
 }
diff --git a/contracts/libraries/logic/GenericLogic.sol b/contracts/libraries/logic/GenericLogic.sol
index ead09d38..efe053a0 100644
--- a/contracts/libraries/logic/GenericLogic.sol
+++ b/contracts/libraries/logic/GenericLogic.sol
@@ -24,7 +24,8 @@ library GenericLogic {
   using ReserveConfiguration for ReserveConfiguration.Map;
   using UserConfiguration for UserConfiguration.Map;
 
-  uint256 public constant HEALTH_FACTOR_LIQUIDATION_THRESHOLD = 1e18;
+  uint256 public constant HEALTH_FACTOR_LIQUIDATION_THRESHOLD = 1 ether;
+  uint256 public constant HEALTH_FACTOR_CRITICAL_THRESHOLD = 0.98 ether;
 
   struct balanceDecreaseAllowedLocalVars {
     uint256 decimals;
diff --git a/contracts/libraries/logic/ReserveLogic.sol b/contracts/libraries/logic/ReserveLogic.sol
index 607c8c63..06d08499 100644
--- a/contracts/libraries/logic/ReserveLogic.sol
+++ b/contracts/libraries/logic/ReserveLogic.sol
@@ -68,7 +68,6 @@ library ReserveLogic {
     uint40 lastUpdateTimestamp;
     //the index of the reserve in the list of the active reserves
     uint8 index;
-   
   }
 
   /**
@@ -122,7 +121,7 @@ library ReserveLogic {
    * a formal specification.
    * @param reserve the reserve object
    **/
-    function updateCumulativeIndexesAndTimestamp(ReserveData storage reserve) internal {
+  function updateCumulativeIndexesAndTimestamp(ReserveData storage reserve) internal {
     uint256 currentLiquidityRate = reserve.currentLiquidityRate;
 
     //only cumulating if there is any income being produced
@@ -144,10 +143,8 @@ library ReserveLogic {
           reserve.currentVariableBorrowRate,
           lastUpdateTimestamp
         );
-        index = cumulatedVariableBorrowInterest.rayMul(
-          reserve.lastVariableBorrowIndex
-        );
-        require(index < (1 << 128),  Errors.VARIABLE_BORROW_INDEX_OVERFLOW);
+        index = cumulatedVariableBorrowInterest.rayMul(reserve.lastVariableBorrowIndex);
+        require(index < (1 << 128), Errors.VARIABLE_BORROW_INDEX_OVERFLOW);
         reserve.lastVariableBorrowIndex = uint128(index);
       }
     }
@@ -172,9 +169,7 @@ library ReserveLogic {
 
     uint256 result = amountToLiquidityRatio.add(WadRayMath.ray());
 
-    result = result.rayMul(
-      reserve.lastLiquidityIndex
-    );
+    result = result.rayMul(reserve.lastLiquidityIndex);
     require(result < (1 << 128), Errors.LIQUIDITY_INDEX_OVERFLOW);
 
     reserve.lastLiquidityIndex = uint128(result);
@@ -217,6 +212,7 @@ library ReserveLogic {
     uint256 newStableRate;
     uint256 newVariableRate;
   }
+
   /**
    * @dev Updates the reserve current stable borrow rate Rf, the current variable borrow rate Rv and the current liquidity rate Rl.
    * Also updates the lastUpdateTimestamp value. Please refer to the whitepaper for further information.
@@ -234,7 +230,8 @@ library ReserveLogic {
     UpdateInterestRatesLocalVars memory vars;
 
     vars.stableDebtTokenAddress = reserve.stableDebtTokenAddress;
-    vars.currentAvgStableRate = IStableDebtToken(vars.stableDebtTokenAddress).getAverageStableRate();
+    vars.currentAvgStableRate = IStableDebtToken(vars.stableDebtTokenAddress)
+      .getAverageStableRate();
     vars.availableLiquidity = IERC20(reserveAddress).balanceOf(aTokenAddress);
 
     (
@@ -248,9 +245,9 @@ library ReserveLogic {
       IERC20(reserve.variableDebtTokenAddress).totalSupply(),
       vars.currentAvgStableRate
     );
-    require(vars.newLiquidityRate < (1 << 128), "ReserveLogic: Liquidity rate overflow");
-    require(vars.newStableRate < (1 << 128), "ReserveLogic: Stable borrow rate overflow");
-    require(vars.newVariableRate < (1 << 128), "ReserveLogic: Variable borrow rate overflow");
+    require(vars.newLiquidityRate < (1 << 128), 'ReserveLogic: Liquidity rate overflow');
+    require(vars.newStableRate < (1 << 128), 'ReserveLogic: Stable borrow rate overflow');
+    require(vars.newVariableRate < (1 << 128), 'ReserveLogic: Variable borrow rate overflow');
 
     reserve.currentLiquidityRate = uint128(vars.newLiquidityRate);
     reserve.currentStableBorrowRate = uint128(vars.newStableRate);
diff --git a/contracts/libraries/logic/ValidationLogic.sol b/contracts/libraries/logic/ValidationLogic.sol
index 7a640458..9be3f828 100644
--- a/contracts/libraries/logic/ValidationLogic.sol
+++ b/contracts/libraries/logic/ValidationLogic.sol
@@ -321,10 +321,10 @@ library ValidationLogic {
   }
 
   /**
-  * @dev validates a flashloan action
-  * @param mode the flashloan mode (0 = classic flashloan, 1 = open a stable rate loan, 2 = open a variable rate loan)
-  * @param premium the premium paid on the flashloan
-  **/
+   * @dev validates a flashloan action
+   * @param mode the flashloan mode (0 = classic flashloan, 1 = open a stable rate loan, 2 = open a variable rate loan)
+   * @param premium the premium paid on the flashloan
+   **/
   function validateFlashloan(uint256 mode, uint256 premium) internal pure {
     require(premium > 0, Errors.REQUESTED_AMOUNT_TOO_SMALL);
     require(mode <= uint256(ReserveLogic.InterestRateMode.VARIABLE), Errors.INVALID_FLASHLOAN_MODE);
diff --git a/contracts/libraries/math/MathUtils.sol b/contracts/libraries/math/MathUtils.sol
index 2d9c76a4..13cec3fb 100644
--- a/contracts/libraries/math/MathUtils.sol
+++ b/contracts/libraries/math/MathUtils.sol
@@ -55,17 +55,17 @@ library MathUtils {
       return WadRayMath.ray();
     }
 
-    uint256 expMinusOne = exp-1;
+    uint256 expMinusOne = exp - 1;
 
-    uint256 expMinusTwo = exp > 2 ? exp-2 : 0;
+    uint256 expMinusTwo = exp > 2 ? exp - 2 : 0;
 
-    uint256 ratePerSecond = rate/SECONDS_PER_YEAR;
+    uint256 ratePerSecond = rate / SECONDS_PER_YEAR;
 
     uint256 basePowerTwo = ratePerSecond.rayMul(ratePerSecond);
     uint256 basePowerThree = basePowerTwo.rayMul(ratePerSecond);
 
-    uint256 secondTerm = exp.mul(expMinusOne).mul(basePowerTwo)/2;
-    uint256 thirdTerm = exp.mul(expMinusOne).mul(expMinusTwo).mul(basePowerThree)/6;
+    uint256 secondTerm = exp.mul(expMinusOne).mul(basePowerTwo) / 2;
+    uint256 thirdTerm = exp.mul(expMinusOne).mul(expMinusTwo).mul(basePowerThree) / 6;
 
     return WadRayMath.ray().add(ratePerSecond.mul(exp)).add(secondTerm).add(thirdTerm);
   }
diff --git a/contracts/libraries/math/PercentageMath.sol b/contracts/libraries/math/PercentageMath.sol
index 4d14107e..b853f1db 100644
--- a/contracts/libraries/math/PercentageMath.sol
+++ b/contracts/libraries/math/PercentageMath.sol
@@ -1,7 +1,6 @@
 // SPDX-License-Identifier: agpl-3.0
 pragma solidity ^0.6.8;
 
-
 import {Errors} from '../helpers/Errors.sol';
 
 /**
@@ -13,7 +12,6 @@ import {Errors} from '../helpers/Errors.sol';
  **/
 
 library PercentageMath {
-
   uint256 constant PERCENTAGE_FACTOR = 1e4; //percentage plus two decimals
   uint256 constant HALF_PERCENT = PERCENTAGE_FACTOR / 2;
 
@@ -24,19 +22,19 @@ library PercentageMath {
    * @return the percentage of value
    **/
   function percentMul(uint256 value, uint256 percentage) internal pure returns (uint256) {
-      if(value == 0){
+    if (value == 0) {
       return 0;
     }
-    
-    uint256 result = value*percentage;
-    
-    require(result/value == percentage, Errors.MULTIPLICATION_OVERFLOW);
-    
-    result+=HALF_PERCENT;
-    
+
+    uint256 result = value * percentage;
+
+    require(result / value == percentage, Errors.MULTIPLICATION_OVERFLOW);
+
+    result += HALF_PERCENT;
+
     require(result >= HALF_PERCENT, Errors.ADDITION_OVERFLOW);
 
-    return result/PERCENTAGE_FACTOR;
+    return result / PERCENTAGE_FACTOR;
   }
 
   /**
@@ -48,15 +46,15 @@ library PercentageMath {
   function percentDiv(uint256 value, uint256 percentage) internal pure returns (uint256) {
     require(percentage != 0, Errors.DIVISION_BY_ZERO);
     uint256 halfPercentage = percentage / 2;
- 
-    uint256 result = value*PERCENTAGE_FACTOR;
 
-    require(result/PERCENTAGE_FACTOR == value, Errors.MULTIPLICATION_OVERFLOW);
+    uint256 result = value * PERCENTAGE_FACTOR;
+
+    require(result / PERCENTAGE_FACTOR == value, Errors.MULTIPLICATION_OVERFLOW);
 
     result += halfPercentage;
 
     require(result >= halfPercentage, Errors.ADDITION_OVERFLOW);
 
-    return result/percentage;
+    return result / percentage;
   }
 }
diff --git a/contracts/libraries/math/SafeMath.sol b/contracts/libraries/math/SafeMath.sol
index 8ce54b91..0b251214 100644
--- a/contracts/libraries/math/SafeMath.sol
+++ b/contracts/libraries/math/SafeMath.sol
@@ -15,149 +15,149 @@ pragma solidity 0.6.8;
  * class of bugs, so it's recommended to use it always.
  */
 library SafeMath {
-    /**
-     * @dev Returns the addition of two unsigned integers, reverting on
-     * overflow.
-     *
-     * Counterpart to Solidity's `+` operator.
-     *
-     * Requirements:
-     * - Addition cannot overflow.
-     */
-    function add(uint256 a, uint256 b) internal pure returns (uint256) {
-        uint256 c = a + b;
-        require(c >= a, 'SafeMath: addition overflow');
+  /**
+   * @dev Returns the addition of two unsigned integers, reverting on
+   * overflow.
+   *
+   * Counterpart to Solidity's `+` operator.
+   *
+   * Requirements:
+   * - Addition cannot overflow.
+   */
+  function add(uint256 a, uint256 b) internal pure returns (uint256) {
+    uint256 c = a + b;
+    require(c >= a, 'SafeMath: addition overflow');
 
-        return c;
+    return c;
+  }
+
+  /**
+   * @dev Returns the subtraction of two unsigned integers, reverting on
+   * overflow (when the result is negative).
+   *
+   * Counterpart to Solidity's `-` operator.
+   *
+   * Requirements:
+   * - Subtraction cannot overflow.
+   */
+  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
+    return sub(a, b, 'SafeMath: subtraction overflow');
+  }
+
+  /**
+   * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
+   * overflow (when the result is negative).
+   *
+   * Counterpart to Solidity's `-` operator.
+   *
+   * Requirements:
+   * - Subtraction cannot overflow.
+   */
+  function sub(
+    uint256 a,
+    uint256 b,
+    string memory errorMessage
+  ) internal pure returns (uint256) {
+    require(b <= a, errorMessage);
+    uint256 c = a - b;
+
+    return c;
+  }
+
+  /**
+   * @dev Returns the multiplication of two unsigned integers, reverting on
+   * overflow.
+   *
+   * Counterpart to Solidity's `*` operator.
+   *
+   * Requirements:
+   * - Multiplication cannot overflow.
+   */
+  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
+    // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
+    // benefit is lost if 'b' is also tested.
+    // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
+    if (a == 0) {
+      return 0;
     }
 
-    /**
-     * @dev Returns the subtraction of two unsigned integers, reverting on
-     * overflow (when the result is negative).
-     *
-     * Counterpart to Solidity's `-` operator.
-     *
-     * Requirements:
-     * - Subtraction cannot overflow.
-     */
-    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
-        return sub(a, b, 'SafeMath: subtraction overflow');
-    }
+    uint256 c = a * b;
+    require(c / a == b, 'SafeMath: multiplication overflow');
 
-    /**
-     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
-     * overflow (when the result is negative).
-     *
-     * Counterpart to Solidity's `-` operator.
-     *
-     * Requirements:
-     * - Subtraction cannot overflow.
-     */
-    function sub(
-        uint256 a,
-        uint256 b,
-        string memory errorMessage
-    ) internal pure returns (uint256) {
-        require(b <= a, errorMessage);
-        uint256 c = a - b;
+    return c;
+  }
 
-        return c;
-    }
+  /**
+   * @dev Returns the integer division of two unsigned integers. Reverts on
+   * division by zero. The result is rounded towards zero.
+   *
+   * Counterpart to Solidity's `/` operator. Note: this function uses a
+   * `revert` opcode (which leaves remaining gas untouched) while Solidity
+   * uses an invalid opcode to revert (consuming all remaining gas).
+   *
+   * Requirements:
+   * - The divisor cannot be zero.
+   */
+  function div(uint256 a, uint256 b) internal pure returns (uint256) {
+    return div(a, b, 'SafeMath: division by zero');
+  }
 
-    /**
-     * @dev Returns the multiplication of two unsigned integers, reverting on
-     * overflow.
-     *
-     * Counterpart to Solidity's `*` operator.
-     *
-     * Requirements:
-     * - Multiplication cannot overflow.
-     */
-    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
-        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
-        // benefit is lost if 'b' is also tested.
-        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
-        if (a == 0) {
-            return 0;
-        }
+  /**
+   * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
+   * division by zero. The result is rounded towards zero.
+   *
+   * Counterpart to Solidity's `/` operator. Note: this function uses a
+   * `revert` opcode (which leaves remaining gas untouched) while Solidity
+   * uses an invalid opcode to revert (consuming all remaining gas).
+   *
+   * Requirements:
+   * - The divisor cannot be zero.
+   */
+  function div(
+    uint256 a,
+    uint256 b,
+    string memory errorMessage
+  ) internal pure returns (uint256) {
+    // Solidity only automatically asserts when dividing by 0
+    require(b > 0, errorMessage);
+    uint256 c = a / b;
+    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
 
-        uint256 c = a * b;
-        require(c / a == b, 'SafeMath: multiplication overflow');
+    return c;
+  }
 
-        return c;
-    }
+  /**
+   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
+   * Reverts when dividing by zero.
+   *
+   * Counterpart to Solidity's `%` operator. This function uses a `revert`
+   * opcode (which leaves remaining gas untouched) while Solidity uses an
+   * invalid opcode to revert (consuming all remaining gas).
+   *
+   * Requirements:
+   * - The divisor cannot be zero.
+   */
+  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
+    return mod(a, b, 'SafeMath: modulo by zero');
+  }
 
-    /**
-     * @dev Returns the integer division of two unsigned integers. Reverts on
-     * division by zero. The result is rounded towards zero.
-     *
-     * Counterpart to Solidity's `/` operator. Note: this function uses a
-     * `revert` opcode (which leaves remaining gas untouched) while Solidity
-     * uses an invalid opcode to revert (consuming all remaining gas).
-     *
-     * Requirements:
-     * - The divisor cannot be zero.
-     */
-    function div(uint256 a, uint256 b) internal pure returns (uint256) {
-        return div(a, b, 'SafeMath: division by zero');
-    }
-
-    /**
-     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
-     * division by zero. The result is rounded towards zero.
-     *
-     * Counterpart to Solidity's `/` operator. Note: this function uses a
-     * `revert` opcode (which leaves remaining gas untouched) while Solidity
-     * uses an invalid opcode to revert (consuming all remaining gas).
-     *
-     * Requirements:
-     * - The divisor cannot be zero.
-     */
-    function div(
-        uint256 a,
-        uint256 b,
-        string memory errorMessage
-    ) internal pure returns (uint256) {
-        // Solidity only automatically asserts when dividing by 0
-        require(b > 0, errorMessage);
-        uint256 c = a / b;
-        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
-
-        return c;
-    }
-
-    /**
-     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
-     * Reverts when dividing by zero.
-     *
-     * Counterpart to Solidity's `%` operator. This function uses a `revert`
-     * opcode (which leaves remaining gas untouched) while Solidity uses an
-     * invalid opcode to revert (consuming all remaining gas).
-     *
-     * Requirements:
-     * - The divisor cannot be zero.
-     */
-    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
-        return mod(a, b, 'SafeMath: modulo by zero');
-    }
-
-    /**
-     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
-     * Reverts with custom message when dividing by zero.
-     *
-     * Counterpart to Solidity's `%` operator. This function uses a `revert`
-     * opcode (which leaves remaining gas untouched) while Solidity uses an
-     * invalid opcode to revert (consuming all remaining gas).
-     *
-     * Requirements:
-     * - The divisor cannot be zero.
-     */
-    function mod(
-        uint256 a,
-        uint256 b,
-        string memory errorMessage
-    ) internal pure returns (uint256) {
-        require(b != 0, errorMessage);
-        return a % b;
-    }
+  /**
+   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
+   * Reverts with custom message when dividing by zero.
+   *
+   * Counterpart to Solidity's `%` operator. This function uses a `revert`
+   * opcode (which leaves remaining gas untouched) while Solidity uses an
+   * invalid opcode to revert (consuming all remaining gas).
+   *
+   * Requirements:
+   * - The divisor cannot be zero.
+   */
+  function mod(
+    uint256 a,
+    uint256 b,
+    string memory errorMessage
+  ) internal pure returns (uint256) {
+    require(b != 0, errorMessage);
+    return a % b;
+  }
 }
diff --git a/contracts/libraries/math/WadRayMath.sol b/contracts/libraries/math/WadRayMath.sol
index 1a1bdabd..7da5fc81 100644
--- a/contracts/libraries/math/WadRayMath.sol
+++ b/contracts/libraries/math/WadRayMath.sol
@@ -10,7 +10,6 @@ import {Errors} from '../helpers/Errors.sol';
  **/
 
 library WadRayMath {
-
   uint256 internal constant WAD = 1e18;
   uint256 internal constant halfWAD = WAD / 2;
 
@@ -55,20 +54,19 @@ library WadRayMath {
    * @return the result of a*b, in wad
    **/
   function wadMul(uint256 a, uint256 b) internal pure returns (uint256) {
-    
-    if(a == 0){
+    if (a == 0) {
       return 0;
     }
-    
-    uint256 result = a*b;
-    
-    require(result/a == b, Errors.MULTIPLICATION_OVERFLOW);
-    
-    result+=halfWAD;
-    
+
+    uint256 result = a * b;
+
+    require(result / a == b, Errors.MULTIPLICATION_OVERFLOW);
+
+    result += halfWAD;
+
     require(result >= halfWAD, Errors.ADDITION_OVERFLOW);
 
-    return result/WAD;
+    return result / WAD;
   }
 
   /**
@@ -82,15 +80,15 @@ library WadRayMath {
 
     uint256 halfB = b / 2;
 
-    uint256 result = a*WAD;
+    uint256 result = a * WAD;
 
-    require(result/WAD == a, Errors.MULTIPLICATION_OVERFLOW);
+    require(result / WAD == a, Errors.MULTIPLICATION_OVERFLOW);
 
     result += halfB;
 
     require(result >= halfB, Errors.ADDITION_OVERFLOW);
 
-    return result/b;
+    return result / b;
   }
 
   /**
@@ -100,19 +98,19 @@ library WadRayMath {
    * @return the result of a*b, in ray
    **/
   function rayMul(uint256 a, uint256 b) internal pure returns (uint256) {
-     if(a == 0){
+    if (a == 0) {
       return 0;
     }
-    
-    uint256 result = a*b;
-    
-    require(result/a == b, Errors.MULTIPLICATION_OVERFLOW);
-    
-    result+=halfRAY;
-    
+
+    uint256 result = a * b;
+
+    require(result / a == b, Errors.MULTIPLICATION_OVERFLOW);
+
+    result += halfRAY;
+
     require(result >= halfRAY, Errors.ADDITION_OVERFLOW);
 
-    return result/RAY;
+    return result / RAY;
   }
 
   /**
@@ -126,16 +124,15 @@ library WadRayMath {
 
     uint256 halfB = b / 2;
 
-    uint256 result = a*RAY;
+    uint256 result = a * RAY;
 
-    require(result/RAY == a, Errors.MULTIPLICATION_OVERFLOW);
+    require(result / RAY == a, Errors.MULTIPLICATION_OVERFLOW);
 
     result += halfB;
 
     require(result >= halfB, Errors.ADDITION_OVERFLOW);
 
-    return result/b;
-
+    return result / b;
   }
 
   /**
@@ -145,10 +142,10 @@ library WadRayMath {
    **/
   function rayToWad(uint256 a) internal pure returns (uint256) {
     uint256 halfRatio = WAD_RAY_RATIO / 2;
-    uint256 result = halfRatio+a;
+    uint256 result = halfRatio + a;
     require(result >= halfRatio, Errors.ADDITION_OVERFLOW);
 
-    return result/WAD_RAY_RATIO;
+    return result / WAD_RAY_RATIO;
   }
 
   /**
@@ -157,8 +154,8 @@ library WadRayMath {
    * @return a converted in ray
    **/
   function wadToRay(uint256 a) internal pure returns (uint256) {
-    uint256 result = a*WAD_RAY_RATIO;
-    require(result/WAD_RAY_RATIO == a, Errors.MULTIPLICATION_OVERFLOW);
+    uint256 result = a * WAD_RAY_RATIO;
+    require(result / WAD_RAY_RATIO == a, Errors.MULTIPLICATION_OVERFLOW);
     return result;
   }
 }
diff --git a/contracts/misc/Address.sol b/contracts/misc/Address.sol
index 2233df49..be5026db 100644
--- a/contracts/misc/Address.sol
+++ b/contracts/misc/Address.sol
@@ -5,57 +5,57 @@ pragma solidity 0.6.8;
  * @dev Collection of functions related to the address type
  */
 library Address {
-    /**
-     * @dev Returns true if `account` is a contract.
-     *
-     * [IMPORTANT]
-     * ====
-     * It is unsafe to assume that an address for which this function returns
-     * false is an externally-owned account (EOA) and not a contract.
-     *
-     * Among others, `isContract` will return false for the following
-     * types of addresses:
-     *
-     *  - an externally-owned account
-     *  - a contract in construction
-     *  - an address where a contract will be created
-     *  - an address where a contract lived, but was destroyed
-     * ====
-     */
-    function isContract(address account) internal view returns (bool) {
-        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
-        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
-        // for accounts without code, i.e. `keccak256('')`
-        bytes32 codehash;
-        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
-        // solhint-disable-next-line no-inline-assembly
-        assembly {
-            codehash := extcodehash(account)
-        }
-        return (codehash != accountHash && codehash != 0x0);
+  /**
+   * @dev Returns true if `account` is a contract.
+   *
+   * [IMPORTANT]
+   * ====
+   * It is unsafe to assume that an address for which this function returns
+   * false is an externally-owned account (EOA) and not a contract.
+   *
+   * Among others, `isContract` will return false for the following
+   * types of addresses:
+   *
+   *  - an externally-owned account
+   *  - a contract in construction
+   *  - an address where a contract will be created
+   *  - an address where a contract lived, but was destroyed
+   * ====
+   */
+  function isContract(address account) internal view returns (bool) {
+    // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
+    // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
+    // for accounts without code, i.e. `keccak256('')`
+    bytes32 codehash;
+    bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
+    // solhint-disable-next-line no-inline-assembly
+    assembly {
+      codehash := extcodehash(account)
     }
+    return (codehash != accountHash && codehash != 0x0);
+  }
 
-    /**
-     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
-     * `recipient`, forwarding all available gas and reverting on errors.
-     *
-     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
-     * of certain opcodes, possibly making contracts go over the 2300 gas limit
-     * imposed by `transfer`, making them unable to receive funds via
-     * `transfer`. {sendValue} removes this limitation.
-     *
-     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
-     *
-     * IMPORTANT: because control is transferred to `recipient`, care must be
-     * taken to not create reentrancy vulnerabilities. Consider using
-     * {ReentrancyGuard} or the
-     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
-     */
-    function sendValue(address payable recipient, uint256 amount) internal {
-        require(address(this).balance >= amount, 'Address: insufficient balance');
+  /**
+   * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
+   * `recipient`, forwarding all available gas and reverting on errors.
+   *
+   * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
+   * of certain opcodes, possibly making contracts go over the 2300 gas limit
+   * imposed by `transfer`, making them unable to receive funds via
+   * `transfer`. {sendValue} removes this limitation.
+   *
+   * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
+   *
+   * IMPORTANT: because control is transferred to `recipient`, care must be
+   * taken to not create reentrancy vulnerabilities. Consider using
+   * {ReentrancyGuard} or the
+   * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
+   */
+  function sendValue(address payable recipient, uint256 amount) internal {
+    require(address(this).balance >= amount, 'Address: insufficient balance');
 
-        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
-        (bool success, ) = recipient.call{value: amount}('');
-        require(success, 'Address: unable to send value, recipient may have reverted');
-    }
+    // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
+    (bool success, ) = recipient.call{value: amount}('');
+    require(success, 'Address: unable to send value, recipient may have reverted');
+  }
 }
diff --git a/contracts/misc/Context.sol b/contracts/misc/Context.sol
index 7208e0c4..fb4afa42 100644
--- a/contracts/misc/Context.sol
+++ b/contracts/misc/Context.sol
@@ -12,12 +12,12 @@ pragma solidity 0.6.8;
  * This contract is only required for intermediate, library-like contracts.
  */
 abstract contract Context {
-    function _msgSender() internal virtual view returns (address payable) {
-        return msg.sender;
-    }
+  function _msgSender() internal virtual view returns (address payable) {
+    return msg.sender;
+  }
 
-    function _msgData() internal virtual view returns (bytes memory) {
-        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
-        return msg.data;
-    }
+  function _msgData() internal virtual view returns (bytes memory) {
+    this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
+    return msg.data;
+  }
 }
diff --git a/contracts/misc/SafeERC20.sol b/contracts/misc/SafeERC20.sol
index d1fa0c94..11416ac9 100644
--- a/contracts/misc/SafeERC20.sol
+++ b/contracts/misc/SafeERC20.sol
@@ -2,9 +2,9 @@
 
 pragma solidity 0.6.8;
 
-import {IERC20} from "../interfaces/IERC20.sol";
-import {SafeMath} from "../libraries/math/SafeMath.sol";
-import {Address} from "./Address.sol";
+import {IERC20} from '../interfaces/IERC20.sol';
+import {SafeMath} from '../libraries/math/SafeMath.sol';
+import {Address} from './Address.sol';
 
 /**
  * @title SafeERC20
@@ -16,34 +16,49 @@ import {Address} from "./Address.sol";
  * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
  */
 library SafeERC20 {
-    using SafeMath for uint256;
-    using Address for address;
+  using SafeMath for uint256;
+  using Address for address;
 
-    function safeTransfer(IERC20 token, address to, uint256 value) internal {
-        callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
-    }
-
-    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
-        callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
-    }
-
-    function safeApprove(IERC20 token, address spender, uint256 value) internal {
-        require((value == 0) || (token.allowance(address(this), spender) == 0),
-            "SafeERC20: approve from non-zero to non-zero allowance"
-        );
-        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
-    }
-    
-    function callOptionalReturn(IERC20 token, bytes memory data) private {
-        require(address(token).isContract(), "SafeERC20: call to non-contract");
-
-        // solhint-disable-next-line avoid-low-level-calls
-        (bool success, bytes memory returndata) = address(token).call(data);
-        require(success, "SafeERC20: low-level call failed");
-
-        if (returndata.length > 0) { // Return data is optional
-            // solhint-disable-next-line max-line-length
-            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
-        }
+  function safeTransfer(
+    IERC20 token,
+    address to,
+    uint256 value
+  ) internal {
+    callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
+  }
+
+  function safeTransferFrom(
+    IERC20 token,
+    address from,
+    address to,
+    uint256 value
+  ) internal {
+    callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
+  }
+
+  function safeApprove(
+    IERC20 token,
+    address spender,
+    uint256 value
+  ) internal {
+    require(
+      (value == 0) || (token.allowance(address(this), spender) == 0),
+      'SafeERC20: approve from non-zero to non-zero allowance'
+    );
+    callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
+  }
+
+  function callOptionalReturn(IERC20 token, bytes memory data) private {
+    require(address(token).isContract(), 'SafeERC20: call to non-contract');
+
+    // solhint-disable-next-line avoid-low-level-calls
+    (bool success, bytes memory returndata) = address(token).call(data);
+    require(success, 'SafeERC20: low-level call failed');
+
+    if (returndata.length > 0) {
+      // Return data is optional
+      // solhint-disable-next-line max-line-length
+      require(abi.decode(returndata, (bool)), 'SafeERC20: ERC20 operation did not succeed');
     }
+  }
 }
diff --git a/contracts/mocks/flashloan/MockSwapAdapter.sol b/contracts/mocks/flashloan/MockSwapAdapter.sol
new file mode 100644
index 00000000..85c7d84b
--- /dev/null
+++ b/contracts/mocks/flashloan/MockSwapAdapter.sol
@@ -0,0 +1,60 @@
+// 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 '@openzeppelin/contracts/token/ERC20/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);
+    }
+}
\ No newline at end of file
diff --git a/contracts/tokenization/AToken.sol b/contracts/tokenization/AToken.sol
index de178819..53870c24 100644
--- a/contracts/tokenization/AToken.sol
+++ b/contracts/tokenization/AToken.sol
@@ -10,7 +10,7 @@ import {
 } from '../libraries/openzeppelin-upgradeability/VersionedInitializable.sol';
 import {IAToken} from './interfaces/IAToken.sol';
 import {IERC20} from '../interfaces/IERC20.sol';
-import {SafeERC20} from "../misc/SafeERC20.sol";
+import {SafeERC20} from '../misc/SafeERC20.sol';
 
 /**
  * @title Aave ERC20 AToken
diff --git a/contracts/tokenization/StableDebtToken.sol b/contracts/tokenization/StableDebtToken.sol
index 4fdcad09..8e5da21b 100644
--- a/contracts/tokenization/StableDebtToken.sol
+++ b/contracts/tokenization/StableDebtToken.sol
@@ -118,7 +118,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
       .add(vars.amountInRay.rayMul(rate))
       .rayDiv(currentBalance.add(amount).wadToRay());
 
-    require(vars.newStableRate < (1 << 128), "Debt token: stable rate overflow");
+    require(vars.newStableRate < (1 << 128), 'Debt token: stable rate overflow');
     _usersData[user] = vars.newStableRate;
 
     //solium-disable-next-line
diff --git a/contracts/tokenization/VariableDebtToken.sol b/contracts/tokenization/VariableDebtToken.sol
index 580151eb..e52f7c61 100644
--- a/contracts/tokenization/VariableDebtToken.sol
+++ b/contracts/tokenization/VariableDebtToken.sol
@@ -76,7 +76,7 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
     _mint(user, amount.add(balanceIncrease));
 
     uint256 newUserIndex = POOL.getReserveNormalizedVariableDebt(UNDERLYING_ASSET);
-    require(newUserIndex < (1 << 128), "Debt token: Index overflow");
+    require(newUserIndex < (1 << 128), 'Debt token: Index overflow');
     _usersData[user] = newUserIndex;
 
     emit MintDebt(user, amount, previousBalance, currentBalance, balanceIncrease, newUserIndex);
@@ -104,7 +104,7 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
     //if user not repaid everything
     if (currentBalance != amount) {
       newUserIndex = POOL.getReserveNormalizedVariableDebt(UNDERLYING_ASSET);
-      require(newUserIndex < (1 << 128), "Debt token: Index overflow");
+      require(newUserIndex < (1 << 128), 'Debt token: Index overflow');
     }
     _usersData[user] = newUserIndex;
 
diff --git a/contracts/tokenization/base/DebtTokenBase.sol b/contracts/tokenization/base/DebtTokenBase.sol
index 04009023..a6bd4005 100644
--- a/contracts/tokenization/base/DebtTokenBase.sol
+++ b/contracts/tokenization/base/DebtTokenBase.sol
@@ -5,7 +5,9 @@ import {Context} from '@openzeppelin/contracts/GSN/Context.sol';
 import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol';
 import {ILendingPoolAddressesProvider} from '../../interfaces/ILendingPoolAddressesProvider.sol';
 import {ILendingPool} from '../../interfaces/ILendingPool.sol';
-import {VersionedInitializable} from '../../libraries/openzeppelin-upgradeability/VersionedInitializable.sol';
+import {
+  VersionedInitializable
+} from '../../libraries/openzeppelin-upgradeability/VersionedInitializable.sol';
 import {ERC20} from '../ERC20.sol';
 import {Errors} from '../../libraries/helpers/Errors.sol';
 
@@ -16,7 +18,6 @@ import {Errors} from '../../libraries/helpers/Errors.sol';
  */
 
 abstract contract DebtTokenBase is ERC20, VersionedInitializable {
-
   address internal immutable UNDERLYING_ASSET;
   ILendingPool internal immutable POOL;
   mapping(address => uint256) internal _usersData;
@@ -29,7 +30,7 @@ abstract contract DebtTokenBase is ERC20, VersionedInitializable {
     _;
   }
 
-  /** 
+  /**
    * @dev The metadata of the token will be set on the proxy, that the reason of
    * passing "NULL" and 0 as metadata
    */
@@ -37,7 +38,7 @@ abstract contract DebtTokenBase is ERC20, VersionedInitializable {
     address pool,
     address underlyingAssetAddress,
     string memory name,
-    string memory symbol  
+    string memory symbol
   ) public ERC20(name, symbol, 18) {
     POOL = ILendingPool(pool);
     UNDERLYING_ASSET = underlyingAssetAddress;
@@ -76,32 +77,59 @@ abstract contract DebtTokenBase is ERC20, VersionedInitializable {
    * standard ERC20 functions for transfer and allowance.
    **/
   function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
-    recipient; amount;
+    recipient;
+    amount;
     revert('TRANSFER_NOT_SUPPORTED');
   }
 
-  function allowance(address owner, address spender) public virtual override view returns (uint256) {
-    owner; spender;
+  function allowance(address owner, address spender)
+    public
+    virtual
+    override
+    view
+    returns (uint256)
+  {
+    owner;
+    spender;
     revert('ALLOWANCE_NOT_SUPPORTED');
   }
 
   function approve(address spender, uint256 amount) public virtual override returns (bool) {
-    spender; amount;
+    spender;
+    amount;
     revert('APPROVAL_NOT_SUPPORTED');
   }
 
-  function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
-    sender; recipient; amount;
+  function transferFrom(
+    address sender,
+    address recipient,
+    uint256 amount
+  ) public virtual override returns (bool) {
+    sender;
+    recipient;
+    amount;
     revert('TRANSFER_NOT_SUPPORTED');
   }
 
-  function increaseAllowance(address spender, uint256 addedValue) public virtual override returns (bool) {
-    spender; addedValue;
+  function increaseAllowance(address spender, uint256 addedValue)
+    public
+    virtual
+    override
+    returns (bool)
+  {
+    spender;
+    addedValue;
     revert('ALLOWANCE_NOT_SUPPORTED');
   }
 
-  function decreaseAllowance(address spender, uint256 subtractedValue) public virtual override returns (bool) {
-    spender; subtractedValue;
+  function decreaseAllowance(address spender, uint256 subtractedValue)
+    public
+    virtual
+    override
+    returns (bool)
+  {
+    spender;
+    subtractedValue;
     revert('ALLOWANCE_NOT_SUPPORTED');
   }
 
@@ -111,7 +139,15 @@ abstract contract DebtTokenBase is ERC20, VersionedInitializable {
    * @return The previous principal balance, the new principal balance, the balance increase
    * and the new user index
    **/
-  function _calculateBalanceIncrease(address user) internal view returns (uint256, uint256, uint256) {
+  function _calculateBalanceIncrease(address user)
+    internal
+    view
+    returns (
+      uint256,
+      uint256,
+      uint256
+    )
+  {
     uint256 previousPrincipalBalance = principalBalanceOf(user);
 
     if (previousPrincipalBalance == 0) {
diff --git a/deployed-contracts.json b/deployed-contracts.json
index d04816b9..cb373f29 100644
--- a/deployed-contracts.json
+++ b/deployed-contracts.json
@@ -174,7 +174,7 @@
   },
   "WalletBalanceProvider": {
     "buidlerevm": {
-      "address": "0xBEF0d4b9c089a5883741fC14cbA352055f35DDA2",
+      "address": "0xDf73fC454FA018051D4a1509e63D11530A59DE10",
       "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
     },
     "localhost": {
@@ -414,7 +414,7 @@
   },
   "AaveProtocolTestHelpers": {
     "buidlerevm": {
-      "address": "0xDf73fC454FA018051D4a1509e63D11530A59DE10"
+      "address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4"
     },
     "localhost": {
       "address": "0xDf73fC454FA018051D4a1509e63D11530A59DE10"
@@ -489,5 +489,10 @@
       "address": "0xA8083d78B6ABC328b4d3B714F76F384eCC7147e1",
       "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
     }
+  },
+  "MockSwapAdapter": {
+    "buidlerevm": {
+      "address": "0xBEF0d4b9c089a5883741fC14cbA352055f35DDA2"
+    }
   }
-}
\ No newline at end of file
+}
diff --git a/helpers/contracts-helpers.ts b/helpers/contracts-helpers.ts
index b5b483d3..4bebd442 100644
--- a/helpers/contracts-helpers.ts
+++ b/helpers/contracts-helpers.ts
@@ -31,10 +31,11 @@ import BigNumber from 'bignumber.js';
 import {Ierc20Detailed} from '../types/Ierc20Detailed';
 import {StableDebtToken} from '../types/StableDebtToken';
 import {VariableDebtToken} from '../types/VariableDebtToken';
+import {MockSwapAdapter} from '../types/MockSwapAdapter';
 
 export const registerContractInJsonDb = async (contractId: string, contractInstance: Contract) => {
   const currentNetwork = BRE.network.name;
-  if (currentNetwork !== 'buidlerevm' && currentNetwork !== 'soliditycoverage') {
+  if (currentNetwork !== 'buidlerevm' && !currentNetwork.includes('coverage')) {
     console.log(`*** ${contractId} ***\n`);
     console.log(`Network: ${currentNetwork}`);
     console.log(`tx: ${contractInstance.deployTransaction.hash}`);
@@ -212,6 +213,9 @@ export const deployMockFlashLoanReceiver = async (addressesProvider: tEthereumAd
     addressesProvider,
   ]);
 
+export const deployMockSwapAdapter = async (addressesProvider: tEthereumAddress) =>
+  await deployContract<MockSwapAdapter>(eContractid.MockSwapAdapter, [addressesProvider]);
+
 export const deployWalletBalancerProvider = async (addressesProvider: tEthereumAddress) =>
   await deployContract<WalletBalanceProvider>(eContractid.WalletBalanceProvider, [
     addressesProvider,
@@ -387,6 +391,14 @@ export const getMockFlashLoanReceiver = async (address?: tEthereumAddress) => {
   );
 };
 
+export const getMockSwapAdapter = async (address?: tEthereumAddress) => {
+  return await getContract<MockSwapAdapter>(
+    eContractid.MockSwapAdapter,
+    address ||
+      (await getDb().get(`${eContractid.MockSwapAdapter}.${BRE.network.name}`).value()).address
+  );
+};
+
 export const getLendingRateOracle = async (address?: tEthereumAddress) => {
   return await getContract<LendingRateOracle>(
     eContractid.LendingRateOracle,
diff --git a/helpers/types.ts b/helpers/types.ts
index e18ca909..79a810c2 100644
--- a/helpers/types.ts
+++ b/helpers/types.ts
@@ -32,6 +32,7 @@ export enum eContractid {
   LendingPoolLiquidationManager = 'LendingPoolLiquidationManager',
   InitializableAdminUpgradeabilityProxy = 'InitializableAdminUpgradeabilityProxy',
   MockFlashLoanReceiver = 'MockFlashLoanReceiver',
+  MockSwapAdapter = 'MockSwapAdapter',
   WalletBalanceProvider = 'WalletBalanceProvider',
   AToken = 'AToken',
   MockAToken = 'MockAToken',
@@ -111,7 +112,7 @@ export enum ProtocolErrors {
   INVALID_REDIRECTION_ADDRESS = 'Invalid redirection address',
   INVALID_HF = 'Invalid health factor',
   TRANSFER_AMOUNT_EXCEEDS_BALANCE = 'ERC20: transfer amount exceeds balance',
-  SAFEERC20_LOWLEVEL_CALL = 'SafeERC20: low-level call failed'
+  SAFEERC20_LOWLEVEL_CALL = 'SafeERC20: low-level call failed',
 }
 
 export type tEthereumAddress = string;
diff --git a/package.json b/package.json
index 606aaaf9..3da86f23 100644
--- a/package.json
+++ b/package.json
@@ -13,8 +13,10 @@
     "types-gen": "typechain --target ethers-v5 --outDir ./types './artifacts/*.json'",
     "test": "buidler test",
     "test-scenarios": "buidler test test/__setup.spec.ts test/scenario.spec.ts",
+    "test-repay-with-collateral": "buidler test test/__setup.spec.ts test/repay-with-collateral.spec.ts",
+    "test-liquidate-with-collateral": "buidler test test/__setup.spec.ts test/flash-liquidation-with-collateral.spec.ts",
     "test-flash": "buidler test test/__setup.spec.ts test/flashloan.spec.ts",
-    "dev:coverage": "buidler coverage",
+    "dev:coverage": "buidler coverage --network coverage",
     "dev:deployment": "buidler dev-deployment",
     "dev:deployExample": "buidler deploy-Example",
     "dev:prettier": "prettier --write .",
diff --git a/test/__setup.spec.ts b/test/__setup.spec.ts
index 342b7b64..e2db2752 100644
--- a/test/__setup.spec.ts
+++ b/test/__setup.spec.ts
@@ -23,6 +23,7 @@ import {
   deployStableDebtToken,
   deployVariableDebtToken,
   deployGenericAToken,
+  deployMockSwapAdapter,
 } from '../helpers/contracts-helpers';
 import {LendingPoolAddressesProvider} from '../types/LendingPoolAddressesProvider';
 import {ContractTransaction, Signer} from 'ethers';
@@ -503,6 +504,9 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => {
   const mockFlashLoanReceiver = await deployMockFlashLoanReceiver(addressesProvider.address);
   await insertContractAddressInDb(eContractid.MockFlashLoanReceiver, mockFlashLoanReceiver.address);
 
+  const mockSwapAdapter = await deployMockSwapAdapter(addressesProvider.address);
+  await insertContractAddressInDb(eContractid.MockSwapAdapter, mockSwapAdapter.address);
+
   await deployWalletBalancerProvider(addressesProvider.address);
 
   const testHelpers = await deployAaveProtocolTestHelpers(addressesProvider.address);
diff --git a/test/flash-liquidation-with-collateral.spec.ts b/test/flash-liquidation-with-collateral.spec.ts
new file mode 100644
index 00000000..87edf6d6
--- /dev/null
+++ b/test/flash-liquidation-with-collateral.spec.ts
@@ -0,0 +1,916 @@
+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 {waitForTx} from './__setup.spec';
+import {timeLatest, BRE, increaseTime} 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} = ProtocolErrors;
+
+  it('User 1 provides some liquidity for others to borrow', async () => {
+    const {pool, weth, dai, usdc} = testEnv;
+
+    await weth.mint(parseEther('200'));
+    await weth.approve(pool.address, parseEther('200'));
+    await pool.deposit(weth.address, parseEther('200'), 0);
+    await dai.mint(parseEther('20000'));
+    await dai.approve(pool.address, parseEther('20000'));
+    await pool.deposit(dai.address, parseEther('20000'), 0);
+    await usdc.mint(parseEther('20000'));
+    await usdc.approve(pool.address, parseEther('20000'));
+    await pool.deposit(usdc.address, parseEther('20000'), 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} = 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, '0');
+
+    const usdcPrice = await oracle.getAssetPrice(usdc.address);
+
+    await pool.connect(user.signer).borrow(usdc.address, amountToBorrow, 2, 0);
+
+    await pool.connect(user.signer).borrow(usdc.address, amountToBorrow, 1, 0);
+
+    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 pool.getReserveConfigurationData(weth.address)
+    ).decimals.toString();
+    const principalDecimals = (
+      await pool.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,
+      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, '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);
+  });
+
+  it('User 5 liquidates half the USDC loan of User 3 by swapping his WETH collateral', async () => {
+    const {pool, weth, usdc, users, mockSwapAdapter, oracle} = 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.totalBorrowsVariable.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 pool.getReserveConfigurationData(weth.address)
+    ).decimals.toString();
+    const principalDecimals = (
+      await pool.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;
+
+    // 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} = 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.totalBorrowsVariable.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 pool.getReserveConfigurationData(weth.address)
+    ).decimals.toString();
+    const principalDecimals = (
+      await pool.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, '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);
+  });
+
+  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.totalBorrowsVariable.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.totalBorrowsVariable.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} = 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.totalBorrowsVariable.multipliedBy(0.6).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 pool.getReserveConfigurationData(weth.address)
+    ).decimals.toString();
+    const principalDecimals = (
+      await pool.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} = 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.totalBorrowsVariable.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 pool.getReserveConfigurationData(weth.address)
+    ).decimals.toString();
+    const principalDecimals = (
+      await pool.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} = 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, '0');
+    await pool.connect(user.signer).deposit(dai.address, amountToDepositDAI, '0');
+
+    await pool.connect(user.signer).borrow(usdc.address, amountToBorrowVariable, 2, 0);
+
+    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 pool.getReserveConfigurationData(weth.address);
+
+    const collateralDecimals = collateralConfig.decimals.toString();
+    const principalDecimals = (
+      await pool.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.equal(
+      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 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('60');
+    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, '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, '0');
+
+    await pool.connect(user.signer).borrow(usdc.address, amountToBorrow, 2, 0);
+  });
+
+  it('Liquidator tries to liquidates User 5 USDC loan by swapping his WETH collateral, should revert due WETH collateral disabled', async () => {
+    const {pool, weth, 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;
+
+    // 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/flashloan.spec.ts b/test/flashloan.spec.ts
index 79db4bcb..7b964158 100644
--- a/test/flashloan.spec.ts
+++ b/test/flashloan.spec.ts
@@ -21,7 +21,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
     REQUESTED_AMOUNT_TOO_SMALL,
     TRANSFER_AMOUNT_EXCEEDS_BALANCE,
     INVALID_FLASHLOAN_MODE,
-    SAFEERC20_LOWLEVEL_CALL
+    SAFEERC20_LOWLEVEL_CALL,
   } = ProtocolErrors;
 
   before(async () => {
@@ -340,8 +340,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
     await _mockFlashLoanReceiver.setFailExecutionTransfer(true);
 
     await pool
-        .connect(caller.signer)
-        .flashLoan(_mockFlashLoanReceiver.address, weth.address, flashAmount, 1, '0x10', '0');
+      .connect(caller.signer)
+      .flashLoan(_mockFlashLoanReceiver.address, weth.address, flashAmount, 1, '0x10', '0');
 
     const {stableDebtTokenAddress} = await pool.getReserveTokensAddresses(weth.address);
 
@@ -353,6 +353,5 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
     const callerDebt = await wethDebtToken.balanceOf(caller.address);
 
     expect(callerDebt.toString()).to.be.equal('800720000000000000', 'Invalid user debt');
-  
   });
 });
diff --git a/test/helpers/actions.ts b/test/helpers/actions.ts
index be0daac5..4442b052 100644
--- a/test/helpers/actions.ts
+++ b/test/helpers/actions.ts
@@ -845,7 +845,7 @@ const getTxCostAndTimestamp = async (tx: ContractReceipt) => {
   return {txCost, txTimestamp};
 };
 
-const getContractsData = async (reserve: string, user: string, testEnv: TestEnv) => {
+export const getContractsData = async (reserve: string, user: string, testEnv: TestEnv) => {
   const {pool} = testEnv;
   const reserveData = await getReserveData(pool, reserve);
   const userData = await getUserData(pool, reserve, user);
diff --git a/test/helpers/make-suite.ts b/test/helpers/make-suite.ts
index e6e5df98..a0787a17 100644
--- a/test/helpers/make-suite.ts
+++ b/test/helpers/make-suite.ts
@@ -9,6 +9,7 @@ import {
   getMintableErc20,
   getLendingPoolConfiguratorProxy,
   getPriceOracle,
+  getMockSwapAdapter,
 } from '../../helpers/contracts-helpers';
 import {tEthereumAddress} from '../../helpers/types';
 import {LendingPool} from '../../types/LendingPool';
@@ -23,6 +24,7 @@ import bignumberChai from 'chai-bignumber';
 import {almostEqual} from './almost-equal';
 import {PriceOracle} from '../../types/PriceOracle';
 import {LendingPoolAddressesProvider} from '../../types/LendingPoolAddressesProvider';
+import { MockSwapAdapter } from '../../types/MockSwapAdapter';
 chai.use(bignumberChai());
 chai.use(almostEqual());
 
@@ -44,6 +46,7 @@ export interface TestEnv {
   usdc: MintableErc20;
   lend: MintableErc20;
   addressesProvider: LendingPoolAddressesProvider;
+  mockSwapAdapter: MockSwapAdapter;
 }
 
 let buidlerevmSnapshotId: string = '0x1';
@@ -67,6 +70,7 @@ const testEnv: TestEnv = {
   usdc: {} as MintableErc20,
   lend: {} as MintableErc20,
   addressesProvider: {} as LendingPoolAddressesProvider,
+  mockSwapAdapter: {} as MockSwapAdapter
 } as TestEnv;
 
 export async function initializeMakeSuite() {
@@ -125,6 +129,8 @@ export async function initializeMakeSuite() {
   testEnv.usdc = await getMintableErc20(usdcAddress);
   testEnv.lend = await getMintableErc20(lendAddress);
   testEnv.weth = await getMintableErc20(wethAddress);
+
+  testEnv.mockSwapAdapter = await getMockSwapAdapter()
 }
 
 export function makeSuite(name: string, tests: (testEnv: TestEnv) => void) {
diff --git a/test/helpers/utils/calculations.ts b/test/helpers/utils/calculations.ts
index 4ff03b19..13c8da78 100644
--- a/test/helpers/utils/calculations.ts
+++ b/test/helpers/utils/calculations.ts
@@ -7,9 +7,9 @@ import {
   EXCESS_UTILIZATION_RATE,
   ZERO_ADDRESS,
 } from '../../../helpers/constants';
-import { IReserveParams, iAavePoolAssets, RateMode } from '../../../helpers/types';
+import {IReserveParams, iAavePoolAssets, RateMode} from '../../../helpers/types';
 import './math';
-import { ReserveData, UserReserveData } from './interfaces';
+import {ReserveData, UserReserveData} from './interfaces';
 
 export const strToBN = (amount: string): BigNumber => new BigNumber(amount);
 
@@ -687,7 +687,7 @@ export const calcExpectedUserDataAfterSetUseAsCollateral = (
   userDataBeforeAction: UserReserveData,
   txCost: BigNumber
 ): UserReserveData => {
-  const expectedUserData = { ...userDataBeforeAction };
+  const expectedUserData = {...userDataBeforeAction};
 
   expectedUserData.usageAsCollateralEnabled = useAsCollateral;
 
@@ -793,7 +793,7 @@ export const calcExpectedUserDataAfterSwapRateMode = (
   txCost: BigNumber,
   txTimestamp: BigNumber
 ): UserReserveData => {
-  const expectedUserData = { ...userDataBeforeAction };
+  const expectedUserData = {...userDataBeforeAction};
 
   const variableBorrowBalance = calcExpectedVariableDebtTokenBalance(
     reserveDataBeforeAction,
@@ -937,7 +937,7 @@ export const calcExpectedUserDataAfterStableRateRebalance = (
   txCost: BigNumber,
   txTimestamp: BigNumber
 ): UserReserveData => {
-  const expectedUserData = { ...userDataBeforeAction };
+  const expectedUserData = {...userDataBeforeAction};
 
   expectedUserData.principalVariableDebt = calcExpectedVariableDebtTokenBalance(
     reserveDataBeforeAction,
@@ -992,8 +992,8 @@ export const calcExpectedUsersDataAfterRedirectInterest = (
   txCost: BigNumber,
   txTimestamp: BigNumber
 ): UserReserveData[] => {
-  const expectedFromData = { ...fromDataBeforeAction };
-  const expectedToData = { ...toDataBeforeAction };
+  const expectedFromData = {...fromDataBeforeAction};
+  const expectedToData = {...toDataBeforeAction};
 
   expectedFromData.currentStableDebt = calcExpectedStableDebtTokenBalance(
     fromDataBeforeAction,
@@ -1164,7 +1164,7 @@ export const calcExpectedVariableDebtTokenBalance = (
 ) => {
   const debt = calcExpectedReserveNormalizedDebt(reserveDataBeforeAction, currentTimestamp);
 
-  const { principalVariableDebt, variableBorrowIndex } = userDataBeforeAction;
+  const {principalVariableDebt, variableBorrowIndex} = userDataBeforeAction;
 
   if (variableBorrowIndex.eq(0)) {
     return principalVariableDebt;
@@ -1177,7 +1177,7 @@ export const calcExpectedStableDebtTokenBalance = (
   userDataBeforeAction: UserReserveData,
   currentTimestamp: BigNumber
 ) => {
-  const { principalStableDebt, stableBorrowRate, stableRateLastUpdated } = userDataBeforeAction;
+  const {principalStableDebt, stableBorrowRate, stableRateLastUpdated} = userDataBeforeAction;
 
   if (
     stableBorrowRate.eq(0) ||
@@ -1250,7 +1250,7 @@ const calcExpectedInterestRates = (
   totalBorrowsVariable: BigNumber,
   averageStableBorrowRate: BigNumber
 ): BigNumber[] => {
-  const { reservesParams } = configuration;
+  const {reservesParams} = configuration;
 
   const reserveIndex = Object.keys(reservesParams).findIndex((value) => value === reserveSymbol);
   const [, reserveConfiguration] = (Object.entries(reservesParams) as [string, IReserveParams][])[
@@ -1340,7 +1340,7 @@ const calcExpectedReserveNormalizedIncome = (
   reserveData: ReserveData,
   currentTimestamp: BigNumber
 ) => {
-  const { liquidityRate, liquidityIndex, lastUpdateTimestamp } = reserveData;
+  const {liquidityRate, liquidityIndex, lastUpdateTimestamp} = reserveData;
 
   //if utilization rate is 0, nothing to compound
   if (liquidityRate.eq('0')) {
@@ -1362,7 +1362,7 @@ const calcExpectedReserveNormalizedDebt = (
   reserveData: ReserveData,
   currentTimestamp: BigNumber
 ) => {
-  const { variableBorrowRate, variableBorrowIndex, lastUpdateTimestamp } = reserveData;
+  const {variableBorrowRate, variableBorrowIndex, lastUpdateTimestamp} = reserveData;
 
   //if utilization rate is 0, nothing to compound
   if (variableBorrowRate.eq('0')) {
diff --git a/test/liquidation-atoken.spec.ts b/test/liquidation-atoken.spec.ts
index 921114f0..9ee03e45 100644
--- a/test/liquidation-atoken.spec.ts
+++ b/test/liquidation-atoken.spec.ts
@@ -192,7 +192,7 @@ makeSuite('LendingPool liquidation - liquidator receiving aToken', (testEnv) =>
     );
 
     //the liquidity index of the principal reserve needs to be bigger than the index before
-    expect(daiReserveDataAfter.liquidityIndex.toString()).to.be.bignumber.gt(
+    expect(daiReserveDataAfter.liquidityIndex.toString()).to.be.bignumber.gte(
       daiReserveDataBefore.liquidityIndex.toString(),
       'Invalid liquidity index'
     );
@@ -213,6 +213,7 @@ makeSuite('LendingPool liquidation - liquidator receiving aToken', (testEnv) =>
     const {users, pool, usdc, oracle, weth} = testEnv;
     const depositor = users[3];
     const borrower = users[4];
+
     //mints USDC to depositor
     await usdc
       .connect(depositor.signer)
@@ -246,7 +247,7 @@ makeSuite('LendingPool liquidation - liquidator receiving aToken', (testEnv) =>
       usdc.address,
       new BigNumber(userGlobalData.availableBorrowsETH.toString())
         .div(usdcPrice.toString())
-        .multipliedBy(0.95)
+        .multipliedBy(0.9502)
         .toFixed(0)
     );
 
@@ -274,7 +275,7 @@ makeSuite('LendingPool liquidation - liquidator receiving aToken', (testEnv) =>
     const ethReserveDataBefore = await pool.getReserveData(weth.address);
 
     const amountToLiquidate = new BigNumber(userReserveDataBefore.currentStableDebt.toString())
-      .div(2)
+      .multipliedBy(0.5)
       .toFixed(0);
 
     await pool.liquidationCall(
@@ -328,7 +329,7 @@ makeSuite('LendingPool liquidation - liquidator receiving aToken', (testEnv) =>
     );
 
     //the liquidity index of the principal reserve needs to be bigger than the index before
-    expect(usdcReserveDataAfter.liquidityIndex.toString()).to.be.bignumber.gt(
+    expect(usdcReserveDataAfter.liquidityIndex.toString()).to.be.bignumber.gte(
       usdcReserveDataBefore.liquidityIndex.toString(),
       'Invalid liquidity index'
     );
diff --git a/test/liquidation-underlying.spec.ts b/test/liquidation-underlying.spec.ts
index 064e3856..9ae7f81b 100644
--- a/test/liquidation-underlying.spec.ts
+++ b/test/liquidation-underlying.spec.ts
@@ -1,6 +1,6 @@
 import BigNumber from 'bignumber.js';
 
-import {BRE} from '../helpers/misc-utils';
+import {BRE, increaseTime} from '../helpers/misc-utils';
 import {APPROVAL_AMOUNT_LENDING_POOL, oneEther} from '../helpers/constants';
 import {convertToCurrencyDecimals} from '../helpers/contracts-helpers';
 import {makeSuite} from './helpers/make-suite';
@@ -15,6 +15,14 @@ const {expect} = chai;
 makeSuite('LendingPool liquidation - liquidator receiving the underlying asset', (testEnv) => {
   const {INVALID_HF} = ProtocolErrors;
 
+  before('Before LendingPool liquidation: set config', () => {
+    BigNumber.config({DECIMAL_PLACES: 0, ROUNDING_MODE: BigNumber.ROUND_DOWN});
+  });
+
+  after('After LendingPool liquidation: reset config', () => {
+    BigNumber.config({DECIMAL_PLACES: 20, ROUNDING_MODE: BigNumber.ROUND_HALF_UP});
+  });
+
   it('LIQUIDATION - Deposits WETH, borrows DAI', async () => {
     const {dai, weth, users, pool, oracle} = testEnv;
     const depositor = users[0];
@@ -103,6 +111,8 @@ makeSuite('LendingPool liquidation - liquidator receiving the underlying asset',
 
     const amountToLiquidate = userReserveDataBefore.currentStableDebt.div(2).toFixed(0);
 
+    await increaseTime(100);
+
     const tx = await pool
       .connect(liquidator.signer)
       .liquidationCall(weth.address, dai.address, borrower.address, amountToLiquidate, false);
@@ -150,7 +160,7 @@ makeSuite('LendingPool liquidation - liquidator receiving the underlying asset',
     );
 
     //the liquidity index of the principal reserve needs to be bigger than the index before
-    expect(daiReserveDataAfter.liquidityIndex.toString()).to.be.bignumber.gt(
+    expect(daiReserveDataAfter.liquidityIndex.toString()).to.be.bignumber.gte(
       daiReserveDataBefore.liquidityIndex.toString(),
       'Invalid liquidity index'
     );
@@ -216,7 +226,7 @@ makeSuite('LendingPool liquidation - liquidator receiving the underlying asset',
       usdc.address,
       new BigNumber(userGlobalData.availableBorrowsETH.toString())
         .div(usdcPrice.toString())
-        .multipliedBy(0.95)
+        .multipliedBy(0.9502)
         .toFixed(0)
     );
 
@@ -244,10 +254,11 @@ makeSuite('LendingPool liquidation - liquidator receiving the underlying asset',
     const usdcReserveDataBefore = await pool.getReserveData(usdc.address);
     const ethReserveDataBefore = await pool.getReserveData(weth.address);
 
-    const amountToLiquidate = new BigNumber(userReserveDataBefore.currentStableDebt.toString())
+    const amountToLiquidate = BRE.ethers.BigNumber.from(
+      userReserveDataBefore.currentStableDebt.toString()
+    )
       .div(2)
-      .decimalPlaces(0, BigNumber.ROUND_DOWN)
-      .toFixed(0);
+      .toString();
 
     await pool
       .connect(liquidator.signer)
@@ -292,7 +303,7 @@ makeSuite('LendingPool liquidation - liquidator receiving the underlying asset',
     );
 
     //the liquidity index of the principal reserve needs to be bigger than the index before
-    expect(usdcReserveDataAfter.liquidityIndex.toString()).to.be.bignumber.gt(
+    expect(usdcReserveDataAfter.liquidityIndex.toString()).to.be.bignumber.gte(
       usdcReserveDataBefore.liquidityIndex.toString(),
       'Invalid liquidity index'
     );
diff --git a/test/repay-with-collateral.spec.ts b/test/repay-with-collateral.spec.ts
new file mode 100644
index 00000000..2fbe66fc
--- /dev/null
+++ b/test/repay-with-collateral.spec.ts
@@ -0,0 +1,640 @@
+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 {waitForTx} from './__setup.spec';
+import {timeLatest} from '../helpers/misc-utils';
+import {tEthereumAddress} from '../helpers/types';
+import {parse} from 'path';
+
+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) => {
+  it('User 1 provides some liquidity for others to borrow', async () => {
+    const {pool, weth, dai, usdc} = testEnv;
+
+    await weth.mint(parseEther('200'));
+    await weth.approve(pool.address, parseEther('200'));
+    await pool.deposit(weth.address, parseEther('200'), 0);
+    await dai.mint(parseEther('20000'));
+    await dai.approve(pool.address, parseEther('20000'));
+    await pool.deposit(dai.address, parseEther('20000'), 0);
+    await usdc.mint(parseEther('20000'));
+    await usdc.approve(pool.address, parseEther('20000'));
+    await pool.deposit(usdc.address, parseEther('20000'), 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, '0');
+
+    await pool.connect(user.signer).borrow(dai.address, amountToBorrow, 2, 0);
+  });
+
+  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} = 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 pool.getReserveConfigurationData(weth.address)
+    ).decimals.toString();
+    const principalDecimals = (
+      await pool.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, '0');
+
+    await pool.connect(user.signer).borrow(usdc.address, amountToBorrow, 2, 0);
+  });
+
+  it('User 3 repays completely his USDC loan by swapping his WETH collateral', async () => {
+    const {pool, weth, usdc, users, mockSwapAdapter, oracle} = 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 pool.getReserveConfigurationData(weth.address)
+    ).decimals.toString();
+    const principalDecimals = (
+      await pool.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} = 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, '0');
+
+    await pool.connect(user.signer).borrow(usdc.address, amountToBorrowVariable, 2, 0);
+
+    await pool.connect(user.signer).borrow(usdc.address, amountToBorrowStable, 1, 0);
+
+    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 pool.getReserveConfigurationData(weth.address)
+    ).decimals.toString();
+    const principalDecimals = (
+      await pool.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,
+      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} = 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, '0');
+    await pool.connect(user.signer).deposit(dai.address, amountToDepositDAI, '0');
+
+    await pool.connect(user.signer).borrow(dai.address, amountToBorrowVariable, 2, 0);
+
+    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 pool.getReserveConfigurationData(weth.address);
+
+    const collateralDecimals = collateralConfig.decimals.toString();
+    const principalDecimals = (
+      await pool.getReserveConfigurationData(dai.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(
+      daiReserveDataBefore,
+      daiUserDataBefore,
+      new BigNumber(repayWithCollateralTimestamp)
+    ).minus(daiUserDataBefore.currentVariableDebt);
+
+    expect(daiUserDataAfter.currentVariableDebt).to.be.bignumber.equal(
+      new BigNumber(daiUserDataBefore.currentVariableDebt)
+        .minus(expectedDebtCovered.toString())
+        .plus(expectedVariableDebtIncrease),
+      'INVALID_VARIABLE_DEBT_POSITION'
+    );
+
+    expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal(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, '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, '0');
+
+    await pool.connect(user.signer).borrow(usdc.address, amountToBorrow, 2, 0);
+  });
+
+  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} = 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 pool.getReserveConfigurationData(weth.address)
+    ).decimals.toString();
+    const principalDecimals = (
+      await pool.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;
+  });
+});
diff --git a/test/scenario.spec.ts b/test/scenario.spec.ts
index 5d449d76..54fe7433 100644
--- a/test/scenario.spec.ts
+++ b/test/scenario.spec.ts
@@ -8,8 +8,6 @@ import {getReservesConfigByPool} from '../helpers/constants';
 import {AavePools, iAavePoolAssets, IReserveParams} from '../helpers/types';
 import {executeStory} from './helpers/scenario-engine';
 
-BigNumber.config({DECIMAL_PLACES: 0, ROUNDING_MODE: BigNumber.ROUND_DOWN});
-
 const scenarioFolder = './test/helpers/scenarios/';
 
 const selectedScenarios: string[] = [];
@@ -21,12 +19,19 @@ fs.readdirSync(scenarioFolder).forEach((file) => {
 
   makeSuite(scenario.title, async (testEnv) => {
     before('Initializing configuration', async () => {
+      // Sets BigNumber for this suite, instead of globally
+      BigNumber.config({DECIMAL_PLACES: 0, ROUNDING_MODE: BigNumber.ROUND_DOWN});
+
       actionsConfiguration.skipIntegrityCheck = false; //set this to true to execute solidity-coverage
 
       calculationsConfiguration.reservesParams = <iAavePoolAssets<IReserveParams>>(
         getReservesConfigByPool(AavePools.proto)
       );
     });
+    after('Reset', () => {
+      // Reset BigNumber
+      BigNumber.config({DECIMAL_PLACES: 20, ROUNDING_MODE: BigNumber.ROUND_HALF_UP});
+    });
 
     for (const story of scenario.stories) {
       it(story.description, async () => {