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: 68/141
Findings: 2
Award: $103.09
π Selected for report: 0
π Solo Findings: 0
π Selected for report: xiaoming90
Also found by: 0x1f8b, 0x29A, 0x52, 0xA5DF, 0xDjango, 0xNazgul, 0xNineDec, 0xf15ers, 0xsanson, 0xsolstars, 242, 8olidity, Amithuddar, Aymen0909, Bnke0x0, BowTiedWardens, David_, Deivitto, ElKu, Funen, Hawkeye, IllIllI, JC, Kaiziron, Keen_Sheen, Kthere, Kulk0, Kumpa, Lambda, MEP, ReyAdmirado, Rohan16, Ruhum, Sm4rty, TomJ, Tomio, Treasure-Seeker, TrungOre, Tutturu, Viksaa39, Waze, _Adam, __141345__, ak1, apostle0x01, asutorufos, async, ayeslick, aysha, bbrho, benbaessler, berndartmueller, c3phas, cccz, chatch, cloudjunky, codexploder, cryptphi, delfin454000, dipp, durianSausage, dy, exd0tpy, fatherOfBlocks, hake, hansfriese, horsefacts, hubble, joestakey, jonatascm, kebabsec, kenzo, kyteg, mektigboy, neumo, oyc_109, pashov, pedr02b2, peritoflores, rajatbeladiya, rbserver, robee, rokinot, s3cunda, sach1r0, sahar, sashik_eth, scaraven, shenwilly, simon135, sorrynotsorry, sseefried, svskaushik, unforgiven, z3s, zzzitron
65.5363 USDC - $65.54
To improve algorithm precision instead using division in comparison use multiplication in the following scenario:
Instead a < b / c use a * c < b.
In all of the big and trusted contracts this rule is maintained.
Buyout.sol, 208, if ( (tokenBalance * 1000) / IVaultRegistry(registry).totalSupply(_vault) > 500 ) {
The following functions are missing commenting as describe below:
FERC1155.sol, INITIAL_CONTROLLER (public), @return is missing FERC1155.sol, VAULT_REGISTRY (public), @return is missing FERC1155.sol, uri (public), @return is missing
To give more trust to users: functions that set key/critical variables should be put behind a timelock.
https://github.com/code-423n4/2022-07-fractional/tree/main/src/utils/Metadata.sol#L24 https://github.com/code-423n4/2022-07-fractional/tree/main/src/FERC1155.sol#L198 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Migration.sol#L220
external / public functions parameters should be validated to make sure the address is not 0. Otherwise if not given the right input it can mistakenly lead to loss of user funds.
MockERC20.sol.mint to Migration.sol.migrateVaultERC721 _token BaseVault.sol.batchDepositERC1155 _from
WETH address is hardcoded but it may differ on other chains, e.g. Polygon, so make sure to check this before deploying and update if necessary You should consider injecting WETH address via the constructor. (previous issue: https://github.com/code-423n4/2021-10-ambire-findings/issues/54)
Hardcoded weth address in SafeSend.sol
owner param should be validated to make sure the owner address is not address(0). Otherwise if not given the right input all only owner accessible functions will be unaccessible.
VaultRegistry.sol.createFor _owner FERC1155.sol.permitAll _owner FERC1155.sol.permit _owner VaultFactory.sol.deployFor _owner
Users can mistakenly think that the return value is the named return, but it is actually the actualreturn statement that comes after. To know that the user needs to read the code and is confusing. Furthermore, removing either the actual return or the named return will save gas.
MerkleBase.sol, log2ceil_naive Multicall.sol, multicall MerkleBase.sol, hashLeafPairs
The following contracts have a function that allows them an admin to change it to a different address. If the admin accidentally uses an invalid address for which they do not have the private key, then the system gets locked. It is important to have two steps admin change where the first is announcing a pending new admin and the new address should then claim its ownership. A similar issue was reported in a previous contest and was assigned a severity of medium: code-423n4/2021-06-realitycards-findings#105
IVault.sol
The following functions are missing reentrancy modifier although some other pulbic/external functions does use reentrancy modifer. Even though I did not find a way to exploit it, it seems like those functions should have the nonReentrant modifier as the other functions have it as well..
Migration.sol, migrateVaultERC721 is missing a reentrancy modifier Migration.sol, withdrawContribution is missing a reentrancy modifier Migration.sol, migrateVaultERC1155 is missing a reentrancy modifier Migration.sol, leave is missing a reentrancy modifier
Open TODOs can hint at programming or architectural errors that still need to be fixed. These files has open TODOs:
Open TODO in MerkleBase.sol line 23 : // TODO: This can be aesthetically simplified with a switch. Not sure it will
Transferring tokens to the zero address is usually prohibited to accidentally avoid "burning" tokens by sending them to an unrecoverable zero address.
https://github.com/code-423n4/2022-07-fractional/tree/main/src/targets/Transfer.sol#L481 https://github.com/code-423n4/2022-07-fractional/tree/main/src/modules/Buyout.sol#L75
Need to use safeTransfer instead of transfer. As there are popular tokens, such as USDT that transfer/trasnferFrom method doesnβt return anything. The transfer return value has to be checked (as there are some other tokens that returns false instead revert), that means you must
TransferReference.sol, 22 (ERC20Transfer), IERC20(_token).transfer(_to, _value); BaseVault.sol, 65 (batchDepositERC20), IERC20(_tokens[i]).transferFrom(_from, _to, _amounts[i]);
#0 - HardlyDifficult
2022-08-07T15:43:40Z
π 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
37.5523 USDC - $37.55
In the following files there are state variables that could be set immutable to save gas.
registry in BaseVault.sol supply in Minter.sol
Caching the array length is more gas efficient. This is because access to a local variable in solidity is more efficient than query storage / calldata / memory. We recommend to change from:
for (uint256 i=0; i<array.length; i++) { ... }
to:
uint len = array.length for (uint256 i=0; i<len; i++) { ... }
BaseVault.sol, _tokens, 83 Buyout.sol, permissions, 454 BaseVault.sol, _tokens, 64
In for loops you initialize the index to start from 0, but it already initialized to 0 in default and this assignment cost gas. It is more clear and gas efficient to declare without assigning 0 and will have the same meaning:
BaseVault.sol, 83 BaseVault.sol, 64
Use bytes32 instead of string to save gas whenever possible. String is a dynamic data structure and therefore is more gas consuming then bytes32.
FERC1155.sol (L15), string public constant NAME = "FERC1155"; FERC1155.sol (L17), string public constant VERSION = "1";
The following require messages are of length more than 32 and we think are short enough to short them into exactly 32 characters such that it will be placed in one slot of memory and the require function will cost less gas. The list:
Solidity file: MerkleBase.sol, In line 62, Require message length to shorten: 34, The message: wont generate root for single leaf Solidity file: MerkleBase.sol, In line 78, Require message length to shorten: 35, The message: wont generate proof for single leaf
Using != 0 is slightly cheaper than > 0. (see https://github.com/code-423n4/2021-12-maple-findings/issues/75 for similar issue)
MerkleBase.sol, 186: change 'x > 0' to 'x != 0'
You can use unchecked in the following calculations since there is no risk to overflow:
Migration.sol (L#194) - if (block.timestamp > proposal.startTime + PROPOSAL_PERIOD)
The following functions are used exactly once. Therefore you can inline them and save gas and improve code clearness.
Migration.sol, _calculateContribution FERC1155.sol, _computePermitStructHash SafeSend.sol, _attemptETHTransfer FERC1155.sol, _computePermitAllStructHash Multicall.sol, _revertedWithReason