Native tokens can remain stuck in some contracts forever
Description
The ERC7786GatewayReceiver has an executeMessage()
function intended to be called by trusted cross-chain senders to execute cross-chain smart contract calls. Although this function is marked payable
, the function does not do anything with msg.value
.
The ERC7786GatewaySource contract has a sendMessage()
function that is intended to be called when messages are to be relayed to another chain. Although this function is marked payable
, it does not use the msg.value
nor does it have any method to retrieve native tokens from the contract.
The ProxyDomaRecord contract has three payable
functions: bridge()
, claimOwnership()
, and requestTokenization()
. The intention is for users to pass in a fee through msg.value
and for this fee to be transferred to the treasury. However, it does not prevent users from attaching more than the fee in msg.value
.
Impact
In the ERC7786GatewayReceiver case, if the cross-chain sender accidentally attaches any msg.value
to their transaction, the tokens will get stuck in this contract. There is no way to retrieve these tokens currently. This has a low impact.
In the ERC7786GatewaySource case, this is currently not an issue as none of the callers pass in any msg.value
. This has an informational impact.
In the ProxyDomaRecord case, if a user accidentally passes in more fees than required by the functions, any excess fees will stay stuck in the contract. There is no way to retrieve these tokens currently. This has a low impact.
Recommendations
We recommend adding a function to these contracts that allows withdrawing any native Ether that gets stuck.
Alternatively, either remove the payable
modifier from the functions that do not need it, or add stricter checks on the msg.value
so that excess tokens have no way of getting stuck.
Remediation
This issue has been acknowledged by D3, and a fix was implemented in commit 49d8c644↗.