diff --git a/contracts/adapters/BaseParaSwapAdapter.sol b/contracts/adapters/BaseParaSwapAdapter.sol
index 9b84dd93f..7fe34e587 100644
--- a/contracts/adapters/BaseParaSwapAdapter.sol
+++ b/contracts/adapters/BaseParaSwapAdapter.sol
@@ -37,11 +37,23 @@ abstract contract BaseParaSwapAdapter is FlashLoanReceiverBase, Ownable {
 
   IPriceOracleGetter public immutable ORACLE;
 
-  event Swapped(address indexed fromAsset, address indexed toAsset, uint256 fromAmount, uint256 receivedAmount);
+  event Swapped(
+    address indexed fromAsset,
+    address indexed toAsset,
+    uint256 fromAmount,
+    uint256 receivedAmount
+  );
+  event Bought(
+    address indexed fromAsset,
+    address indexed toAsset,
+    uint256 amountSold,
+    uint256 receivedAmount
+  );
 
-  constructor(
-    ILendingPoolAddressesProvider addressesProvider
-  ) public FlashLoanReceiverBase(addressesProvider) {
+  constructor(ILendingPoolAddressesProvider addressesProvider)
+    public
+    FlashLoanReceiverBase(addressesProvider)
+  {
     ORACLE = IPriceOracleGetter(addressesProvider.getPriceOracle());
   }
 
@@ -73,6 +85,17 @@ abstract contract BaseParaSwapAdapter is FlashLoanReceiverBase, Ownable {
     return LENDING_POOL.getReserveData(asset);
   }
 
+  function _pullATokenAndWithdraw(
+    address reserve,
+    address user,
+    uint256 amount,
+    PermitSignature memory permitSignature
+  ) internal {
+    IERC20WithPermit reserveAToken =
+      IERC20WithPermit(_getReserveData(address(reserve)).aTokenAddress);
+    _pullATokenAndWithdraw(reserve, reserveAToken, user, amount, permitSignature);
+  }
+
   /**
    * @dev Pull the ATokens from the user
    * @param reserve address of the asset
diff --git a/contracts/adapters/BaseParaSwapBuyAdapter.sol b/contracts/adapters/BaseParaSwapBuyAdapter.sol
new file mode 100644
index 000000000..60780987b
--- /dev/null
+++ b/contracts/adapters/BaseParaSwapBuyAdapter.sol
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: agpl-3.0
+pragma solidity 0.6.12;
+pragma experimental ABIEncoderV2;
+
+import {BaseParaSwapAdapter} from './BaseParaSwapAdapter.sol';
+import {PercentageMath} from '../protocol/libraries/math/PercentageMath.sol';
+import {IParaSwapAugustus} from '../interfaces/IParaSwapAugustus.sol';
+import {IParaSwapAugustusRegistry} from '../interfaces/IParaSwapAugustusRegistry.sol';
+import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
+import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol';
+
+/**
+ * @title BaseParaSwapBuyAdapter
+ * @notice Implements the logic for buying tokens on ParaSwap
+ */
+abstract contract BaseParaSwapBuyAdapter is BaseParaSwapAdapter {
+  using PercentageMath for uint256;
+
+  IParaSwapAugustusRegistry public immutable AUGUSTUS_REGISTRY;
+
+  constructor(
+    ILendingPoolAddressesProvider addressesProvider,
+    IParaSwapAugustusRegistry augustusRegistry
+  ) public BaseParaSwapAdapter(addressesProvider) {
+    // Do something on Augustus registry to check the right contract was passed
+    require(!augustusRegistry.isValidAugustus(address(0)), "Not a valid Augustus address");
+    AUGUSTUS_REGISTRY = augustusRegistry;
+  }
+
+  /**
+   * @dev Swaps a token for another using ParaSwap
+   * @param toAmountOffset Offset of toAmount in Augustus calldata if it should be overwritten, otherwise 0
+   * @param paraswapData Data for Paraswap Adapter
+   * @param assetToSwapFrom Address of the asset to be swapped from
+   * @param assetToSwapTo Address of the asset to be swapped to
+   * @param maxAmountToSwap Max amount to be swapped
+   * @param amountToReceive Amount to be received from the swap
+   * @return amountSold The amount sold during the swap
+   */
+  function _buyOnParaSwap(
+    uint256 toAmountOffset,
+    bytes memory paraswapData,
+    IERC20Detailed assetToSwapFrom,
+    IERC20Detailed assetToSwapTo,
+    uint256 maxAmountToSwap,
+    uint256 amountToReceive
+  ) internal returns (uint256 amountSold) {
+    (bytes memory buyCalldata, IParaSwapAugustus augustus) =
+      abi.decode(paraswapData, (bytes, IParaSwapAugustus));
+
+    require(AUGUSTUS_REGISTRY.isValidAugustus(address(augustus)), 'INVALID_AUGUSTUS');
+
+    {
+      uint256 fromAssetDecimals = _getDecimals(assetToSwapFrom);
+      uint256 toAssetDecimals = _getDecimals(assetToSwapTo);
+
+      uint256 fromAssetPrice = _getPrice(address(assetToSwapFrom));
+      uint256 toAssetPrice = _getPrice(address(assetToSwapTo));
+
+      uint256 expectedMaxAmountToSwap =
+        amountToReceive
+          .mul(toAssetPrice.mul(10**fromAssetDecimals))
+          .div(fromAssetPrice.mul(10**toAssetDecimals))
+          .percentMul(PercentageMath.PERCENTAGE_FACTOR.add(MAX_SLIPPAGE_PERCENT));
+
+      require(maxAmountToSwap <= expectedMaxAmountToSwap, 'maxAmountToSwap exceed max slippage');
+    }
+
+    uint256 balanceBeforeAssetFrom = assetToSwapFrom.balanceOf(address(this));
+    require(balanceBeforeAssetFrom >= maxAmountToSwap, 'INSUFFICIENT_BALANCE_BEFORE_SWAP');
+    uint256 balanceBeforeAssetTo = assetToSwapTo.balanceOf(address(this));
+
+    address tokenTransferProxy = augustus.getTokenTransferProxy();
+    assetToSwapFrom.safeApprove(tokenTransferProxy, 0);
+    assetToSwapFrom.safeApprove(tokenTransferProxy, maxAmountToSwap);
+
+    if (toAmountOffset != 0) {
+      // Ensure 256 bit (32 bytes) toAmountOffset value is within bounds of the
+      // calldata, not overlapping with the first 4 bytes (function selector).
+      require(
+        toAmountOffset >= 4 && toAmountOffset <= buyCalldata.length.sub(32),
+        'TO_AMOUNT_OFFSET_OUT_OF_RANGE'
+      );
+      // Overwrite the toAmount with the correct amount for the buy.
+      // In memory, buyCalldata consists of a 256 bit length field, followed by
+      // the actual bytes data, that is why 32 is added to the byte offset.
+      assembly {
+        mstore(add(buyCalldata, add(toAmountOffset, 32)), amountToReceive)
+      }
+    }
+    (bool success, ) = address(augustus).call(buyCalldata);
+    if (!success) {
+      // Copy revert reason from call
+      assembly {
+        returndatacopy(0, 0, returndatasize())
+        revert(0, returndatasize())
+      }
+    }
+
+    uint256 balanceAfterAssetFrom = assetToSwapFrom.balanceOf(address(this));
+    amountSold = balanceBeforeAssetFrom - balanceAfterAssetFrom;
+    require(amountSold <= maxAmountToSwap, 'WRONG_BALANCE_AFTER_SWAP');
+    uint256 amountReceived = assetToSwapTo.balanceOf(address(this)).sub(balanceBeforeAssetTo);
+    require(amountReceived >= amountToReceive, 'INSUFFICIENT_AMOUNT_RECEIVED');
+
+    emit Bought(address(assetToSwapFrom), address(assetToSwapTo), amountSold, amountReceived);
+  }
+}
diff --git a/contracts/adapters/ParaSwapRepayAdapter.sol b/contracts/adapters/ParaSwapRepayAdapter.sol
new file mode 100644
index 000000000..99fc67068
--- /dev/null
+++ b/contracts/adapters/ParaSwapRepayAdapter.sol
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: agpl-3.0
+pragma solidity 0.6.12;
+pragma experimental ABIEncoderV2;
+
+import {BaseParaSwapBuyAdapter} from './BaseParaSwapBuyAdapter.sol';
+import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
+import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
+import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
+import {IParaSwapAugustus} from '../interfaces/IParaSwapAugustus.sol';
+import {IParaSwapAugustusRegistry} from '../interfaces/IParaSwapAugustusRegistry.sol';
+import {ReentrancyGuard} from '../dependencies/openzeppelin/contracts/ReentrancyGuard.sol';
+import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol';
+import {IERC20WithPermit} from '../interfaces/IERC20WithPermit.sol';
+
+/**
+ * @title UniswapRepayAdapter
+ * @notice Uniswap V2 Adapter to perform a repay of a debt with collateral.
+ * @author Aave
+ **/
+contract ParaSwapRepayAdapter is BaseParaSwapBuyAdapter, ReentrancyGuard {
+  struct RepayParams {
+    address collateralAsset;
+    uint256 collateralAmount;
+    uint256 rateMode;
+    PermitSignature permitSignature;
+    bool useEthPath;
+  }
+
+  constructor(
+    ILendingPoolAddressesProvider addressesProvider,
+    IParaSwapAugustusRegistry augustusRegistry
+  ) public BaseParaSwapBuyAdapter(addressesProvider, augustusRegistry) {
+    // This is only required to initialize BaseParaSwapBuyAdapter
+  }
+
+  /**
+   * @dev Uses the received funds from the flash loan to repay a debt on the protocol on behalf of the user. Then pulls
+   * the collateral from the user and swaps it to the debt asset to repay the flash loan.
+   * The user should give this contract allowance to pull the ATokens in order to withdraw the underlying asset, swap it
+   * and repay the flash loan.
+   * Supports only one asset on the flash loan.
+   * @param assets Address of collateral asset(Flash loan asset)
+   * @param amounts Amount of flash loan taken
+   * @param premiums Fee of the flash loan
+   * @param initiator Address of the user
+   * @param params Additional variadic field to include extra params. Expected parameters:
+   *   IERC20Detailed debtAsset Address of the debt asset
+   *   uint256 debtAmount Amount of debt to be repaid
+   *   uint256 rateMode Rate modes of the debt to be repaid
+   *   uint256 deadline Deadline for the permit signature
+   *   uint256 debtRateMode Rate mode of the debt to be repaid
+   *   bytes paraswapData Paraswap Data
+   *                    * bytes buyCallData Call data for augustus
+   *                    * IParaSwapAugustus augustus Address of Augustus Swapper
+   *   PermitSignature permitParams Struct containing the permit signatures, set to all zeroes if not used
+   */
+  function executeOperation(
+    address[] calldata assets,
+    uint256[] calldata amounts,
+    uint256[] calldata premiums,
+    address initiator,
+    bytes calldata params
+  ) external override nonReentrant returns (bool) {
+    require(msg.sender == address(LENDING_POOL), 'CALLER_MUST_BE_LENDING_POOL');
+
+    require(
+      assets.length == 1 && amounts.length == 1 && premiums.length == 1,
+      'FLASHLOAN_MULTIPLE_ASSETS_NOT_SUPPORTED'
+    );
+
+    uint256 collateralAmount = amounts[0];
+    uint256 premium = premiums[0];
+    address initiatorLocal = initiator;
+
+    IERC20Detailed collateralAsset = IERC20Detailed(assets[0]);
+
+    _swapAndRepay(params, premium, initiatorLocal, collateralAsset, collateralAmount);
+
+    return true;
+  }
+
+  /**
+   * @dev Swaps the user collateral for the debt asset and then repay the debt on the protocol on behalf of the user
+   * without using flash loans. This method can be used when the temporary transfer of the collateral asset to this
+   * contract does not affect the user position.
+   * The user should give this contract allowance to pull the ATokens in order to withdraw the underlying asset
+   * @param collateralAsset Address of asset to be swapped
+   * @param debtAsset Address of debt asset
+   * @param collateralAmount max Amount of the collateral to be swapped
+   * @param debtRepayAmount Amount of the debt to be repaid, or maximum amount when repaying entire debt
+   * @param debtRateMode Rate mode of the debt to be repaid
+   * @param buyAllBalanceOffset Set to offset of toAmount in Augustus calldata if wanting to pay entire debt, otherwise 0
+   * @param paraswapData Data for Paraswap Adapter
+   * @param permitSignature struct containing the permit signature
+
+   */
+  function swapAndRepay(
+    IERC20Detailed collateralAsset,
+    IERC20Detailed debtAsset,
+    uint256 collateralAmount,
+    uint256 debtRepayAmount,
+    uint256 debtRateMode,
+    uint256 buyAllBalanceOffset,
+    bytes calldata paraswapData,
+    PermitSignature calldata permitSignature
+  ) external nonReentrant {
+    debtRepayAmount = getDebtRepayAmount(
+      debtAsset,
+      debtRateMode,
+      buyAllBalanceOffset,
+      debtRepayAmount,
+      msg.sender
+    );
+
+    // Pull aTokens from user
+    _pullATokenAndWithdraw(address(collateralAsset), msg.sender, collateralAmount, permitSignature);
+    //buy debt asset using collateral asset
+    uint256 amountSold =
+      _buyOnParaSwap(
+        buyAllBalanceOffset,
+        paraswapData,
+        collateralAsset,
+        debtAsset,
+        collateralAmount,
+        debtRepayAmount
+      );
+
+    uint256 collateralBalanceLeft = collateralAmount - amountSold;
+
+    //deposit collateral back in the pool, if left after the swap(buy)
+    if (collateralBalanceLeft > 0) {
+      IERC20(collateralAsset).safeApprove(address(LENDING_POOL), 0);
+      IERC20(collateralAsset).safeApprove(address(LENDING_POOL), collateralBalanceLeft);
+      LENDING_POOL.deposit(address(collateralAsset), collateralBalanceLeft, msg.sender, 0);
+    }
+
+    // Repay debt. Approves 0 first to comply with tokens that implement the anti frontrunning approval fix
+    IERC20(debtAsset).safeApprove(address(LENDING_POOL), 0);
+    IERC20(debtAsset).safeApprove(address(LENDING_POOL), debtRepayAmount);
+    LENDING_POOL.repay(address(debtAsset), debtRepayAmount, debtRateMode, msg.sender);
+  }
+
+  /**
+   * @dev Perform the repay of the debt, pulls the initiator collateral and swaps to repay the flash loan
+   * @param premium Fee of the flash loan
+   * @param initiator Address of the user
+   * @param collateralAsset Address of token to be swapped
+   * @param collateralAmount Amount of the reserve to be swapped(flash loan amount)
+   */
+
+  function _swapAndRepay(
+    bytes calldata params,
+    uint256 premium,
+    address initiator,
+    IERC20Detailed collateralAsset,
+    uint256 collateralAmount
+  ) private {
+    (
+      IERC20Detailed debtAsset,
+      uint256 debtRepayAmount,
+      uint256 buyAllBalanceOffset,
+      uint256 rateMode,
+      bytes memory paraswapData,
+      PermitSignature memory permitSignature
+    ) = abi.decode(params, (IERC20Detailed, uint256, uint256, uint256, bytes, PermitSignature));
+
+    debtRepayAmount = getDebtRepayAmount(
+      debtAsset,
+      rateMode,
+      buyAllBalanceOffset,
+      debtRepayAmount,
+      initiator
+    );
+
+    uint256 amountSold = debtRepayAmount;
+
+    if (collateralAsset != debtAsset) {
+      amountSold = _buyOnParaSwap(
+        buyAllBalanceOffset,
+        paraswapData,
+        collateralAsset,
+        debtAsset,
+        collateralAmount,
+        debtRepayAmount
+      );
+    }
+
+    // Repay debt. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.
+    IERC20(debtAsset).safeApprove(address(LENDING_POOL), 0);
+    IERC20(debtAsset).safeApprove(address(LENDING_POOL), debtRepayAmount);
+    LENDING_POOL.repay(address(debtAsset), debtRepayAmount, rateMode, initiator);
+
+    uint256 neededForFlashLoanRepay = amountSold.add(premium);
+
+    // Pull aTokens from user
+    _pullATokenAndWithdraw(
+      address(collateralAsset),
+      initiator,
+      neededForFlashLoanRepay,
+      permitSignature
+    );
+
+    // Repay flashloan. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.
+    IERC20(collateralAsset).safeApprove(address(LENDING_POOL), 0);
+    IERC20(collateralAsset).safeApprove(address(LENDING_POOL), collateralAmount.add(premium));
+  }
+
+  function getDebtRepayAmount(
+    IERC20Detailed debtAsset,
+    uint256 rateMode,
+    uint256 buyAllBalanceOffset,
+    uint256 debtRepayAmount,
+    address initiator
+  ) private view returns (uint256) {
+    DataTypes.ReserveData memory debtReserveData = _getReserveData(address(debtAsset));
+
+    address debtToken =
+      DataTypes.InterestRateMode(rateMode) == DataTypes.InterestRateMode.STABLE
+        ? debtReserveData.stableDebtTokenAddress
+        : debtReserveData.variableDebtTokenAddress;
+
+    uint256 currentDebt = IERC20(debtToken).balanceOf(initiator);
+
+    if (buyAllBalanceOffset != 0) {
+      require(currentDebt <= debtRepayAmount, 'INSUFFICIENT_AMOUNT_TO_REPAY');
+      debtRepayAmount = currentDebt;
+    } else {
+      require(debtRepayAmount <= currentDebt, 'INVALID_DEBT_REPAY_AMOUNT');
+    }
+
+    return debtRepayAmount;
+  }
+}
diff --git a/contracts/interfaces/IChainlinkAggregator.sol b/contracts/interfaces/IChainlinkAggregator.sol
index 756863712..4b8c40df8 100644
--- a/contracts/interfaces/IChainlinkAggregator.sol
+++ b/contracts/interfaces/IChainlinkAggregator.sol
@@ -3,7 +3,7 @@ pragma solidity 0.6.12;
 
 interface IChainlinkAggregator {
   function decimals() external view returns (uint8);
-  
+
   function latestAnswer() external view returns (int256);
 
   function latestTimestamp() external view returns (uint256);
@@ -16,4 +16,4 @@ interface IChainlinkAggregator {
 
   event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 timestamp);
   event NewRound(uint256 indexed roundId, address indexed startedBy);
-}
\ No newline at end of file
+}
diff --git a/contracts/misc/UiIncentiveDataProviderV2.sol b/contracts/misc/UiIncentiveDataProviderV2.sol
index 56b3c0b89..5ba549b4b 100644
--- a/contracts/misc/UiIncentiveDataProviderV2.sol
+++ b/contracts/misc/UiIncentiveDataProviderV2.sol
@@ -52,7 +52,9 @@ contract UiIncentiveDataProviderV2 is IUiIncentiveDataProviderV2 {
 
       DataTypes.ReserveData memory baseData = lendingPool.getReserveData(reserves[i]);
 
-      try IStableDebtToken(baseData.aTokenAddress).getIncentivesController() returns (IAaveIncentivesController aTokenIncentiveController) {
+      try IStableDebtToken(baseData.aTokenAddress).getIncentivesController() returns (
+        IAaveIncentivesController aTokenIncentiveController
+      ) {
         if (address(aTokenIncentiveController) != address(0)) {
           address aRewardToken = aTokenIncentiveController.REWARD_TOKEN();
 
@@ -72,7 +74,9 @@ contract UiIncentiveDataProviderV2 is IUiIncentiveDataProviderV2 {
               IERC20Detailed(aRewardToken).decimals(),
               aTokenIncentiveController.PRECISION()
             );
-          } catch (bytes memory /*lowLevelData*/) {
+          } catch (
+            bytes memory /*lowLevelData*/
+          ) {
             (
               uint256 aEmissionPerSecond,
               uint256 aIncentivesLastUpdateTimestamp,
@@ -90,15 +94,18 @@ contract UiIncentiveDataProviderV2 is IUiIncentiveDataProviderV2 {
               IERC20Detailed(aRewardToken).decimals(),
               aTokenIncentiveController.PRECISION()
             );
-          } 
+          }
         }
-      } catch(bytes memory /*lowLevelData*/) {
+      } catch (
+        bytes memory /*lowLevelData*/
+      ) {
         // Will not get here
-      } 
+      }
 
-      try IStableDebtToken(baseData.stableDebtTokenAddress).getIncentivesController() returns (IAaveIncentivesController sTokenIncentiveController) {
+      try IStableDebtToken(baseData.stableDebtTokenAddress).getIncentivesController() returns (
+        IAaveIncentivesController sTokenIncentiveController
+      ) {
         if (address(sTokenIncentiveController) != address(0)) {
-
           address sRewardToken = sTokenIncentiveController.REWARD_TOKEN();
           try sTokenIncentiveController.getAssetData(baseData.stableDebtTokenAddress) returns (
             uint256 sTokenIncentivesIndex,
@@ -116,7 +123,9 @@ contract UiIncentiveDataProviderV2 is IUiIncentiveDataProviderV2 {
               IERC20Detailed(sRewardToken).decimals(),
               sTokenIncentiveController.PRECISION()
             );
-          } catch (bytes memory /*lowLevelData*/) {
+          } catch (
+            bytes memory /*lowLevelData*/
+          ) {
             (
               uint256 sEmissionPerSecond,
               uint256 sIncentivesLastUpdateTimestamp,
@@ -134,13 +143,17 @@ contract UiIncentiveDataProviderV2 is IUiIncentiveDataProviderV2 {
               IERC20Detailed(sRewardToken).decimals(),
               sTokenIncentiveController.PRECISION()
             );
-          } 
+          }
         }
-      } catch(bytes memory /*lowLevelData*/) {
+      } catch (
+        bytes memory /*lowLevelData*/
+      ) {
         // Will not get here
       }
 
-      try IStableDebtToken(baseData.variableDebtTokenAddress).getIncentivesController() returns (IAaveIncentivesController vTokenIncentiveController) {
+      try IStableDebtToken(baseData.variableDebtTokenAddress).getIncentivesController() returns (
+        IAaveIncentivesController vTokenIncentiveController
+      ) {
         if (address(vTokenIncentiveController) != address(0)) {
           address vRewardToken = vTokenIncentiveController.REWARD_TOKEN();
 
@@ -160,7 +173,9 @@ contract UiIncentiveDataProviderV2 is IUiIncentiveDataProviderV2 {
               IERC20Detailed(vRewardToken).decimals(),
               vTokenIncentiveController.PRECISION()
             );
-          } catch (bytes memory /*lowLevelData*/) {
+          } catch (
+            bytes memory /*lowLevelData*/
+          ) {
             (
               uint256 vEmissionPerSecond,
               uint256 vIncentivesLastUpdateTimestamp,
@@ -180,7 +195,9 @@ contract UiIncentiveDataProviderV2 is IUiIncentiveDataProviderV2 {
             );
           }
         }
-      } catch(bytes memory /*lowLevelData*/) {
+      } catch (
+        bytes memory /*lowLevelData*/
+      ) {
         // Will not get here
       }
     }
@@ -215,74 +232,77 @@ contract UiIncentiveDataProviderV2 is IUiIncentiveDataProviderV2 {
 
       IUiIncentiveDataProviderV2.UserIncentiveData memory aUserIncentiveData;
 
-      try IAToken(baseData.aTokenAddress).getIncentivesController() returns (IAaveIncentivesController aTokenIncentiveController) {
+      try IAToken(baseData.aTokenAddress).getIncentivesController() returns (
+        IAaveIncentivesController aTokenIncentiveController
+      ) {
         if (address(aTokenIncentiveController) != address(0)) {
           address aRewardToken = aTokenIncentiveController.REWARD_TOKEN();
           aUserIncentiveData.tokenincentivesUserIndex = aTokenIncentiveController.getUserAssetData(
             user,
             baseData.aTokenAddress
           );
-          aUserIncentiveData.userUnclaimedRewards = aTokenIncentiveController.getUserUnclaimedRewards(
-            user
-          );
+          aUserIncentiveData.userUnclaimedRewards = aTokenIncentiveController
+            .getUserUnclaimedRewards(user);
           aUserIncentiveData.tokenAddress = baseData.aTokenAddress;
           aUserIncentiveData.rewardTokenAddress = aRewardToken;
           aUserIncentiveData.incentiveControllerAddress = address(aTokenIncentiveController);
           aUserIncentiveData.rewardTokenDecimals = IERC20Detailed(aRewardToken).decimals();
         }
-      } catch (bytes memory /*lowLevelData*/) {
-
-      }
+      } catch (
+        bytes memory /*lowLevelData*/
+      ) {}
 
       userReservesIncentivesData[i].aTokenIncentivesUserData = aUserIncentiveData;
 
       UserIncentiveData memory vUserIncentiveData;
 
-      try IVariableDebtToken(baseData.variableDebtTokenAddress).getIncentivesController() returns(IAaveIncentivesController vTokenIncentiveController) {
+      try IVariableDebtToken(baseData.variableDebtTokenAddress).getIncentivesController() returns (
+        IAaveIncentivesController vTokenIncentiveController
+      ) {
         if (address(vTokenIncentiveController) != address(0)) {
           address vRewardToken = vTokenIncentiveController.REWARD_TOKEN();
           vUserIncentiveData.tokenincentivesUserIndex = vTokenIncentiveController.getUserAssetData(
             user,
             baseData.variableDebtTokenAddress
           );
-          vUserIncentiveData.userUnclaimedRewards = vTokenIncentiveController.getUserUnclaimedRewards(
-            user
-          );
+          vUserIncentiveData.userUnclaimedRewards = vTokenIncentiveController
+            .getUserUnclaimedRewards(user);
           vUserIncentiveData.tokenAddress = baseData.variableDebtTokenAddress;
           vUserIncentiveData.rewardTokenAddress = vRewardToken;
           vUserIncentiveData.incentiveControllerAddress = address(vTokenIncentiveController);
           vUserIncentiveData.rewardTokenDecimals = IERC20Detailed(vRewardToken).decimals();
         }
-      } catch (bytes memory /*lowLevelData*/) {
-
-      }
+      } catch (
+        bytes memory /*lowLevelData*/
+      ) {}
 
       userReservesIncentivesData[i].vTokenIncentivesUserData = vUserIncentiveData;
 
       UserIncentiveData memory sUserIncentiveData;
 
-      try IStableDebtToken(baseData.stableDebtTokenAddress).getIncentivesController() returns (IAaveIncentivesController sTokenIncentiveController) {
+      try IStableDebtToken(baseData.stableDebtTokenAddress).getIncentivesController() returns (
+        IAaveIncentivesController sTokenIncentiveController
+      ) {
         if (address(sTokenIncentiveController) != address(0)) {
           address sRewardToken = sTokenIncentiveController.REWARD_TOKEN();
           sUserIncentiveData.tokenincentivesUserIndex = sTokenIncentiveController.getUserAssetData(
             user,
             baseData.stableDebtTokenAddress
           );
-          sUserIncentiveData.userUnclaimedRewards = sTokenIncentiveController.getUserUnclaimedRewards(
-            user
-          );
+          sUserIncentiveData.userUnclaimedRewards = sTokenIncentiveController
+            .getUserUnclaimedRewards(user);
           sUserIncentiveData.tokenAddress = baseData.stableDebtTokenAddress;
           sUserIncentiveData.rewardTokenAddress = sRewardToken;
           sUserIncentiveData.incentiveControllerAddress = address(sTokenIncentiveController);
           sUserIncentiveData.rewardTokenDecimals = IERC20Detailed(sRewardToken).decimals();
         }
-      } catch (bytes memory /*lowLevelData*/) {
-
-      }
+      } catch (
+        bytes memory /*lowLevelData*/
+      ) {}
 
       userReservesIncentivesData[i].sTokenIncentivesUserData = sUserIncentiveData;
     }
 
     return (userReservesIncentivesData);
   }
-}
\ No newline at end of file
+}
diff --git a/contracts/misc/UiIncentiveDataProviderV2V3.sol b/contracts/misc/UiIncentiveDataProviderV2V3.sol
index 5c2dff1ae..eff299f1d 100644
--- a/contracts/misc/UiIncentiveDataProviderV2V3.sol
+++ b/contracts/misc/UiIncentiveDataProviderV2V3.sol
@@ -46,8 +46,8 @@ contract UiIncentiveDataProviderV2V3 is IUiIncentiveDataProviderV3 {
   {
     ILendingPool lendingPool = ILendingPool(provider.getLendingPool());
     address[] memory reserves = lendingPool.getReservesList();
-    AggregatedReserveIncentiveData[]
-      memory reservesIncentiveData = new AggregatedReserveIncentiveData[](reserves.length);
+    AggregatedReserveIncentiveData[] memory reservesIncentiveData =
+      new AggregatedReserveIncentiveData[](reserves.length);
 
     for (uint256 i = 0; i < reserves.length; i++) {
       AggregatedReserveIncentiveData memory reserveIncentiveData = reservesIncentiveData[i];
@@ -67,20 +67,19 @@ contract UiIncentiveDataProviderV2V3 is IUiIncentiveDataProviderV3 {
             uint256 aEmissionPerSecond,
             uint256 aIncentivesLastUpdateTimestamp
           ) {
-
-              aRewardsInformation[0] = RewardInfo(
-                getSymbol(aRewardToken),
-                aRewardToken,
-                address(0),
-                aEmissionPerSecond,
-                aIncentivesLastUpdateTimestamp,
-                aTokenIncentivesIndex,
-                aTokenIncentiveController.DISTRIBUTION_END(),
-                0,
-                IERC20Detailed(aRewardToken).decimals(),
-                aTokenIncentiveController.PRECISION(),
-                0
-              );
+            aRewardsInformation[0] = RewardInfo(
+              getSymbol(aRewardToken),
+              aRewardToken,
+              address(0),
+              aEmissionPerSecond,
+              aIncentivesLastUpdateTimestamp,
+              aTokenIncentivesIndex,
+              aTokenIncentiveController.DISTRIBUTION_END(),
+              0,
+              IERC20Detailed(aRewardToken).decimals(),
+              aTokenIncentiveController.PRECISION(),
+              0
+            );
             reserveIncentiveData.aIncentiveData = IncentiveData(
               baseData.aTokenAddress,
               address(aTokenIncentiveController),
@@ -274,9 +273,8 @@ contract UiIncentiveDataProviderV2V3 is IUiIncentiveDataProviderV3 {
     ILendingPool lendingPool = ILendingPool(provider.getLendingPool());
     address[] memory reserves = lendingPool.getReservesList();
 
-    UserReserveIncentiveData[] memory userReservesIncentivesData = new UserReserveIncentiveData[](
-      user != address(0) ? reserves.length : 0
-    );
+    UserReserveIncentiveData[] memory userReservesIncentivesData =
+      new UserReserveIncentiveData[](user != address(0) ? reserves.length : 0);
 
     for (uint256 i = 0; i < reserves.length; i++) {
       DataTypes.ReserveData memory baseData = lendingPool.getReserveData(reserves[i]);
@@ -395,4 +393,4 @@ contract UiIncentiveDataProviderV2V3 is IUiIncentiveDataProviderV3 {
     }
     return string(bytesArray);
   }
-}
\ No newline at end of file
+}
diff --git a/contracts/misc/UiPoolDataProvider.sol b/contracts/misc/UiPoolDataProvider.sol
index 8c01f81c2..d3bf1c52a 100644
--- a/contracts/misc/UiPoolDataProvider.sol
+++ b/contracts/misc/UiPoolDataProvider.sol
@@ -142,13 +142,13 @@ contract UiPoolDataProvider is IUiPoolDataProvider {
           reserveData.aEmissionPerSecond,
           reserveData.aIncentivesLastUpdateTimestamp
         ) = incentivesController.getAssetData(reserveData.aTokenAddress);
-     
+
         (
           reserveData.sTokenIncentivesIndex,
           reserveData.sEmissionPerSecond,
           reserveData.sIncentivesLastUpdateTimestamp
         ) = incentivesController.getAssetData(reserveData.stableDebtTokenAddress);
-     
+
         (
           reserveData.vTokenIncentivesIndex,
           reserveData.vEmissionPerSecond,
@@ -315,14 +315,14 @@ contract UiPoolDataProvider is IUiPoolDataProvider {
           reserveData.aTokenIncentivesIndex,
           reserveData.aEmissionPerSecond,
           reserveData.aIncentivesLastUpdateTimestamp
-        ) = incentivesController.getAssetData(reserveData.aTokenAddress); 
-     
+        ) = incentivesController.getAssetData(reserveData.aTokenAddress);
+
         (
           reserveData.sTokenIncentivesIndex,
           reserveData.sEmissionPerSecond,
           reserveData.sIncentivesLastUpdateTimestamp
         ) = incentivesController.getAssetData(reserveData.stableDebtTokenAddress);
-     
+
         (
           reserveData.vTokenIncentivesIndex,
           reserveData.vEmissionPerSecond,
diff --git a/contracts/misc/UiPoolDataProviderV2.sol b/contracts/misc/UiPoolDataProviderV2.sol
index bb561683f..583a56992 100644
--- a/contracts/misc/UiPoolDataProviderV2.sol
+++ b/contracts/misc/UiPoolDataProviderV2.sol
@@ -15,7 +15,9 @@ import {ReserveConfiguration} from '../protocol/libraries/configuration/ReserveC
 import {UserConfiguration} from '../protocol/libraries/configuration/UserConfiguration.sol';
 import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
 import {IChainlinkAggregator} from '../interfaces/IChainlinkAggregator.sol';
-import {DefaultReserveInterestRateStrategy} from '../protocol/lendingpool/DefaultReserveInterestRateStrategy.sol';
+import {
+  DefaultReserveInterestRateStrategy
+} from '../protocol/lendingpool/DefaultReserveInterestRateStrategy.sol';
 import {IERC20DetailedBytes} from './interfaces/IERC20DetailedBytes.sol';
 
 contract UiPoolDataProviderV2 is IUiPoolDataProviderV2 {
@@ -80,9 +82,8 @@ contract UiPoolDataProviderV2 is IUiPoolDataProviderV2 {
       reserveData.underlyingAsset = reserves[i];
 
       // reserve current state
-      DataTypes.ReserveData memory baseData = lendingPool.getReserveData(
-        reserveData.underlyingAsset
-      );
+      DataTypes.ReserveData memory baseData =
+        lendingPool.getReserveData(reserveData.underlyingAsset);
       reserveData.liquidityIndex = baseData.liquidityIndex;
       reserveData.variableBorrowIndex = baseData.variableBorrowIndex;
       reserveData.liquidityRate = baseData.currentLiquidityRate;
@@ -150,8 +151,8 @@ contract UiPoolDataProviderV2 is IUiPoolDataProviderV2 {
       if (ETH_CURRENCY_UNIT == baseCurrencyUnit) {
         baseCurrencyInfo.marketReferenceCurrencyUnit = ETH_CURRENCY_UNIT;
         baseCurrencyInfo
-        .marketReferenceCurrencyPriceInUsd = marketReferenceCurrencyPriceInUsdProxyAggregator
-        .latestAnswer();
+          .marketReferenceCurrencyPriceInUsd = marketReferenceCurrencyPriceInUsdProxyAggregator
+          .latestAnswer();
       } else {
         baseCurrencyInfo.marketReferenceCurrencyUnit = baseCurrencyUnit;
         baseCurrencyInfo.marketReferenceCurrencyPriceInUsd = int256(baseCurrencyUnit);
@@ -178,9 +179,8 @@ contract UiPoolDataProviderV2 is IUiPoolDataProviderV2 {
     address[] memory reserves = lendingPool.getReservesList();
     DataTypes.UserConfigurationMap memory userConfig = lendingPool.getUserConfiguration(user);
 
-    UserReserveData[] memory userReservesData = new UserReserveData[](
-      user != address(0) ? reserves.length : 0
-    );
+    UserReserveData[] memory userReservesData =
+      new UserReserveData[](user != address(0) ? reserves.length : 0);
 
     for (uint256 i = 0; i < reserves.length; i++) {
       DataTypes.ReserveData memory baseData = lendingPool.getReserveData(reserves[i]);
@@ -194,16 +194,20 @@ contract UiPoolDataProviderV2 is IUiPoolDataProviderV2 {
 
       if (userConfig.isBorrowing(i)) {
         userReservesData[i].scaledVariableDebt = IVariableDebtToken(
-          baseData.variableDebtTokenAddress
-        ).scaledBalanceOf(user);
+          baseData
+            .variableDebtTokenAddress
+        )
+          .scaledBalanceOf(user);
         userReservesData[i].principalStableDebt = IStableDebtToken(baseData.stableDebtTokenAddress)
           .principalBalanceOf(user);
         if (userReservesData[i].principalStableDebt != 0) {
           userReservesData[i].stableBorrowRate = IStableDebtToken(baseData.stableDebtTokenAddress)
             .getUserStableRate(user);
           userReservesData[i].stableBorrowLastUpdateTimestamp = IStableDebtToken(
-            baseData.stableDebtTokenAddress
-          ).getUserLastUpdated(user);
+            baseData
+              .stableDebtTokenAddress
+          )
+            .getUserLastUpdated(user);
         }
       }
     }
@@ -222,4 +226,4 @@ contract UiPoolDataProviderV2 is IUiPoolDataProviderV2 {
     }
     return string(bytesArray);
   }
-}
\ No newline at end of file
+}
diff --git a/contracts/misc/UiPoolDataProviderV2V3.sol b/contracts/misc/UiPoolDataProviderV2V3.sol
index cf9a59296..9b90d34d0 100644
--- a/contracts/misc/UiPoolDataProviderV2V3.sol
+++ b/contracts/misc/UiPoolDataProviderV2V3.sol
@@ -238,4 +238,4 @@ contract UiPoolDataProviderV2V3 is IUiPoolDataProviderV3 {
     }
     return string(bytesArray);
   }
-}
+}
\ No newline at end of file
diff --git a/contracts/misc/interfaces/IAaveOracle.sol b/contracts/misc/interfaces/IAaveOracle.sol
index 4c6014162..0bb0c6d8d 100644
--- a/contracts/misc/interfaces/IAaveOracle.sol
+++ b/contracts/misc/interfaces/IAaveOracle.sol
@@ -8,6 +8,7 @@ pragma solidity 0.6.12;
 
 interface IAaveOracle {
   function BASE_CURRENCY() external view returns (address); // if usd returns 0x0, if eth returns weth address
+
   function BASE_CURRENCY_UNIT() external view returns (uint256);
 
   /***********
diff --git a/contracts/misc/interfaces/IERC20DetailedBytes.sol b/contracts/misc/interfaces/IERC20DetailedBytes.sol
index 8c47df162..81c837bb3 100644
--- a/contracts/misc/interfaces/IERC20DetailedBytes.sol
+++ b/contracts/misc/interfaces/IERC20DetailedBytes.sol
@@ -9,4 +9,4 @@ interface IERC20DetailedBytes is IERC20 {
   function symbol() external view returns (bytes32);
 
   function decimals() external view returns (uint8);
-}
\ No newline at end of file
+}
diff --git a/contracts/misc/interfaces/IUiIncentiveDataProviderV2.sol b/contracts/misc/interfaces/IUiIncentiveDataProviderV2.sol
index f397a30c7..99a419e0b 100644
--- a/contracts/misc/interfaces/IUiIncentiveDataProviderV2.sol
+++ b/contracts/misc/interfaces/IUiIncentiveDataProviderV2.sol
@@ -55,4 +55,4 @@ interface IUiIncentiveDataProviderV2 {
     external
     view
     returns (AggregatedReserveIncentiveData[] memory, UserReserveIncentiveData[] memory);
-}
\ No newline at end of file
+}
diff --git a/contracts/misc/interfaces/IUiIncentiveDataProviderV3.sol b/contracts/misc/interfaces/IUiIncentiveDataProviderV3.sol
index 857546583..45190ad8e 100644
--- a/contracts/misc/interfaces/IUiIncentiveDataProviderV3.sol
+++ b/contracts/misc/interfaces/IUiIncentiveDataProviderV3.sol
@@ -38,13 +38,13 @@ interface IUiIncentiveDataProviderV3 {
     UserIncentiveData vTokenIncentivesUserData;
     UserIncentiveData sTokenIncentivesUserData;
   }
-  
+
   struct UserIncentiveData {
     address tokenAddress;
     address incentiveControllerAddress;
     UserRewardInfo[] userRewardsInformation;
   }
-  
+
   struct UserRewardInfo {
     string rewardTokenSymbol;
     address rewardOracleAddress;
@@ -54,7 +54,6 @@ interface IUiIncentiveDataProviderV3 {
     int256 rewardPriceFeed;
     uint8 priceFeedDecimals;
     uint8 rewardTokenDecimals;
-
   }
 
   function getReservesIncentivesData(ILendingPoolAddressesProvider provider)
@@ -72,4 +71,4 @@ interface IUiIncentiveDataProviderV3 {
     external
     view
     returns (AggregatedReserveIncentiveData[] memory, UserReserveIncentiveData[] memory);
-} 
\ No newline at end of file
+}
diff --git a/contracts/misc/interfaces/IUiPoolDataProviderV2.sol b/contracts/misc/interfaces/IUiPoolDataProviderV2.sol
index a286f9ccc..1741eef6f 100644
--- a/contracts/misc/interfaces/IUiPoolDataProviderV2.sol
+++ b/contracts/misc/interfaces/IUiPoolDataProviderV2.sol
@@ -68,15 +68,10 @@ interface IUiPoolDataProviderV2 {
   function getReservesData(ILendingPoolAddressesProvider provider)
     external
     view
-    returns (
-      AggregatedReserveData[] memory,
-      BaseCurrencyInfo memory
-    );
+    returns (AggregatedReserveData[] memory, BaseCurrencyInfo memory);
 
   function getUserReservesData(ILendingPoolAddressesProvider provider, address user)
     external
     view
-    returns (
-      UserReserveData[] memory
-    );
-}
\ No newline at end of file
+    returns (UserReserveData[] memory);
+}
diff --git a/contracts/mocks/swap/MockParaSwapAugustus.sol b/contracts/mocks/swap/MockParaSwapAugustus.sol
index 1cf321717..b243c1e28 100644
--- a/contracts/mocks/swap/MockParaSwapAugustus.sol
+++ b/contracts/mocks/swap/MockParaSwapAugustus.sol
@@ -12,10 +12,15 @@ contract MockParaSwapAugustus is IParaSwapAugustus {
   bool _expectingSwap;
   address _expectedFromToken;
   address _expectedToToken;
+  
   uint256 _expectedFromAmountMin;
   uint256 _expectedFromAmountMax;
   uint256 _receivedAmount;
 
+  uint256 _fromAmount;
+  uint256 _expectedToAmountMax;
+  uint256 _expectedToAmountMin;
+
   constructor() public {
     TOKEN_TRANSFER_PROXY = new MockParaSwapTokenTransferProxy();
   }
@@ -39,6 +44,21 @@ contract MockParaSwapAugustus is IParaSwapAugustus {
     _receivedAmount = receivedAmount;
   }
 
+  function expectBuy(
+    address fromToken,
+    address toToken,
+    uint256 fromAmount,
+    uint256 toAmountMin,
+    uint256 toAmountMax
+  ) external {
+    _expectingSwap = true;
+    _expectedFromToken = fromToken;
+    _expectedToToken = toToken;
+    _fromAmount = fromAmount;
+    _expectedToAmountMin = toAmountMin;
+    _expectedToAmountMax = toAmountMax;
+  }
+
   function swap(
     address fromToken,
     address toToken,
@@ -56,4 +76,22 @@ contract MockParaSwapAugustus is IParaSwapAugustus {
     _expectingSwap = false;
     return _receivedAmount;
   }
+
+  function buy(
+    address fromToken,
+    address toToken,
+    uint256 fromAmount,
+    uint256 toAmount
+  ) external returns (uint256) {
+    require(_expectingSwap, 'Not expecting swap');
+    require(fromToken == _expectedFromToken, 'Unexpected from token');
+    require(toToken == _expectedToToken, 'Unexpected to token');
+    require(toAmount >= _expectedToAmountMin && toAmount <= _expectedToAmountMax, 'To amount out of range');
+    require(_fromAmount <= fromAmount, 'From amount of tokens are higher than expected');
+    TOKEN_TRANSFER_PROXY.transferFrom(fromToken, msg.sender, address(this), _fromAmount);
+    MintableERC20(toToken).mint(toAmount);
+    IERC20(toToken).transfer(msg.sender, toAmount);
+    _expectingSwap = false;
+    return fromAmount;
+  }
 }
diff --git a/helpers/configuration.ts b/helpers/configuration.ts
index ddc568d76..e4e29c018 100644
--- a/helpers/configuration.ts
+++ b/helpers/configuration.ts
@@ -23,7 +23,7 @@ export enum ConfigNames {
   Aave = 'Aave',
   Matic = 'Matic',
   Amm = 'Amm',
-  Avalanche = 'Avalanche'
+  Avalanche = 'Avalanche',
 }
 
 export const loadPoolConfig = (configName: ConfigNames): PoolConfiguration => {
@@ -34,8 +34,8 @@ export const loadPoolConfig = (configName: ConfigNames): PoolConfiguration => {
       return MaticConfig;
     case ConfigNames.Amm:
       return AmmConfig;
-      case ConfigNames.Avalanche:
-        return AvalancheConfig;
+    case ConfigNames.Avalanche:
+      return AvalancheConfig;
     case ConfigNames.Commons:
       return CommonsConfig;
     default:
@@ -65,7 +65,7 @@ export const getReservesConfigByPool = (pool: AavePools): iMultiPoolsAssets<IRes
       },
       [AavePools.avalanche]: {
         ...AvalancheConfig.ReservesConfig,
-      }
+      },
     },
     pool
   );
diff --git a/helpers/contracts-deployments.ts b/helpers/contracts-deployments.ts
index 7292a217f..e28500cb6 100644
--- a/helpers/contracts-deployments.ts
+++ b/helpers/contracts-deployments.ts
@@ -55,6 +55,7 @@ import {
   UiPoolDataProviderV2V3Factory,
   UiIncentiveDataProviderV2V3,
   UiIncentiveDataProviderV2Factory,
+  ParaSwapRepayAdapterFactory,
 } from '../types';
 import {
   withSaveAndVerify,
@@ -791,3 +792,14 @@ export const deployParaSwapLiquiditySwapAdapter = async (
     args,
     verify
   );
+
+export const deployParaSwapRepayAdapter = async (
+  args: [tEthereumAddress, tEthereumAddress],
+  verify?: boolean
+) =>
+  withSaveAndVerify(
+    await new ParaSwapRepayAdapterFactory(await getFirstSigner()).deploy(...args),
+    eContractid.ParaSwapRepayAdapter,
+    args,
+    verify
+  );
diff --git a/helpers/contracts-getters.ts b/helpers/contracts-getters.ts
index 0395cdd71..5372a83f9 100644
--- a/helpers/contracts-getters.ts
+++ b/helpers/contracts-getters.ts
@@ -33,6 +33,7 @@ import {
   WETH9MockedFactory,
   WETHGatewayFactory,
   FlashLiquidationAdapterFactory,
+  ParaSwapRepayAdapterFactory,
 } from '../types';
 import { IERC20DetailedFactory } from '../types/IERC20DetailedFactory';
 import { getEthersSigners, MockTokenMap } from './contracts-helpers';
@@ -451,3 +452,12 @@ export const getParaSwapLiquiditySwapAdapter = async (address?: tEthereumAddress
       ).address,
     await getFirstSigner()
   );
+
+export const getParaSwapRepayAdapter = async (address?: tEthereumAddress) =>
+  await ParaSwapRepayAdapterFactory.connect(
+    address ||
+      (
+        await getDb().get(`${eContractid.ParaSwapRepayAdapter}.${DRE.network.name}`).value()
+      ).address,
+    await getFirstSigner()
+  );
diff --git a/helpers/contracts-helpers.ts b/helpers/contracts-helpers.ts
index 98cf2236a..a64a753d6 100644
--- a/helpers/contracts-helpers.ts
+++ b/helpers/contracts-helpers.ts
@@ -378,6 +378,46 @@ export const buildParaSwapLiquiditySwapParams = (
   );
 };
 
+export const buildParaswapBuyParams = (
+  buyCalldata: string | Buffer,
+  augustus: tEthereumAddress
+) => {
+  return ethers.utils.defaultAbiCoder.encode(['bytes', 'address'], [buyCalldata, augustus]);
+};
+export const buildParaSwapRepayParams = (
+  collateralAsset: tEthereumAddress,
+  collateralAmount: BigNumberish,
+  buyAllBalanceOffset: BigNumberish,
+  debtRateMode: BigNumberish,
+  buyCalldata: string | Buffer,
+  augustus: tEthereumAddress,
+  permitAmount: BigNumberish,
+  deadline: BigNumberish,
+  v: BigNumberish,
+  r: string | Buffer,
+  s: string | Buffer
+) => {
+  const paraswapData = buildParaswapBuyParams(buyCalldata, augustus);
+  return ethers.utils.defaultAbiCoder.encode(
+    [
+      'address',
+      'uint256',
+      'uint256',
+      'uint256',
+      'bytes',
+      'tuple(uint256,uint256,uint8,bytes32,bytes32)',
+    ],
+    [
+      collateralAsset,
+      collateralAmount,
+      buyAllBalanceOffset,
+      debtRateMode,
+      paraswapData,
+      [permitAmount, deadline, v, r, s],
+    ]
+  );
+};
+
 export const verifyContract = async (
   id: string,
   instance: Contract,
diff --git a/helpers/types.ts b/helpers/types.ts
index d4619ddf8..51b76dea2 100644
--- a/helpers/types.ts
+++ b/helpers/types.ts
@@ -102,6 +102,7 @@ export enum eContractid {
   MockParaSwapAugustus = 'MockParaSwapAugustus',
   MockParaSwapAugustusRegistry = 'MockParaSwapAugustusRegistry',
   ParaSwapLiquiditySwapAdapter = 'ParaSwapLiquiditySwapAdapter',
+  ParaSwapRepayAdapter = 'ParaSwapRepayAdapter',
   UiIncentiveDataProviderV2V3 = 'UiIncentiveDataProviderV2V3',
   UiIncentiveDataProviderV2 = 'UiIncentiveDataProviderV2',
 }
diff --git a/tasks/deployments/deploy-ParaSwapRepayAdapter.ts b/tasks/deployments/deploy-ParaSwapRepayAdapter.ts
new file mode 100644
index 000000000..efbc338d7
--- /dev/null
+++ b/tasks/deployments/deploy-ParaSwapRepayAdapter.ts
@@ -0,0 +1,36 @@
+import { task } from 'hardhat/config';
+
+import { ParaSwapRepayAdapterFactory } from '../../types';
+import { verifyContract } from '../../helpers/contracts-helpers';
+import { getFirstSigner } from '../../helpers/contracts-getters';
+import { eContractid } from '../../helpers/types';
+
+const CONTRACT_NAME = 'ParaSwapRepayAdapter';
+
+task(`deploy-${CONTRACT_NAME}`, `Deploys the ${CONTRACT_NAME} contract`)
+  .addParam('provider', 'Address of the LendingPoolAddressesProvider')
+  .addParam('augustusRegistry', 'Address of ParaSwap AugustusRegistry')
+  .addFlag('verify', `Verify ${CONTRACT_NAME} contract via Etherscan API.`)
+  .setAction(async ({ provider, augustusRegistry, verify }, localBRE) => {
+    await localBRE.run('set-DRE');
+
+    if (!localBRE.network.config.chainId) {
+      throw new Error('INVALID_CHAIN_ID');
+    }
+
+    console.log(`\n- ${CONTRACT_NAME} deployment`);
+    const adapter = await new ParaSwapRepayAdapterFactory(
+      await getFirstSigner()
+    ).deploy(provider, augustusRegistry);
+    await adapter.deployTransaction.wait();
+    console.log(`${CONTRACT_NAME}.address`, adapter.address);
+
+    if (verify) {
+      await verifyContract(eContractid.ParaSwapRepayAdapter, adapter, [
+        provider,
+        augustusRegistry,
+      ]);
+    }
+
+    console.log(`\tFinished ${CONTRACT_NAME} deployment`);
+  });
diff --git a/test-suites/test-aave/__setup.spec.ts b/test-suites/test-aave/__setup.spec.ts
index 38d2a88f8..dbb7afe68 100644
--- a/test-suites/test-aave/__setup.spec.ts
+++ b/test-suites/test-aave/__setup.spec.ts
@@ -29,6 +29,7 @@ import {
   deployMockParaSwapAugustus,
   deployMockParaSwapAugustusRegistry,
   deployParaSwapLiquiditySwapAdapter,
+  deployParaSwapRepayAdapter,
   authorizeWETHGateway,
   deployATokenImplementations,
   deployAaveOracle,
@@ -303,6 +304,8 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => {
 
   await deployParaSwapLiquiditySwapAdapter([addressesProvider.address, augustusRegistry.address]);
 
+  await deployParaSwapRepayAdapter([addressesProvider.address, augustusRegistry.address]);
+
   await deployWalletBalancerProvider();
 
   const gateWay = await deployWETHGateway([mockTokens.WETH.address]);
diff --git a/test-suites/test-aave/helpers/make-suite.ts b/test-suites/test-aave/helpers/make-suite.ts
index c4eb7893d..df7b95861 100644
--- a/test-suites/test-aave/helpers/make-suite.ts
+++ b/test-suites/test-aave/helpers/make-suite.ts
@@ -15,6 +15,7 @@ import {
   getUniswapRepayAdapter,
   getFlashLiquidationAdapter,
   getParaSwapLiquiditySwapAdapter,
+  getParaSwapRepayAdapter,
 } from '../../../helpers/contracts-getters';
 import { eEthereumNetwork, eNetwork, tEthereumAddress } from '../../../helpers/types';
 import { LendingPool } from '../../../types/LendingPool';
@@ -39,7 +40,7 @@ import { WETH9Mocked } from '../../../types/WETH9Mocked';
 import { WETHGateway } from '../../../types/WETHGateway';
 import { solidity } from 'ethereum-waffle';
 import { AaveConfig } from '../../../markets/aave';
-import { FlashLiquidationAdapter } from '../../../types';
+import { FlashLiquidationAdapter, ParaSwapRepayAdapter } from '../../../types';
 import { HardhatRuntimeEnvironment } from 'hardhat/types';
 import { usingTenderly } from '../../../helpers/tenderly-utils';
 
@@ -71,6 +72,8 @@ export interface TestEnv {
   wethGateway: WETHGateway;
   flashLiquidationAdapter: FlashLiquidationAdapter;
   paraswapLiquiditySwapAdapter: ParaSwapLiquiditySwapAdapter;
+  paraswapRepayAdapter: ParaSwapRepayAdapter;
+
 }
 
 let buidlerevmSnapshotId: string = '0x1';
@@ -96,6 +99,7 @@ const testEnv: TestEnv = {
   uniswapRepayAdapter: {} as UniswapRepayAdapter,
   flashLiquidationAdapter: {} as FlashLiquidationAdapter,
   paraswapLiquiditySwapAdapter: {} as ParaSwapLiquiditySwapAdapter,
+  paraswapRepayAdapter: {} as ParaSwapRepayAdapter,
   registry: {} as LendingPoolAddressesProviderRegistry,
   wethGateway: {} as WETHGateway,
 } as TestEnv;
@@ -164,6 +168,7 @@ export async function initializeMakeSuite() {
   testEnv.flashLiquidationAdapter = await getFlashLiquidationAdapter();
 
   testEnv.paraswapLiquiditySwapAdapter = await getParaSwapLiquiditySwapAdapter();
+  testEnv.paraswapRepayAdapter = await getParaSwapRepayAdapter();
 }
 
 const setSnapshot = async () => {
diff --git a/test-suites/test-aave/paraswapAdapters.repay.spec.ts b/test-suites/test-aave/paraswapAdapters.repay.spec.ts
new file mode 100644
index 000000000..7c4d44f07
--- /dev/null
+++ b/test-suites/test-aave/paraswapAdapters.repay.spec.ts
@@ -0,0 +1,1576 @@
+import { makeSuite, TestEnv } from './helpers/make-suite';
+import {
+  convertToCurrencyDecimals,
+  getContract,
+  buildPermitParams,
+  getSignatureFromTypedData,
+  buildRepayAdapterParams,
+  buildParaSwapRepayParams,
+  buildParaswapBuyParams,
+} from '../../helpers/contracts-helpers';
+import {
+  getMockParaSwapAugustus,
+  getMockParaSwapAugustusRegistry,
+} from '../../helpers/contracts-getters';
+import { deployParaSwapRepayAdapter } from '../../helpers/contracts-deployments';
+import { Zero } from '@ethersproject/constants';
+import BigNumber from 'bignumber.js';
+import { DRE, evmRevert, evmSnapshot } from '../../helpers/misc-utils';
+import { ethers } from 'ethers';
+import { eContractid } from '../../helpers/types';
+import { StableDebtToken } from '../../types/StableDebtToken';
+import { BUIDLEREVM_CHAINID } from '../../helpers/buidler-constants';
+import { MAX_UINT_AMOUNT } from '../../helpers/constants';
+import { MockParaSwapAugustus, MockParaSwapAugustusRegistry, VariableDebtToken } from '../../types';
+import exp from 'constants';
+const { parseEther } = ethers.utils;
+
+const { expect } = require('chai');
+
+makeSuite('Paraswap adapters', (testEnv: TestEnv) => {
+  let mockAugustus: MockParaSwapAugustus;
+  let mockAugustusRegistry: MockParaSwapAugustusRegistry;
+  let evmSnapshotId: string;
+
+  before(async () => {
+    mockAugustus = await getMockParaSwapAugustus();
+    mockAugustusRegistry = await getMockParaSwapAugustusRegistry();
+  });
+
+  beforeEach(async () => {
+    evmSnapshotId = await evmSnapshot();
+  });
+
+  afterEach(async () => {
+    await evmRevert(evmSnapshotId);
+  });
+
+  describe('ParaswapRepayAdapter', () => {
+    beforeEach(async () => {
+      const { users, weth, dai, usdc, aave, pool, deployer } = testEnv;
+      const userAddress = users[0].address;
+
+      // Provide liquidity
+      await dai.mint(parseEther('20000'));
+      await dai.approve(pool.address, parseEther('20000'));
+      await pool.deposit(dai.address, parseEther('20000'), deployer.address, 0);
+
+      const usdcLiquidity = await convertToCurrencyDecimals(usdc.address, '2000000');
+      await usdc.mint(usdcLiquidity);
+      await usdc.approve(pool.address, usdcLiquidity);
+      await pool.deposit(usdc.address, usdcLiquidity, deployer.address, 0);
+
+      await weth.mint(parseEther('100'));
+      await weth.approve(pool.address, parseEther('100'));
+      await pool.deposit(weth.address, parseEther('100'), deployer.address, 0);
+
+      await aave.mint(parseEther('1000000'));
+      await aave.approve(pool.address, parseEther('1000000'));
+      await pool.deposit(aave.address, parseEther('1000000'), deployer.address, 0);
+
+      // Make a deposit for user
+      await weth.mint(parseEther('1000'));
+      await weth.approve(pool.address, parseEther('1000'));
+      await pool.deposit(weth.address, parseEther('1000'), userAddress, 0);
+
+      await aave.mint(parseEther('1000000'));
+      await aave.approve(pool.address, parseEther('1000000'));
+      await pool.deposit(aave.address, parseEther('1000000'), userAddress, 0);
+
+      await usdc.mint(usdcLiquidity);
+      await usdc.approve(pool.address, usdcLiquidity);
+      await pool.deposit(usdc.address, usdcLiquidity, userAddress, 0);
+    });
+
+    describe('constructor', () => {
+      it('should deploy with correct parameters', async () => {
+        const { addressesProvider } = testEnv;
+        await deployParaSwapRepayAdapter([addressesProvider.address, mockAugustusRegistry.address]);
+      });
+
+      it('should revert if not valid addresses provider', async () => {
+        await expect(
+          deployParaSwapRepayAdapter([
+            mockAugustus.address, // any invalid contract can be used here
+            mockAugustusRegistry.address,
+          ])
+        ).to.be.reverted;
+      });
+
+      it('should revert if not valid augustus registry', async () => {
+        const { addressesProvider } = testEnv;
+        await expect(
+          deployParaSwapRepayAdapter([
+            addressesProvider.address,
+            mockAugustus.address, // any invalid contract can be used here
+          ])
+        ).to.be.reverted;
+      });
+    });
+
+    describe('executeOperation', () => {
+      it('should correctly swap tokens and repay debt', async () => {
+        const { users, pool, weth, aWETH, oracle, dai, paraswapRepayAdapter, helpersContract } =
+          testEnv;
+        const user = users[0].signer;
+        const userAddress = users[0].address;
+        const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
+
+        const daiPrice = await oracle.getAssetPrice(dai.address);
+        const expectedDaiAmount = await convertToCurrencyDecimals(
+          dai.address,
+          new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
+        );
+        // Open user Debt
+        await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress);
+
+        const daiStableDebtTokenAddress = (
+          await helpersContract.getReserveTokensAddresses(dai.address)
+        ).stableDebtTokenAddress;
+
+        const daiStableDebtContract = await getContract<StableDebtToken>(
+          eContractid.StableDebtToken,
+          daiStableDebtTokenAddress
+        );
+
+        const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress);
+
+        await mockAugustus.expectBuy(
+          weth.address,
+          dai.address,
+          amountWETHtoSwap,
+          expectedDaiAmount,
+          expectedDaiAmount
+        );
+        const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData('buy', [
+          weth.address,
+          dai.address,
+          amountWETHtoSwap,
+          expectedDaiAmount,
+        ]);
+
+        const flashloanPremium = amountWETHtoSwap.mul(9).div(10000);
+        const flashloanTotal = amountWETHtoSwap.add(flashloanPremium);
+        await aWETH.connect(user).approve(paraswapRepayAdapter.address, flashloanTotal);
+        const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
+
+        const params = buildParaSwapRepayParams(
+          dai.address,
+          expectedDaiAmount,
+          0,
+          1,
+          mockAugustusCalldata,
+          mockAugustus.address,
+          0,
+          0,
+          0,
+          '0x0000000000000000000000000000000000000000000000000000000000000000',
+          '0x0000000000000000000000000000000000000000000000000000000000000000'
+        );
+
+        await expect(
+          pool
+            .connect(user)
+            .flashLoan(
+              paraswapRepayAdapter.address,
+              [weth.address],
+              [amountWETHtoSwap.toString()],
+              [0],
+              userAddress,
+              params,
+              0
+            )
+        )
+          .to.emit(paraswapRepayAdapter, 'Bought')
+          .withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount);
+
+        const adapterWethBalance = await weth.balanceOf(paraswapRepayAdapter.address);
+        const adapterDaiBalance = await dai.balanceOf(paraswapRepayAdapter.address);
+        const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress);
+        const userAEthBalance = await aWETH.balanceOf(userAddress);
+
+        expect(adapterWethBalance).to.be.eq(Zero);
+        expect(adapterDaiBalance).to.be.eq(Zero);
+        expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount);
+        expect(userDaiStableDebtAmount).to.be.lt(expectedDaiAmount);
+        expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
+        expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(flashloanTotal));
+      });
+
+      it('should correctly repay debt with same collateral', async () => {
+        const { users, pool, weth, aWETH, paraswapRepayAdapter, helpersContract } = testEnv;
+        const user = users[0].signer;
+        const userAddress = users[0].address;
+        const amountWETHtoRepay = await convertToCurrencyDecimals(weth.address, '10');
+
+        // Open user Debt
+        await pool.connect(user).borrow(weth.address, amountWETHtoRepay, 2, 0, userAddress);
+
+        const wethVariableDebtTokenAddress = (
+          await helpersContract.getReserveTokensAddresses(weth.address)
+        ).variableDebtTokenAddress;
+
+        const wethVariableDebtContract = await getContract<VariableDebtToken>(
+          eContractid.VariableDebtToken,
+          wethVariableDebtTokenAddress
+        );
+
+        const userwethVariableDebtAmountBefore = await wethVariableDebtContract.balanceOf(
+          userAddress
+        );
+
+        await mockAugustus.expectBuy(
+          weth.address,
+          weth.address,
+          amountWETHtoRepay,
+          amountWETHtoRepay,
+          amountWETHtoRepay
+        );
+        const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData('buy', [
+          weth.address,
+          weth.address,
+          amountWETHtoRepay,
+          amountWETHtoRepay,
+        ]);
+
+        const flashloanPremium = amountWETHtoRepay.mul(9).div(10000);
+        const flashloanTotal = amountWETHtoRepay.add(flashloanPremium);
+        await aWETH.connect(user).approve(paraswapRepayAdapter.address, flashloanTotal);
+        const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
+
+        const params = buildParaSwapRepayParams(
+          weth.address,
+          amountWETHtoRepay,
+          0,
+          2,
+          mockAugustusCalldata,
+          mockAugustus.address,
+          0,
+          0,
+          0,
+          '0x0000000000000000000000000000000000000000000000000000000000000000',
+          '0x0000000000000000000000000000000000000000000000000000000000000000'
+        );
+
+        await expect(
+          pool
+            .connect(user)
+            .flashLoan(
+              paraswapRepayAdapter.address,
+              [weth.address],
+              [amountWETHtoRepay.toString()],
+              [0],
+              userAddress,
+              params,
+              0
+            )
+        );
+
+        const adapterWethBalance = await weth.balanceOf(paraswapRepayAdapter.address);
+        const userwethVariableDebtAmount = await wethVariableDebtContract.balanceOf(userAddress);
+        const userAEthBalance = await aWETH.balanceOf(userAddress);
+
+        expect(adapterWethBalance).to.be.eq(Zero);
+        expect(userwethVariableDebtAmountBefore).to.be.gte(amountWETHtoRepay);
+        expect(userwethVariableDebtAmount).to.be.lt(amountWETHtoRepay);
+        expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
+        expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(flashloanTotal));
+      });
+
+      it('should correctly swap tokens and repay debt with permit', async () => {
+        const { users, pool, weth, aWETH, oracle, dai, paraswapRepayAdapter, helpersContract } =
+          testEnv;
+        const user = users[0].signer;
+        const userAddress = users[0].address;
+
+        const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
+
+        const daiPrice = await oracle.getAssetPrice(dai.address);
+        const expectedDaiAmount = await convertToCurrencyDecimals(
+          dai.address,
+          new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
+        );
+
+        // Open user Debt
+        await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress);
+
+        const daiStableDebtTokenAddress = (
+          await helpersContract.getReserveTokensAddresses(dai.address)
+        ).stableDebtTokenAddress;
+
+        const daiStableDebtContract = await getContract<StableDebtToken>(
+          eContractid.StableDebtToken,
+          daiStableDebtTokenAddress
+        );
+
+        const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress);
+
+        await mockAugustus.expectBuy(
+          weth.address,
+          dai.address,
+          amountWETHtoSwap,
+          expectedDaiAmount,
+          expectedDaiAmount
+        );
+        const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData('buy', [
+          weth.address,
+          dai.address,
+          amountWETHtoSwap,
+          expectedDaiAmount,
+        ]);
+
+        const flashloanPremium = amountWETHtoSwap.mul(9).div(10000);
+        const flashloanTotal = amountWETHtoSwap.add(flashloanPremium);
+        await aWETH.connect(user).approve(paraswapRepayAdapter.address, flashloanTotal);
+        const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
+
+        const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID;
+        const deadline = MAX_UINT_AMOUNT;
+        const nonce = (await aWETH._nonces(userAddress)).toNumber();
+        const msgParams = buildPermitParams(
+          chainId,
+          aWETH.address,
+          '1',
+          await aWETH.name(),
+          userAddress,
+          paraswapRepayAdapter.address,
+          nonce,
+          deadline,
+          flashloanTotal.toString()
+        );
+
+        const ownerPrivateKey = require('../../test-wallets.js').accounts[1].secretKey;
+        if (!ownerPrivateKey) {
+          throw new Error('INVALID_OWNER_PK');
+        }
+
+        const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams);
+
+        const params = buildParaSwapRepayParams(
+          dai.address,
+          expectedDaiAmount,
+          0,
+          1,
+          mockAugustusCalldata,
+          mockAugustus.address,
+          flashloanTotal,
+          deadline,
+          v,
+          r,
+          s
+        );
+
+        await expect(
+          pool
+            .connect(user)
+            .flashLoan(
+              paraswapRepayAdapter.address,
+              [weth.address],
+              [amountWETHtoSwap.toString()],
+              [0],
+              userAddress,
+              params,
+              0
+            )
+        )
+          .to.emit(paraswapRepayAdapter, 'Bought')
+          .withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount);
+
+        const adapterWethBalance = await weth.balanceOf(paraswapRepayAdapter.address);
+        const adapterDaiBalance = await dai.balanceOf(paraswapRepayAdapter.address);
+        const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress);
+        const userAEthBalance = await aWETH.balanceOf(userAddress);
+
+        expect(adapterWethBalance).to.be.eq(Zero);
+        expect(adapterDaiBalance).to.be.eq(Zero);
+        expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount);
+        expect(userDaiStableDebtAmount).to.be.lt(expectedDaiAmount);
+        expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
+        expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(flashloanTotal));
+      });
+
+      it('should revert if caller not lending pool', async () => {
+        const { users, pool, weth, aWETH, oracle, dai, paraswapRepayAdapter } = testEnv;
+        const user = users[0].signer;
+        const userAddress = users[0].address;
+
+        const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
+
+        const daiPrice = await oracle.getAssetPrice(dai.address);
+        const expectedDaiAmount = await convertToCurrencyDecimals(
+          dai.address,
+          new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
+        );
+
+        // Open user Debt
+        await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress);
+
+        await mockAugustus.expectBuy(
+          weth.address,
+          dai.address,
+          amountWETHtoSwap,
+          expectedDaiAmount,
+          expectedDaiAmount
+        );
+        const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData('buy', [
+          weth.address,
+          dai.address,
+          amountWETHtoSwap,
+          expectedDaiAmount,
+        ]);
+
+        const flashloanPremium = amountWETHtoSwap.mul(9).div(10000);
+        const flashloanTotal = amountWETHtoSwap.add(flashloanPremium);
+        await aWETH.connect(user).approve(paraswapRepayAdapter.address, flashloanTotal);
+
+        const params = buildParaSwapRepayParams(
+          dai.address,
+          expectedDaiAmount,
+          0,
+          1,
+          mockAugustusCalldata,
+          mockAugustus.address,
+          0,
+          0,
+          0,
+          '0x0000000000000000000000000000000000000000000000000000000000000000',
+          '0x0000000000000000000000000000000000000000000000000000000000000000'
+        );
+
+        await expect(
+          paraswapRepayAdapter
+            .connect(user)
+            .executeOperation(
+              [weth.address],
+              [amountWETHtoSwap.toString()],
+              [0],
+              userAddress,
+              params
+            )
+        ).to.be.revertedWith('CALLER_MUST_BE_LENDING_POOL');
+      });
+
+      it('should revert if there is not debt to repay with the specified rate mode', async () => {
+        const { users, pool, weth, oracle, dai, paraswapRepayAdapter, aWETH } = testEnv;
+        const user = users[0].signer;
+        const userAddress = users[0].address;
+
+        const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
+
+        await weth.connect(user).mint(amountWETHtoSwap);
+        await weth.connect(user).transfer(paraswapRepayAdapter.address, amountWETHtoSwap);
+
+        const daiPrice = await oracle.getAssetPrice(dai.address);
+        const expectedDaiAmount = await convertToCurrencyDecimals(
+          dai.address,
+          new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
+        );
+
+        // Open user Debt
+        await pool.connect(user).borrow(dai.address, expectedDaiAmount, 2, 0, userAddress);
+
+        await mockAugustus.expectBuy(
+          weth.address,
+          dai.address,
+          amountWETHtoSwap,
+          expectedDaiAmount,
+          expectedDaiAmount
+        );
+        const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData('buy', [
+          weth.address,
+          dai.address,
+          amountWETHtoSwap,
+          expectedDaiAmount,
+        ]);
+
+        const flashloanPremium = amountWETHtoSwap.mul(9).div(10000);
+        const flashloanTotal = amountWETHtoSwap.add(flashloanPremium);
+        await aWETH.connect(user).approve(paraswapRepayAdapter.address, flashloanTotal);
+
+        const params = buildParaSwapRepayParams(
+          dai.address,
+          expectedDaiAmount,
+          0,
+          1,
+          mockAugustusCalldata,
+          mockAugustus.address,
+          0,
+          0,
+          0,
+          '0x0000000000000000000000000000000000000000000000000000000000000000',
+          '0x0000000000000000000000000000000000000000000000000000000000000000'
+        );
+
+        await expect(
+          pool
+            .connect(user)
+            .flashLoan(
+              paraswapRepayAdapter.address,
+              [weth.address],
+              [amountWETHtoSwap.toString()],
+              [0],
+              userAddress,
+              params,
+              0
+            )
+        ).to.be.reverted;
+      });
+
+      it('should revert if there is not debt to repay', async () => {
+        const { users, pool, weth, oracle, dai, paraswapRepayAdapter, aWETH } = testEnv;
+        const user = users[0].signer;
+        const userAddress = users[0].address;
+
+        const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
+
+        await weth.connect(user).mint(amountWETHtoSwap);
+        await weth.connect(user).transfer(paraswapRepayAdapter.address, amountWETHtoSwap);
+
+        const daiPrice = await oracle.getAssetPrice(dai.address);
+        const expectedDaiAmount = await convertToCurrencyDecimals(
+          dai.address,
+          new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
+        );
+
+        await mockAugustus.expectBuy(
+          weth.address,
+          dai.address,
+          amountWETHtoSwap,
+          expectedDaiAmount,
+          expectedDaiAmount
+        );
+        const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData('buy', [
+          weth.address,
+          dai.address,
+          amountWETHtoSwap,
+          expectedDaiAmount,
+        ]);
+
+        const flashloanPremium = amountWETHtoSwap.mul(9).div(10000);
+        const flashloanTotal = amountWETHtoSwap.add(flashloanPremium);
+        await aWETH.connect(user).approve(paraswapRepayAdapter.address, flashloanTotal);
+
+        const params = buildParaSwapRepayParams(
+          dai.address,
+          expectedDaiAmount,
+          0,
+          1,
+          mockAugustusCalldata,
+          mockAugustus.address,
+          0,
+          0,
+          0,
+          '0x0000000000000000000000000000000000000000000000000000000000000000',
+          '0x0000000000000000000000000000000000000000000000000000000000000000'
+        );
+
+        await expect(
+          pool
+            .connect(user)
+            .flashLoan(
+              paraswapRepayAdapter.address,
+              [weth.address],
+              [amountWETHtoSwap.toString()],
+              [0],
+              userAddress,
+              params,
+              0
+            )
+        ).to.be.reverted;
+      });
+
+      it('should revert when max amount allowed to swap is bigger than max slippage', async () => {
+        const { users, pool, weth, oracle, dai, aWETH, paraswapRepayAdapter } = testEnv;
+        const user = users[0].signer;
+        const userAddress = users[0].address;
+
+        const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
+
+        const daiPrice = await oracle.getAssetPrice(dai.address);
+        const expectedDaiAmount = await convertToCurrencyDecimals(
+          dai.address,
+          new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
+        );
+
+        // Open user Debt
+        await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress);
+
+        const bigMaxAmountToSwap = amountWETHtoSwap.mul(2);
+        await mockAugustus.expectBuy(
+          weth.address,
+          dai.address,
+          bigMaxAmountToSwap,
+          expectedDaiAmount,
+          expectedDaiAmount
+        );
+        const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData('buy', [
+          weth.address,
+          dai.address,
+          bigMaxAmountToSwap,
+          expectedDaiAmount,
+        ]);
+
+        const flashloanPremium = bigMaxAmountToSwap.mul(9).div(10000);
+        const flashloanTotal = bigMaxAmountToSwap.add(flashloanPremium);
+        await aWETH.connect(user).approve(paraswapRepayAdapter.address, flashloanTotal);
+
+        const params = buildParaSwapRepayParams(
+          dai.address,
+          bigMaxAmountToSwap,
+          0,
+          1,
+          mockAugustusCalldata,
+          mockAugustus.address,
+          0,
+          0,
+          0,
+          '0x0000000000000000000000000000000000000000000000000000000000000000',
+          '0x0000000000000000000000000000000000000000000000000000000000000000'
+        );
+
+        await expect(
+          pool
+            .connect(user)
+            .flashLoan(
+              paraswapRepayAdapter.address,
+              [weth.address],
+              [amountWETHtoSwap.toString()],
+              [0],
+              userAddress,
+              params,
+              0
+            )
+        ).to.be.revertedWith('maxAmountToSwap exceed max slippage');
+      });
+
+      it('should swap, repay debt and pull the needed ATokens leaving no leftovers', async () => {
+        const { users, pool, weth, aWETH, oracle, dai, paraswapRepayAdapter, helpersContract } =
+          testEnv;
+        const user = users[0].signer;
+        const userAddress = users[0].address;
+
+        const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
+
+        const daiPrice = await oracle.getAssetPrice(dai.address);
+        const expectedDaiAmount = await convertToCurrencyDecimals(
+          dai.address,
+          new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
+        );
+
+        // Open user Debt
+        await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress);
+
+        const daiStableDebtTokenAddress = (
+          await helpersContract.getReserveTokensAddresses(dai.address)
+        ).stableDebtTokenAddress;
+
+        const daiStableDebtContract = await getContract<StableDebtToken>(
+          eContractid.StableDebtToken,
+          daiStableDebtTokenAddress
+        );
+
+        const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress);
+
+        await mockAugustus.expectBuy(
+          weth.address,
+          dai.address,
+          amountWETHtoSwap,
+          expectedDaiAmount,
+          expectedDaiAmount
+        );
+        const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData('buy', [
+          weth.address,
+          dai.address,
+          amountWETHtoSwap,
+          expectedDaiAmount,
+        ]);
+
+        const flashloanPremium = amountWETHtoSwap.mul(9).div(10000);
+        const flashloanTotal = amountWETHtoSwap.add(flashloanPremium);
+        await aWETH.connect(user).approve(paraswapRepayAdapter.address, flashloanTotal);
+        const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
+
+        const params = buildParaSwapRepayParams(
+          dai.address,
+          expectedDaiAmount,
+          0,
+          1,
+          mockAugustusCalldata,
+          mockAugustus.address,
+          0,
+          0,
+          0,
+          '0x0000000000000000000000000000000000000000000000000000000000000000',
+          '0x0000000000000000000000000000000000000000000000000000000000000000'
+        );
+
+        await expect(
+          pool
+            .connect(user)
+            .flashLoan(
+              paraswapRepayAdapter.address,
+              [weth.address],
+              [amountWETHtoSwap.toString()],
+              [0],
+              userAddress,
+              params,
+              0
+            )
+        )
+          .to.emit(paraswapRepayAdapter, 'Bought')
+          .withArgs(weth.address, dai.address, amountWETHtoSwap.toString(), expectedDaiAmount);
+
+        const adapterWethBalance = await weth.balanceOf(paraswapRepayAdapter.address);
+        const adapterDaiBalance = await dai.balanceOf(paraswapRepayAdapter.address);
+        const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress);
+        const userAEthBalance = await aWETH.balanceOf(userAddress);
+        const adapterAEthBalance = await aWETH.balanceOf(paraswapRepayAdapter.address);
+
+        expect(adapterAEthBalance).to.be.eq(Zero);
+        expect(adapterWethBalance).to.be.eq(Zero);
+        expect(adapterDaiBalance).to.be.eq(Zero);
+        expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount);
+        expect(userDaiStableDebtAmount).to.be.lt(expectedDaiAmount);
+        expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
+        expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(flashloanTotal));
+      });
+
+      it('should correctly swap tokens and repay the whole stable debt', async () => {
+        const { users, pool, weth, aWETH, oracle, dai, paraswapRepayAdapter, helpersContract } =
+          testEnv;
+        const user = users[0].signer;
+        const userAddress = users[0].address;
+
+        const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
+
+        const daiPrice = await oracle.getAssetPrice(dai.address);
+        const expectedDaiAmount = await convertToCurrencyDecimals(
+          dai.address,
+          new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
+        );
+
+        // Open user Debt
+        await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress);
+
+        const daiStableDebtTokenAddress = (
+          await helpersContract.getReserveTokensAddresses(dai.address)
+        ).stableDebtTokenAddress;
+
+        const daiStableDebtContract = await getContract<StableDebtToken>(
+          eContractid.StableDebtToken,
+          daiStableDebtTokenAddress
+        );
+
+        const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress);
+
+        // Add a % to repay on top of the debt
+        const flashLoanAmount = await convertToCurrencyDecimals(weth.address, '11');
+        const amountToRepay = new BigNumber(expectedDaiAmount.toString())
+          .multipliedBy(1.1)
+          .toFixed(0);
+        const liquidityToSwap = await convertToCurrencyDecimals(weth.address, '10.8');
+        await mockAugustus.expectBuy(
+          weth.address,
+          dai.address,
+          liquidityToSwap,
+          expectedDaiAmount,
+          amountToRepay
+        );
+
+        const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData('buy', [
+          weth.address,
+          dai.address,
+          flashLoanAmount,
+          expectedDaiAmount,
+        ]);
+
+        const flashloanPremium = flashLoanAmount.mul(9).div(10000);
+        const flashloanTotal = flashLoanAmount.add(flashloanPremium);
+        await aWETH.connect(user).approve(paraswapRepayAdapter.address, flashloanTotal);
+        const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
+
+        // Add a % to repay on top of the debt
+
+        const params = buildParaSwapRepayParams(
+          dai.address,
+          amountToRepay,
+          4 + 3 * 32,
+          1,
+          mockAugustusCalldata,
+          mockAugustus.address,
+          0,
+          0,
+          0,
+          '0x0000000000000000000000000000000000000000000000000000000000000000',
+          '0x0000000000000000000000000000000000000000000000000000000000000000'
+        );
+
+        await pool
+          .connect(user)
+          .flashLoan(
+            paraswapRepayAdapter.address,
+            [weth.address],
+            [flashLoanAmount.toString()],
+            [0],
+            userAddress,
+            params,
+            0
+          );
+
+        const adapterWethBalance = await weth.balanceOf(paraswapRepayAdapter.address);
+        const adapterDaiBalance = await dai.balanceOf(paraswapRepayAdapter.address);
+        const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress);
+        const userAEthBalance = await aWETH.balanceOf(userAddress);
+        const adapterAEthBalance = await aWETH.balanceOf(paraswapRepayAdapter.address);
+
+        expect(adapterAEthBalance).to.be.eq(Zero);
+        expect(adapterWethBalance).to.be.eq(Zero);
+        expect(adapterDaiBalance).to.be.eq(Zero);
+        expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount);
+        expect(userDaiStableDebtAmount).to.be.eq(Zero);
+        expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
+        expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(flashloanTotal));
+      });
+
+      it('should correctly swap tokens and repay the whole variable debt', async () => {
+        const { users, pool, weth, aWETH, oracle, dai, paraswapRepayAdapter, helpersContract } =
+          testEnv;
+        const user = users[0].signer;
+        const userAddress = users[0].address;
+
+        const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
+
+        const daiPrice = await oracle.getAssetPrice(dai.address);
+        const expectedDaiAmount = await convertToCurrencyDecimals(
+          dai.address,
+          new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
+        );
+
+        // Open user Debt
+        await pool.connect(user).borrow(dai.address, expectedDaiAmount, 2, 0, userAddress);
+
+        const daiStableVariableTokenAddress = (
+          await helpersContract.getReserveTokensAddresses(dai.address)
+        ).variableDebtTokenAddress;
+
+        const daiVariableDebtContract = await getContract<StableDebtToken>(
+          eContractid.VariableDebtToken,
+          daiStableVariableTokenAddress
+        );
+
+        const userDaiVariableDebtAmountBefore = await daiVariableDebtContract.balanceOf(
+          userAddress
+        );
+
+        const flashLoanAmount = await convertToCurrencyDecimals(weth.address, '11');
+        const liquidityToSwap = await convertToCurrencyDecimals(weth.address, '10.8');
+        const amountToRepay = new BigNumber(expectedDaiAmount.toString())
+          .multipliedBy(1.1)
+          .toFixed(0);
+
+        await mockAugustus.expectBuy(
+          weth.address,
+          dai.address,
+          liquidityToSwap,
+          expectedDaiAmount,
+          amountToRepay
+        );
+        const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData('buy', [
+          weth.address,
+          dai.address,
+          flashLoanAmount,
+          expectedDaiAmount,
+        ]);
+
+        const flashloanPremium = flashLoanAmount.mul(9).div(10000);
+        const flashloanTotal = flashLoanAmount.add(flashloanPremium);
+        await aWETH.connect(user).approve(paraswapRepayAdapter.address, flashloanTotal);
+        const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
+
+        const params = buildParaSwapRepayParams(
+          dai.address,
+          amountToRepay,
+          4 + 3 * 32,
+          2,
+          mockAugustusCalldata,
+          mockAugustus.address,
+          0,
+          0,
+          0,
+          '0x0000000000000000000000000000000000000000000000000000000000000000',
+          '0x0000000000000000000000000000000000000000000000000000000000000000'
+        );
+
+        await pool
+          .connect(user)
+          .flashLoan(
+            paraswapRepayAdapter.address,
+            [weth.address],
+            [flashLoanAmount.toString()],
+            [0],
+            userAddress,
+            params,
+            0
+          );
+
+        const adapterWethBalance = await weth.balanceOf(paraswapRepayAdapter.address);
+        const adapterDaiBalance = await dai.balanceOf(paraswapRepayAdapter.address);
+        const userDaiVariableDebtAmount = await daiVariableDebtContract.balanceOf(userAddress);
+        const userAEthBalance = await aWETH.balanceOf(userAddress);
+        const adapterAEthBalance = await aWETH.balanceOf(paraswapRepayAdapter.address);
+
+        expect(adapterAEthBalance).to.be.eq(Zero);
+        expect(adapterWethBalance).to.be.eq(Zero);
+        expect(adapterDaiBalance).to.be.eq(Zero);
+        expect(userDaiVariableDebtAmountBefore).to.be.gte(expectedDaiAmount);
+        expect(userDaiVariableDebtAmount).to.be.eq(Zero);
+        expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
+        expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(flashloanTotal));
+      });
+    });
+
+    describe('swapAndRepay', () => {
+      it('should correctly swap tokens and repay debt', async () => {
+        const { users, pool, weth, aWETH, oracle, dai, paraswapRepayAdapter, helpersContract } =
+          testEnv;
+        const user = users[0].signer;
+        const userAddress = users[0].address;
+
+        const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
+
+        const daiPrice = await oracle.getAssetPrice(dai.address);
+        const expectedDaiAmount = await convertToCurrencyDecimals(
+          dai.address,
+          new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
+        );
+
+        // Open user Debt
+        await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress);
+
+        const daiStableDebtTokenAddress = (
+          await helpersContract.getReserveTokensAddresses(dai.address)
+        ).stableDebtTokenAddress;
+
+        const daiStableDebtContract = await getContract<StableDebtToken>(
+          eContractid.StableDebtToken,
+          daiStableDebtTokenAddress
+        );
+
+        const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress);
+
+        const liquidityToSwap = amountWETHtoSwap;
+        const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
+
+        await mockAugustus.expectBuy(
+          weth.address,
+          dai.address,
+          liquidityToSwap,
+          expectedDaiAmount,
+          expectedDaiAmount
+        );
+        const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData('buy', [
+          weth.address,
+          dai.address,
+          liquidityToSwap,
+          expectedDaiAmount,
+        ]);
+
+        await aWETH.connect(user).approve(paraswapRepayAdapter.address, liquidityToSwap);
+        const params = buildParaswapBuyParams(mockAugustusCalldata, mockAugustus.address);
+        await paraswapRepayAdapter
+          .connect(user)
+          .swapAndRepay(
+            weth.address,
+            dai.address,
+            liquidityToSwap,
+            expectedDaiAmount,
+            1,
+            0,
+            params,
+            {
+              amount: 0,
+              deadline: 0,
+              v: 0,
+              r: '0x0000000000000000000000000000000000000000000000000000000000000000',
+              s: '0x0000000000000000000000000000000000000000000000000000000000000000',
+            }
+          );
+
+        const adapterWethBalance = await weth.balanceOf(paraswapRepayAdapter.address);
+        const adapterDaiBalance = await dai.balanceOf(paraswapRepayAdapter.address);
+        const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress);
+        const userAEthBalance = await aWETH.balanceOf(userAddress);
+
+        expect(adapterWethBalance).to.be.eq(Zero);
+        expect(adapterDaiBalance).to.be.eq(Zero);
+        expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount);
+        expect(userDaiStableDebtAmount).to.be.lt(expectedDaiAmount);
+        expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
+        expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap));
+      });
+
+      it('should correctly swap tokens and repay debt with permit', async () => {
+        const { users, pool, weth, aWETH, oracle, dai, paraswapRepayAdapter, helpersContract } =
+          testEnv;
+        const user = users[0].signer;
+        const userAddress = users[0].address;
+
+        const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
+
+        const daiPrice = await oracle.getAssetPrice(dai.address);
+        const expectedDaiAmount = await convertToCurrencyDecimals(
+          dai.address,
+          new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
+        );
+
+        // Open user Debt
+        await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress);
+
+        const daiStableDebtTokenAddress = (
+          await helpersContract.getReserveTokensAddresses(dai.address)
+        ).stableDebtTokenAddress;
+
+        const daiStableDebtContract = await getContract<StableDebtToken>(
+          eContractid.StableDebtToken,
+          daiStableDebtTokenAddress
+        );
+
+        const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress);
+
+        const liquidityToSwap = amountWETHtoSwap;
+        const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
+
+        await mockAugustus.expectBuy(
+          weth.address,
+          dai.address,
+          liquidityToSwap,
+          expectedDaiAmount,
+          expectedDaiAmount
+        );
+        const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData('buy', [
+          weth.address,
+          dai.address,
+          liquidityToSwap,
+          expectedDaiAmount,
+        ]);
+
+        const params = buildParaswapBuyParams(mockAugustusCalldata, mockAugustus.address);
+
+        const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID;
+        const deadline = MAX_UINT_AMOUNT;
+        const nonce = (await aWETH._nonces(userAddress)).toNumber();
+        const msgParams = buildPermitParams(
+          chainId,
+          aWETH.address,
+          '1',
+          await aWETH.name(),
+          userAddress,
+          paraswapRepayAdapter.address,
+          nonce,
+          deadline,
+          liquidityToSwap.toString()
+        );
+
+        const ownerPrivateKey = require('../../test-wallets.js').accounts[1].secretKey;
+        if (!ownerPrivateKey) {
+          throw new Error('INVALID_OWNER_PK');
+        }
+
+        const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams);
+
+        await paraswapRepayAdapter
+          .connect(user)
+          .swapAndRepay(
+            weth.address,
+            dai.address,
+            liquidityToSwap,
+            expectedDaiAmount,
+            1,
+            0,
+            params,
+            {
+              amount: liquidityToSwap,
+              deadline,
+              v,
+              r,
+              s,
+            }
+          );
+
+        const adapterWethBalance = await weth.balanceOf(paraswapRepayAdapter.address);
+        const adapterDaiBalance = await dai.balanceOf(paraswapRepayAdapter.address);
+        const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress);
+        const userAEthBalance = await aWETH.balanceOf(userAddress);
+
+        expect(adapterWethBalance).to.be.eq(Zero);
+        expect(adapterDaiBalance).to.be.eq(Zero);
+        expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount);
+        expect(userDaiStableDebtAmount).to.be.lt(expectedDaiAmount);
+        expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
+        expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap));
+      });
+
+      it('should revert if there is not debt to repay', async () => {
+        const { users, weth, aWETH, oracle, dai, paraswapRepayAdapter } = testEnv;
+        const user = users[0].signer;
+
+        const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
+
+        const daiPrice = await oracle.getAssetPrice(dai.address);
+        const expectedDaiAmount = await convertToCurrencyDecimals(
+          dai.address,
+          new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
+        );
+
+        const liquidityToSwap = amountWETHtoSwap;
+
+        await mockAugustus.expectBuy(
+          weth.address,
+          dai.address,
+          liquidityToSwap,
+          expectedDaiAmount,
+          expectedDaiAmount
+        );
+        const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData('buy', [
+          weth.address,
+          dai.address,
+          liquidityToSwap,
+          expectedDaiAmount,
+        ]);
+
+        const params = buildParaswapBuyParams(mockAugustusCalldata, mockAugustus.address);
+        await aWETH.connect(user).approve(paraswapRepayAdapter.address, liquidityToSwap);
+
+        await expect(
+          paraswapRepayAdapter
+            .connect(user)
+            .swapAndRepay(
+              weth.address,
+              dai.address,
+              liquidityToSwap,
+              expectedDaiAmount,
+              1,
+              0,
+              params,
+              {
+                amount: 0,
+                deadline: 0,
+                v: 0,
+                r: '0x0000000000000000000000000000000000000000000000000000000000000000',
+                s: '0x0000000000000000000000000000000000000000000000000000000000000000',
+              }
+            )
+        ).to.be.reverted;
+      });
+
+      it('should revert when max amount allowed to swap is bigger than max slippage', async () => {
+        const { users, pool, weth, aWETH, oracle, dai, paraswapRepayAdapter } = testEnv;
+        const user = users[0].signer;
+        const userAddress = users[0].address;
+
+        const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
+
+        const daiPrice = await oracle.getAssetPrice(dai.address);
+        const expectedDaiAmount = await convertToCurrencyDecimals(
+          dai.address,
+          new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
+        );
+
+        // Open user Debt
+        await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress);
+
+        const bigMaxAmountToSwap = amountWETHtoSwap.mul(2);
+        await aWETH.connect(user).approve(paraswapRepayAdapter.address, bigMaxAmountToSwap);
+
+        await mockAugustus.expectBuy(
+          weth.address,
+          dai.address,
+          bigMaxAmountToSwap,
+          expectedDaiAmount,
+          expectedDaiAmount
+        );
+        const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData('buy', [
+          weth.address,
+          dai.address,
+          bigMaxAmountToSwap,
+          expectedDaiAmount,
+        ]);
+
+        const params = buildParaswapBuyParams(mockAugustusCalldata, mockAugustus.address);
+        await expect(
+          paraswapRepayAdapter
+            .connect(user)
+            .swapAndRepay(
+              weth.address,
+              dai.address,
+              bigMaxAmountToSwap,
+              expectedDaiAmount,
+              1,
+              0,
+              params,
+              {
+                amount: 0,
+                deadline: 0,
+                v: 0,
+                r: '0x0000000000000000000000000000000000000000000000000000000000000000',
+                s: '0x0000000000000000000000000000000000000000000000000000000000000000',
+              }
+            )
+        ).to.be.revertedWith('maxAmountToSwap exceed max slippage');
+      });
+
+      it('should swap, repay debt and pull the needed ATokens leaving no leftovers', async () => {
+        const { users, pool, weth, aWETH, oracle, dai, paraswapRepayAdapter, helpersContract } =
+          testEnv;
+        const user = users[0].signer;
+        const userAddress = users[0].address;
+
+        const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
+
+        const daiPrice = await oracle.getAssetPrice(dai.address);
+        const expectedDaiAmount = await convertToCurrencyDecimals(
+          dai.address,
+          new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
+        );
+
+        // Open user Debt
+        await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress);
+
+        const daiStableDebtTokenAddress = (
+          await helpersContract.getReserveTokensAddresses(dai.address)
+        ).stableDebtTokenAddress;
+
+        const daiStableDebtContract = await getContract<StableDebtToken>(
+          eContractid.StableDebtToken,
+          daiStableDebtTokenAddress
+        );
+
+        const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress);
+
+        const liquidityToSwap = amountWETHtoSwap;
+
+        await mockAugustus.expectBuy(
+          weth.address,
+          dai.address,
+          liquidityToSwap,
+          expectedDaiAmount,
+          expectedDaiAmount
+        );
+        const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData('buy', [
+          weth.address,
+          dai.address,
+          liquidityToSwap,
+          expectedDaiAmount,
+        ]);
+
+        const params = buildParaswapBuyParams(mockAugustusCalldata, mockAugustus.address);
+        await aWETH.connect(user).approve(paraswapRepayAdapter.address, liquidityToSwap);
+        const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
+        const userWethBalanceBefore = await weth.balanceOf(userAddress);
+
+        await paraswapRepayAdapter
+          .connect(user)
+          .swapAndRepay(
+            weth.address,
+            dai.address,
+            liquidityToSwap,
+            expectedDaiAmount,
+            1,
+            0,
+            params,
+            {
+              amount: 0,
+              deadline: 0,
+              v: 0,
+              r: '0x0000000000000000000000000000000000000000000000000000000000000000',
+              s: '0x0000000000000000000000000000000000000000000000000000000000000000',
+            }
+          );
+
+        const adapterWethBalance = await weth.balanceOf(paraswapRepayAdapter.address);
+        const adapterDaiBalance = await dai.balanceOf(paraswapRepayAdapter.address);
+        const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress);
+        const userAEthBalance = await aWETH.balanceOf(userAddress);
+        const adapterAEthBalance = await aWETH.balanceOf(paraswapRepayAdapter.address);
+        const userWethBalance = await weth.balanceOf(userAddress);
+
+        expect(adapterAEthBalance).to.be.eq(Zero);
+        expect(adapterWethBalance).to.be.eq(Zero);
+        expect(adapterDaiBalance).to.be.eq(Zero);
+        expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount);
+        expect(userDaiStableDebtAmount).to.be.lt(expectedDaiAmount);
+        expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
+        expect(userAEthBalance).to.be.eq(userAEthBalanceBefore.sub(liquidityToSwap));
+        expect(userWethBalance).to.be.eq(userWethBalanceBefore);
+      });
+
+      it('should swap (not whole amount), repay debt and pull the needed ATokens leaving no leftovers', async () => {
+        const { users, pool, weth, aWETH, oracle, dai, paraswapRepayAdapter, helpersContract } =
+          testEnv;
+        const user = users[0].signer;
+        const userAddress = users[0].address;
+
+        const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
+
+        const daiPrice = await oracle.getAssetPrice(dai.address);
+        const expectedDaiAmount = await convertToCurrencyDecimals(
+          dai.address,
+          new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
+        );
+
+        // Open user Debt
+        await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress);
+
+        const daiStableDebtTokenAddress = (
+          await helpersContract.getReserveTokensAddresses(dai.address)
+        ).stableDebtTokenAddress;
+
+        const daiStableDebtContract = await getContract<StableDebtToken>(
+          eContractid.StableDebtToken,
+          daiStableDebtTokenAddress
+        );
+
+        const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress);
+
+        const liquidityToSwap = amountWETHtoSwap;
+        const swappedAmount = await convertToCurrencyDecimals(weth.address, '9.9');
+
+        await mockAugustus.expectBuy(
+          weth.address,
+          dai.address,
+          swappedAmount,
+          expectedDaiAmount,
+          expectedDaiAmount
+        );
+        const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData('buy', [
+          weth.address,
+          dai.address,
+          liquidityToSwap,
+          expectedDaiAmount,
+        ]);
+
+        const params = buildParaswapBuyParams(mockAugustusCalldata, mockAugustus.address);
+        await aWETH.connect(user).approve(paraswapRepayAdapter.address, liquidityToSwap);
+        const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
+        const userWethBalanceBefore = await weth.balanceOf(userAddress);
+
+        await paraswapRepayAdapter
+          .connect(user)
+          .swapAndRepay(
+            weth.address,
+            dai.address,
+            liquidityToSwap,
+            expectedDaiAmount,
+            1,
+            0,
+            params,
+            {
+              amount: 0,
+              deadline: 0,
+              v: 0,
+              r: '0x0000000000000000000000000000000000000000000000000000000000000000',
+              s: '0x0000000000000000000000000000000000000000000000000000000000000000',
+            }
+          );
+
+        const adapterWethBalance = await weth.balanceOf(paraswapRepayAdapter.address);
+        const adapterDaiBalance = await dai.balanceOf(paraswapRepayAdapter.address);
+        const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress);
+        const userAEthBalance = await aWETH.balanceOf(userAddress);
+        const adapterAEthBalance = await aWETH.balanceOf(paraswapRepayAdapter.address);
+        const userWethBalance = await weth.balanceOf(userAddress);
+
+        expect(adapterAEthBalance).to.be.eq(Zero);
+        expect(adapterWethBalance).to.be.eq(Zero);
+        expect(adapterDaiBalance).to.be.eq(Zero);
+        expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount);
+        expect(userDaiStableDebtAmount).to.be.lt(expectedDaiAmount);
+        expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
+        expect(userAEthBalance).to.be.eq(userAEthBalanceBefore.sub(swappedAmount));
+        expect(userWethBalance).to.be.eq(userWethBalanceBefore);
+      });
+
+      it('should correctly swap tokens and repay the whole stable debt', async () => {
+        const { users, pool, weth, aWETH, oracle, dai, paraswapRepayAdapter, helpersContract } =
+          testEnv;
+        const user = users[0].signer;
+        const userAddress = users[0].address;
+
+        const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
+
+        const daiPrice = await oracle.getAssetPrice(dai.address);
+        const expectedDaiAmount = await convertToCurrencyDecimals(
+          dai.address,
+          new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
+        );
+
+        // Open user Debt
+        await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress);
+
+        const daiStableDebtTokenAddress = (
+          await helpersContract.getReserveTokensAddresses(dai.address)
+        ).stableDebtTokenAddress;
+
+        const daiStableDebtContract = await getContract<StableDebtToken>(
+          eContractid.StableDebtToken,
+          daiStableDebtTokenAddress
+        );
+
+        const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress);
+
+        // Add a % to repay on top of the debt
+        const liquidityToSwap = new BigNumber(amountWETHtoSwap.toString())
+          .multipliedBy(1.1)
+          .toFixed(0);
+
+        // Add a % to repay on top of the debt
+        const amountToRepay = new BigNumber(expectedDaiAmount.toString())
+          .multipliedBy(1.1)
+          .toFixed(0);
+
+        await mockAugustus.expectBuy(
+          weth.address,
+          dai.address,
+          liquidityToSwap,
+          expectedDaiAmount,
+          amountToRepay
+        );
+        const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData('buy', [
+          weth.address,
+          dai.address,
+          liquidityToSwap,
+          expectedDaiAmount,
+        ]);
+
+        const params = buildParaswapBuyParams(mockAugustusCalldata, mockAugustus.address);
+        await aWETH.connect(user).approve(paraswapRepayAdapter.address, liquidityToSwap);
+        const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
+
+        await paraswapRepayAdapter
+          .connect(user)
+          .swapAndRepay(
+            weth.address,
+            dai.address,
+            liquidityToSwap,
+            amountToRepay,
+            1,
+            4 + 3 * 32,
+            params,
+            {
+              amount: 0,
+              deadline: 0,
+              v: 0,
+              r: '0x0000000000000000000000000000000000000000000000000000000000000000',
+              s: '0x0000000000000000000000000000000000000000000000000000000000000000',
+            }
+          );
+
+        const adapterWethBalance = await weth.balanceOf(paraswapRepayAdapter.address);
+        const adapterDaiBalance = await dai.balanceOf(paraswapRepayAdapter.address);
+        const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress);
+        const userAEthBalance = await aWETH.balanceOf(userAddress);
+        const adapterAEthBalance = await aWETH.balanceOf(paraswapRepayAdapter.address);
+
+        expect(adapterAEthBalance).to.be.eq(Zero);
+        expect(adapterWethBalance).to.be.eq(Zero);
+        expect(adapterDaiBalance).to.be.eq(Zero);
+        expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount);
+        expect(userDaiStableDebtAmount).to.be.eq(Zero);
+        expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
+        expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap));
+      });
+
+      it('should correctly swap tokens and repay the whole variable debt', async () => {
+        const { users, pool, weth, aWETH, oracle, dai, paraswapRepayAdapter, helpersContract } =
+          testEnv;
+        const user = users[0].signer;
+        const userAddress = users[0].address;
+
+        const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
+
+        const daiPrice = await oracle.getAssetPrice(dai.address);
+        const expectedDaiAmount = await convertToCurrencyDecimals(
+          dai.address,
+          new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
+        );
+
+        // Open user Debt
+        await pool.connect(user).borrow(dai.address, expectedDaiAmount, 2, 0, userAddress);
+
+        const daiStableVariableTokenAddress = (
+          await helpersContract.getReserveTokensAddresses(dai.address)
+        ).variableDebtTokenAddress;
+
+        const daiVariableDebtContract = await getContract<StableDebtToken>(
+          eContractid.VariableDebtToken,
+          daiStableVariableTokenAddress
+        );
+
+        const userDaiVariableDebtAmountBefore = await daiVariableDebtContract.balanceOf(
+          userAddress
+        );
+
+        // Add a % to repay on top of the debt
+        const liquidityToSwap = new BigNumber(amountWETHtoSwap.toString())
+          .multipliedBy(1.1)
+          .toFixed(0);
+
+        // Add a % to repay on top of the debt
+        const amountToRepay = new BigNumber(expectedDaiAmount.toString())
+          .multipliedBy(1.1)
+          .toFixed(0);
+
+        await mockAugustus.expectBuy(
+          weth.address,
+          dai.address,
+          liquidityToSwap,
+          expectedDaiAmount,
+          amountToRepay
+        );
+        const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData('buy', [
+          weth.address,
+          dai.address,
+          liquidityToSwap,
+          expectedDaiAmount,
+        ]);
+
+        const params = buildParaswapBuyParams(mockAugustusCalldata, mockAugustus.address);
+        await aWETH.connect(user).approve(paraswapRepayAdapter.address, liquidityToSwap);
+        const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
+
+        await paraswapRepayAdapter
+          .connect(user)
+          .swapAndRepay(
+            weth.address,
+            dai.address,
+            liquidityToSwap,
+            amountToRepay,
+            2,
+            4 + 3 * 32,
+            params,
+            {
+              amount: 0,
+              deadline: 0,
+              v: 0,
+              r: '0x0000000000000000000000000000000000000000000000000000000000000000',
+              s: '0x0000000000000000000000000000000000000000000000000000000000000000',
+            }
+          );
+
+        const adapterWethBalance = await weth.balanceOf(paraswapRepayAdapter.address);
+        const adapterDaiBalance = await dai.balanceOf(paraswapRepayAdapter.address);
+        const userDaiVariableDebtAmount = await daiVariableDebtContract.balanceOf(userAddress);
+        const userAEthBalance = await aWETH.balanceOf(userAddress);
+        const adapterAEthBalance = await aWETH.balanceOf(paraswapRepayAdapter.address);
+
+        expect(adapterAEthBalance).to.be.eq(Zero);
+        expect(adapterWethBalance).to.be.eq(Zero);
+        expect(adapterDaiBalance).to.be.eq(Zero);
+        expect(userDaiVariableDebtAmountBefore).to.be.gte(expectedDaiAmount);
+        expect(userDaiVariableDebtAmount).to.be.eq(Zero);
+        expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
+        expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap));
+      });
+    });
+  });
+});