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: 93/141
Findings: 1
Award: $73.67
🌟 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
73.6702 USDC - $73.67
The list of Permission hashes is fixed at length 6 in generateMerkleTree here:
hashes = new bytes32[](6);
However the _modules passed to deployVault might have more Permissions than 6.
If there are more than 6 Permissions deployVault() will revert with raiseOutOfBounds.
Consider counting up the number of Permissions first before creating the hashes array. Migration.generateMerkleTree does this here:
uint256 treeLength; uint256 modulesLength = _modules.length; unchecked { for (uint256 i; i < modulesLength; ++i) { treeLength += IModule(_modules[i]).getLeafNodes().length; } }
Marking low severity as if this limit is hit, a new protoform contract could be built, deployed and used. ie. it's not built into core contracts like the VaultRegistry.
From the prb-proxy repo README.md A minimum gas reserve is saved in storage such that the proxy does not become unusable if EVM opcode gas costs change in the future.
In Vault.sol it's a constant
so can't be modified in the future without redeploying the Vault and VaultFactory contracts.
This was probably done to save gas but consider making it modifiable for the future. Some Vault's will continue working for a long time and it's possible gas costs will change again in the future.
In the worst case the Vaults would fail to execute transactions due to out of gas failures.
I marked this non-critical but if opcode costs were to change this could potentially become a high or critical.
NOTE: This issue could also apply to COST_PER_WORD
in Transfer.sol however there is a path to swap plugins and migrate Vaults to use new modules so it's less of an issue in contracts like Transfer.
There is no mention of the EIP2981 standard in the docs or code but the FERC1155 does implement that standard.
So it would benefit from returning true for calls to supportsInterface(0x2a55205a)
. see https://eips.ethereum.org/EIPS/eip-2981 for details of the interface.
With that in place exchanges can see the standard is supported and attempt to honor the royalty setting.
The docs mention 51% as the required buyout threshold multiple times. For example If a pool has more than 51% of the total supply after 4 days, the buyout is successful
. See https://docs.fractional.art/fractional-v2-1/smart-contracts/modules/buyout.
However the Buyout.sol logic uses 50%. For example see the check in the end() function here: https://github.com/code-423n4/2022-07-fractional/blob/f862c14f86adf7de232cd4e9cca6b611e6023b98/src/modules/Buyout.sol#L211.
Update either the docs or the code so they are consistently using one of either 50% or 51%.
nonce
in Vault.sol is used as a flag to indicate if the Vault has been initialized or not. However it's stored as a uint256.
Changing it to a bool would make it's purpose and usage a little clearer. It would also save 20k deployment gas if the nonce
declaration was moved above merkleRoot
when changed to bool. This is because it can share a slot with the address owner
.
Functions getLeafNodes
an getPermissions
can be removed from IBuyout.sol as they are already defined in the parent contract IModule.sol.