# LenderActions's moveQuoteToken can create a total debt undercoverage

Ajna's moveQuoteToken applies unutilized deposit fee reducing total deposits without checking debt <= deposits, breaking LUP invariant and pool accounting.

- Payout: Contest reward
- Severity: medium
- Program: Ajna
- Credited: hyh
- Disclosed: 2023-04-20
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-04-ajna-judging/issues/88
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-04-ajna%3AM-4
- Tags: domain:web3 impact:integrity kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** LenderActions.moveQuoteToken in Ajna core pool contract
**Root cause:** moveQuoteToken applies the unutilized deposit fee when moving quote tokens from above LUP to below LUP, shrinking total deposits, but unlike removeQuoteToken it never verifies poolState_.debt <= Deposits.treeSum(deposits_) afterward.
**Steps:**
1. Call moveQuoteToken moving quote tokens from a bucket price >= LUP to a bucket price < LUP so the unutilized deposit fee is applied (`movedAmount_ = Maths.wmul(movedAmount_, Maths.WAD - _depositFeeRate(poolState_.rate))`).
2. Fee reduces total deposits tree sum while debt stays unchanged.
3. Only check performed is `params_.fromIndex < params_.toIndex && vars.htp > lup_`; no debt-vs-deposits check, so poolState_.debt can exceed Deposits.treeSum(deposits_).
4. LUP computed via getLup/findIndexOfSum assumes debt < deposits, yielding miscalculated LUP below HTP.
**How found:** Code-reading comparison: noticed removeQuoteToken guards `poolState_.debt > Deposits.treeSum(deposits_)` but moveQuoteToken, which also mutates deposits via the unutilized deposit fee, lacks the same guard; traced getLup's assumption that debt is bounded by deposits.
**Insight:** When a function mutates a shared accounting structure (deposits tree) via fees, diff its post-condition checks against sibling functions that mutate the same structure; missing invariant guards are the bug.
