# Locks unlocking at the nexttimestamp will not trigger noactivelocks

Inconsistent unlockTime invariants in GaugeController voting let locks expiring at nextTimestamp bypass the NoActiveLocks check and corrupt vote accounting.

- Payout: Contest reward
- Severity: medium
- Program: Opal
- Credited: J4X98
- Disclosed: 2024-03-30
- Write-up quality: 6/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_opal_feb2024.pdf#3.3.14
- Library page: https://bugbountylibrary.com/r/cantina%3Aopal_feb2024%3A3.3.14
- Tags: domain:web3 impact:integrity kind:contest platform:cantina sev:medium tech:solidity technique:source-review vuln:business-logic vuln:governance

**Target:** GaugeController.sol _voteForGaugeweight voting logic
**Root cause:** Three checks use different cutoffs (nextTimestamp vs block.timestamp) for lock eligibility, so locks unlocking exactly at nextTimestamp pass the NoActiveLocks guard but are excluded from vote summation and unlock tracking.
**Steps:**
1. Read `_voteForGaugeweight()` in GaugeController.sol#L494.
2. Note guard: `locks[len-1].unlockTime < vars.nextTimestamp` reverts NoActiveLocks.
3. Note summation loop: `while (currentLock.unlockTime > vars.nextTimestamp)` excludes locks equal to nextTimestamp.
4. Note tracking loop: `if (unlocks[l].unlockTime <= block.timestamp) continue;` uses block.timestamp instead.
5. Submit a vote where the longest lock unlockTime == nextTimestamp to observe inconsistent accounting.
**How found:** Code review comparing the three unlockTime conditionals in the voting function and noticing they use different reference timestamps.
**Exploitation:** A user whose only lock unlocks exactly at nextTimestamp passes the NoActiveLocks guard but contributes zero weighted amount, producing a vote with no counted power and inconsistent unlock records.
**Insight:** When a function enforces the same conceptual invariant (lock eligibility) in multiple loops, diff the comparison operators and reference timestamps across all of them; boundary equality (== nextTimestamp) is where mismatched cutoffs diverge.
