OrderBook

First Flight #43
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Impact: low
Likelihood: low
Invalid

Emergency Withdrawal Function Lacks Balance Validation Leading to Transaction Failures

Root + Impact

Description

  • The emergencyWithdrawERC20() function does not validate that the contract actually holds the requested amount of tokens before attempting the transfer.

  • This can lead to failed transactions when the owner tries to withdraw more tokens than available.

  • Additionally, the function lacks validation for zero amounts, allowing wasteful transactions:


    Current problematic implementation:

function emergencyWithdrawERC20(address _tokenAddress, uint256 _amount, address _to) external onlyOwner {
// ...address validation...
// @> No check if _amount == 0
IERC20 token = IERC20(_tokenAddress);
token.safeTransfer(_to, _amount); // @> No balance check before transfer
emit EmergencyWithdrawal(_tokenAddress, _amount, _to); // @> Event emitted even if transfer fails
}

Risk

Likelihood:

  • Emergency situations require quick action where the owner may not have time to check exact token balances before calling the function.

  • Multiple emergency withdrawal attempts may occur during incident response, increasing chances of exceeding available balance.

Impact:

  • Transaction failures waste gas and delay emergency response when time-sensitive token recovery is needed.

  • Failed emergency withdrawals may prevent recovery of accidentally sent tokens during critical time windows.

Proof of Concept

  • The following scenario demonstrates how the lack of balance validation can cause transaction failures during emergency situations. An owner attempting to recover accidentally sent tokens may not know the exact contract balance and could request more than available, causing the entire transaction to revert and preventing legitimate emergency recovery operations.


// 1. Contract receives 100 LINK tokens accidentally
IERC20 linkToken = IERC20(0x514910771AF9Ca656af840dff83E8264EcF986CA);
// linkToken.balanceOf(address(orderBook)) == 100e18
// 2. Owner tries to withdraw more than available balance
orderBook.emergencyWithdrawERC20(
address(linkToken),
500e18, // Requesting 500 LINK but only 100 available
ownerWallet
); // ❌ Transaction reverts due to insufficient balance
// 3. Owner also tries with zero amount (wasteful but succeeds)
orderBook.emergencyWithdrawERC20(address(linkToken),
0, // Zero amount withdrawal
ownerWallet
); // ✅ Succeeds but wastes gas and emits misleading event
// 4. Both scenarios prevent efficient emergency token recovery

Recommended Mitigation

The fix involves adding proper balance validation and zero amount checks to ensure the emergency function operates reliably and efficiently.

This prevents transaction failures during emergency situations and ensures the function can only be used for legitimate recovery amounts. The validation also prevents wasteful zero-amount transactions that consume gas unnecessarily.

By checking the contract's actual token balance before attempting transfer, the owner can reliably recover accidentally sent tokens without encountering unexpected transaction reverts.

function emergencyWithdrawERC20(address _tokenAddress, uint256 _amount, address _to) external onlyOwner {
if (
_tokenAddress == address(iWETH) || _tokenAddress == address(iWBTC) || _tokenAddress == address(iWSOL)
|| _tokenAddress == address(iUSDC)
) {
revert("Cannot withdraw core order book tokens via emergency function");
}
if (_to == address(0)) {
revert InvalidAddress();
}
+ if (_amount == 0) {
+ revert InvalidAmount();
+ }
IERC20 token = IERC20(_tokenAddress);
+ uint256 contractBalance = token.balanceOf(address(this));
+ if (_amount > contractBalance) {
+ revert InvalidAmount();
+ }
token.safeTransfer(_to, _amount);
emit EmergencyWithdrawal(_tokenAddress,
Updates

Lead Judging Commences

yeahchibyke Lead Judge 9 days ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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