# ControllerPeggedAssetV2: `triggerEndEpoch` function can be called even if epoch is null epoch leading to loss of funds

ControllerPeggedAssetV2.triggerEndEpoch lacks a null-epoch check, so an expired epoch with an empty collateral vault moves premium-vault funds into it, losing user funds.

- Payout: Contest reward
- Severity: medium
- Program: Y2K
- Credited: 0xRobocop
- Disclosed: 2023-03-06
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/108
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-03-Y2K%3AM-2
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:medium tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** ControllerPeggedAssetV2 epoch resolution (triggerEndEpoch)
**Root cause:** triggerEndEpoch only checks epoch existence and expiry, not whether either vault has zero totalAssets for the epoch; it assumes triggerNullEpoch will always be called first.
**Steps:**
1. Deploy/observe an epoch where premium vault has deposits but collateral vault totalAssets(_epochId)==0 (null epoch condition).
2. Do not call triggerNullEpoch before epochEnd.
3. After block.timestamp > epochEnd, call `triggerEndEpoch(_epochId)`; it passes existence/expiry checks.
4. Function transfers premium vault funds into the empty collateral vault, where they are stranded/lost.
**How found:** Code reading of the three resolution paths (triggerDepeg/triggerEndEpoch/triggerNullEpoch); noticed triggerEndEpoch assumes triggerNullEpoch is always invoked in time, an assumption not enforced on-chain.
**Exploitation:** Anyone can call triggerEndEpoch after expiry on a null epoch; premium vault funds are sent to the collateral vault that has no depositors, permanently losing them for premium depositors.
**Insight:** When a protocol has multiple mutually-exclusive resolution functions, check whether each enforces the preconditions of the others; an unenforced assumption that 'the right function will be called first' is a fund-loss bug.
