From 105baafdb65ab700859b55f2280530cc767cc0dc Mon Sep 17 00:00:00 2001 From: miguelmtz <36620902+miguelmtzinf@users.noreply.github.com> Date: Tue, 17 Sep 2024 09:23:27 +0200 Subject: [PATCH] fix: Transfer excess back and reset allowance (#49) --- .../paraswap/BaseParaSwapBuyAdapter.sol | 13 ++++++---- .../paraswap/BaseParaSwapSellAdapter.sol | 1 + .../paraswap/ParaSwapRepayAdapter.sol | 26 +++++++++++++++---- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/periphery/contracts/adapters/paraswap/BaseParaSwapBuyAdapter.sol b/src/periphery/contracts/adapters/paraswap/BaseParaSwapBuyAdapter.sol index 9fcfdc11..522ac1c8 100644 --- a/src/periphery/contracts/adapters/paraswap/BaseParaSwapBuyAdapter.sol +++ b/src/periphery/contracts/adapters/paraswap/BaseParaSwapBuyAdapter.sol @@ -39,6 +39,7 @@ abstract contract BaseParaSwapBuyAdapter is BaseParaSwapAdapter { * @param maxAmountToSwap Max amount to be swapped * @param amountToReceive Amount to be received from the swap * @return amountSold The amount sold during the swap + * @return amountBought The amount bought during the swap */ function _buyOnParaSwap( uint256 toAmountOffset, @@ -47,7 +48,7 @@ abstract contract BaseParaSwapBuyAdapter is BaseParaSwapAdapter { IERC20Detailed assetToSwapTo, uint256 maxAmountToSwap, uint256 amountToReceive - ) internal returns (uint256 amountSold) { + ) internal returns (uint256 amountSold, uint256 amountBought) { (bytes memory buyCalldata, IParaSwapAugustus augustus) = abi.decode( paraswapData, (bytes, IParaSwapAugustus) @@ -75,7 +76,6 @@ abstract contract BaseParaSwapBuyAdapter is BaseParaSwapAdapter { uint256 balanceBeforeAssetTo = assetToSwapTo.balanceOf(address(this)); address tokenTransferProxy = augustus.getTokenTransferProxy(); - assetToSwapFrom.safeApprove(tokenTransferProxy, 0); assetToSwapFrom.safeApprove(tokenTransferProxy, maxAmountToSwap); if (toAmountOffset != 0) { @@ -101,12 +101,15 @@ abstract contract BaseParaSwapBuyAdapter is BaseParaSwapAdapter { } } + // Reset allowance + assetToSwapFrom.safeApprove(tokenTransferProxy, 0); + 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'); + amountBought = assetToSwapTo.balanceOf(address(this)).sub(balanceBeforeAssetTo); + require(amountBought >= amountToReceive, 'INSUFFICIENT_AMOUNT_RECEIVED'); - emit Bought(address(assetToSwapFrom), address(assetToSwapTo), amountSold, amountReceived); + emit Bought(address(assetToSwapFrom), address(assetToSwapTo), amountSold, amountBought); } } diff --git a/src/periphery/contracts/adapters/paraswap/BaseParaSwapSellAdapter.sol b/src/periphery/contracts/adapters/paraswap/BaseParaSwapSellAdapter.sol index 8086a5c0..ce34288c 100644 --- a/src/periphery/contracts/adapters/paraswap/BaseParaSwapSellAdapter.sol +++ b/src/periphery/contracts/adapters/paraswap/BaseParaSwapSellAdapter.sol @@ -98,6 +98,7 @@ abstract contract BaseParaSwapSellAdapter is BaseParaSwapAdapter { revert(0, returndatasize()) } } + require( assetToSwapFrom.balanceOf(address(this)) == balanceBeforeAssetFrom - amountToSwap, 'WRONG_BALANCE_AFTER_SWAP' diff --git a/src/periphery/contracts/adapters/paraswap/ParaSwapRepayAdapter.sol b/src/periphery/contracts/adapters/paraswap/ParaSwapRepayAdapter.sol index f776c757..f199b9ba 100644 --- a/src/periphery/contracts/adapters/paraswap/ParaSwapRepayAdapter.sol +++ b/src/periphery/contracts/adapters/paraswap/ParaSwapRepayAdapter.sol @@ -114,7 +114,7 @@ contract ParaSwapRepayAdapter is BaseParaSwapBuyAdapter, ReentrancyGuard { // Pull aTokens from user _pullATokenAndWithdraw(address(collateralAsset), msg.sender, collateralAmount, permitSignature); //buy debt asset using collateral asset - uint256 amountSold = _buyOnParaSwap( + (uint256 amountSold, uint256 amountBought) = _buyOnParaSwap( buyAllBalanceOffset, paraswapData, collateralAsset, @@ -127,15 +127,23 @@ contract ParaSwapRepayAdapter is BaseParaSwapBuyAdapter, ReentrancyGuard { //deposit collateral back in the pool, if left after the swap(buy) if (collateralBalanceLeft > 0) { - IERC20(collateralAsset).safeApprove(address(POOL), 0); IERC20(collateralAsset).safeApprove(address(POOL), collateralBalanceLeft); POOL.deposit(address(collateralAsset), collateralBalanceLeft, msg.sender, 0); + IERC20(collateralAsset).safeApprove(address(POOL), 0); } // Repay debt. Approves 0 first to comply with tokens that implement the anti frontrunning approval fix - IERC20(debtAsset).safeApprove(address(POOL), 0); IERC20(debtAsset).safeApprove(address(POOL), debtRepayAmount); POOL.repay(address(debtAsset), debtRepayAmount, debtRateMode, msg.sender); + IERC20(debtAsset).safeApprove(address(POOL), 0); + + { + //transfer excess of debtAsset back to the user, if any + uint256 debtAssetExcess = amountBought - debtRepayAmount; + if (debtAssetExcess > 0) { + IERC20(debtAsset).safeTransfer(msg.sender, debtAssetExcess); + } + } } /** @@ -170,7 +178,7 @@ contract ParaSwapRepayAdapter is BaseParaSwapBuyAdapter, ReentrancyGuard { initiator ); - uint256 amountSold = _buyOnParaSwap( + (uint256 amountSold, uint256 amountBought) = _buyOnParaSwap( buyAllBalanceOffset, paraswapData, collateralAsset, @@ -180,9 +188,9 @@ contract ParaSwapRepayAdapter is BaseParaSwapBuyAdapter, ReentrancyGuard { ); // Repay debt. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix. - IERC20(debtAsset).safeApprove(address(POOL), 0); IERC20(debtAsset).safeApprove(address(POOL), debtRepayAmount); POOL.repay(address(debtAsset), debtRepayAmount, rateMode, initiator); + IERC20(debtAsset).safeApprove(address(POOL), 0); uint256 neededForFlashLoanRepay = amountSold.add(premium); @@ -194,6 +202,14 @@ contract ParaSwapRepayAdapter is BaseParaSwapBuyAdapter, ReentrancyGuard { permitSignature ); + { + //transfer excess of debtAsset back to the user, if any + uint256 debtAssetExcess = amountBought - debtRepayAmount; + if (debtAssetExcess > 0) { + IERC20(debtAsset).safeTransfer(initiator, debtAssetExcess); + } + } + // Repay flashloan. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix. IERC20(collateralAsset).safeApprove(address(POOL), 0); IERC20(collateralAsset).safeApprove(address(POOL), collateralAmount.add(premium));