The Standard

The Standard
DeFiHardhat
20,000 USDC
View results
Submission Details
Severity: low
Invalid

Users will keep swapping and not be notified if #WETH withdrawal was successful if they encounter any issue

Summary

The code contains a potential vulnerability related to the withdrawal of Wrapped Ether (WETH). While it checks if the WETH balance is greater than zero before calling weth.withdraw(wethBalance), it lacks proper error handling to address potential failures during the withdrawal process. This can result in unforeseen issues if the withdrawal transaction fails for any reason.

Vulnerability Details

function swap(bytes32 _inToken, bytes32 _outToken, uint256 _amount) external onlyOwner {
uint256 swapFee = _amount * ISmartVaultManagerV3(manager).swapFeeRate() / ISmartVaultManagerV3(manager).HUNDRED_PC();
address inToken = getSwapAddressFor(_inToken);
uint256 minimumAmountOut = calculateMinimumAmountOut(_inToken, _outToken, _amount);
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
tokenIn: inToken,
tokenOut: getSwapAddressFor(_outToken),
fee: 3000,
recipient: address(this),
deadline: block.timestamp, <---- @audit Enables swapping consecutively with no deadline attached to the exhausted gas used.
amountIn: _amount - swapFee,
amountOutMinimum: minimumAmountOut,
sqrtPriceLimitX96: 0
});
inToken == ISmartVaultManagerV3(manager).weth() ?
executeNativeSwapAndFee(params, swapFee) :
executeERC20SwapAndFee(params, swapFee);
}

Alice initiates a swap transaction, triggering the executeNativeSwapAndFee function.
The contract holds some WETH, and the balance is greater than zero.

function executeERC20SwapAndFee(ISwapRouter.ExactInputSingleParams memory _params, uint256 _swapFee) private {
IERC20(_params.tokenIn).safeTransfer(ISmartVaultManagerV3(manager).protocol(), _swapFee);
IERC20(_params.tokenIn).safeApprove(ISmartVaultManagerV3(manager).swapRouter2(), _params.amountIn);
ISwapRouter(ISmartVaultManagerV3(manager).swapRouter2()).exactInputSingle(_params);
IWETH weth = IWETH(ISmartVaultManagerV3(manager).weth());
// convert potentially received weth to eth
uint256 wethBalance = weth.balanceOf(address(this));
if (wethBalance > 0) weth.withdraw(wethBalance); <--- @audit no error handling here!
}

During the execution of weth.withdraw(wethBalance), the withdrawal transaction encounters an issue, such as running out of gas, hitting a gas limit, or encountering a contract-specific failure.
The current code lacks proper error handling for the weth.withdraw call. If the withdrawal fails, the contract continues execution without addressing the failure.

The failure to withdraw WETH goes unnoticed, potentially leaving the contract in an inconsistent state.
Any subsequent logic assuming the successful withdrawal of WETH may be compromised, leading to unexpected behavior or loss of functionality.

Tools Used

Google and Github

Recommendations

https://github.com/Cyfrin/2023-12-the-standard/compare/main...Mylifechangefast:2023-12-the-standard:patch-2#diff-32d8c4063004c8579c2a378d7bcebd66ed8c94dee12713d69f3b4c0b241a3545

@@ -201,6 +201,8 @@ contract SmartVaultV3 is ISmartVault {
// convert potentially received weth to eth
uint256 wethBalance = weth.balanceOf(address(this));
if (wethBalance > 0) weth.withdraw(wethBalance);
(bool success,) = to.call{value: wethBalance}('');
require(success, 'WITHDRAW_TO_CALL_FAILED');
}
Updates

Lead Judging Commences

hrishibhat Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

informational/invalid

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.