sherlock-audit / 2024-03-flat-money-fix-review-contest-judging

3 stars 2 forks source link

bareli - Oracle can return different prices in same transaction #1

Closed sherlock-admin3 closed 3 months ago

sherlock-admin3 commented 3 months ago

bareli

high

Oracle can return different prices in same transaction

Summary

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. OracleModule.sol uses Pyth network as the primary source of price feeds. This oracle works in the following way:

Vulnerability Detail

OracleModule.sol uses Pyth network as the primary source of price feeds. This oracle works in the following way:

A dedicated network keeps track of the latest price consensus, together with the timestamp. This data is queried off-chain and submitted to the on-chain oracle. It is checked that the data submitted is valid and the new price data is stored. New requests for the latest price will now return the data submitted until a more recent price is submitted. One 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.

This can be used to create some arbitrage opportunities that can make a profit with no risk.

How this can be exploited An example of how this can be exploited, and showed in the PoC, would be:

Create a small leverage position. Announce an adjustment order to increase the size of the position by some amount. In the same block, announce a limit close order. After the minimum execution time has elapsed, retrieve two prices from the Pyth oracle where the second price is higher than the first one. Execute the adjustment order sending the first price. Execute the limit close order sending the second price. The result is approximately a profit of

adjustmentSize (secondPrice - firstPrice) - (adjustmentSize tradeFees * 2) Note: 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.

The following things are required to make a profit out of this attack:

Submit 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. Obtain 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. In 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.

Another possible strategy would pass through the following steps:

Create a leverage position. Announce another leverage position with the same size. In the same block, announce a limit close order. After the minimum execution time has elapsed, retrieve two prices from the Pyth oracle where the second price is lower than the first one. Execute the limit close order sending the first price. Execute the open order sending the second price. The 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.

Impact

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.

Code Snippet

https://github.com/sherlock-audit/2024-03-flat-money-fix-review-contest/blob/main/flatcoin-v1/src/OracleModule.sol#L58

Tool used

Manual Review

Recommendation

File: OracleModule.sol FlatcoinStructs.OffchainOracle public offchainOracle; // Offchain Pyth network oracle

Duplicate of #27

sherlock-admin4 commented 3 months ago

1 comment(s) were left on this issue during the judging contest.

santipu_ commented:

Medium