# The totalAssets() calculation may lead to unfair situations

Term Structure vault's totalAssets() includes uncollected performance fees, so users who redeem after the curator withdraws fees receive fewer assets than earlier redeemers.

- Payout: Contest reward
- Severity: medium
- Program: Term Structure
- Credited: Nyksx
- Disclosed: 2025-03-20
- Write-up quality: 6/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_term_structure_february2025.pdf#3.2.7
- Library page: https://bugbountylibrary.com/r/cantina%3Aterm_structure_february2025%3A3.2.7
- Tags: domain:web3 impact:funds-loss kind:contest platform:cantina sev:medium tech:evm tech:solidity technique:race-window technique:source-review vuln:business-logic vuln:reward-distribution

**Target:** ERC-4626 vault totalAssets() share pricing
**Root cause:** totalAssets() returns previewPrincipal + previewPerformanceFee, counting fees not yet withdrawn as depositor-owned assets; when the curator later withdraws the fee, totalAssets drops and remaining redeemers get less.
**Steps:**
1. Deposit equal amounts as user1 and user2 into the vault at the same time, receiving equal shares.
2. Accrue interest via market swaps over time so performance fees build up.
3. user1 calls `vault.redeem(user1Shares, user1, user1)` before fees are taken.
4. Curator calls `vault.withdrawPerformanceFee(curator, performanceFee)`, reducing totalAssets.
5. user2 calls `vault.redeem(user2Shares, user2, user2)` and receives fewer assets despite identical shares.
**How found:** Reviewer read totalAssets() and noticed it sums principal plus accrued performance fee, then reasoned that fee withdrawal later reduces totalAssets, creating a timing-dependent payout difference; confirmed with a Foundry PoC comparing two equal depositors.
**Exploitation:** A depositor simply redeems before the curator collects performance fees to capture a share of the fee amount; later redeemers absorb the shortfall. No capital or special access needed beyond being a vault depositor.
**Insight:** In ERC-4626 vaults, any value in totalAssets() that is not actually owned by shareholders (pending fees, unclaimed rewards, donations) creates a first-out-wins race; check every component of totalAssets() against who can later withdraw it.
