diff --git a/src/contracts/ParaSwapDebtSwapAdapter.sol b/src/contracts/ParaSwapDebtSwapAdapter.sol index e53ad0a..891a4fe 100644 --- a/src/contracts/ParaSwapDebtSwapAdapter.sol +++ b/src/contracts/ParaSwapDebtSwapAdapter.sol @@ -38,6 +38,16 @@ abstract contract ParaSwapDebtSwapAdapter is address owner ) BaseParaSwapBuyAdapter(addressesProvider, pool, augustusRegistry) { transferOwnership(owner); + // set initial approval for all reserves + address[] memory reserves = POOL.getReservesList(); + for (uint256 i = 0; i < reserves.length; i++) { + IERC20WithPermit(reserves[i]).safeApprove(address(POOL), type(uint256).max); + } + } + + function renewAllowance(address reserve) public { + IERC20WithPermit(reserve).safeApprove(address(POOL), 0); + IERC20WithPermit(reserve).safeApprove(address(POOL), type(uint256).max); } /** @@ -121,9 +131,8 @@ abstract contract ParaSwapDebtSwapAdapter is // this might lead to a slight excess decrease uint256 excess = excessAfter > excessBefore ? excessAfter - excessBefore : 0; if (excess > 0) { - IERC20WithPermit(debtSwapParams.newDebtAsset).safeApprove(address(POOL), excess); + _conditionalRenewAllowance(debtSwapParams.newDebtAsset, excess); POOL.repay(debtSwapParams.newDebtAsset, excess, 2, msg.sender); - IERC20WithPermit(debtSwapParams.newDebtAsset).safeApprove(address(POOL), 0); } } @@ -155,7 +164,6 @@ abstract contract ParaSwapDebtSwapAdapter is * enough funds to repay and has approved the Pool to pull the total amount * @param assets The addresses of the flash-borrowed assets * @param amounts The amounts of the flash-borrowed assets - * @param fees The fees of the flash-borrowed assets * @param initiator The address of the flashloan initiator * @param params The byte-encoded params passed when initiating the flashloan * @return True if the execution of the operation succeeds, false otherwise @@ -163,7 +171,7 @@ abstract contract ParaSwapDebtSwapAdapter is function executeOperation( address[] calldata assets, uint256[] calldata amounts, - uint256[] calldata fees, + uint256[] calldata, address initiator, bytes calldata params ) external returns (bool) { @@ -179,9 +187,7 @@ abstract contract ParaSwapDebtSwapAdapter is uint256 collateralAmount = amounts[0]; // Supply - IERC20WithPermit(collateralAsset).safeApprove(address(POOL), collateralAmount); _supply(collateralAsset, collateralAmount, flashParams.user, REFERRER); - IERC20WithPermit(collateralAsset).safeApprove(address(POOL), 0); // Execute the nested flashloan address newAsset = flashParams.nestedFlashloanDebtAsset; @@ -192,8 +198,7 @@ abstract contract ParaSwapDebtSwapAdapter is (, , address aToken) = _getReserveData(collateralAsset); IERC20WithPermit(aToken).safeTransferFrom(flashParams.user, address(this), collateralAmount); // Could be rounding error but it's insignificant POOL.withdraw(collateralAsset, collateralAmount, address(this)); - - IERC20WithPermit(collateralAsset).safeApprove(address(POOL), collateralAmount + fees[0]); + _conditionalRenewAllowance(collateralAsset, collateralAmount); } else { // There is no need for additional collateral, execute the swap. _swapAndRepay(flashParams, IERC20Detailed(assets[0]), amounts[0]); @@ -221,14 +226,14 @@ abstract contract ParaSwapDebtSwapAdapter is swapParams.debtRepayAmount ); - IERC20WithPermit(swapParams.debtAsset).safeApprove(address(POOL), swapParams.debtRepayAmount); + _conditionalRenewAllowance(swapParams.debtAsset, swapParams.debtRepayAmount); + POOL.repay( address(swapParams.debtAsset), swapParams.debtRepayAmount, swapParams.debtRateMode, swapParams.user ); - IERC20WithPermit(swapParams.debtAsset).safeApprove(address(POOL), 0); //transfer excess of old debt asset back to the user, if any uint256 debtAssetExcess = amountBought - swapParams.debtRepayAmount; @@ -237,4 +242,11 @@ abstract contract ParaSwapDebtSwapAdapter is } return amountSold; } + + function _conditionalRenewAllowance(address asset, uint256 minAmount) internal { + uint256 allowance = IERC20(asset).allowance(address(this), address(POOL)); + if (allowance < minAmount) { + renewAllowance(asset); + } + } } diff --git a/src/contracts/ParaSwapDebtSwapAdapterV2.sol b/src/contracts/ParaSwapDebtSwapAdapterV2.sol index b49ed3f..2a6caea 100644 --- a/src/contracts/ParaSwapDebtSwapAdapterV2.sol +++ b/src/contracts/ParaSwapDebtSwapAdapterV2.sol @@ -19,9 +19,7 @@ contract ParaSwapDebtSwapAdapterV2 is ParaSwapDebtSwapAdapter { address owner ) ParaSwapDebtSwapAdapter(addressesProvider, pool, augustusRegistry, owner) {} - function _getReserveData( - address asset - ) internal view override returns (address, address, address) { + function _getReserveData(address asset) internal view override returns (address, address, address) { DataTypes.ReserveData memory reserveData = ILendingPool(address(POOL)).getReserveData(asset); return ( reserveData.variableDebtTokenAddress, diff --git a/src/contracts/ParaSwapDebtSwapAdapterV3GHO.sol b/src/contracts/ParaSwapDebtSwapAdapterV3GHO.sol index 431aa6c..a1da142 100644 --- a/src/contracts/ParaSwapDebtSwapAdapterV3GHO.sol +++ b/src/contracts/ParaSwapDebtSwapAdapterV3GHO.sol @@ -28,7 +28,9 @@ contract ParaSwapDebtSwapAdapterV3GHO is ParaSwapDebtSwapAdapterV3, IERC3156Flas address pool, IParaSwapAugustusRegistry augustusRegistry, address owner - ) ParaSwapDebtSwapAdapterV3(addressesProvider, pool, augustusRegistry, owner) {} + ) ParaSwapDebtSwapAdapterV3(addressesProvider, pool, augustusRegistry, owner) { + IERC20(GHO).approve(address(GHO_FLASH_MINTER), type(uint256).max); + } /// @dev ERC-3156 Flash loan callback (in this case flash mint) function onFlashLoan( @@ -46,7 +48,6 @@ contract ParaSwapDebtSwapAdapterV3GHO is ParaSwapDebtSwapAdapterV3, IERC3156Flas POOL.borrow(GHO, (amountSold + fee), 2, REFERRER, swapParams.user); - IERC20(GHO).approve(address(GHO_FLASH_MINTER), amount + fee); return keccak256('ERC3156FlashBorrower.onFlashLoan'); } diff --git a/tests/DebtSwapV3.t.sol b/tests/DebtSwapV3.t.sol index 61da742..bc10416 100644 --- a/tests/DebtSwapV3.t.sol +++ b/tests/DebtSwapV3.t.sol @@ -248,7 +248,7 @@ contract DebtSwapV3Test is BaseTest { address(debtSwapAdapter), address(AaveV3Ethereum.POOL) ), - 0 + type(uint256).max ); vm.record();