# Oracle can return different prices in same transaction

Pyth oracle allows submitting two different prices in one transaction, letting a trader execute adjust and limit-close orders at different prices for risk-free arbitrage against LPs.

- Payout: Contest reward
- Severity: medium
- Program: Flatmoney
- Credited: shaka
- Disclosed: 2023-12-11
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2023-12-flatmoney-judging/issues/216
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-12-flatmoney%3AM-8
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:chained technique:source-review vuln:business-logic vuln:oracle-manipulation

**Target:** OracleModule.sol Pyth price update path in a perp/leverage protocol
**Root cause:** updatePythPrice accepts and stores any valid Pyth price update without deduplicating per-block, so multiple distinct prices can be pushed and read within the same transaction.
**Steps:**
1. Open a small leverage position via announceAndExecuteLeverageOpen.
2. Announce a leverage adjustment (large additionalSizeAdjustment) and, in the same block, announce a limit close order with wide thresholds.
3. Wait minExecutabilityAge so orders are executable.
4. Fetch two Pyth price updates where secondPrice > firstPrice (e.g. `getPriceUpdateData(price)` then `getPriceUpdateData(price+1.2e8)`).
5. Call `delayedOrderProxy.executeOrder(alice, priceUpdateData1)` then `limitOrderProxy.executeLimitOrder(tokenId, priceUpdateData2)` in one tx.
6. Profit = adjustmentSize*(secondPrice-firstPrice) - adjustmentSize*tradeFees*2; cancel limit order if delta insufficient.
**How found:** Researcher noted Pyth updates every 400ms and on-chain submission cannot match that latency, so multiple valid prices can be pushed and read in one tx; verified via a Base tx calling updatePriceFeeds twice with different prices, then built a Foundry PoC.
**Exploitation:** Attacker controls both order executions atomically, feeding a lower price to the adjustment and a higher price to the limit close, capturing the delta from LPs; downside capped at trade fees since the limit order can be cancelled if no favorable delta appears.
**Escalation:** Combining with a separate fee-bypass issue (#212) lowers the break-even delta from 2x to 1x trade fees, increasing profitability.
**Insight:** When a protocol pulls an off-chain push oracle (Pyth/Chainlink push) per call, check whether two updates can be consumed in one tx to price two legs of the same trade differently; look for order pairs (adjust + close) executable in the same block.
