Vanguard

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

_resetPerAddressTracking doesn't reset address data

Author Revealed upon completion

Root + Impact

Description

  • Normal behavior: When the contract advances launch phases the hook should clear per-address swap tracking so each address starts fresh for the new phase (so limits and cooldowns are applied per-phase).

  • Specific issue: The reset helper writes to address(0) (or otherwise does not clear the intended address), so per-address counters are not cleared when the phase changes — existing swap history remains associated with user addresses and may cause incorrect penalties or limits to be applied.

// Root cause in the codebase with @> marks to highlight the relevant section
function _resetPerAddressTracking() internal {
@> addressSwappedAmount[address(0)] = 0;
@> addressLastSwapBlock[address(0)] = 0;
}

Risk

Likelihood:

  • Phase rollovers during launch call _resetPerAddressTracking(); this occurs when the contract transitions between phase 1/2/3 during normal launch progression.

  • Any user who swapped prior to the phase change will still have recorded swap amounts / last-swap blocks after the rollover, so the incorrect state is observed on their next swap.

Impact:

  • Legitimate users receive incorrect penalties (dynamic fee overrides) or are blocked from swapping because historical amounts/cooldowns were not cleared.

  • Unexpected fee collection, UX breakage, or denial-of-service of trading for affected users during critical launch windows.

Proof of Concept

// Sequence demonstrating the problem (conceptual PoC)
1) User A swaps during phase 1:
addressSwappedAmount[A] = X > 0
addressLastSwapBlock[A] = B
2) Contract advances to phase 2 and calls the bad reset:
_resetPerAddressTracking() // only writes to address(0), not A
3) User A attempts a new swap in phase 2:
contract reads addressSwappedAmount[A] == X (not reset)
combined amount may exceed phase 2 limit → contract applies penalty/overrides fees

Recommended Mitigation

- function _resetPerAddressTracking() internal {
- addressSwappedAmount[address(0)] = 0;
- addressLastSwapBlock[address(0)] = 0;
- }
+ function _resetPerAddressTracking(address sender) internal {
+ addressSwappedAmount[sender] = 0;
+ addressLastSwapBlock[sender] = 0;
+ }

and update the caller site to pass the affected address:

- _resetPerAddressTracking();
+ _resetPerAddressTracking(sender);

Notes:

  • If the intent is to clear all addresses at once, replace per-address clearing with a versioning approach (increment a phaseVersion and treat address data with mismatched versions as cleared) to avoid iterating/zeroing mappings on-chain.

  • Validate that any callers pass the correct sender and that view helpers consult the same versioning or clearing logic so UX and on-chain checks remain consistent.

Support

FAQs

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

Give us feedback!