prePO contest - rjs's results

Decentralized Exchange for Pre-IPO Stocks & Pre-IDO Tokens.

General Information

Platform: Code4rena

Start Date: 09/12/2022

Pot Size: $36,500 USDC

Total HM: 9

Participants: 69

Period: 3 days

Judge: Picodes

Total Solo HM: 2

Id: 190

League: ETH

prePO

Findings Distribution

Researcher Performance

Rank: 68/69

Findings: 1

Award: $25.05

Gas:
grade-b

๐ŸŒŸ Selected for report: 0

๐Ÿš€ Solo Findings: 0

Findings Information

Awards

25.0472 USDC - $25.05

Labels

bug
G (Gas Optimization)
grade-b
G-18

External Links

Introduction

The PrePO code base is well-written and employs many common gas optimizations in sensible places. It was quite a challenge to find improvements ๐Ÿ‘.

Summary

IDFindingInstances
G-01Single-child inheritance hierarchies can be flattened1
G-02x = x + yย is more efficient thanย x += y;5
G-03Use named variables in function returns2
G-04Redundant return statement2
G-05Cache variables in hot loops1

Gas Optimization Findings

[G-01] Single-child inheritance hierarchies can be flattened

Deployment Gas saved: โœ” Transaction Gas saved: โœ”

NFTScoreRequirement has only one descendant

DepositHook is the only class to inherit from NFTScoreRequirement. While it is good practice to separate concerns like this, it could be argued that this is a premature optimization until a second child contract has actually been implemented. Given that DepositHook is a hot path for PrePO, and hooks cannot be set by 3rd parties, I would consider flattening this hierarchy for the deployment and transaction (JUMP/stack) gas savings until there is a second descendant of NFTScoreRequirement.

  • packages/prepo-shared-contracts/contracts/NFTScoreRequirement.sol
7: contract NFTScoreRequirement is INFTScoreRequirement {
  • apps/smart-contracts/core/contracts/DepositHook.sol
12: contract DepositHook is IDepositHook, AccountListCaller, NFTScoreRequirement, TokenSenderCaller, SafeAccessControlEnumerable {

[G-02] x = x + yย is more efficient thanย x += y;

Deployment Gas saved: โœ” Transaction Gas saved: โŒ

  • apps/smart-contracts/core/contracts/DepositRecord.sol
31:     globalNetDepositAmount += _amount;
32:     userToDeposits[_sender] += _amount;
  • apps/smart-contracts/core/contracts/WithdrawHook.sol
64:       globalAmountWithdrawnThisPeriod += _amountBeforeFee;
  • apps/smart-contracts/core/contracts/WithdrawHook.sol
71:       userToAmountWithdrawnThisPeriod[_sender] += _amountBeforeFee;
  • packages/prepo-shared-contracts/contracts/NFTScoreRequirement.sol
60:       score += IERC721(collection).balanceOf(account) > 0 ? collectionScore : 0;

[G-03] Use named variables in function returns

Deployment Gas saved: โœ” Transaction Gas saved: โŒ

Declaring additional variables rather than using named return variables is a waste of deployment gas.

  • apps/smart-contracts/core/contracts/Collateral.sol
45:   function deposit(address _recipient, uint256 _amount) external override nonReentrant returns (uint256) {
...
60:     uint256 _collateralMintAmount = (_amountAfterFee * 1e18) / baseTokenDenominator;
...
63:     return _collateralMintAmount;
64:   }
  • packages/prepo-shared-contracts/contracts/NFTScoreRequirement.sol
55:   function getAccountScore(address account) public view virtual override returns (uint256) {
56:     uint256 score;
...
65:     return score;
66:   }

[G-04] Redundant return statement

Deployment Gas saved: โœ” Transaction Gas saved: โŒ

If you set values for all named variable in a function return, it is not necessary to use the return statement, see line 71 below:

  • apps/smart-contracts/core/contracts/PrePOMarketFactory.sol
59:   function _createPairTokens(
...
64:   ) internal returns (LongShortToken _newLongToken, LongShortToken _newShortToken) {
...
69:     _newLongToken = new LongShortToken{salt: _longTokenSalt}(_longTokenName, _longTokenSymbol);
70:     _newShortToken = new LongShortToken{salt: _shortTokenSalt}(_shortTokenName, _shortTokenSymbol);
71:     return (_newLongToken, _newShortToken); // <-- remove
72:   }

Alternatively, if you are just returning the default value, it is also redundant:

  • packages/prepo-shared-contracts/contracts/NFTScoreRequirement.sol
50:   function getCollectionScore(IERC721 collection) external view virtual override returns (uint256) {
51:     if (_collectionToScore.contains(address(collection))) return _collectionToScore.get(address(collection));
52:     return 0; // <-- remove
53:   }

[G-05] Cache variables in hot loops

Deployment Gas saved: โœ” Transaction Gas saved: โœ”

  • packages/prepo-shared-contracts/contracts/NFTScoreRequirement.sol

Before:

25: for (uint256 i = 0; i < numCollections; ) { 26: require(scores[i] > 0, "score == 0"); 27: _collectionToScore.set(address(collections[i]), scores[i]); 28: unchecked { 29: ++i; 30: } 31: }
ยท-----------------------------------------------------------|---------------------------|-------------|-----------------------------ยท | Solc version: 0.8.7 ยท Optimizer enabled: true ยท Runs: 200 ยท Block limit: 30000000 gas โ”‚ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท | Methods โ”‚ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท | Contract ยท Method ยท Min ยท Max ยท Avg ยท # calls ยท eur (avg) โ”‚ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท | DepositHook ยท setCollectionScores ยท 118079 ยท 118307 ยท 118155 ยท 3 ยท - โ”‚ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท

After:

25:     uint256 score;
26:     for (uint256 i = 0; i < numCollections; ) {
27:       score = scores[i];
28:       require(score > 0, "score == 0");
29:       _collectionToScore.set(address(collections[i]), score);
30:       unchecked {
31:         ++i;
32:       }
33:     }
ยท-----------------------------------------|---------------------------|-------------|-----------------------------ยท | Solc version: 0.8.7 ยท Optimizer enabled: true ยท Runs: 200 ยท Block limit: 30000000 gas โ”‚ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท | Methods โ”‚ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท | Contract ยท Method ยท Min ยท Max ยท Avg ยท # calls ยท eur (avg) โ”‚ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท | DepositHook ยท setCollectionScores ยท 118043 ยท 118271 ยท 118119 ยท 3 ยท - โ”‚ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท

#0 - c4-judge

2022-12-19T11:59:13Z

Picodes 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