# `moveQuoteToken()` can cause bucket to go bankrupt but it is not reflected in the accounting

moveQuoteToken() drains a bucket to zero quote tokens without marking it bankrupt, so future depositors' LPs get diluted by stale shares.

- Payout: Contest reward
- Severity: high
- Program: Ajna
- Credited: yixxas
- Disclosed: 2022-12-21
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-01-ajna-judging/issues/83
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-01-ajna%3AH-9
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** LenderActions.sol moveQuoteToken() in Ajna lending pool
**Root cause:** moveQuoteToken() lacks the bankruptcy check present in removeQuoteToken(): when bucketCollateral==0, unscaledRemaining==0 and lpsRemaining!=0, it fails to zero lps and set bankruptcyTime, leaving stale LP shares in a drained bucket.
**Steps:**
1. Call `moveQuoteToken()` moving out all quote tokens from a bucket so unscaledRemaining becomes 0
2. Ensure bucketCollateral == 0 and lpsRemaining != 0
3. Observe bucket.lps is not zeroed and bankruptcyTime not set (unlike removeQuoteToken)
4. A new depositor into the bucket receives fewer LPs than expected, diluted by the stale lpsRemaining
**How found:** Code-reading comparison: noticed removeQuoteToken() and moveQuoteToken() have identical effects on fromBucket, but only removeQuoteToken() contains the bankruptcy update block, so the check was missing in the move path.
**Exploitation:** Attacker drains a bucket's quote tokens via moveQuoteToken to another bucket, leaving the source bucket effectively bankrupt but still carrying stale LP shares; subsequent depositors into that bucket are diluted, benefiting existing stale LP holders.
**Insight:** When two functions share identical state effects on the same struct, diff their post-condition blocks line by line; a bankruptcy/liquidation flag set in one path but not the sibling path leaves stale accounting that dilutes later users.
