# Refunds to EOAs on unsuccessful cross-chain messages fail, leaving users’ funds stuck in the gateway

Failed cross-chain Transfer messages refund EOAs via functionCallWithValue, which reverts on codeless addresses, trapping funds in the gateway.

- Payout: Contest reward
- Severity: medium
- Program: Recall
- Credited: muellerberndt
- Disclosed: 2026-03-13
- Write-up quality: 7/10
- Original: https://code4rena.com/reports/2025-02-recall#m-02
- Library page: https://bugbountylibrary.com/r/c4%3A2025-02-recall%3AM-02
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** IPC gateway cross-chain message refund path (CrossMsgHelper/AssetHelper)
**Root cause:** Result message refunds use AssetHelper.functionCallWithValue, which requires the recipient to be a contract; EOAs have no code so the refund call reverts and value stays in the gateway.
**Steps:**
1. Register a subnet actor with genesis circulating supply on the gateway diamond.
2. Construct an IpcEnvelope of kind Transfer from an EOA to a destination subnet with value TEST_AMOUNT.
3. Build a ResultMsg with OutcomeType.SystemErr and wrap it in an IpcEnvelope of kind Result from original.to to original.from (the EOA) carrying the refund value.
4. Commit a BottomUpCheckpoint containing that Result envelope via `checkpointer().commitCheckpoint(checkpoint)`.
5. Observe EOA balance unchanged and gateway balance unchanged — refund reverted silently.
**How found:** Code reading: noticed LibGateway.sendReceipt comment claims Transfer messages are handled by the peer client, but code sends receipts for both Call and Transfer; then traced the refund path to AssetHelper.functionCallWithValue and realized it reverts for codeless EOA addresses.
**Exploitation:** Any user whose cross-chain Transfer fails gets a Result message routed back; the refund path calls functionCallWithValue on the EOA, reverts, and the value remains locked in the gateway with no alternative refund mechanism.
**Insight:** When a comment says a code path is handled elsewhere, verify the actual implementation — here the receipt logic contradicted its own comment, and the refund helper's contract-only assumption silently broke EOA refunds.
