## Description
The `getCurrentPhase` function is intended to report the current status of the launch (Phase 1, Phase 2, or Phase 3) to external callers, such as frontends or other smart contracts. This data is typically used to estimate fees and limits before a user submits a transaction.
However, there is a logic inconsistency between how `getCurrentPhase` calculates the phase and how the core logic `_beforeSwap` calculates it.
* **`_beforeSwap` (Execution):** Uses inclusive comparison (`<=`).
* Logic: `if (blocksSinceLaunch <= phase1Duration)`
\
* **`getCurrentPhase` (View):** Uses strict inequality (`<`).
* Logic: `if (blocksSinceLaunch < phase1Duration)`
\
At the exact boundary block where blocksSinceLaunch == phase1Duration, the view function reports that the protocol has moved to the **next phase**, while the execution logic still enforces the **previous phase**.
This mismatch applies to both the transition from Phase 1 to 2, and Phase 2 to 3.
```solidity
// TokenLaunchHook.sol
function getCurrentPhase() public view returns (uint256) {
// ...
uint256 blocksSinceLaunch = block.number - launchStartBlock;
// @audit Uses '<' instead of '<='
if (blocksSinceLaunch < phase1Duration) {
return 1;
} else if (blocksSinceLaunch < phase1Duration + phase2Duration) { // @audit Same error here
return 2;
} else {
return 3;
}
}
```
## Risk
**Likelihood**: Medium
* This occurs exactly on the specific blocks that mark the end of a phase. While infrequent, in a high-volume launch, it is statistically probable that transactions will be included in these blocks.
**Impact**: High
* **Financial Discrepancy:**
* **Phase 1 -> 2:** User sees Phase 2 (lower fee/penalty). User submits tx. User pays Phase 1 (higher fee/penalty).
* **Phase 2 -> 3:** User sees Phase 3 (Standard 0.3% Fee). User submits tx. User pays Phase 2 (e.g., 2% Penalty).
\
* **Failed Transactions:** If the Phase 1 limit is stricter than Phase 2, a user might submit a swap size valid for Phase 2 (as reported by the view) which reverts under Phase 1 rules.
## Proof of Concept
**Scenario:**
* `launchStartBlock` = 1000.
* `phase1Duration` = 100 blocks.
* `phase1Penalty` = 5%.
* `phase2Penalty` = 2%.
**At Block 1100:**
**Calculation:** `blocksSinceLaunch` = `1100 - 1000` = `100`.
**Frontend Check (`getCurrentPhase`):**
* `100 < 100` evaluates to **FALSE**.
* Function returns **Phase 2**.
* **User Expectation:** "I will pay 2% penalty."
\
**Execution (`_beforeSwap`):**
* `100 <= 100` evaluates to **TRUE**.
* Function enforces **Phase 1**.
* **Actual Result:** User pays **5% penalty**.
\
## Recommended Mitigation
Update the comparison operators in `getCurrentPhase` to use `<=` to strictly match the logic in `_beforeSwap`.
```diff
function getCurrentPhase() public view returns (uint256) {
if (launchStartBlock == 0) return 0;
uint256 blocksSinceLaunch = block.number - launchStartBlock;
- if (blocksSinceLaunch < phase1Duration) {
+ if (blocksSinceLaunch <= phase1Duration) {
return 1;
- } else if (blocksSinceLaunch < phase1Duration + phase2Duration) {
+ } else if (blocksSinceLaunch <= phase1Duration + phase2Duration) {
return 2;
} else {
return 3;
}
}
```
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.