# Incorrect handling of first deposit for new modules leads to all liquidity sent to vault manager

New module's first-deposit dust-removal logic withdraws entire pool liquidity to the vault manager, then a malicious executor DoSes recovery via setPoolManager(address(0)).

- Payout: Contest reward
- Severity: high
- Program: Arrakis
- Credited: cu5t0mPe0
- Disclosed: 2024-03-02
- Write-up quality: 8/10
- Original: https://github.com/sherlock-audit/2024-03-arrakis-judging/issues/27
- Library page: https://bugbountylibrary.com/r/sherlock%3A2024-03-arrakis%3AH-2
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:sherlock sev:high tech:evm tech:solidity technique:chained technique:source-review vuln:accounting-error vuln:business-logic vuln:dos

**Target:** ValantisHOTModulePublic.deposit / ArrakisMetaVault.setModule
**Root cause:** deposit() assumes pool reserves are dust on first deposit and withdraws them to the manager, but setModule() transfers all old-module liquidity into the new module before notFirstDeposit is set, so reserves equal full liquidity.
**Steps:**
1. Deploy vault with old module; user mints via old module so pool holds full liquidity.
2. Whitelist a new module via timelock and call ArrakisStandardManager.setModule(vault, newModule, [initializePosition]) — old module withdraws 100% liquidity to new module and deposits into new pool.
3. New module's notFirstDeposit is still false.
4. First minter calls mint(1e3) on vault; deposit() reads pool.getReserves() as full liquidity and calls alm.withdrawLiquidity(_amt0,_amt1,manager,0,0), sending all liquidity to ArrakisStandardManager.
5. DoS: malicious executor calls rebalance(vault, [swap payload wrapping SovereignPool.setPoolManager(address(0))]) after seeding 1 wei fees; poolManager becomes address(0).
6. withdrawManagerBalance(vault) now reverts because claimPoolManagerFees() fails, locking funds.
**How found:** Code reading of deposit()'s first-deposit dust-removal branch, noticing notFirstDeposit is per-module state that stays false after setModule() pre-funds the new module with full liquidity; then probing rebalance payloads to find setPoolManager(address(0)) breaks claimPoolManagerFees.
**Exploitation:** Attacker (or any first depositor after a module swap) triggers the dust-removal branch, moving 100% of pool liquidity to the trusted ArrakisStandardManager; a malicious executor then bricks recovery by setting poolManager to address(0) via a rebalance payload, so withdrawManagerBalance reverts and shares are worthless.
**Escalation:** Chains the deposit bug with an unverified-call payload in rebalance to DoS the manager's fund-recovery path, forcing redeployment of a new vault to recover tokens.
**Insight:** Per-module initialization flags (notFirstDeposit) are not reset when a module is reused/re-funded via setModule; check whether 'first deposit' assumptions about dust reserves hold when liquidity is pre-seeded by admin flows, and whether recovery functions depend on state an untrusted executor payload can mutate.
