# Tokens received from Curve's `remove_liquidity()` should be added to the assets list even if `_min_amounts` are set to `0`

Sentiment's Curve controller only registered underlying tokens with minAmount>0 as assets, so tokens withdrawn with _min_amounts=0 were uncounted, enabling premature liquidation.

- Payout: Contest reward
- Severity: high
- Program: Sentiment
- Credited: WATCHPUG
- Disclosed: 2022-08-30
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2022-08-sentiment-judging/tree/main/267-H
- Library page: https://bugbountylibrary.com/r/sherlock%3A2022-08-sentiment%3AH-7
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:solidity technique:source-review vuln:accounting-error vuln:liquidation

**Target:** Curve StableSwap2PoolController canRemoveLiquidity
**Root cause:** canRemoveLiquidity decoded _min_amounts and only added coins[i] to tokensIn when amounts[i]>0, but Curve's remove_liquidity always transfers all underlying coins regardless of min amounts.
**Steps:**
1. Read StableSwap2PoolController.canRemoveLiquidity: decodes (uint256, uint256[2]) and loops adding coins(i) only if amounts[i]>0.
2. Compare to Curve pool remove_liquidity: transfers value = old_balance*_burn_amount/total_supply for every coin, asserting value >= _min_amounts[i].
3. Call remove_liquidity with _min_amounts=[0,0]; both underlying tokens are received but only tokens with nonzero min are added to account assets list.
4. RiskEngine._getBalance counts only assets in the list, so received tokens are invisible collateral, lowering health and enabling earlier liquidation.
**How found:** Code-reading of the controller's token-tracking logic against Curve's actual remove_liquidity semantics; noticed min amounts are slippage bounds, not the set of tokens received.
**Insight:** When a controller whitelists tokens received from a protocol call, derive the token set from the protocol's actual transfer semantics, not from user-supplied slippage/min parameters that can be zero.
