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: 79/111
Findings: 1
Award: $24.30
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: c3phas
Also found by: 0x11singh99, 0xAnah, 0xn006e7, LeoS, Rageur, Raihan, ReyAdmirado, Rolezn, SAAJ, SAQ, SM3_SS, Udsen, alymurtazamemon, hunter_w3b, koxuan, naman1778, petrichor, ybansal2403
24.2984 USDC - $24.30
Number | Optimization Details | Instances |
---|---|---|
[G-01] | Use constants instead of type(uintx).max or type(uintx).min or type(intx).max or type(intx).min | 6 |
[G-02] | If’s/require() statements that check input arguments should be at the top of the function | 1 |
[G-03] | Use unchecked{} whenever underflow/overflow not possible | 4 |
[G-04] | Non efficient zero initialization | 2 |
[G-05] | Using ternary operator instead of if else saves gas | 5 |
[G-06] | Make 3 event parameters indexed when possible | 8 |
[G-07] | x + y is more efficient than using += for state variables (likewise for -=) | 3 |
[G-08] | Use storage instead of memory for structs/arrays | 3 |
[G-09] | Storage variables should be cached in stack(if possible) variables rather than re-reading them from memory | 7 |
[G-10] | The result of a function call should be cached rather than re-calling the function | 1 |
Total 10 issues
Total 6 instances - 1 file:
File: /claimer/src/libraries/LinearVRGDALib.sol 56: targetTimeUnwrapped > 0 && decayConstantUnwrapped > type(int256).max / targetTimeUnwrapped
File: /claimer/src/libraries/LinearVRGDALib.sol 62: targetTimeUnwrapped < 0 && decayConstantUnwrapped > type(int256).min / targetTimeUnwrapped
File: /claimer/src/libraries/LinearVRGDALib.sol 82: if (targetPriceInt > type(int256).max / expResult) {
File: /claimer/src/libraries/LinearVRGDALib.sol 83: return type(uint256).max;
File: /claimer/src/libraries/LinearVRGDALib.sol 89: if (targetPriceInt > type(int256).max / extraPrecisionExpResult) {
File: /claimer/src/libraries/LinearVRGDALib.sol 90: return type(uint256).max;
1 instance - 1 file:
File: /prize-pool/src/PrizePool.sol 278:drawManager = params.drawManager; 279: if (params.drawManager != address(0)) { 280: emit DrawManagerSet(params.drawManager); 281: }
4 instances - 2 files:
File: /claimer/src/Claimer.sol 68: for (uint i = 0; i < winners.length; i++) {
File: /claimer/src/Claimer.sol 144: for (uint i = 0; i < _claimCount; i++) {
File: prize-pool/src/abstract/TieredLiquidityDistributor.sol 361: for (uint8 i = start; i < end; i++) {
File: prize-pool/src/abstract/TieredLiquidityDistributor.sol 630: for (uint8 i = start; i < end; i++) {
2 instances - 1 file:
File: /claimer/src/Claimer.sol 68: for (uint i = 0; i < winners.length; i++) {
File: /claimer/src/Claimer.sol 144: for (uint i = 0; i < _claimCount; i++) {
5 instances - 3 file:
File: /claimer/src/Claimer.sol 171: if (_tier != _canaryTier) { 172: // canary tier 173: return _computeMaxFee(prizePool.getTierPrizeSize(_canaryTier - 1)); 174: } else { 175: return _computeMaxFee(prizePool.getTierPrizeSize(_canaryTier)); 176: }
File: /prize-pool/src/abstract/TieredLiquidityDistributor.sol 353: if (_nextNumberOfTiers > numTiers) { 354: start = numTiers - 1; 355: end = _nextNumberOfTiers; 356: } else { 357: // just reset the canary tier 358: start = _nextNumberOfTiers - 1; 359: end = _nextNumberOfTiers; 360: }
File: /prize-pool/src/abstract/TieredLiquidityDistributor.sol 565:if (_isCanaryTier(_tier, _numberOfTiers)) { 566: prizeSize = _computePrizeSize( 567: _tierPrizeTokenPerShare, 568: _prizeTokenPerShare, 569: _canaryPrizeCountFractional(_numberOfTiers), 570: canaryShares 571: ); 572: } else { 573: prizeSize = _computePrizeSize( 574: _tierPrizeTokenPerShare, 575: _prizeTokenPerShare, 576: toUD60x18(TierCalculationLib.prizeCount(_tier)), 577: tierShares 578: ); 579: }
File: /prize-pool/src/abstract/TieredLiquidityDistributor.sol 622: if (_nextNumberOfTiers < _numberOfTiers) { 623: start = _nextNumberOfTiers - 1; 624: end = _numberOfTiers; 625: } else { 626: // just reset the canary tier 627: start = _numberOfTiers - 1; 628: end = _numberOfTiers; 629: }
File: /prize-pool/src/PrizePool.sol 440: if (_isCanaryTier(_tier, numberOfTiers)) { 441: canaryClaimCount++; 442: } else { 443: claimCount++; 444: }
8 instances - 2 file:
It’s the most gas efficient to make up to 3 event parameters indexed. If there are less than 3 parameters, you need to make all parameters indexed.
File: /prize-pool/src/abstract/TieredLiquidityDistributor.sol 41: event ReserveConsumed(uint256 amount);
File: /prize-pool/src/PrizePool.sol 138:event ClaimedPrize( 139: address indexed vault, 140: address indexed winner, 141: address indexed recipient, 142: uint16 drawId, 143: uint8 tier, 144: uint32 prizeIndex, 145: uint152 payout, 146: uint96 fee, 147: address feeRecipient 148: );
File: /prize-pool/src/PrizePool.sol 158: event DrawClosed( 159: uint16 indexed drawId, 160: uint256 winningRandomNumber, 161: uint8 numTiers, 162: uint8 nextNumTiers, 163: uint104 reserve, 164: UD34x4 prizeTokensPerShare, 165: uint64 drawStartedAt 166: );
File: /prize-pool/src/PrizePool.sol 171:event WithdrawReserve(address indexed to, uint256 amount);
File: /prize-pool/src/PrizePool.sol 176:event IncreaseReserve(address user, uint256 amount);
File: /prize-pool/src/PrizePool.sol 182: event ContributePrizeTokens(address indexed vault, uint16 indexed drawId, uint256 amount);
File: /prize-pool/src/PrizePool.sol 188: event WithdrawClaimRewards(address indexed to, uint256 amount, uint256 available);
File: /prize-pool/src/PrizePool.sol 193: event IncreaseClaimRewards(address indexed to, uint256 amount);
3 instances - 1 file:
File: /prize-pool/src/PrizePool.sol 339: _reserve -= _amount;
File: /prize-pool/src/PrizePool.sol 490: claimerRewards[msg.sender] -= _amount;
File: /prize-pool/src/PrizePool.sol 770: _nextExpectedEndTime += 771:drawPeriodSeconds * 772: (uint64((block.timestamp - _nextExpectedEndTime) / drawPeriodSeconds));
3 instances - 2 file:
File: /prize-pool/src/abstract/TieredLiquidityDistributor.sol 472: Tier memory tier = _tiers[_tier];
File: /prize-pool/src/abstract/TieredLiquidityDistributor.sol 631: Tier memory tierLiquidity = _tiers[i];
File: /prize-pool/src/PrizePool.sol 415: Tier memory tierLiquidity = _getTier(_tier, numberOfTiers);
7 instances - 2 file:
lastClosedDrawId
can be cached to stack variableFindings are labeled with ' <= FOUND
File: /prize-pool/src/abstract/TieredLiquidityDistributor.sol 311:function contributePrizeTokens(address _prizeVault, uint256 _amount) external returns (uint256) { 312: uint256 _deltaBalance = prizeToken.balanceOf(address(this)) - _accountedBalance(); 313: if (_deltaBalance < _amount) { 314: revert ContributionGTDeltaBalance(_amount, _deltaBalance); 315: } 316: DrawAccumulatorLib.add( 317: vaultAccumulator[_prizeVault], 318: _amount, 319: lastClosedDrawId + 1,// <=FOUND 320: smoothing.intoSD59x18() 321: ); 322: DrawAccumulatorLib.add( 323: totalAccumulator, 324: _amount, 325: lastClosedDrawId + 1, 326: smoothing.intoSD59x18() 327: ); 328: emit ContributePrizeTokens(_prizeVault, lastClosedDrawId + 1, _amount);// <=FOUND 329: return _deltaBalance; 330: }
_reserve
can be cached to stack variableFindings are labeled with ' <= FOUND
File: /prize-pool/src/PrizePool.sol 335:function withdrawReserve(address _to, uint104 _amount) external onlyDrawManager { 336: if (_amount > _reserve) {//<= FOUND 337: revert InsufficientReserve(_amount, _reserve);//<= FOUND 338: } 339: _reserve -= _amount;//<= FOUND 340: _transfer(_to, _amount); 341: emit WithdrawReserve(_to, _amount); 342: }
lastClosedDrawId
can be cached to stack variableFile: /prize-pool/src/PrizePool.sol 618:uint96(_contributionsForDraw(lastClosedDrawId + 1))
lastClosedDrawId
can be cached to stack variableFile: /prize-pool/src/PrizePool.sol 626:return _contributionsForDraw(lastClosedDrawId);
drawPeriodSeconds
can be cached to stack variableFindings are labeled with ' <= FOUND
File: /prize-pool/src/PrizePool.sol 685: endTimestamp = _lastClosedDrawStartedAt + drawPeriodSeconds;//<= FOUND 686: SD59x18 tierOdds = _tierOdds(_tier, _numberOfTiers); 687: uint256 durationInSeconds = TierCalculationLib.estimatePrizeFrequencyInDraws(tierOdds) * drawPeriodSeconds;//<= FOUND
drawPeriodSeconds
can be cached to stack variableFindings are labeled with ' <= FOUND
File: /prize-pool/src/PrizePool.sol 749: function _openDrawStartedAt() internal view returns (uint64) { 750: return _openDrawEndsAt() - drawPeriodSeconds;//<= FOUND 751: }
_lastClosedDrawStartedAt
,lastClosedDrawId
,drawPeriodSeconds
,numMissedDraws
can be cached to stack variableFindings are labeled with ' <= FOUND
File: /prize-pool/src/PrizePool.sol 760: function _openDrawEndsAt() internal view returns (uint64) { 761: // If this is the first draw, we treat _lastClosedDrawStartedAt as the start of this draw 762: uint64 _nextExpectedEndTime = _lastClosedDrawStartedAt +//<= FOUND 763: (lastClosedDrawId == 0 ? 1 : 2) *//<= FOUND 764: drawPeriodSeconds;//<= FOUND 765: 766: if (block.timestamp > _nextExpectedEndTime) { 767: // Use integer division to get the number of draw periods passed between the expected end time and now 768: // Offset the end time by the total duration of the missed draws 769: // drawPeriodSeconds * numMissedDraws//<= FOUND 770: _nextExpectedEndTime += 771: drawPeriodSeconds *//<= FOUND 772: (uint64((block.timestamp - _nextExpectedEndTime) / drawPeriodSeconds));//<= FOUND 773: } 774: 775: return _nextExpectedEndTime; 776: }
1 instance - 1 file:
smoothing.intoSD59x18()
can be cached to stack variableFindings are labeled with ' <= FOUND
File: /prize-pool/src/abstract/TieredLiquidityDistributor.sol 311:function contributePrizeTokens(address _prizeVault, uint256 _amount) external returns (uint256) { 312: uint256 _deltaBalance = prizeToken.balanceOf(address(this)) - _accountedBalance(); 313: if (_deltaBalance < _amount) { 314: revert ContributionGTDeltaBalance(_amount, _deltaBalance); 315: } 316: DrawAccumulatorLib.add( 317: vaultAccumulator[_prizeVault], 318: _amount, 319: lastClosedDrawId + 1, 320: smoothing.intoSD59x18()// <=FOUND 321: ); 322: DrawAccumulatorLib.add( 323: totalAccumulator, 324: _amount, 325: lastClosedDrawId + 1, 326: smoothing.intoSD59x18()// <=FOUND 327: ); 328: emit ContributePrizeTokens(_prizeVault, lastClosedDrawId + 1, _amount); 329: return _deltaBalance; 330: }
#0 - c4-judge
2023-07-18T18:59:01Z
Picodes marked the issue as grade-b
#1 - PierrickGT
2023-09-05T23:11:40Z
G-01: this suggestion does not save any gas
G-02: fixed in https://github.com/GenerationSoftware/pt-v5-prize-pool/pull/57
G-03: unchecked { ++i }
would have to be at the end of the function and would reduce clarity, so we are not going to implement these kind of suggestions.
G-04: same for i = 0
, it would reduce clarity.
G-05: fixed in the following PR: https://github.com/GenerationSoftware/pt-v5-prize-pool/pull/57
G-06: no need to index amounts
G-07: won't fix cause we would lose in code clarity
G-08: it's preferable to use memory
instead of storage
G-09: fixed in the following PR: https://github.com/GenerationSoftware/pt-v5-prize-pool/pull/57
G-10: has been removed