From 773bdd252b311a1929c26b9339ace1b78c41e533 Mon Sep 17 00:00:00 2001
From: The3D <frangellaemilio@gmail.com>
Date: Thu, 14 Jan 2021 15:21:42 +0100
Subject: [PATCH] Added latest fixes

---
 contracts/adapters/BaseUniswapAdapter.sol     | 28 ++++++++---
 .../adapters/UniswapLiquiditySwapAdapter.sol  | 46 +++++++++++++------
 contracts/adapters/UniswapRepayAdapter.sol    | 21 +++++----
 3 files changed, 64 insertions(+), 31 deletions(-)

diff --git a/contracts/adapters/BaseUniswapAdapter.sol b/contracts/adapters/BaseUniswapAdapter.sol
index 8cd80faf..b04bc8a1 100644
--- a/contracts/adapters/BaseUniswapAdapter.sol
+++ b/contracts/adapters/BaseUniswapAdapter.sol
@@ -150,7 +150,9 @@ abstract contract BaseUniswapAdapter is FlashLoanReceiverBase, IBaseUniswapAdapt
 
     require(expectedMinAmountOut < minAmountOut, 'minAmountOut exceed max slippage');
 
-    IERC20(assetToSwapFrom).approve(address(UNISWAP_ROUTER), amountToSwap);
+    // Approves the transfer for the swap. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.
+    IERC20(assetToSwapFrom).safeApprove(address(UNISWAP_ROUTER), 0);
+    IERC20(assetToSwapFrom).safeApprove(address(UNISWAP_ROUTER), amountToSwap);
 
     address[] memory path;
     if (useEthPath) {
@@ -190,7 +192,8 @@ abstract contract BaseUniswapAdapter is FlashLoanReceiverBase, IBaseUniswapAdapt
     address assetToSwapFrom,
     address assetToSwapTo,
     uint256 maxAmountToSwap,
-    uint256 amountToReceive
+    uint256 amountToReceive,
+    bool useEthPath
   ) internal returns (uint256) {
     uint256 fromAssetDecimals = _getDecimals(assetToSwapFrom);
     uint256 toAssetDecimals = _getDecimals(assetToSwapTo);
@@ -206,11 +209,22 @@ abstract contract BaseUniswapAdapter is FlashLoanReceiverBase, IBaseUniswapAdapt
 
     require(maxAmountToSwap < expectedMaxAmountToSwap, 'maxAmountToSwap exceed max slippage');
 
-    IERC20(assetToSwapFrom).approve(address(UNISWAP_ROUTER), maxAmountToSwap);
+    // Approves the transfer for the swap. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.
+    IERC20(assetToSwapFrom).safeApprove(address(UNISWAP_ROUTER), 0);
+    IERC20(assetToSwapFrom).safeApprove(address(UNISWAP_ROUTER), maxAmountToSwap);
+
+    address[] memory path;
+    if (useEthPath) {
+      path = new address[](3);
+      path[0] = assetToSwapFrom;
+      path[1] = WETH_ADDRESS;
+      path[2] = assetToSwapTo;
+    } else {
+      path = new address[](2);
+      path[0] = assetToSwapFrom;
+      path[1] = assetToSwapTo;
+    }
 
-    address[] memory path = new address[](2);
-    path[0] = assetToSwapFrom;
-    path[1] = assetToSwapTo;
     uint256[] memory amounts =
       UNISWAP_ROUTER.swapTokensForExactTokens(
         amountToReceive,
@@ -472,7 +486,7 @@ abstract contract BaseUniswapAdapter is FlashLoanReceiverBase, IBaseUniswapAdapt
       amountsWithoutWeth = resultAmounts;
 
       return
-        (amountsWithWeth[2] > amountsWithoutWeth[1])
+        (amountsWithWeth[0] < amountsWithoutWeth[0] && amountsWithWeth[0] != 0)
           ? (amountsWithWeth, pathWithWeth)
           : (amountsWithoutWeth, simplePath);
     } catch {
diff --git a/contracts/adapters/UniswapLiquiditySwapAdapter.sol b/contracts/adapters/UniswapLiquiditySwapAdapter.sol
index aaf13406..44745ad5 100644
--- a/contracts/adapters/UniswapLiquiditySwapAdapter.sol
+++ b/contracts/adapters/UniswapLiquiditySwapAdapter.sol
@@ -170,7 +170,8 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter {
       );
 
       // Deposit new reserve
-      IERC20(assetToSwapToList[vars.i]).approve(address(LENDING_POOL), vars.receivedAmount);
+      IERC20(assetToSwapToList[vars.i]).safeApprove(address(LENDING_POOL), 0);
+      IERC20(assetToSwapToList[vars.i]).safeApprove(address(LENDING_POOL), vars.receivedAmount);
       LENDING_POOL.deposit(assetToSwapToList[vars.i], vars.receivedAmount, msg.sender, 0);
     }
   }
@@ -186,6 +187,16 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter {
    * @param permitSignature List of struct containing the permit signature
    * @param useEthPath true if the swap needs to occur using ETH in the routing, false otherwise
    */
+   
+  struct SwapLiquidityLocalVars {
+   address aToken;
+   uint256 aTokenInitiatorBalance;
+   uint256 amountToSwap;
+   uint256 receivedAmount;
+   uint256 flashLoanDebt;
+   uint256 amountToPull;
+  }
+  
   function _swapLiquidity(
     address assetFrom,
     address assetTo,
@@ -197,28 +208,33 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter {
     PermitSignature memory permitSignature,
     bool useEthPath
   ) internal {
-    address aToken = _getReserveData(assetFrom).aTokenAddress;
+    
+    SwapLiquidityLocalVars memory vars;
+    
+    vars.aToken = _getReserveData(assetFrom).aTokenAddress;
 
-    uint256 aTokenInitiatorBalance = IERC20(aToken).balanceOf(initiator);
-    uint256 amountToSwap =
-      swapAllBalance && aTokenInitiatorBalance.sub(premium) <= amount
-        ? aTokenInitiatorBalance.sub(premium)
+    vars.aTokenInitiatorBalance = IERC20(vars.aToken).balanceOf(initiator);
+    vars.amountToSwap =
+      swapAllBalance && vars.aTokenInitiatorBalance.sub(premium) <= amount
+        ? vars.aTokenInitiatorBalance.sub(premium)
         : amount;
 
-    uint256 receivedAmount =
-      _swapExactTokensForTokens(assetFrom, assetTo, amountToSwap, minAmountToReceive, useEthPath);
+    vars.receivedAmount =
+      _swapExactTokensForTokens(assetFrom, assetTo, vars.amountToSwap, minAmountToReceive, useEthPath);
 
     // Deposit new reserve
-    IERC20(assetTo).approve(address(LENDING_POOL), receivedAmount);
-    LENDING_POOL.deposit(assetTo, receivedAmount, initiator, 0);
+    IERC20(assetTo).safeApprove(address(LENDING_POOL), 0);
+    IERC20(assetTo).safeApprove(address(LENDING_POOL), vars.receivedAmount);
+    LENDING_POOL.deposit(assetTo, vars.receivedAmount, initiator, 0);
 
-    uint256 flashLoanDebt = amount.add(premium);
-    uint256 amountToPull = amountToSwap.add(premium);
+    vars.flashLoanDebt = amount.add(premium);
+    vars.amountToPull = vars.amountToSwap.add(premium);
 
-    _pullAToken(assetFrom, aToken, initiator, amountToPull, permitSignature);
+    _pullAToken(assetFrom, vars.aToken, initiator, vars.amountToPull, permitSignature);
 
     // Repay flash loan
-    IERC20(assetFrom).approve(address(LENDING_POOL), flashLoanDebt);
+    IERC20(assetFrom).safeApprove(address(LENDING_POOL), 0);
+    IERC20(assetFrom).safeApprove(address(LENDING_POOL), vars.flashLoanDebt);
   }
 
   /**
@@ -261,4 +277,4 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter {
         useEthPath
       );
   }
-}
+}
\ No newline at end of file
diff --git a/contracts/adapters/UniswapRepayAdapter.sol b/contracts/adapters/UniswapRepayAdapter.sol
index b5ce12bb..c4e7817e 100644
--- a/contracts/adapters/UniswapRepayAdapter.sol
+++ b/contracts/adapters/UniswapRepayAdapter.sol
@@ -129,7 +129,7 @@ contract UniswapRepayAdapter is BaseUniswapAdapter {
       );
 
       // Swap collateral for debt asset
-      _swapTokensForExactTokens(collateralAsset, debtAsset, amounts[0], amountToRepay);
+      _swapTokensForExactTokens(collateralAsset, debtAsset, amounts[0], amountToRepay, useEthPath);
     } else {
       // Pull aTokens from user
       _pullAToken(
@@ -141,8 +141,9 @@ contract UniswapRepayAdapter is BaseUniswapAdapter {
       );
     }
 
-    // Repay debt
-    IERC20(debtAsset).approve(address(LENDING_POOL), amountToRepay);
+    // 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), amountToRepay);
     LENDING_POOL.repay(debtAsset, amountToRepay, debtRateMode, msg.sender);
   }
 
@@ -171,8 +172,9 @@ contract UniswapRepayAdapter is BaseUniswapAdapter {
   ) internal {
     DataTypes.ReserveData memory collateralReserveData = _getReserveData(collateralAsset);
 
-    // Repay debt
-    IERC20(debtAsset).approve(address(LENDING_POOL), amount);
+    // 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), amount);
     uint256 repaidAmount = IERC20(debtAsset).balanceOf(address(this));
     LENDING_POOL.repay(debtAsset, amount, rateMode, initiator);
     repaidAmount = repaidAmount.sub(IERC20(debtAsset).balanceOf(address(this)));
@@ -198,7 +200,7 @@ contract UniswapRepayAdapter is BaseUniswapAdapter {
       );
 
       // Swap collateral asset to the debt asset
-      _swapTokensForExactTokens(collateralAsset, debtAsset, amounts[0], neededForFlashLoanDebt);
+      _swapTokensForExactTokens(collateralAsset, debtAsset, amounts[0], neededForFlashLoanDebt, useEthPath);
     } else {
       // Pull aTokens from user
       _pullAToken(
@@ -210,8 +212,9 @@ contract UniswapRepayAdapter is BaseUniswapAdapter {
       );
     }
 
-    // Repay flash loan
-    IERC20(debtAsset).approve(address(LENDING_POOL), amount.add(premium));
+    // Repay flashloan. 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), amount.add(premium));
   }
 
   /**
@@ -253,4 +256,4 @@ contract UniswapRepayAdapter is BaseUniswapAdapter {
         useEthPath
       );
   }
-}
+}
\ No newline at end of file