Vanguard

First Flight #56
Beginner FriendlyDeFiFoundry
100 EXP
View results
Submission Details
Severity: medium
Valid

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

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.

Updates

Appeal created

chaossr Lead Judge 17 days ago
Submission Judgement Published
Validated
Assigned finding tags:

Anti-Bot Protection Does Not Distinguish Buy vs Sell Directions

Support

FAQs

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

Give us feedback!