# Duplicate request early-return skips registration

Dedup or idempotency guard returns early before per-caller registration or state advance

_Area: Smart contract access control and control flow. Seen in 2 disclosed reports; latest 2023-10-26. Updated 2026-10-23._

## How it works
A function is meant to run once per key (oracle version, chain, inbound tx) and uses an early return to skip repeated work. The guard is placed above lines that must still run for every caller: registering the caller's market/account for callbacks, advancing a per-chain counter, or recording a tracker. The first caller is handled; every later caller is silently dropped or, worse, mutates shared state again. The broken assumption is that "already seen" means "nothing left to do for this caller."

## Where it shows up
- Early `return`/`continue` on a duplicate key sitting above callback-list appends or per-caller bookkeeping.
- Permissionless entry points that increment a shared counter or stage variable with no per-key sent flag.
- Dedup/cleanup logic that only runs on the success path, so failed or duplicate entries persist.
- State machines gated by an equality check (`fundsReceived == activeVaults`) reachable by repeat calls.
- Registries keyed by version/timestamp that assume one requester per key.

## How to review
For each guard, list the mutations below it and ask: must this run per caller or per key? The invariant: every caller that should be registered is registered exactly once, and every per-key counter advances at most once per key. Check that dedup state is written before the early return, that per-caller registration is outside the guard, and that permissionless increment paths have an explicit sent/processed flag. Trace cleanup: entries that fail validation must be removed, not left for observers to re-process.

## Variants seen
- Missing executed-check lets anyone re-add already-processed inbound trackers; observers keep re-voting, causing congestion/DoS [E1](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-29.md).
- Early return on duplicate oracle version skips callback registration for all later market+account pairs, so they never settle [E2](https://bugbountylibrary.com/r/sherlock%3A2023-10-perennial%3AM-4.md).
- No per-chain sent flag: repeat `pushVaultAmounts` inflates `fundsReceived` past `activeVaults`, blocking stage transit [E3](https://bugbountylibrary.com/r/sherlock%3A2023-01-derby%3AH-12.md).

## Impact and severity
Medium to high. Effects ranged from unsettled requests [E2](https://bugbountylibrary.com/r/sherlock%3A2023-10-perennial%3AM-4.md) and halted cross-chain rebalancing [E3](https://bugbountylibrary.com/r/sherlock%3A2023-01-derby%3AH-12.md) to network-wide congestion from unbounded re-processing [E1](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-29.md). Severity rises when the entry point is permissionless and the corrupted state gates a liveness-critical transition, since any user can trigger it repeatedly at low cost.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-29.md
- E2: https://bugbountylibrary.com/r/sherlock%3A2023-10-perennial%3AM-4.md
- E3: https://bugbountylibrary.com/r/sherlock%3A2023-01-derby%3AH-12.md
