Negative ticks when fetching the price from the Uniswap pool are not rounded towards 0, which will give a higher price for pools using TWAP. This will allow opening positions with less margin leading to bad debt accruing over time.
Here we can see that in case tick is negative, it is not being round down towards 0, that will usually give higher prices for the pools that are using TWAP. For reference here is the Uniswap implementation which uses the correct approach.
The impact of this misconfiguration will be observed in the code that uses this functionality:
PositionCalculator::calculateMinMargin
This function is used to determine whether position is eligible for liquidation when opening new trade or in the liquidation itself.
When false higher price is being returned, there will be unsafe positions that will appear safe, until they become insolvent.
PerpMarketV1::predyTradeAfterCallback
_calculateInitialMargin which internally ends up calling the PositionCalculator::getSqrtIndexPrice which will use the flawed TWAP implementation in case no Chainlink price feed is set. When there is a negative tick that is not rounded properly _calculateInitialMargin will return smaller number because it will overvalue the position here:
Then depending on whether marginAmountUpdate is positive or negative, 2 inconsistencies will occur:
[PerpMarketV1.sol](https://github.com/code-423n4/2024-05-predy/blob/main/src/markets/perp/PerpMarketV1.sol#L102-L142)
- Positive - `PredyPool` will receive less than tokens, because they have false higher price, calculated in the `_calculateInitialMargin`
- Negative - trader will be transferred more tokens in the `GlobalData::take`:
[GlobalData.sol](https://github.com/code-423n4/2024-05-predy/blob/main/src/types/GlobalData.sol#L72-L86)
Lines of code
https://github.com/code-423n4/2024-05-predy/blob/a9246db5f874a91fb71c296aac6a66902289306a/src/libraries/UniHelper.sol#L35-L66
Vulnerability details
Impact
Negative ticks when fetching the price from the Uniswap pool are not rounded towards 0, which will give a higher price for pools using TWAP. This will allow opening positions with less margin leading to bad debt accruing over time.
Proof of Concept
UniHelper.sol
Here we can see that in case
tick
is negative, it is not being round down towards 0, that will usually give higher prices for the pools that are using TWAP. For reference here is the Uniswap implementation which uses the correct approach.The impact of this misconfiguration will be observed in the code that uses this functionality:
PositionCalculator::calculateMinMargin
This function is used to determine whether position is eligible for liquidation when opening new trade or in the liquidation itself.
When false higher price is being returned, there will be unsafe positions that will appear safe, until they become insolvent.
PerpMarketV1::predyTradeAfterCallback
_calculateInitialMargin
which internally ends up calling thePositionCalculator::getSqrtIndexPrice
which will use the flawed TWAP implementation in case no Chainlink price feed is set. When there is a negative tick that is not rounded properly_calculateInitialMargin
will return smaller number because it will overvalue the position here:PerpMarketV1.sol
Here are similar issue for reference:
Tools Used
Manual Review
Recommended Mitigation Steps
Add this line.
Assessed type
Oracle