# Bridged tokens would be lost if sender and receiver are contracts that don't implement fallback/receive

ERC20Vault.onMessageInvocation always calls sendEther even with zero value, reverting bridging to contracts lacking receive/fallback and locking tokens.

- Payout: Contest reward
- Severity: medium
- Program: Taiko
- Credited: Shield
- Disclosed: 2024-04-26
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2024-03-taiko-findings/issues/226
- Library page: https://bugbountylibrary.com/r/c4%3A2024-03-taiko%3AM-08
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:dos

**Target:** ERC20Vault bridge contract (onMessageInvocation/sendEther)
**Root cause:** onMessageInvocation unconditionally calls to.sendEther(msg.value) even when msg.value is zero; sendEther performs an empty-data call that reverts on contracts without fallback/receive.
**Steps:**
1. Deploy a contract `NoFallback` with no fallback/receive.
2. On dest chain, call `sendReceiveERC20ToERC20Vault(...)` with `to = address(new NoFallback())` and `amount = 0`.
3. Observe revert `ETH_TRANSFER_FAILED()` because sendEther is invoked with zero value.
4. For recall path: set sender to a NoFallback contract, call `sendToken(...)`, then `bridge.recallMessage(...)`; recall reverts similarly.
**How found:** Code reading of onMessageInvocation revealed sendEther is called unconditionally regardless of msg.value; PoC with a no-fallback contract confirmed the revert.
**Exploitation:** Bridged ERC20 transfers to a contract recipient without fallback/receive revert at finalization; recall also reverts if the original sender is such a contract, leaving tokens stuck in the vault.
**Insight:** When auditing bridge/vault message handlers, check for unconditional native-value sends (even zero-value) to arbitrary recipient addresses; contracts without receive/fallback will revert, and the same recipient may also block the recall path.
