Vanguard

First Flight #56
Beginner FriendlyDeFiFoundry
0 EXP
Submission Details
Impact: high
Likelihood: high

totalPenaltyFeesCollected is Never Updated, Leading to Failed Accounting

Author Revealed upon completion

ROOT + IMPACT

Description

The contract declares a public state variable totalPenaltyFeesCollected, intended to track the cumulative value of penalty fees levied against users during the launch phases.

However, in the _beforeSwap function, while the penalty fee is applied via feeOverride, there is no logic to calculate the fee amount or update this variable. As a result, totalPenaltyFeesCollected will permanently remain 0, breaking the protocol's ability to track the efficacy of its anti-bot measures or report revenue.

Furthermore, the implementation uses LPFeeLibrary.OVERRIDE_FEE_FLAG, which directs the penalty fees to the Liquidity Providers of the pool. If the intention of totalPenaltyFeesCollected was for the Protocol to withdraw these fees later, the current implementation fails to capture that revenue entirely.

Solidity

// TokenLaunchHook.sol
// @audit Variable declared here
uint256 public totalPenaltyFeesCollected;
function _beforeSwap(...) {
// ...
if (applyPenalty) {
feeOverride = uint24((phasePenaltyBps * 100));
// @audit MISSING: totalPenaltyFeesCollected += calculatedFeeAmount;
}
return (..., feeOverride | LPFeeLibrary.OVERRIDE_FEE_FLAG);
}

Risk

Likelihood: High (Certainty)

  • The variable is mathematically unreachable in the current code.

Impact: Low / Medium

  • Broken Metrics: The owner cannot see how much penalty has been enforced.

  • Potential Revenue Loss: If this variable was intended to track funds withdrawable by the owner, those funds are currently lost to LPs.

Recommended Mitigation

If the goal is simply to track how much LPs earned from penalties, implement the math to estimate the fee based on the swap amount.

Note: Calculating exact fees in beforeSwap can be complex depending on whether the swap is ExactInput or ExactOutput.

Diff

if (applyPenalty) {
feeOverride = uint24((phasePenaltyBps * 100));
+ // Approximate fee calculation (Assuming ExactInput for simplicity)
+ uint256 feeAmount = (swapAmount * phasePenaltyBps) / 10000;
+ totalPenaltyFeesCollected += feeAmount;
}

If the goal was for the Protocol to keep the fees, the entire fee mechanism needs to be changed (e.g., using Hooks.beforeDonate or taking a cut via BeforeSwapDelta).

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!