Platform: Code4rena
Start Date: 07/07/2022
Pot Size: $75,000 USDC
Total HM: 32
Participants: 141
Period: 7 days
Judge: HardlyDifficult
Total Solo HM: 4
Id: 144
League: ETH
Rank: 122/141
Findings: 1
Award: $38.36
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: joestakey
Also found by: 0x1f8b, 0x29A, 0xA5DF, 0xKitsune, 0xNazgul, 0xNineDec, 0xalpharush, 0xkatana, 0xsanson, 0xsolstars, 8olidity, Avci, Bnke0x0, BowTiedWardens, Chom, Deivitto, ElKu, Fitraldys, Funen, IllIllI, JC, Kaiziron, Lambda, Limbooo, MEP, NoamYakov, PwnedNoMore, RedOneN, ReyAdmirado, Rohan16, Ruhum, Saintcode_, Sm4rty, TomJ, Tomio, TrungOre, Tutturu, Waze, _Adam, __141345__, ajtra, apostle0x01, asutorufos, benbaessler, brgltd, c3phas, codexploder, cryptphi, delfin454000, dharma09, djxploit, durianSausage, fatherOfBlocks, giovannidisiena, gogo, horsefacts, hrishibhat, hyh, ignacio, jocxyen, jonatascm, karanctf, kebabsec, kyteg, m_Rassska, mektigboy, oyc_109, pedr02b2, rbserver, robee, rokinot, sach1r0, sashik_eth, simon135, slywaters
38.3569 USDC - $38.36
Solidity does not recognize null as a value, so uint variables are initialized to zero. Setting a uint variable to zero is redundant and can waste gas.
Locations where this was found include https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/protoforms/BaseVault.sol#L64 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/protoforms/BaseVault.sol#L83 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/protoforms/BaseVault.sol#L107 https://github.com/code-423n4/2022-07-fractional/tree/main/src/Vault.sol#L78 https://github.com/code-423n4/2022-07-fractional/tree/main/src/Vault.sol#L104 https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/MerkleBase.sol#L51
Remove the redundant zero initialization
uint256 i;
instead of uint256 i = 0;
Caching the array length outside a loop saves reading it on each iteration, as long as the array's length is not changed during the loop. This saves gas.
Locations where this was found include https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/protoforms/BaseVault.sol#L64 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/protoforms/BaseVault.sol#L83 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/protoforms/BaseVault.sol#L107 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/protoforms/BaseVault.sol#L130 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/protoforms/BaseVault.sol#L132
Cache the array length before the for loop
Using > 0
uses slightly more gas than using != 0
. Use != 0
when comparing uint variables to zero, which cannot hold values below zero
Locations where this was found include https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/MerkleBase.sol#L186
Replace > 0
with != 0
to save gas
Strings in solidity are handled in 32 byte chunks. A require string longer than 32 bytes uses more gas. Shortening these strings will save gas.
Locations where this was found include https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/MerkleBase.sol#L78 https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/MerkleBase.sol#L62
Shorten all require strings to less than 32 characters
Using a prefix increment (++i) instead of a postfix increment (i++) saves gas for each loop cycle and so can have a big gas impact when the loop executes on a large number of elements.
Locations where this was found include https://github.com/code-423n4/2022-07-fractional/tree/main/src/FERC1155.sol#L339 https://github.com/code-423n4/2022-07-fractional/tree/main/src/FERC1155.sol#L363 https://github.com/code-423n4/2022-07-fractional/tree/main/src/Vault.sol#L78 https://github.com/code-423n4/2022-07-fractional/tree/main/src/Vault.sol#L104
Use prefix not postfix to increment in a loop
Using calldata instead of memory for function arguments saves gas sometimes. This can happen when a function is called externally and the memory array values are kept in calldata
and copied to memory
during ABI decoding (using the opcode calldataload
and mstore
). If the array is used in a for loop, arr[i]
accesses the value in memory using a mload
. If calldata is used instead, then instead of going via memory, the value is directly read from calldata
using calldataload
. That is, there are no intermediate memory operations that carries this value.
Locations where this was found include https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Minter.sol#L24 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Buyout.sol#L450 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Migration.sol#L487 https://github.com/code-423n4/2022-07-fractional/tree/main/src/Vault.sol#L73 https://github.com/code-423n4/2022-07-fractional/tree/main/src/Vault.sol#L101 https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/MerkleBase.sol#L61 https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/MerkleBase.sol#L73 https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/MerkleBase.sol#L125 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IBuyout.sol#L112 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IBuyout.sol#L114 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IBuyout.sol#L123 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IMigration.sol#L100 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IModule.sol#L8 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IVault.sol#L49 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IVault.sol#L64 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IERC1155.sol#L29
Change function arguments from memory to calldata
For loops that use i++ do not need to use safemath for this operation because the loop would run out of gas long before this point. Making this addition operation unsafe using unchecked saves gas.
Sample code to make the for loop increment unsafe
for (uint i = 0; i < length; i = unchecked_inc(i)) { // do something that doesn't change the value of i } function unchecked_inc(uint i) returns (uint) { unchecked { return i + 1; } }
Idea borrowed from https://gist.github.com/hrkrshnn/ee8fabd532058307229d65dcd5836ddc#the-increment-in-for-loop-post-condition-can-be-made-unchecked
Locations where this was found include https://github.com/code-423n4/2022-07-fractional/tree/main/src/FERC1155.sol#L339 https://github.com/code-423n4/2022-07-fractional/tree/main/src/FERC1155.sol#L363 https://github.com/code-423n4/2022-07-fractional/tree/main/src/Vault.sol#L78 https://github.com/code-423n4/2022-07-fractional/tree/main/src/Vault.sol#L104
Make the increment in for loops unsafe to save gas
Comparing a value to zero can be done using the iszero
EVM opcode. This can save gas
Source from t11s https://twitter.com/transmissions11/status/1474465495243898885
Locations where this was found include https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Buyout.sol#L59 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Buyout.sol#L64 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Buyout.sol#L117 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Buyout.sol#L154 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Buyout.sol#L189 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Buyout.sol#L249 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Buyout.sol#L256 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Buyout.sol#L281 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Buyout.sol#L320 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Buyout.sol#L352 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Buyout.sol#L388 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Buyout.sol#L425 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Migration.sol#L82 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Migration.sol#L114 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Migration.sol#L146 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Migration.sol#L187 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Migration.sol#L299 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Migration.sol#L436 https://github.com/code-423n4/2022-07-fractional/tree/main/src/FERC1155.sol#L276 https://github.com/code-423n4/2022-07-fractional/tree/main/src/Vault.sol#L124 https://github.com/code-423n4/2022-07-fractional/tree/main/src/Vault.sol#L136 https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/Multicall.sol#L23 https://github.com/code-423n4/2022-07-fractional/tree/main/src/VaultRegistry.sol#L42 https://github.com/code-423n4/2022-07-fractional/tree/main/src/VaultRegistry.sol#L120
Use the assembly iszero
evm opcode to compare values to zero
Use unchecked math when there is no overflow risk to save gas. Before index is decreased in remove it is checked for zero condition. This means index will not underflow and can be unchecked.
Locations where this was found include https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Buyout.sol#L86-L87
Add unchecked around math that can't overflow for gas savings. In Solidity before 0.8.0, use the normal math operators instead of safe math functions.
Identifying a constructor as payable saves gas. Constructors should only be called by the admin or deployer and should not mistakenly receive ETH. Constructors can be payable to save gas.
Locations where this was found include https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/protoforms/BaseVault.sol#L24 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Minter.sol#L17 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Buyout.sol#L42 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Migration.sol#L53 https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/MerkleBase.sol#L8 https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/Metadata.sol#L16 https://github.com/code-423n4/2022-07-fractional/tree/main/src/references/SupplyReference.sol#L15 https://github.com/code-423n4/2022-07-fractional/tree/main/src/VaultRegistry.sol#L28 https://github.com/code-423n4/2022-07-fractional/tree/main/src/VaultFactory.sol#L20 https://github.com/code-423n4/2022-07-fractional/tree/main/src/targets/Supply.sol#L16
Add payable to these functions for gas savings
An internal function can save gas vs. a modifier. A modifier inlines the code of the original function but an internal function does not.
Locations where this was found include https://github.com/code-423n4/2022-07-fractional/tree/main/src/FERC1155.sol#L37 https://github.com/code-423n4/2022-07-fractional/tree/main/src/FERC1155.sol#L45
Use internal functions in place of modifiers to save gas.
Booleans are more expensive than uint256 or any type that takes up a full word because each write operation emits an extra SLOAD to first read the slot's contents, replace the bits taken up by the boolean, and then write back. This is the compiler's defense against contract upgrades and pointer aliasing, and it cannot be disabled.
Locations where this was found include https://github.com/code-423n4/2022-07-fractional/tree/main/src/FERC1155.sol#L102 https://github.com/code-423n4/2022-07-fractional/tree/main/src/FERC1155.sol#L148 https://github.com/code-423n4/2022-07-fractional/tree/main/src/FERC1155.sol#L189 https://github.com/code-423n4/2022-07-fractional/tree/main/src/FERC1155.sol#L328 https://github.com/code-423n4/2022-07-fractional/tree/main/src/FERC1155.sol#L353 https://github.com/code-423n4/2022-07-fractional/tree/main/src/Vault.sol#L53 https://github.com/code-423n4/2022-07-fractional/tree/main/src/Vault.sol#L117 https://github.com/code-423n4/2022-07-fractional/tree/main/src/constants/Permit.sol#L11 https://github.com/code-423n4/2022-07-fractional/tree/main/src/constants/Permit.sol#L16 https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/SafeSend.sol#L20 https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/Multicall.sol#L18 https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/SelfPermit.sol#L21 https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/SelfPermit.sol#L48 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IMigration.sol#L26 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IMigration.sol#L32 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IMigration.sol#L98 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IMigration.sol#L140 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IMigration.sol#L143 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IFERC1155.sol#L40 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IFERC1155.sol#L84 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IFERC1155.sol#L94 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IFERC1155.sol#L117 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IVault.sol#L45 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IERC721.sol#L14 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IERC721.sol#L47 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IERC1155.sol#L9 https://github.com/code-423n4/2022-07-fractional/tree/main/src/interfaces/IERC1155.sol#L52
Replace bool variables with uints
Solidity errors introduced in version 0.8.4 can save gas on revert conditions https://blog.soliditylang.org/2021/04/21/custom-errors/ https://twitter.com/PatrickAlphaC/status/1505197417884528640
Locations where this was found include https://github.com/code-423n4/2022-07-fractional/tree/main/src/FERC1155.sol#L263 https://github.com/code-423n4/2022-07-fractional/tree/main/src/FERC1155.sol#L275 https://github.com/code-423n4/2022-07-fractional/tree/main/src/FERC1155.sol#L297 https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/MerkleBase.sol#L62 https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/MerkleBase.sol#L78
Replace require blocks with new solidity errors described in https://blog.soliditylang.org/2021/04/21/custom-errors/
When multiply or dividing by a power of two, it is cheaper to bitshift than to use standard math operations.
There is a divide by 2 operation on these lines https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/MerkleBase.sol#L100 https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/MerkleBase.sol#L136 https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/MerkleBase.sol#L142
Bitshift right by one bit instead of dividing by 2 to save gas
Many constant variables are public, but changing the visibility of these variables to private or internal can save gas.
Locations where this was found include https://github.com/code-423n4/2022-07-fractional/tree/main/src/FERC1155.sol#L15 https://github.com/code-423n4/2022-07-fractional/tree/main/src/FERC1155.sol#L17 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Buyout.sol#L35 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Buyout.sol#L37 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Migration.sol#L43
Declare some public variables as private or internal to save gas
The contracts are all written entirely in solidity. Writing contracts with vyper instead of solidity can save gas.
Source https://twitter.com/eiber_david/status/1515737811881807876 doggo demonstrates https://twitter.com/fubuloubu/status/1528179581974417414?t=-hcq_26JFDaHdAQZ-wYxCA&s=19
Write some or all of the contracts in vyper to save gas