Contracts that implement access control, e.g. owner, should consider implementing a two-step transfer pattern.
Otherwise, it is possible that the role mistakenly transfers ownership to the wrong address, resulting in losing the role.
It is recommended separate the ownership transfer into 2 functions, first to set a pending owner, and second to approve the pending owner set using the first function and actually implementing the change of the ownership.
Buyout.end(address,bytes32[]) (src/modules/Buyout.sol#184-239) ignores return value by IVault(address(_vault)).execute(supply,data,_burnProof) (src/modules/Buyout.sol#219)
Buyout.cash(address,bytes32[]) (src/modules/Buyout.sol#244-273) ignores return value by IVault(address(_vault)).execute(supply,data,_burnProof) (src/modules/Buyout.sol#264)
Buyout.redeem(address,bytes32[]) (src/modules/Buyout.sol#278-303) ignores return value by IVault(address(_vault)).execute(supply,data,_burnProof) (src/modules/Buyout.sol#294)
Buyout.withdrawERC20(address,address,address,uint256,bytes32[]) (src/modules/Buyout.sol#311-335) ignores return value by IVault(address(_vault)).execute(transfer,data,_erc20TransferProof) (src/modules/Buyout.sol#334)
Buyout.withdrawERC721(address,address,address,uint256,bytes32[]) (src/modules/Buyout.sol#343-367) ignores return value by IVault(address(_vault)).execute(transfer,data,_erc721TransferProof) (src/modules/Buyout.sol#366)
Buyout.withdrawERC1155(address,address,address,uint256,uint256,bytes32[]) (src/modules/Buyout.sol#376-404) ignores return value by IVault(address(_vault)).execute(transfer,data,_erc1155TransferProof) (src/modules/Buyout.sol#403)
Buyout.batchWithdrawERC1155(address,address,address,uint256[],uint256[],bytes32[]) (src/modules/Buyout.sol#413-445) ignores return value by IVault(address(_vault)).execute(transfer,data,_erc1155BatchTransferProof) (src/modules/Buyout.sol#440-444)
Minter._mintFractions(address,address,uint256,bytes32[]) (src/modules/Minter.sol#50-61) ignores return value by IVault(address(_vault)).execute(supply,data,_mintProof) (src/modules/Minter.sol#60)
Recommendation
Ensure that all the return values of the function calls are used.
Reentrancy in Migration.commit(address,uint256) (src/modules/Migration.sol#182-217):
External calls:
- IFERC1155(token).setApprovalFor(address(buyout),id,true) (src/modules/Migration.sol#211)
- IBuyout(buyout).start{value: proposal.totalEth}(_vault) (src/modules/Migration.sol#213)
External calls sending eth:
- IBuyout(buyout).start{value: proposal.totalEth}(_vault) (src/modules/Migration.sol#213)
State variables written after the call(s):
- proposal.isCommited = true (src/modules/Migration.sol#214)
Reentrancy in VaultFactory.deployFor(address) (src/VaultFactory.sol#62-89):
External calls:
- Vault(vault).init() (src/VaultFactory.sol#70)
- Vault(vault).transferOwnership(_owner) (src/VaultFactory.sol#73)
State variables written after the call(s):
- nextSeeds[tx.origin] = bytes32(uint256(seed) + 1) (src/VaultFactory.sol#77)
Reentrancy in Migration.join(address,uint256,uint256) (src/modules/Migration.sol#108-139):
External calls:
- IFERC1155(token).safeTransferFrom(msg.sender,address(this),id,_amount,) (src/modules/Migration.sol#129-135)
State variables written after the call(s):
- proposal.totalFractions += _amount (src/modules/Migration.sol#137)
Reentrancy in Migration.settleFractions(address,uint256,bytes32[]) (src/modules/Migration.sol#260-290):
External calls:
- _mintFractions(proposal.newVault,address(this),proposal.newFractionSupply,_mintProof) (src/modules/Migration.sol#275-280)
- data = abi.encodeCall(ISupply.mint,(_to,_fractionSupply)) (src/modules/Minter.sol#56-59)
- IVault(address(_vault)).execute(supply,data,_mintProof) (src/modules/Minter.sol#60)
State variables written after the call(s):
- migrationInfo[_vault][_proposalId].fractionsMigrated = true (src/modules/Migration.sol#282)
Reentrancy in Migration.settleVault(address,uint256) (src/modules/Migration.sol#223-254):
External calls:
- newVault = IVaultRegistry(registry).create(merkleRoot,proposal.plugins,proposal.selectors) (src/modules/Migration.sol#238-242)
State variables written after the call(s):
- proposal.newVault = newVault (src/modules/Migration.sol#244)
Unsafe ERC20 Operation(s)
Information : L001 - Unsafe ERC20 Operation(s)
Instances include :
Recommendation
It is recommended to always use OpenZeppelin's
SafeERC20
library, for example :_safeMint
should be used instead of_mint
wherever possibleIt is encouraged to use
_safeMint
instead of_mint
, as_safeMint
ensures that the recipient is an EOA (Externally Owned Account).Instances include :
Recommendation
It is recommended to use
_safeMint
instead of_mint
wherever possible, for example :Use two-step transfer pattern for access controls
Contracts that implement access control, e.g.
owner
, should consider implementing a two-step transfer pattern. Otherwise, it is possible that the role mistakenly transfers ownership to the wrong address, resulting in losing the role.Instances include :
https://github.com/code-423n4/2022-07-fractional/blob/main/src/Vault.sol#L93-L97
Recommendation
It is recommended separate the ownership transfer into 2 functions, first to set a pending owner, and second to approve the pending owner set using the first function and actually implementing the change of the ownership.
Use of block.timestamp
Information : Block timestamp
Instances include :
Recommendation
Avoid relying on
block.timestamp
.Calls inside a loop
Information : Calls inside a loop
Instances include :
Recommendation
Favor pull over push strategy for external calls.
Unused return
Information : Unused return
Instances include :
Recommendation
Ensure that all the return values of the function calls are used.
Divide before multiply
Information : Divide before multiply
Instances include :
Recommendation
Consider ordering multiplication before division.
Reentrancy vulnerabilities
Information : reentrancy-events reentrancy-benign reentrancy-no-eth reentrancy-eth check-effects-interactions pattern
Instances include :
Recommendation
Apply the check-effects-interactions pattern.