# Uneven deduction of performance fee causes some KangarooVault users to lose part of their token value

KangarooVault's getTokenPrice includes premiumCollected but not the performanceFee, letting a user withdraw before fee deduction and shift the fee onto remaining holders.

- Payout: Contest reward
- Severity: high
- Program: Polynomial Protocol
- Credited: peakbolt
- Disclosed: 2023-08-01
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-03-polynomial-findings/issues/161
- Library page: https://bugbountylibrary.com/r/c4%3A2023-03-polynomial%3AH-05
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:race-window technique:source-review vuln:accounting-error vuln:business-logic vuln:fee-bypass

**Target:** KangarooVault vault contract (Solidity)
**Root cause:** getTokenPrice() counts positionData.premiumCollected in totalValue but does not subtract the performanceFee that _resetTrade() will later deduct, so token price is overstated until the fee is charged.
**Steps:**
1. Deposit equal amounts for user_2 and user_3 into KangarooVault via `initiateDeposit` and `processDepositQueue`.
2. Open a position with `openPosition(amt,0)`, `executePerpOrders`, `clearPendingOpenOrders`.
3. Drop asset price (`setAssetPrice(initialPrice - 100e18)`) to accrue premiumCollected.
4. Both users call `initiateWithdrawal` for their full balance.
5. Close position with `closePosition(amt, 1000000e18)` and `executePerpOrders`.
6. user_2 calls `processWithdrawalQueue(1)` before `clearPendingCloseOrders(0)` to exit at the inflated token price.
7. `clearPendingCloseOrders(0)` triggers `_resetTrade()` deducting performanceFee; user_3 then withdraws at lower price.
**How found:** Code-reading comparison: noticed _resetTrade deducts performanceFee from premiumCollected, but getTokenPrice includes premiumCollected without subtracting that fee, creating a timing gap between price and fee settlement.
**Exploitation:** A withdrawing user front-runs the `clearPendingCloseOrders()` call that triggers `_resetTrade()` and the performanceFee deduction, redeeming at the pre-fee token price. The fee is then borne by remaining holders, who receive less SUSD for equal shares.
**Insight:** When a fee is deducted at settlement but the accrued value backing shares is already reflected in the share price, look for a window where holders can redeem before the fee hits and dump it on remaining holders.
