# Drained oracle fees from market by depositing and withdrawing immediately without triggering settlement fees

Perennial Market lets users open/close dust positions each block to trigger oracle requests without paying settlement fees, draining keeper incentives and DoSing price commits.

- Payout: Contest reward
- Severity: medium
- Program: Perennial
- Credited: 0x73696d616f
- Disclosed: 2023-07-17
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-07-perennial-judging/issues/153
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AM-10
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:sherlock sev:medium tech:evm tech:solidity vuln:business-logic vuln:dos vuln:fee-bypass

**Target:** Perennial Market.sol / PythOracle settlement fee accounting
**Root cause:** Oracle/keeper fees are only debited on settlement; a position opened and closed within the same oracle version never settles, so the request is triggered without any fee being charged to the user.
**Steps:**
1. Call `market.update(user, dustPosition, 0, 0, dustCollateral, false)` with a 1-wei-scale maker position to trigger `oracle.request`.
2. Immediately call `market.update(user, 0, 0, 0, -dustCollateral, false)` to close, still within the same oracle version.
3. Repeat each block (increment `block.timestamp`) to queue many oracle requests with zero fee paid.
4. Act as keeper and commit the queued prices within MIN/MAX_VALID_TIME_AFTER_VERSION to collect the oracleFee incentives.
**How found:** Code reading of Market.update: noticed oracle request fires whenever order is non-empty, but oracleFee is only increased on settlement; realized a same-version open/close never settles, so no fee is charged.
**Exploitation:** Attacker loops dust open/close across blocks to accumulate oracle requests without paying settlement fees, then submits valid prices as keeper to collect the accumulated oracleFee, draining the market's keeper fee pool until price commits become unaffordable (DoS).
**Escalation:** Repeating across many blocks drains the entire keeper fee reserve, causing DoS since a keeper amount must exist before a new oracle version can be requested for settlement.
**Insight:** When a fee is only accrued at settlement, check whether a position can be opened and closed within a single oracle version so the settlement path (and its fee debit) is skipped while the side-effect (oracle request) still fires.
