code-423n4 / 2023-03-polynomial-findings

2 stars 1 forks source link

`getIndexPrice()` should used up to date `normalizationFactor` #169

Closed code423n4 closed 1 year ago

code423n4 commented 1 year ago

Lines of code

https://github.com/code-423n4/2023-03-polynomial/blob/aeecafc8aaceab1ebeb94117459946032ccdff1e/src/Exchange.sol#L154-L164 https://github.com/code-423n4/2023-03-polynomial/blob/aeecafc8aaceab1ebeb94117459946032ccdff1e/src/Exchange.sol#L409-L424

Vulnerability details

Impact

The normalizationFactor used in getIndexPrice() is not up to date, the mismatch of baseAssetPrice^2 and normalizationFactor will lead to inaccurate funding rate, index price and mark price. The distorted price values will have impacts on many places across the protocol:

Proof of Concept

Currently, in getIndexPrice(), the baseAssetPrice^2 is scaled by normalizationFactor to get indexPrice. The spot baseAssetPrice used is returned from pool.baseAssetPrice(), but normalizationFactor is only updated in _updateFundingRate():

File: src/Exchange.sol
154:     /// @notice Index price
155:     function getIndexPrice() public view override returns (uint256 indexPrice, bool isInvalid) {
156:         (uint256 baseAssetPrice, bool invalid) = pool.baseAssetPrice();
157:         isInvalid = invalid;
158: 
159:         // base_asset_price^2 / pricing_constant
160:         indexPrice = baseAssetPrice.mulDivDown(baseAssetPrice, PRICING_CONSTANT);
161: 
162:         // multiply by normalization factor for applying historic funding rate
163:         indexPrice = indexPrice.mulWadDown(normalizationFactor);
164:     }

409:     function _updateFundingRate() internal {
410:         (int256 fundingRate,) = getFundingRate();
411:         fundingRate = fundingRate / 1 days;
412: 
413:         int256 currentTimeStamp = int256(block.timestamp);
414:         int256 fundingLastUpdatedTimestamp = int256(fundingLastUpdated);
415: 
416:         int256 totalFunding = wadMul(fundingRate, (currentTimeStamp - fundingLastUpdatedTimestamp));
417:         int256 normalizationUpdate = 1e18 - totalFunding;
418: 
419:         normalizationFactor = normalizationFactor.mulWadDown(uint256(normalizationUpdate));
420: 
421:         emit UpdateFundingRate(fundingLastUpdated, normalizationFactor);
422: 
423:         fundingLastUpdated = block.timestamp;
424:     }

So, the normalizationFactor used in getIndexPrice() is from previous timestamp, the mismatch of baseAssetPrice and normalizationFactor could lead to inaccurate indexPrice being returned. Later this indexPrice will be used in getFundingRate() and getMarkPrice() to return further distorted price.

Tools Used

Manual analysis.

Recommended Mitigation Steps

Then, in getFundingRate(), all the values used at up to date, skew, normalizationFactor and indexPrice.

mubaris commented 1 year ago

Index price should only be updated if there's an actual trade

c4-sponsor commented 1 year ago

mubaris marked the issue as sponsor disputed

c4-judge commented 1 year ago

JustDravee marked the issue as unsatisfactory: Invalid