Vanguard

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

Router-based enforcement breaks per-user anti-bot limits and cooldowns

Author Revealed upon completion

Root + Impact

Description

  • The protocol is designed to enforce per-user anti-bot protections during token launches by applying swap limits, cooldowns, and penalties to individual swappers in early phases.

  • The hook tracks swap activity using the sender parameter of the beforeSwap hook, which corresponds to the swap router rather than the actual swap initiator. As a result, limits and cooldowns are enforced per router instead of per user.

function _beforeSwap(
address sender,
PoolKey calldata key,
SwapParams calldata params,
bytes calldata
) internal override returns (bytes4, BeforeSwapDelta, uint24) {
...
if (addressLastSwapBlock[sender] > 0) {
uint256 blocksSinceLastSwap = block.number - addressLastSwapBlock[sender];
if (blocksSinceLastSwap < phaseCooldown) {
applyPenalty = true;
}
}
if (!applyPenalty && addressSwappedAmount[sender] + swapAmount > maxSwapAmount) {
applyPenalty = true;
}
// @> Swap tracking is applied to the router, not the user
addressSwappedAmount[sender] += swapAmount;
addressLastSwapBlock[sender] = block.number;
...
}

Because most users interact through the same router, swap limits and cooldowns become shared across all users instead of being enforced individually.

Risk

Likelihood:

  • The issue occurs for every swap executed through a Uniswap V4 router, which is the standard interaction path.

  • All users interacting through the same router are automatically subject to shared state tracking.

Impact:

  • Bots can rotate EOAs to bypass per-user protections while continuing to trade through the same router.

  • Legitimate users may trigger penalties or cooldowns due to other users’ activity.

  • The protocol’s advertised per-user anti-bot guarantees during launch phases are significantly weakened.

Proof of Concept

// Conceptual PoC
// User A and User B both swap through the same router address
swapRouter.swap(...); // User A
swapRouter.swap(...); // User B
// Internally, both swaps are tracked under:
addressSwappedAmount[address(swapRouter)]
addressLastSwapBlock[address(swapRouter)]
// Limits and cooldowns are shared across all users of the router

This behavior is also observable in the test suite, where swap activity is asserted against the router address rather than individual users.

Recommended Mitigation

If feasible within Uniswap V4 constraints, enforce limits based on the actual swap initiator rather than the router.

- addressSwappedAmount[sender] += swapAmount;
- addressLastSwapBlock[sender] = block.number;
+ address user = /* extract or pass actual user identity */;
+ addressSwappedAmount[user] += swapAmount;
+ addressLastSwapBlock[user] = block.number;

If per-user identification is not possible, explicitly document router-level enforcement and adjust protocol guarantees accordingly to avoid misleading assumptions about per-user protection.

Support

FAQs

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

Give us feedback!