# Malicious liquidity provider can put pool into highly manipulatable state

HydraDX StableSwap withdraw_asset_amount omits total-issuance check, letting an LP transfer 1 share out then drain, leaving pool at 1 share and manipulatable.

- Payout: Contest reward
- Severity: medium
- Program: HydraDX
- Credited: J4X
- Disclosed: 2024-04-10
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2024-02-hydradx-findings/issues/154
- Library page: https://bugbountylibrary.com/r/c4%3A2024-02-hydradx%3AM-02
- Tags: domain:web3 impact:dos impact:integrity kind:contest platform:code4rena sev:medium tech:solidity technique:incomplete-fix technique:source-review vuln:access-control vuln:business-logic vuln:share-inflation

**Target:** StableSwap AMM pallet withdraw_asset_amount extrinsic
**Root cause:** withdraw_asset_amount only checks the caller's share balance against MinPoolLiquidity, not total pool issuance, so transferring 1 share to a second address lets the caller withdraw all remaining shares while total issuance stays at 1.
**Steps:**
1. Deposit MinPoolLiquidity worth of shares into the pool.
2. Transfer 1 share to a second attacker-controlled address.
3. Call `withdraw_asset_amount()` to withdraw all remaining shares; the per-user check passes since the caller withdraws their full balance.
4. Pool total issuance is now 1 share, below MinPoolLiquidity, breaking the invariant and enabling cheap price manipulation.
5. Alternatively, a second LP's `remove_liquidity_one_asset()` now reverts because total issuance minus their shares falls below MinPoolLiquidity.
**How found:** Compared the two withdrawal paths and noticed remove_liquidity_one_asset enforces both per-user and total-issuance checks while withdraw_asset_amount enforces only the per-user check; realized share transfers let a user satisfy the per-user check while breaking the total invariant.
**Exploitation:** Attacker deposits minimum liquidity, moves 1 share to a sock-puppet address, then drains via withdraw_asset_amount, leaving a 1-share pool that is trivially manipulatable; or strands a contract LP that can only exit via remove_liquidity_one_asset.
**Escalation:** Low-liquidity pool enables price manipulation; DoS on remove_liquidity_one_asset for contract LPs that cannot switch functions.
**Insight:** When an invariant is enforced per-caller rather than on aggregate state, check whether transferable shares/tokens let an attacker split balances across addresses to satisfy the per-caller check while violating the global invariant.
