Open receive function can lock native ETH
Description
The LidoVault has a public payable receive function:
/// @notice Function to receive Ether. msg.data must be empty
receive() external payable {}
This is so that it can receive native ETH sent by the Lido withdrawal queue.
Impact
However, users may accidentally send ETH to the contract, which results in the ETH being stuck and effectively burned.
Recommendations
We recommend at least whitelisting the payable receive function to the Lido withdrawal value sender so that users cannot accidentally transfer value to the contract.
Another solution is to have a state variable that is temporarily set before any call to Lido's claimWithdrawal
and unset afterwards, and only allow the receive hook to not revert if that variable is set. This would prevent ETH from being locked by users calling claimWithdrawalsTo
with the recipient being the LidoVault. However, that situation is not likely something that a user accidentally does.
Note that it is not possible to completely prevent value from being stuck in the LidoVault without a permissioned emergency withdrawal function that sends it back out, because of self destructs, coinbase transfers, and transfers of value before deployment.
Remediation
This issue has been acknowledged by Saffron, and fixes were implemented in the following commits: