Platform: Code4rena
Start Date: 12/12/2022
Pot Size: $36,500 USDC
Total HM: 8
Participants: 103
Period: 7 days
Judge: berndartmueller
Id: 193
League: ETH
Rank: 79/103
Findings: 1
Award: $14.83
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Rolezn
Also found by: 0x1f8b, 0xAgro, 0xSmartContract, 0xab00, 0xhacksmithh, Aymen0909, Bnke0x0, Breeje, Diana, HardlyCodeMan, IllIllI, JC, JrNet, Madalad, NoamYakov, RaymondFam, ReyAdmirado, SleepingBugs, UdarTeam, c3phas, carlitox477, cryptonue, gz627, lukris02, millersplanet, oyc_109, pavankv, ret2basic, saneryee, tnevler
14.833 USDC - $14.83
Two gas optimisations in two areas were found other than the C4udit public findings.
Area | Gas Saving |
---|---|
Deployment | 60500 |
owner() | 144 - 2144 |
Owned.sol
is only really utilised (through the onlyOwner modifier) in LPToken.sol
and therefore inherited into Pair.sol
via import. There is no actual utilisation of Owned.sol
in Caviar.sol
other than setting the owner variable which is called in Pair.sol
returning address(msg.sender)
from the contract creation.
By removing Owned.sol
utility from Caviar.sol
and simply using address public immutable owner;
and setting owner = msg.sender
in constructor()
, the owner variable is still availbe to Pair.sol
via caviar.owner()
due to the owner variable being public and solidity automatically creatign a getter function for it. There is no code to suggest any change in ownership so the variable can also be set immutable, saving further gas at runtime.
import "../lib/solmate/src/auth/Owned.sol"; ... constructor() Owned(msg.sender) {}
//import "../lib/solmate/src/auth/Owned.sol"; ... address public immutable owner; constructor() { owner = msg.sender; }
Area | |
---|---|
(Pre) Deployment Cost | 4625247 |
(Post) Deployment Cost | 4564747 |
Cost Saving | 60500 |
Function Name | min | avg | median | max | # calls |
---|---|---|---|---|---|
(Pre) owner | 348 | 1681 | 2348 | 2348 | 12 |
(Post) owner | 204 | 204 | 204 | 204 | 12 |
Gas Diff | 144 | 1477 | 2144 | 2144 | 0 |
The automated findings correctly reported tokenIds.length should be cached outside for loops in Pair.sol, however additionally to the use of tokenIds.length
in the loops witin wrap()
and unwrap()
there is an additional use to within these functions fractionalTokenAmount = tokenIds.length * ONE;
which should also be referenced by the recommended fix of cached uint for the array length.
// *** Effects *** // uint arrayLen = tokenIds.length; /// @audit Cache array length for multiple references as well as use in the for loop // mint fractional tokens to sender fractionalTokenAmount = arrayLen * ONE; /// @audit used cached value _mint(msg.sender, fractionalTokenAmount); // *** Interactions *** // // transfer nfts from sender for (uint256 i = 0; i < arrayLen; i++) { /// @audit used cached value ERC721(nft).safeTransferFrom(msg.sender, address(this), tokenIds[i]); }```
#0 - c4-judge
2023-01-14T17:19:56Z
berndartmueller marked the issue as grade-b