Vanguard

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

_resetPerAddressTracking() Only Resets address(0) - User Limits Persist Across Phases, Defeating Anti-Bot Protection

Author Revealed upon completion

Root + Impact

Description

  • Describe the normal behavior in one or more sentences

  • Explain the specific issue or problem in one or more sentences

Root + Impact

Description

The _resetPerAddressTracking() function is supposed to clear per-address swap limits and cooldowns when the protocol transitions between phases. However, it only resets mappings for address(0) instead of actual users:

function _resetPerAddressTracking() internal {
addressSwappedAmount[address(0)] = 0; // @> BUG: Only resets address(0)
addressLastSwapBlock[address(0)] = 0; // @> Not actual users!
}

This means addressSwappedAmount[user] and addressLastSwapBlock[user] persist indefinitely across all phases.

Risk

Impact: HIGH - Users who participated in Phase 1 have their swap amounts counted against Phase 2 limits. A user who swapped their full 1% Phase 1 allocation will only have 4% available in Phase 2 (instead of the intended 5%). This unfairly penalizes legitimate early participants.

Anti-Bot Protection Defeated: Bots can trivially bypass restrictions by using fresh wallets each phase (getting full limits), while legitimate users who participated early are penalized. This INVERTS the security model.

Proof of Concept

function testStateResetFailure() public {
// Phase 1: Alice swaps her full 1% limit
vm.prank(alice);
// addressSwappedAmount[alice] = 1%
// Phase transition
vm.roll(block.number + PHASE1_DURATION + 1);
// _resetPerAddressTracking() called but doesn't reset alice
// Phase 2: Alice should have 5% limit
uint256 aliceRemaining = hook.getUserRemainingLimit(alice);
// BUG: aliceRemaining = 4% (5% - 1% carryover)
// Bot with fresh address gets full 5%
uint256 botRemaining = hook.getUserRemainingLimit(bot);
// botRemaining = 5%
assertLt(aliceRemaining, botRemaining); // Legitimate user penalized
}

Recommended Mitigation

Use epoch-based tracking:

uint256 public currentEpoch;
mapping(address => mapping(uint256 => uint256)) public addressSwappedAmountByEpoch;
function _resetPerAddressTracking() internal {
currentEpoch++; // All previous data becomes irrelevant
}
// Root cause in the codebase with @> marks to highlight the relevant section

Risk

Likelihood:

  • Reason 1 // Describe WHEN this will occur (avoid using "if" statements)

  • Reason 2

Impact:

  • Impact 1

  • Impact 2

Proof of Concept

Recommended Mitigation

- remove this code
+ add this code

Support

FAQs

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

Give us feedback!