Platform: Code4rena
Start Date: 07/07/2023
Pot Size: $121,650 USDC
Total HM: 36
Participants: 111
Period: 7 days
Judge: Picodes
Total Solo HM: 13
Id: 258
League: ETH
Rank: 39/111
Findings: 2
Award: $360.73
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Udsen
Also found by: 0x11singh99, 0xPsuedoPandit, Daniel526, Darwin, Inspecktor, Jorgect, Nyx, Praise, Tripathi, YY, catellatech, namx05, squeaky_cactus, xuwinnie
19.2867 USDC - $19.29
setDrawManager
offers Attacker to frontrun the tx which can lock drawManager
role.
User will have to do costly redeployment which again prone to frontrun attack if he doesn't specify drawManager
role in constructor and leads to DOS .
scenarios
if drawManager
has not been set in constructor [DOS]
this will lead to DOS as for every deployment Attacker can frontrun the setDrawManager
. This will lock the
drawManager
role and so prizePool
As in constructor there is no address check for address so invalid address will cost redeployment
see Impact
File: src/PrizePool.sol 258 constructor( ConstructorParams memory params ) TieredLiquidityDistributor( params.numberOfTiers, params.tierShares, params.canaryShares, params.reserveShares ) { if (unwrap(params.smoothing) >= unwrap(UNIT)) { revert SmoothingGTEOne(unwrap(params.smoothing)); } prizeToken = params.prizeToken; twabController = params.twabController; smoothing = params.smoothing; claimExpansionThreshold = params.claimExpansionThreshold; drawPeriodSeconds = params.drawPeriodSeconds; _lastClosedDrawStartedAt = params.firstDrawStartsAt; drawManager = params.drawManager; if (params.drawManager != address(0)) { emit DrawManagerSet(params.drawManager); } 282 } 299 function setDrawManager(address _drawManager) external { if (drawManager != address(0)) { revert DrawManagerAlreadySet(); } drawManager = _drawManager; 306 emit DrawManagerSet(_drawManager); }
Manual
set the drawManager
role to deployer(msg.sender
) in constructor and then add a option to change setdrawManager
where deployer can set drawManager
to any address
Access Control
#0 - c4-judge
2023-07-14T22:59:58Z
Picodes marked the issue as duplicate of #356
#1 - c4-judge
2023-08-06T10:31:36Z
Picodes changed the severity to 2 (Med Risk)
#2 - c4-judge
2023-08-06T10:32:12Z
Picodes marked the issue as satisfactory
🌟 Selected for report: catellatech
341.4422 USDC - $341.44
https://github.com/PaulRBerg/prb-math/blob/df27d3d12ce12153fb166e1e310c8351210dc7ba/src/sd59x18/Math.sol#L596-L609 https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/libraries/DrawAccumulatorLib.sol#L390-L399
Protocol is highly dependent on the computation of area under the curve c(d) = −t ∗ ln(α)∗α ^ d
which uses PRB-Math's Pow() function to calculate . Recently It has been found this pow()
function can give inconsistent values and break the computation.
PRBMath's pow()
function takes two signed integer (say a and b) and returns a**b
A proper implementation of power function states that :
for any a >= b and x >= 0 , a ** x >= b ** x
Simplifying this further as (a>=b)= ((a/b)>=1) and so (a/b)**x >=1 [x>=0]
this pow()
function doesn't follow this and gives inconsistent values.
This Mainly affects integrate
function of DrawAccumulatorLib.sol
which integrate from a lower value higher value for the exponential weighted average
File: prb-math/src/sd59x18/Math.sol 596: function pow(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { int256 xInt = x.unwrap(); int256 yInt = y.unwrap(); if (xInt == 0) { result = yInt == 0 ? UNIT : ZERO; } else { if (yInt == uUNIT) { result = x; } else { result = exp2(mul(log2(x), y)); } } 609: }
Test Function
function testPow() public { uint128 high = 505456470057136353; uint128 low = 505456461792312955; assert(high > low); SD59x18 exp = UD2x18.wrap(31414735).intoSD59x18(); SD59x18 highPow = high.intoSD59x18().pow(exp); SD59x18 lowPow = low.intoSD59x18().pow(exp); assert(SD59x18.unwrap(highPow) < SD59x18.unwrap(lowPow)); }
Root cause described by a senior watson - "in the exp2() function, bit masks are applied to multiply the result by root(2,2^-i) for each position i with a value of 1. However at Common.sol#L170, the value is incorrectly included as 0xFF00000000 instead of 0xFF000000 "
Manual , Foundry Testing
Ensure that calculation is accurate by adjusting the comparison value in exp2()
function
Math
#0 - c4-judge
2023-07-14T22:37:38Z
Picodes marked the issue as duplicate of #423
#1 - Picodes
2023-07-29T15:47:02Z
Downgrading to Med as this report doesn't show how it could qualify for High severity
#2 - c4-judge
2023-08-05T21:55:56Z
Picodes changed the severity to 2 (Med Risk)
#3 - c4-judge
2023-08-05T21:56:04Z
Picodes marked the issue as selected for report
#4 - c4-judge
2023-08-07T16:42:58Z
Picodes marked the issue as satisfactory
#5 - catellaTech
2023-08-08T18:52:13Z
Hello, Picodes! While the issue with that function is real, I believe the appropriate mitigation was proposed by Obront you can see more about this in this post , as the co-founder of the project being audited is also the creator of PRBMath. Therefore, it seems out of reach for the PT team to fix the function directly, and instead, the suitable mitigation would be the one proposed by the PRBMath team after they resolved the problem with exp2(). I discussed this further in my report.
Additionally, I think this issue should be considered of high severity because even though the problem was with exp2(), there were some inconsistencies in functions like div and mul, which are heavily used in important calculations within PT. The PRBMath team has already resolved these inconsistencies in version 4.
#6 - c4-judge
2023-08-12T16:26:42Z
Picodes marked issue #423 as primary and marked this issue as a duplicate of 423
#7 - Picodes
2023-08-12T16:34:40Z
@catellaTech thank you for your comment. You are correct about the mitigation. Regarding the severity, I downgraded these issues to Med because in my opinion none of these reports properly demonstrates that this could lead to a credible loss of funds scenario. From my understanding, the issue on pow
occurs only in a specific range (it is related to a bitmask error and required 50000 fuzz tests to be uncovered), so there is a significant probability that the affected zone cannot be touched by DrawAccumulatorLib.sol
TierCalculationLib.sol
, or that the resulting inconsistencies aren't large enough to lead to a loss of funds. Overall I think Medium severity is more appropriate here - although if we dig into it the issue might be High.
#8 - catellaTech
2023-08-12T16:39:39Z
Thanks so much for the answer! 😊👍
#9 - asselstine
2023-08-17T21:30:58Z