Rubicon contest - UnusualTurtle's results

An order book protocol for Ethereum, built on L2s.

General Information

Platform: Code4rena

Start Date: 23/05/2022

Pot Size: $50,000 USDC

Total HM: 44

Participants: 99

Period: 5 days

Judge: hickuphh3

Total Solo HM: 11

Id: 129

League: ETH

Rubicon

Findings Distribution

Researcher Performance

Rank: 69/99

Findings: 2

Award: $82.91

🌟 Selected for report: 0

🚀 Solo Findings: 0

Title

Upgrade pragma to at least 0.8.4

Impact

Using newer compiler versions and the optimizer gives gas optimizations and additional safety checks are available for free.

The advantages of versions 0.8.* over <0.8.0 are:

  • Safemath by default from 0.8.0 (can be more gas efficient than library based safemath.)
  • Low-level inliner : from 0.8.2, leads to cheaper runtime gas. Especially relevant when the contract has small functions. For example, OpenZeppelin libraries typically have a lot of small helper functions and if they are not inlined, they cost an additional 20 to 40 gas because of 2 extra jump instructions and additional stack operations needed for function calls.
  • Optimizer improvements in packed structs: Before 0.8.3, storing packed structs, in some cases used an additional storage read operation. After EIP-2929, if the slot was already cold, this means unnecessary stack operations and extra deploy time costs. However, if the slot was already warm, this means an additional cost of 100 gas alongside the same unnecessary stack operations and extra deploy time costs.
  • Custom errors from 0.8.4, leads to cheaper deploy time cost and run time cost. Note: the run time cost is only relevant when the revert condition is met. In short, replace revert strings by custom errors.

Reference

https://docs.soliditylang.org/en/v0.8.14/#:~:text=When%20deploying%20contracts%2C%20you%20should%20use%20the%20latest%20released%20version%20of%20Solidity

POC

https://github.com/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/rubiconPools/BathToken.sol#L8

  1. Using Prefix (++i) rather than postfix (i++) in increment/decrement operators in for-loops

POC

Examples of this issue in the codebase:

https://github.com/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/RubiconRouter.sol#L227

impact

using the prefix increment/decrement operators (++i/--i) cost less gas PER LOOP than the postfix increment/decrement operators (i++/i--)

  1. Boolean Comparisons

POC

Example of this issue in the codebase:

https://github.com/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/rubiconPools/BathHouse.sol#L372

impact

Comparing to a constant (true or false) is a bit more expensive than directly checking the returned boolean value.

approvedStrategists[wouldBeStrategist] == true can be changed to approvedStrategists[wouldBeStrategist]

  1. Avoiding initialization of loop index can save a little gas

POC

Examples of this issue in the codebase:

https://github.com/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/rubiconPools/BathPair.sol#L427

https://github.com/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/rubiconPools/BathPair.sol#L480

impact

The local variable used for the loop index need not be initialized to 0 because the default value is 0. Avoiding this anti-pattern can save a few opcodes and therefore a tiny bit of gas.

  1. Use != 0 instead of > 0

POC

Examples of this issue in the codebase:

https://github.com/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/RubiconMarket.sol#L400

https://github.com/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/RubiconMarket.sol#L402

impact

Using != 0 is slightly cheaper than > 0.

  1. Avoiding initialization of loop index can save a little gas

POC

Examples of this issue in the codebase:

https://github.com/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/rubiconPools/BathToken.sol#L635

https://github.com/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/rubiconPools/BathPair.sol#L480

https://github.com/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/rubiconPools/BathToken.sol#L635

impact

The local variable used for the loop index need not be initialized to 0 because the default value is 0. Avoiding this anti-pattern can save a few opcodes and therefore a tiny bit of gas.

  1. Storage

POC

Examples of this issue in the codebase:

here, bonusTokens can be cached as a memory to save gas https://github.com/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/rubiconPools/BathToken.sol#L634

here allowance[from][msg.sender] can be cached as memory to save gas https://github.com/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/rubiconPools/BathToken.sol#L703

impact

The code can be optimized by minimizing the number of SLOADs. SLOADs are expensive (100 gas) compared to MLOADs/MSTOREs (3 gas).

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