# Reentrancy in flashAction() allows draining liquidity pools

ERC777 callback during flashAction lets attacker self-liquidate and bid tiny amount, zeroing collateral value so remaining debt is written off, draining pool.

- Payout: Contest reward
- Severity: high
- Program: Arcadia
- Credited: 0xadrii
- Disclosed: 2023-12-17
- Write-up quality: 9/10
- Original: https://github.com/sherlock-audit/2023-12-arcadia-judging/issues/153
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-12-arcadia%3AH-2
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:evm tech:solidity technique:chained technique:source-review vuln:business-logic vuln:liquidation vuln:oracle-manipulation vuln:reentrancy

**Target:** LendingPool.flashAction / Liquidator.bid / settleLiquidationUnhappyFlow
**Root cause:** flashAction mints debt then transfers borrowed ERC777 to attacker-controlled actionTarget before health check; the callback reenters Liquidator to self-liquidate and bid, and _settleAuction treats collateral below minUsdValue as zero, triggering unhappy-flow debt write-off.
**Steps:**
1. Open margin account on creditor whose asset is ERC777.
2. Deposit collateral exactly at minUsdValue (e.g. 1 USDT -> 1e18 USD).
3. Call `LendingPool.flashAction(100 ether, account, actionHandler, callData, emptyBytes3)` with empty actionData.
4. In actionHandler's ERC777 `tokensReceived` callback: call `liquidator.liquidateAccount(account)`.
5. Then call `liquidator.bid(account, [1], true)` asking 1 wei of collateral, paying tiny price via `auctionRepay`.
6. Collateral value drops below minUsdValue -> getCollateralValue()==0 -> `_settleAuction` calls `settleLiquidationUnhappyFlow`, burning all remaining debt.
7. flashActionByCreditor health check passes (no debt); attacker keeps borrowed funds.
**How found:** Noticed flashAction transfers borrowed ERC777 to arbitrary actionTarget before flashActionByCreditor health check, enabling reentrancy; combined with minUsdValue rounding collateral to zero and _settleAuction's collateralValue==0 branch writing off debt.
**Exploitation:** Attacker needs an ERC777-underlying pool with liquidity. Flash-borrows full pool amount; borrowed funds land in attacker contract triggering ERC777 callback; self-liquidates own account (now unhealthy due to minted debt) and bids 1 wei of collateral with endAuction=true; minUsdValue rounding zeroes collateral value, forcing unhappy-flow settlement that writes off all debt; attacker retains borrowed tokens minus tiny bid payment.
**Escalation:** Repeatable against any creditor whose asset is ERC777; drains entire pool liquidity.
**Insight:** When a protocol rounds collateral below a minUsdValue threshold to zero, any code path that reads that rounded value to decide 'all collateral sold' can be forced by removing a dust amount; look for ERC777/ERC677/hook tokens reaching arbitrary attacker addresses before health checks.
