Platform: Code4rena
Start Date: 28/09/2023
Pot Size: $36,500 USDC
Total HM: 5
Participants: 115
Period: 6 days
Judge: 0xDjango
Total Solo HM: 1
Id: 290
League: ETH
Rank: 72/115
Findings: 1
Award: $15.69
š Selected for report: 0
š Solo Findings: 0
š Selected for report: DavidGiladi
Also found by: 0x3b, 0xWaitress, 0xhacksmithh, 0xprinc, hihen, jkoppel, lsaudit, oakcobalt, pavankv, pontifex
15.6862 USDC - $15.69
Total 43 instances over 7 issueswith 20773 gas saved:
ID | Issue | Instances | Gas |
---|---|---|---|
[Gā01] | Use shift right instead of division if possible | 4 | 80 |
[Gā02] | Using ++X/ --Xinstead of X++/ X--` can save gas | 19 | 95 |
[Gā03] | Do not cache state variables that are used only once | 9 | 27 |
[Gā04] | Functions that revert when called by normal users can be marked payable | 3 | 63 |
[Gā05] | Use x += y instead of x = x + y for mapping state variables | 3 | 120 |
[Gā06] | Contracts can use fewer storage slots by truncating state variables | 1 | 20000 |
[Gā07] | State variable access within a loop | 1 | 97 |
Shifting right by n
is like dividing by 2^n
, while the shifting cost less gas because it does not require checks and jumps.
There are 4 instances:
/// @audit div 0x100000000000000000000000000000000 122: r += (z * (0x100000000000000000000000000000000 - y)) / 0x100000000000000000000000000000000; /// @audit div 0x200000000000000000000000000000000 124: r += (z * (0x0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - y)) / 0x200000000000000000000000000000000; /// @audit div 0x400000000000000000000000000000000 128: r += (z * (0x092492492492492492492492492492492 - y)) / 0x400000000000000000000000000000000; /// @audit div 0x800000000000000000000000000000000 136: r += (z * (0x088888888888888888888888888888888 - y)) / 0x800000000000000000000000000000000; // add y^15 / 15 - y^16 / 16
++X/
--Xinstead of
X++/
X--` can save gasIt can save 5 gas for each execution / per iteration.
There are 19 instances (click to show):
189: i++; 217: j++; 221: pendingScoreUpdates--; 225: i++; 250: i++; 345: i++; 355: i++; 614: i++; 636: i++; 711: totalIrrevocable++; 713: totalRevocable++; 740: i++; 745: totalIrrevocable--; 747: totalRevocable--; 766: totalIrrevocable++; 767: totalRevocable--; 819: nextScoreUpdateRoundId++; 828: if (totalScoreUpdatesRequired > 0) totalScoreUpdatesRequired--; 831: pendingScoreUpdates--;
It's cheaper to access the state variable directly if it is accessed only once. This can save the 3 gas cost of the extra stack allocation.
There are 9 instances:
181: uint256 accrued = interests[market][user].accrued; 503: uint256 userScore = interests[market][user].score; 504: uint256 totalScore = markets[market].sumOfMembersScore; 763: Token storage userToken = tokens[user]; 920: uint256 score = interests[vToken][user].score;
233: uint256 distributionSpeed = tokenDistributionSpeeds[token_]; 235: uint256 accrued = tokenAmountAccrued[token_]; 289: uint256 initializedBlock = lastAccruedBlock[token_]; 333: uint256 lastBlockAccrued = lastAccruedBlock[token_];
payable
If a function modifier such as onlyOwner
is used, the function will revert if a normal user tries to pay the function. Marking the function as payable
will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided.
The extra opcodes avoided are:
CALLVALUE(2), DUP1(3), ISZERO(3), PUSH2(3), JUMPI(10), PUSH1(3), DUP1(3), REVERT(0), JUMPDEST(1), POP(2)
which cost an average of about 21 gas per call to the function, in addition to the extra deployment cost.
There are 3 instances:
118: function initializeTokens(address[] calldata tokens_) external onlyOwner { 177: function setPrimeToken(address prime_) external onlyOwner { 216: function sweepToken(IERC20Upgradeable token_, address to_, uint256 amount_) external onlyOwner {
x += y
instead of x = x + y
for mapping state variablesUsing +=
for mappings saves 40 gas due to not having to recalculate the mapping's value's hash. The same applies to -=
, *=
, etc.
There are 3 instances:
588: markets[vToken].rewardIndex = markets[vToken].rewardIndex + delta; 633: markets[market].sumOfMembersScore = markets[market].sumOfMembersScore + score; 733: markets[_allMarkets[i]].sumOfMembersScore = 734: markets[_allMarkets[i]].sumOfMembersScore - 735: interests[_allMarkets[i]][user].score;
Some state variables can be safely modified so that the contract uses fewer storage slots. Each saved slot can avoid an extra Gsset (20000 gas) for the first setting of the struct. Subsequent reads as well as writes have smaller gas savings.
There is 1 instance (click to show):
/// @audit Truncate `nextScoreUpdateRoundId` to `uint64` /// @audit Fewer storage usage (49 slots -> 48 slots): /// 800 B: uint256[25] __gap /// 32 B: mapping(address => Token) tokens /// 32 B: uint256 totalIrrevocable /// 32 B: uint256 totalRevocable /// 32 B: uint256 revocableLimit /// 32 B: uint256 irrevocableLimit /// 32 B: mapping(address => uint256) stakedAt /// 32 B: mapping(address => Market) markets /// 32 B: mapping(address => mapping(address => Interest)) interests /// 32 B: address[] allMarkets /// 32 B: uint256 xvsVaultPoolId /// 32 B: mapping(uint256 => mapping(address => bool)) isScoreUpdated /// 32 B: uint256 totalScoreUpdatesRequired /// 32 B: uint256 pendingScoreUpdates /// 32 B: mapping(address => address) vTokenForAsset /// 32 B: mapping(address => uint256) unreleasedPSRIncome /// 32 B: mapping(address => uint256) unreleasedPLPIncome /// 20 B: address xvsVault /// 4 B: uint64 nextScoreUpdateRoundId /// 20 B: address xvsVaultRewardToken /// 20 B: address protocolShareReserve /// 20 B: address comptroller /// 20 B: address primeLiquidityProvider /// 20 B: ResilientOracleInterface oracle /// 16 B: uint128 alphaNumerator /// 16 B: uint128 alphaDenominator 6: contract PrimeStorageV1 {
State variable reads and writes are more expensive than local variable reads and writes. Therefore, it is recommended to replace state variable reads and writes within loops with a local variable. Gas savings should be multiplied by the average loop length.
There are 1 instances:
/// @audit Access `allMarkets.length` within for loop. 246: for (uint256 i = 0; i < allMarkets.length; ) {
#0 - c4-pre-sort
2023-10-07T02:36:35Z
0xRobocop marked the issue as low quality report
#1 - c4-pre-sort
2023-10-07T06:46:00Z
0xRobocop marked the issue as sufficient quality report
#2 - c4-judge
2023-11-03T17:01:30Z
fatherGoose1 marked the issue as grade-b