# Refund mechanism for failed cross-chain transactions does not work

In Tapioca USDO/TOFT cross-chain modules, the refund transfer before a forwarded revert is rolled back, permanently locking bridged funds on failed remote execution.

- Payout: Contest reward
- Severity: high
- Program: Tapioca DAO
- Credited: peakbolt
- Disclosed: 2023-11-16
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-07-tapioca-findings/issues/1163
- Library page: https://bugbountylibrary.com/r/c4%3A2023-07-tapioca%3AH-23
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:chained technique:source-review vuln:accounting-error vuln:business-logic

**Target:** USDO/TOFT cross-chain modules (USDOLeverageModule, USDOMarketModule, USDOOptionsModule, BaseTOFT* modules)
**Root cause:** On delegatecall failure the module safeTransfers the bridged amount back to the user, then reverts to forward the error to the main executor; the revert unwinds the refund transfer, so no funds are returned and retryMessage cannot recover permanent failures.
**Steps:**
1. Add `revert()` at start of `leverageUpInternal()` in USDOLeverageModule.sol to simulate permanent remote failure.
2. Add `console.log` of `USDO_10.balanceOf(deployer.address)` at singularity.test.ts#L4113.
3. Run `'should bounce between 2 chains'` under `multiHopBuyCollateral()` tests.
4. Observe deployer balance does not include the refunded amount; funds remain locked in contract.
**How found:** Code reading of the refund branch in the module delegatecall failure path; noticed the safeTransfer precedes a revert that is forwarded to the main executor, so the refund is undone by the same revert.
**Insight:** When a contract both refunds and reverts to signal failure to a caller, the refund is always rolled back—look for push-refund-before-revert patterns in cross-chain/executor designs and prefer pull-based refund accounting keyed by message hash.
