transfer Causes ETH Withdrawals to Fail for Gas-Heavy ReceiversThe withdraw function transfers ETH using Solidity’s built-in transfer method:
Using transfer is considered a bad practice in modern Solidity development. These methods forward a fixed gas stipend of 2300 gas to the recipient. However, due to protocol upgrades such as EIP-1884, EIP-2929, and subsequent gas repricing changes, certain operations that were previously inexpensive — most notably storage writes inside receive() or fallback()—now require more than 2300 gas.
As a result, if the target address is a smart contract whose receive() function performs any gas-expensive operation (e.g., modifying storage), the ETH transfer will revert. This makes the withdrawal mechanism unreliable and potentially unusable under valid and realistic conditions.
Likelihood: High / Impact: Medium
The likelihood is high because the withdrawal function is publicly callable by the owner and does not restrict the target address to externally owned accounts. Any attempt to withdraw ETH to a smart contract with a non-trivial receive() implementation will consistently revert. The impact is medium: while no funds are directly stolen, ETH held by the contract can become effectively locked, preventing successful withdrawals and breaking a core administrative function of the protocol.
The following proof demonstrates that withdrawing ETH fails when the recipient contract requires more than 2300 gas in its receive() function.
To reproduce the issue, we first deploy a receiver contract that performs a gas-expensive operation upon receiving ETH. As an example, we modify a storage variable, which exceeds the gas stipend provided by transfer.
Next, we attempt to withdraw ETH from the protocol contract to this receiver:
To run the test, use the following Foundry command:
Output:
This confirms that under certain realistic conditions, ETH withdrawals become impossible when using transfer.
Replace the use of transfer with a low-level call, which forwards all remaining gas and properly handles modern gas costs. Additionally, the return value of call should be checked to ensure the transfer succeeds.
A corrected version of the withdrawal function would look as follows:
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.