# `KeeperOracle.request` adds only the first pair of market+account addresses per oracle version to callback list, ignoring all the subsequent ones

KeeperOracle.request returned early on duplicate oracle-version requests, so only the first market+account pair was registered for settlement callbacks, skipping all later requesters.

- Payout: Contest reward
- Severity: medium
- Program: Perennial
- Credited: bin2chen
- Disclosed: 2023-10-26
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-10-perennial-judging/issues/25
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-10-perennial%3AM-4
- Tags: domain:web3 impact:dos kind:contest platform:sherlock sev:medium tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** KeeperOracle settlement callback registry (Solidity contract)
**Root cause:** request() returns early when versions[_global.currentIndex] already equals currentTimestamp, before adding market/account to _globalCallbacks and _localCallbacks, so only the first requester per oracle version is recorded.
**Steps:**
1. Call `KeeperOracle.request(marketA, accountA)` for current oracle version -> adds A to callback sets, increments index.
2. Call `KeeperOracle.request(marketB, accountB)` in same version -> hits `if (versions[_global.currentIndex] == currentTimestamp) return;` and exits before adding B.
3. Oracle settles; only marketA/accountA receive settlement callback; marketB/accountB never settled.
**How found:** Code reading of request() flow: noticed the early-return guard sits above the callback-registration lines, so any second request in the same version skips registration.
**Insight:** When auditing caching/dedup guards, check whether state-mutation lines that should run per-caller sit below the early-return; per-version registries must accumulate all callers, not just the first.
