Oracle can return different prices in same transaction
The Pyth network oracle contract allows to submit and read two different prices in the same transaction. This can be used to create arbitrage opportunities that can make a profit with no risk at the expense of users on the other side of the trade.\\n`OracleModule.sol` uses Pyth network as the primary source of price feeds. This oracle works in the following way:\\nA dedicated network keeps track of the latest price consensus, together with the timestamp.\\nThis data is queried off-chain and submitted to the on-chain oracle.\\nIt is checked that the data submitted is valid and the new price data is stored.\\nNew requests for the latest price will now return the data submitted until a more recent price is submitted.\\nOne thing to note is that the Pyth network is constantly updating the latest price (every 400ms), so when a new price is submitted on-chain it is not necessary that the price is the latest one. Otherwise, the process of querying the data off-chain, building the transaction, and submitting it on-chain would be required to be done with a latency of less than 400ms, which is not feasible. This makes it possible to submit two different prices in the same transaction and, thus, fetch two different prices in the same transaction.\\nThis can be used to create some arbitrage opportunities that can make a profit with no risk.\\nHow this can be exploited\\nAn example of how this can be exploited, and showed in the PoC, would be:\\nCreate a small leverage position.\\nAnnounce an adjustment order to increase the size of the position by some amount.\\nIn the same block, announce a limit close order.\\nAfter the minimum execution time has elapsed, retrieve two prices from the Pyth oracle where the second price is higher than the first one.\\nExecute the adjustment order sending the first price.\\nExecute the limit close order sending the second price.\\nThe result is approximately a profit of\\n```\\nadjustmentSize * (secondPrice - firstPrice) - (adjustmentSize * tradeFees * 2)\\n```\\n\\nNote: For simplicity, we do not take into account the initial size of the position, which in any case can be insignificant compared to the adjustment size. The keeper fee is also not included, as is the owner of the position that is executing the orders.\\nThe following things are required to make a profit out of this attack:\\nSubmit the orders before other keepers. This can be easily achieved, as there are not always enough incentives to execute the orders as soon as possible.\\nObtain a positive delta between two prices in the time frame where the orders are executable that is greater than twice the trade fees. This can be very feasible, especially in moments of high volatility. Note also, that this requirement can be lowered to a delta greater than once the trade fees if we take into account that there is currently another vulnerability that allows to avoid paying fees for the limit order.\\nIn the case of not being able to obtain the required delta or observing that a keeper has already submitted a transaction to execute them before the delta is obtained, the user can simply cancel the limit order and will have just the adjustment order executed.\\nAnother possible strategy would pass through the following steps:\\nCreate a leverage position.\\nAnnounce another leverage position with the same size.\\nIn the same block, announce a limit close order.\\nAfter the minimum execution time has elapsed, retrieve two prices from the Pyth oracle where the second price is lower than the first one.\\nExecute the limit close order sending the first price.\\nExecute the open order sending the second price.\\nThe result in this case is having a position with the same size as the original one, but having either lowered the `position.lastPrice` or getting a profit from the original position, depending on how the price has moved since the original position was opened.\\n\\n
```\\nFile: OracleModule.sol\\n    FlatcoinStructs.OffchainOracle public offchainOracle; // Offchain Pyth network oracle\\n\\n// Add the line below\\n   uint256 public lastOffchainUpdate;\\n\\n    (// rest of code)\\n\\n    function updatePythPrice(address sender, bytes[] calldata priceUpdateData) external payable nonReentrant {\\n// Add the line below\\n       if (lastOffchainUpdate >= block.timestamp) return;\\n// Add the line below\\n       lastOffchainUpdate = block.timestamp;\\n// Add the line below\\n\\n        // Get fee amount to pay to Pyth\\n        uint256 fee = offchainOracle.oracleContract.getUpdateFee(priceUpdateData);\\n```\\n
Different oracle prices can be fetched in the same transaction, which can be used to create arbitrage opportunities that can make a profit with no risk at the expense of users on the other side of the trade.
```\\nadjustmentSize * (secondPrice - firstPrice) - (adjustmentSize * tradeFees * 2)\\n```\\n