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:
getFundingRate() referring to getIndexPrice().
getMarkPrice() referring to getFundingRate().
KangarooVault.sol, LiquidityPool.sol and ShortCollateral.sol call getMarkPrice() in multiple functions, to get token price and collateral evaluation, fee calculation, and trading operations.
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():
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
in _updateFundingRate(), update normalizationFactor with the value from late updated timestamp and the corresponding lasting time span:
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 ingetIndexPrice()
is not up to date, the mismatch ofbaseAssetPrice^2
andnormalizationFactor
will lead to inaccurate funding rate, index price and mark price. The distorted price values will have impacts on many places across the protocol:getFundingRate()
referring togetIndexPrice()
.getMarkPrice()
referring togetFundingRate()
.KangarooVault.sol
,LiquidityPool.sol
andShortCollateral.sol
callgetMarkPrice()
in multiple functions, to get token price and collateral evaluation, fee calculation, and trading operations.Proof of Concept
Currently, in
getIndexPrice()
, thebaseAssetPrice^2
is scaled bynormalizationFactor
to getindexPrice
. The spotbaseAssetPrice
used is returned frompool.baseAssetPrice()
, butnormalizationFactor
is only updated in_updateFundingRate()
:So, the
normalizationFactor
used ingetIndexPrice()
is from previous timestamp, the mismatch ofbaseAssetPrice
andnormalizationFactor
could lead to inaccurateindexPrice
being returned. Later thisindexPrice
will be used ingetFundingRate()
andgetMarkPrice()
to return further distorted price.Tools Used
Manual analysis.
Recommended Mitigation Steps
in
_updateFundingRate()
, updatenormalizationFactor
with the value from late updated timestamp and the corresponding lasting time span: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: }
in
getIndexPrice()
, first call_updateFundingRate()
to updatenormalizationFactor
, then the index price can use the value:_updateFundingRate(); 162: // multiply by normalization factor for applying historic funding rate 163: indexPrice = indexPrice.mulWadDown(normalizationFactor); 164: } 165:
Then, in
getFundingRate()
, all the values used at up to date,skew
,normalizationFactor
andindexPrice
.