# DecentEthRouter.sol#_bridgeWithPayload() - Any refunded ETH (native token) will be refunded to the DecentBridgeAdapter, making them stuck

DecentEthRouter sets LayerZero refundAddress to msg.sender (DecentBridgeAdapter), so excess gas ETH refunds get stuck in a contract with no withdraw function.

- Payout: Contest reward
- Severity: medium
- Program: Decent
- Credited: deth
- Disclosed: 2024-03-22
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2024-01-decent-findings/issues/262
- Library page: https://bugbountylibrary.com/r/c4%3A2024-01-decent%3AM-05
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic

**Target:** DecentEthRouter._bridgeWithPayload / LayerZero sendAndCall refundAddress
**Root cause:** _bridgeWithPayload hardcodes refundAddress to payable(msg.sender), which is the DecentBridgeAdapter when called via UTB; the adapter has no withdraw/refund function, so excess native gas refunds are permanently trapped.
**Steps:**
1. Alice calls UTB.bridgeAndExecute with bridgeId of DecentBridgeAdapter, sending 0.5 ETH for gas
2. UTB.callBridge forwards value to DecentBridgeAdapter.bridge, which calls router.bridgeWithPayload{value: msg.value}
3. _bridgeWithPayload builds LzCallParams with `refundAddress: payable(msg.sender)` = DecentBridgeAdapter
4. LayerZero sendAndCall consumes only ~0.1 ETH, refunds 0.4 ETH to refundAddress (the adapter)
5. Adapter has no withdraw function; 0.4 ETH is stuck forever
**How found:** Traced the bridgeAndExecute -> callBridge -> DecentBridgeAdapter.bridge -> router.bridgeWithPayload call chain and noticed refundAddress is msg.sender rather than the user-supplied refund address, then checked the adapter for any withdraw capability and found none.
**Exploitation:** Any user overpaying native gas on a cross-chain bridge via DecentBridgeAdapter loses the excess; refunds accumulate in the adapter contract with no extraction path.
**Insight:** When a router is called by an intermediary adapter, msg.sender-based refund/recipient fields silently redirect value to the adapter; grep for `refundAddress`, `payable(msg.sender)` and check whether the intermediary can ever move native/ERC20 out.
