Venus Prime - hihen's results

Earn, borrow & lend on the #1 Decentralized Money Market on the BNB chain.

General Information

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

Venus Protocol

Findings Distribution

Researcher Performance

Rank: 72/115

Findings: 1

Award: $15.69

Gas:
grade-b

🌟 Selected for report: 0

šŸš€ Solo Findings: 0

Findings Information

🌟 Selected for report: DavidGiladi

Also found by: 0x3b, 0xWaitress, 0xhacksmithh, 0xprinc, hihen, jkoppel, lsaudit, oakcobalt, pavankv, pontifex

Labels

bug
G (Gas Optimization)
grade-b
sufficient quality report
G-04

Awards

15.6862 USDC - $15.69

External Links

Gas Optimizations

Total 43 instances over 7 issueswith 20773 gas saved:

IDIssueInstancesGas
[G‑01]Use shift right instead of division if possible480
[G‑02]Using ++X/--Xinstead ofX++/X--` can save gas1995
[G‑03]Do not cache state variables that are used only once927
[G‑04]Functions that revert when called by normal users can be marked payable363
[G‑05]Use x += y instead of x = x + y for mapping state variables3120
[G‑06]Contracts can use fewer storage slots by truncating state variables120000
[G‑07]State variable access within a loop197

Gas Optimizations

[G‑01] Use shift right instead of division if possible

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

[G‑02] Using ++X/--Xinstead ofX++/X--` can save gas

It 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--;

[G‑03] Do not cache state variables that are used only once

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_];

[G‑04] Functions that revert when called by normal users can be marked 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 {

[G‑05] Use x += y instead of x = x + y for mapping state variables

Using += 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;

[G‑06] Contracts can use fewer storage slots by truncating state variables

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):

  • PrimeStorage.sol ( #L6 ):
/// @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 {

[G‑07] State variable access within a loop

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

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax Ā© 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter