Allowance was not set to zero first before changing the allowance.
Vulnerability Detail
Some 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.
The following attempt to call the approve() function without setting the allowance to zero first.
However, 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.
File: TradingUtils.sol
110: /// @notice Approve exchange to pull from this contract
111: /// @dev approve up to trade.amount for EXACT_IN trades and up to trade.limit
112: /// for EXACT_OUT trades
113: function _approve(Trade memory trade, address spender) private {
114: uint256 allowance = _isExactIn(trade) ? trade.amount : trade.limit;
115: IERC20(trade.sellToken).checkApprove(spender, allowance);
116: }
File: StrategyUtils.sol
85: IERC20(buyToken).checkApprove(address(Deployments.WRAPPED_STETH), amountBought);
86: uint256 wrappedAmount = Deployments.WRAPPED_STETH.balanceOf(address(this));
87: /// @notice the amount returned by wrap is not always accurate for some reason
88: Deployments.WRAPPED_STETH.wrap(amountBought);
89: amountBought = Deployments.WRAPPED_STETH.balanceOf(address(this)) - wrappedAmount;
Impact
A number of features within the vaults will not work if the approve function reverts.
xiaoming90
medium
Did Not Approve To Zero First
Summary
Allowance was not set to zero first before changing the allowance.
Vulnerability Detail
Some 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.The following attempt to call the
approve()
function without setting the allowance to zero first.https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/utils/TokenUtils.sol#L18
However, 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.https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/balancer/internal/pool/TwoTokenPoolUtils.sol#L159
https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/balancer/internal/pool/Boosted3TokenPoolUtils.sol#L225
https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/trading/TradingUtils.sol#L115
https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/balancer/internal/strategy/StrategyUtils.sol#L85
Impact
A number of features within the vaults will not work if the
approve
function reverts.Code Snippet
https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/utils/TokenUtils.sol#L18 https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/balancer/internal/pool/TwoTokenPoolUtils.sol#L159 https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/balancer/internal/pool/Boosted3TokenPoolUtils.sol#L225 https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/trading/TradingUtils.sol#L115 https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/balancer/internal/strategy/StrategyUtils.sol#L85
Tool used
Manual Review
Recommendation
It is recommended to set the allowance to zero before increasing the allowance and use safeApprove/safeIncreaseAllowance.