Vulnerability: Did Not Approve To Zero First
Severity: medium

Description:
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

Impact:
A number of features within the vaults will not work if the `approve` function reverts.

Recommended mitigation:
It is recommended to set the allowance to zero before increasing the allowance and use safeApprove/safeIncreaseAllowance.