Did Not Approve To Zero First
Allowance was not set to zero first before changing the allowance.\\nSome ERC20 tokens (like USDT) do not work when changing the allowance from an existing non-zero allowance value. For example Tether (USDT)'s `approve()` function will revert if the current approval is not zero, to protect against front-running changes of approvals.\\nThe following attempt to call the `approve()` function without setting the allowance to zero first.\\n```\\nFile: TokenUtils.sol\\n    function checkApprove(IERC20 token, address spender, uint256 amount) internal {\\n        if (address(token) == address(0)) return;\\n\\n        IEIP20NonStandard(address(token)).approve(spender, amount);\\n        _checkReturnCode();\\n    }\\n```\\n\\nHowever, if the token involved is an ERC20 token that does not work when changing the allowance from an existing non-zero allowance value, it will break a number of key functions or features of the protocol as the `TokenUtils.checkApprove` function is utilised extensively within the vault as shown below.\\n```\\nFile: TwoTokenPoolUtils.sol\\n    function _approveBalancerTokens(TwoTokenPoolContext memory poolContext, address bptSpender) internal {\\n        IERC20(poolContext.primaryToken).checkApprove(address(Deployments.BALANCER_VAULT), type(uint256).max);\\n        IERC20(poolContext.secondaryToken).checkApprove(address(Deployments.BALANCER_VAULT), type(uint256).max);\\n        // Allow BPT spender to pull BALANCER_POOL_TOKEN\\n        IERC20(address(poolContext.basePool.pool)).checkApprove(bptSpender, type(uint256).max);\\n    }\\n```\\n\\n```\\nFile: Boosted3TokenPoolUtils.sol\\n    function _approveBalancerTokens(ThreeTokenPoolContext memory poolContext, address bptSpender) internal {\\n        poolContext.basePool._approveBalancerTokens(bptSpender);\\n\\n        IERC20(poolContext.tertiaryToken).checkApprove(address(Deployments.BALANCER_VAULT), type(uint256).max);\\n\\n        // For boosted pools, the tokens inside pool context are AaveLinearPool tokens.\\n        // So, we need to approve the _underlyingToken (primary borrow currency) for trading.\\n        IBoostedPool underlyingPool = IBoostedPool(poolContext.basePool.primaryToken);\\n        address primaryUnderlyingAddress = BalancerUtils.getTokenAddress(underlyingPool.getMainToken());\\n        IERC20(primaryUnderlyingAddress).checkApprove(address(Deployments.BALANCER_VAULT), type(uint256).max);\\n    }\\n```\\n\\n```\\nFile: TradingUtils.sol\\n    /// @notice Approve exchange to pull from this contract\\n    /// @dev approve up to trade.amount for EXACT_IN trades and up to trade.limit\\n    /// for EXACT_OUT trades\\n    function _approve(Trade memory trade, address spender) private {\\n        uint256 allowance = _isExactIn(trade) ? trade.amount : trade.limit;\\n        IERC20(trade.sellToken).checkApprove(spender, allowance);\\n    }\\n```\\n\\n```\\nFile: StrategyUtils.sol\\n            IERC20(buyToken).checkApprove(address(Deployments.WRAPPED_STETH), amountBought);\\n            uint256 wrappedAmount = Deployments.WRAPPED_STETH.balanceOf(address(this));\\n            /// @notice the amount returned by wrap is not always accurate for some reason\\n            Deployments.WRAPPED_STETH.wrap(amountBought);\\n            amountBought = Deployments.WRAPPED_STETH.balanceOf(address(this)) - wrappedAmount;\\n```\\n
It is recommended to set the allowance to zero before increasing the allowance and use safeApprove/safeIncreaseAllowance.
A number of features within the vaults will not work if the `approve` function reverts.
```\\nFile: TokenUtils.sol\\n    function checkApprove(IERC20 token, address spender, uint256 amount) internal {\\n        if (address(token) == address(0)) return;\\n\\n        IEIP20NonStandard(address(token)).approve(spender, amount);\\n        _checkReturnCode();\\n    }\\n```\\n