# Airlock.migrate attempts to transfer native ETH on safeTransfer calls

Airlock.migrate uses Solady safeTransfer with zero msg.value, so native ETH pools fail to transfer funds to the liquidity migrator during migration.

- Payout: Contest reward
- Severity: high
- Program: Doppler
- Credited: jovi.eth
- Disclosed: 2025-02-18
- Write-up quality: 6/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_doppler.pdf#3.1.3
- Library page: https://bugbountylibrary.com/r/cantina%3Adoppler%3A3.1.3
- Tags: domain:web3 impact:dos kind:contest platform:cantina sev:high tech:evm tech:solidity technique:source-review vuln:business-logic

**Target:** Airlock.migrate migration function
**Root cause:** migrate() calls Solady's safeTransfer, which performs a call with value=0, so it cannot move native ETH; native-currency pools revert/fail on migration.
**Steps:**
1. Deploy pool with currency0 = address(0) (native ETH) and currency1 = asset
2. Perform buys via router.buyExactOut with ETH value to accrue balances
3. Warp past DEFAULT_EPOCH_LENGTH and DEFAULT_ENDING_TIME
4. Call `airlock.migrate(asset)`
5. Observe safeTransfer to liquidityMigrator fails because msg.value is 0 and native balance is not forwarded
**How found:** Code review of migrate()'s use of Solady SafeTransferLib; noticed the library's call opcode passes value 0, incompatible with native ETH, then confirmed via Foundry PoC logging balances.
**Exploitation:** Not weaponized; migration of native-ETH pools reverts, blocking liquidity migration and potentially locking funds in the Airlock.
**Insight:** When a contract handles both ERC20 and native currency, check whether the transfer helper used (e.g. Solady safeTransfer) hardcodes call value 0; native-asset paths silently break even though the ERC20 path works.
