Vanguard

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

Missing Zero Cooldown Validation in Constructor

Author Revealed upon completion

Description

  • The constructor validates that phase1Duration and phase2Duration cannot be 0, preventing a broken launch timeline.

  • However, phase1Cooldown and phase2Cooldown are not validated. Setting these to 0 would make the cooldown mechanism completely ineffective.

constructor(
IPoolManager _poolManager,
uint256 _phase1Duration,
uint256 _phase2Duration,
uint256 _phase1LimitBps,
uint256 _phase2LimitBps,
uint256 _phase1Cooldown, // @> No zero check
uint256 _phase2Cooldown, // @> No zero check
uint256 _phase1PenaltyBps,
uint256 _phase2PenaltyBps
) BaseHook(_poolManager) {
// @> Duration is checked for zero
if (_phase1Duration == 0 || _phase2Duration == 0) revert InvalidConstructorParams();
// @> BPS is checked for max, but cooldowns are not checked at all
if (_phase1LimitBps > 10000 || _phase2LimitBps > 10000 ||
_phase1PenaltyBps > 10000 || _phase2PenaltyBps > 10000
) revert InvalidConstructorParams();
// ...
}

Risk

Likelihood:

  • Owner would need to deploy with 0 cooldown values

  • May happen accidentally or intentionally to weaken protection

Impact:

  • Zero cooldown means bots can swap rapidly without penalty

  • Reduces effectiveness of anti-bot protection

  • Defeats one of the two primary protection mechanisms (cooldown + limits)

Proof of Concept

Deploy hook with 0 cooldown values - constructor accepts them without validation.

function test_ZeroCooldownAllowed() public {
bytes memory creationCode = type(TokenLaunchHook).creationCode;
bytes memory constructorArgs = abi.encode(
manager,
phase1Duration,
phase2Duration,
phase1LimitBps,
phase2LimitBps,
0, // @> Zero cooldown - no validation error!
0, // @> Zero cooldown
phase1PenaltyBps,
phase2PenaltyBps
);
uint160 flags = uint160(Hooks.AFTER_INITIALIZE_FLAG | Hooks.BEFORE_SWAP_FLAG);
(, bytes32 salt) = HookMiner.find(address(this), flags, creationCode, constructorArgs);
// This succeeds - zero cooldown is allowed
TokenLaunchHook weakHook = new TokenLaunchHook{salt: salt}(
manager,
phase1Duration,
phase2Duration,
phase1LimitBps,
phase2LimitBps,
0,
0,
phase1PenaltyBps,
phase2PenaltyBps
);
assertEq(weakHook.phase1Cooldown(), 0, "Zero cooldown accepted");
}

Recommended Mitigation

Add zero-check for cooldown parameters in constructor.

constructor(
IPoolManager _poolManager,
uint256 _phase1Duration,
uint256 _phase2Duration,
uint256 _phase1LimitBps,
uint256 _phase2LimitBps,
uint256 _phase1Cooldown,
uint256 _phase2Cooldown,
uint256 _phase1PenaltyBps,
uint256 _phase2PenaltyBps
) BaseHook(_poolManager) {
if (_phase1Duration == 0 || _phase2Duration == 0) revert InvalidConstructorParams();
+ if (_phase1Cooldown == 0 || _phase2Cooldown == 0) revert InvalidConstructorParams();
if (
_phase1LimitBps > 10000 || _phase2LimitBps > 10000 ||
_phase1PenaltyBps > 10000 || _phase2PenaltyBps > 10000
) revert InvalidConstructorParams();
// ...
}

Support

FAQs

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

Give us feedback!