Platform: Code4rena
Start Date: 13/03/2023
Pot Size: $72,500 USDC
Total HM: 33
Participants: 35
Period: 7 days
Judge: Dravee
Total Solo HM: 16
Id: 222
League: ETH
Rank: 9/35
Findings: 1
Award: $1,562.54
🌟 Selected for report: 1
🚀 Solo Findings: 0
🌟 Selected for report: carlitox477
Also found by: KIntern_NA
1562.5386 USDC - $1,562.54
https://github.com/code-423n4/2023-03-polynomial/blob/aeecafc8aaceab1ebeb94117459946032ccdff1e/src/Exchange.sol#L196 https://github.com/code-423n4/2023-03-polynomial/blob/aeecafc8aaceab1ebeb94117459946032ccdff1e/src/Exchange.sol#L416
wad
operations are meant to be done with int/uint which represent numbers with 18 decimals.
While the funding rate follows this representation, a simple time difference does not.
In Exchange.getMarkPrice
as well as in Exchange._updateFundingRate
a wadMul
operation is done to multiply the funding rate per second by a simple time difference, leading to wrong calculation of normalizationFactor
and mark price, affecting critical parts of the protocol
In Exchange.getMarkPrice
first we get the funding rate per second:
(int256 fundingRate,) = getFundingRate(); fundingRate = fundingRate / 1 days; // Funding rate per second
Immediately after, the total funding since last update is calculated:
int256 currentTimeStamp = int256(block.timestamp); int256 fundingLastUpdatedTimestamp = int256(fundingLastUpdated); // @audit funding rate X (time interval) / 1e18 = Number without decimal int256 totalFunding = wadMul(fundingRate, (currentTimeStamp - fundingLastUpdatedTimestamp));
int256 totalFunding = wadMul(fundingRate, (currentTimeStamp - fundingLastUpdatedTimestamp));
is the same that $TOTAL_ FUNDING_{t_{1}; t_{2}} = \frac{FUNDING_ RATE_{sec} \times (t_{2} - t_{1})}{10^{18}}$
However, the division by $10^{18}$ should not happen, given that time difference does not represent a number with 18 decimals.
This ends up in a miscalculation of totalFunding
variable, and as a consequence, a miscalculation of mark price
The same issue happens in _updateFundingRate
function
Here a complete list of function affected by this bug:
As it can be seen, this bug affects multiple critical part of the protocol, calculating the correct mark price as well as updating the funding rate is essential for the protocol correct behavior.
Simply replace current wad
operation for a simple multiplication
function getMarkPrice() public view override returns (uint256 markPrice, bool isInvalid) { // Get base asset price from oracles (uint256 baseAssetPrice, bool invalid) = pool.baseAssetPrice(); isInvalid = invalid; // Get funding rate per second // max 1% or 1e16 (int256 fundingRate,) = getFundingRate(); fundingRate = fundingRate / 1 days; int256 currentTimeStamp = int256(block.timestamp); int256 fundingLastUpdatedTimestamp = int256(fundingLastUpdated); - int256 totalFunding = wadMul(fundingRate, (currentTimeStamp - fundingLastUpdatedTimestamp)); + int256 totalFunding = fundingRate, (currentTimeStamp - fundingLastUpdatedTimestamp); int256 normalizationUpdate = 1e18 - totalFunding; uint256 newNormalizationFactor = normalizationFactor.mulWadDown(uint256(normalizationUpdate)); uint256 squarePrice = baseAssetPrice.mulDivDown(baseAssetPrice, PRICING_CONSTANT); markPrice = squarePrice.mulWadDown(newNormalizationFactor); }
function _updateFundingRate() internal { (int256 fundingRate,) = getFundingRate(); fundingRate = fundingRate / 1 days; int256 currentTimeStamp = int256(block.timestamp); int256 fundingLastUpdatedTimestamp = int256(fundingLastUpdated); - int256 totalFunding = wadMul(fundingRate, (currentTimeStamp - fundingLastUpdatedTimestamp)); + int256 totalFunding = fundingRate, (currentTimeStamp - fundingLastUpdatedTimestamp); int256 normalizationUpdate = 1e18 - totalFunding; normalizationFactor = normalizationFactor.mulWadDown(uint256(normalizationUpdate)); emit UpdateFundingRate(fundingLastUpdated, normalizationFactor); fundingLastUpdated = block.timestamp; }
#0 - c4-sponsor
2023-04-04T13:16:39Z
mubaris marked the issue as sponsor confirmed
#1 - c4-judge
2023-04-22T17:26:11Z
JustDravee marked the issue as primary issue
#2 - c4-judge
2023-05-02T22:25:57Z
JustDravee marked the issue as selected for report