Platform: Code4rena
Start Date: 15/06/2022
Pot Size: $35,000 USDC
Total HM: 1
Participants: 36
Period: 3 days
Judge: Jack the Pug
Total Solo HM: 1
Id: 137
League: ETH
Rank: 7/36
Findings: 2
Award: $189.71
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0xNazgul
Also found by: 0xDjango, 0xFar5eer, 0xf15ers, BowTiedWardens, Chom, Dravee, IllIllI, Meera, MiloTruck, PierrickGT, TerrierLover, _Adam, cccz, codexploder, cryptphi, delfin454000, fatherOfBlocks, hansfriese, joestakey, oyc_109, simon135
153.5218 USDC - $153.52
Ierc20 is already imported in Inestedfactory.sol Feespliter.sol is already imported Inestedfactory.sol NestedReverse.sol is already imprted Insteadfactory.sol NestedFactory:6 NestedFactory:12 safeerc20 imports Ierc20 so you can take out Ierc20 when you import safeerc20.sol NestedFactory:13 IOperatorResolver.sol is already imported in MixinOperatorResolver.sol take out IOperatorResolver.sol from OperatorResolver.sol OperatorResolver:4 https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/operators/Beefy/lp/BeefyZapBiswapLPVaultOperator.sol#L10 https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/operators/Beefy/lp/BeefyZapUniswapLPVaultOperator.sol#L10 https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/operators/Paraswap/ParaswapOperator.sol#L6 safeerc20.sol is already in exchangehelper.sol https://github.com/code-423n4/2022-06-nested/blob/0dc44d779eaca8f40b7526aabdd81a098dcebf25/contracts/libraries/StakingLPVaultHelpers.sol#L10
ex: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; instead do your imports like this import {Ierc20,safeer20} from "import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/NestedFactory.sol#L5 https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/operators/Beefy/lp/BeefyZapBiswapLPVaultOperator.sol#L10
no check that token of i can be zero address token = tokens[i]; instances: https://github.com/code-423n4/2022-06-nested/blob/b4a153c943d54755711a2f7b80cbbf3a5bb49d76/contracts/NestedFactory.sol#L257 https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/operators/Beefy/BeefyVaultOperator.sol#L18 https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/operators/Beefy/lp/BeefyZapBiswapLPVaultOperator.sol#L28
make if (success) into: require(success) to make sure the call dosnt fail https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/NestedFactory.sol#L518
If the initializer is not executed in the same transaction as the constructor, a malicious user can front-run the initialize() call, forcing the contract to be redeployed ex: function initialize(address ownerAddr) external { https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/abstracts/OwnableProxyDelegation.sol#L24
bool success variable should be checked with a require statement if not logic can brake and cause loss of funds https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/libraries/ExchangeHelpers.sol#L22
instead of : liquitiy use : liquidity https://github.com/code-423n4/2022-06-nested/blob/0dc44d779eaca8f40b7526aabdd81a098dcebf25/contracts/libraries/StakingLPVaultHelpers.sol#L52 https://github.com/code-423n4/2022-06-nested/blob/0dc44d779eaca8f40b7526aabdd81a098dcebf25/contracts/libraries/StakingLPVaultHelpers.sol#L85 https://github.com/code-423n4/2022-06-nested/blob/0dc44d779eaca8f40b7526aabdd81a098dcebf25/contracts/libraries/StakingLPVaultHelpers.sol#L115
each event should use three indexed fields if there are there or more fields https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/governance/TimelockControllerEmergency.sol#L50
#0 - obatirou
2022-06-22T15:11:19Z
Check is done in contract when using the library
#1 - Yashiru
2022-06-23T09:04:53Z
Indeed we could do it this way, but it is only a development choice and we prefer to keep our imports as they are.
#2 - obatirou
2022-06-23T10:23:10Z
This statement is confused
The link point to _transferToReserveAndStore
where there is no mention of success variable
#3 - Yashiru
2022-06-23T12:21:30Z
#4 - obatirou
2022-06-24T13:59:33Z
Duplicate from https://github.com/code-423n4/2022-06-nested-findings/issues/11#issuecomment-1165618378
#5 - Yashiru
2022-06-24T14:03:11Z
Duplicated of #45 at Typos
#6 - Yashiru
2022-06-24T14:59:44Z
Duplicated of #61 at 2. Missing address(0) checks
#7 - obatirou
2022-06-27T08:28:10Z
Missed occurences:
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0xKitsune, 0xNazgul, 0xkatana, Chom, ElKu, JC, Meera, MiloTruck, Picodes, PierrickGT, SooYa, TerrierLover, UnusualTurtle, Waze, _Adam, asutorufos, c3phas, delfin454000, fatherOfBlocks, joestakey, minhquanym, oyc_109, robee, sach1r0, simon135
36.189 USDC - $36.19
Require statements including conditions with the && operator can be broken down in multiple require statements to save gas. instances include : NestedFactory.sol:69 https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/operators/Beefy/BeefyVaultOperator.sol#L54 https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/operators/Beefy/lp/BeefyZapBiswapLPVaultOperator.sol#L61-L62 https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/operators/Beefy/lp/BeefyZapUniswapLPVaultOperator.sol#L63-L65 https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/operators/Paraswap/ParaswapOperator.sol#L16
msg.sender is global variable and msgSender() function needs th get that variable making it cost more gas. instances: NestedFactory.sol:104,200,207
Functions marked as payable
are 24 gas cheaper than their counterpart (in non-payable functions, Solidity adds an extra check to ensure msg.value is zero).
When users can't mistakenly send ETH to a function (as an example, when there's an onlyOwner
modifier or alike), it is safe to mark it as payable
Functions with onlyOwner modifier that aren't payable yet:
instances include:
NestedFactory.sol
126: function addOperator(bytes32 operator) external override onlyOwner {
139: function removeOperator(bytes32 operator) external override onlyOwner {
158: function setFeeSplitter(FeeSplitter _feeSplitter) external override onlyOwner {
165: function setEntryFees(uint256 _entryFees) external override onlyOwner {
173: function setExitFees(uint256 _exitFees) external override onlyOwner {
181: function unlockTokens(IERC20 _token) external override onlyOwner {
OpertorResolver.sol
56: ) external override onlyOwner {
74: function rebuildCaches(MixinOperatorResolver[] calldata destinations) public onlyOwner {
https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/operators/Beefy/BeefyVaultStorage.sol#L34
https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/operators/Beefy/BeefyVaultStorage.sol#L24
Mark as payable the functions that have a "safe for users" modifier
If a variable is not set/initialized, it is assumed to have the default value (0 for uint, false for bool, address(0) for address...). Explicitly initializing it with its default value is an anti-pattern and wastes gas.
instances include:
NestedFactory.sol :
130: for (uint256 i = 0; i < operatorsCache.length; i++) {
142: for (uint256 i = 0; i < operatorsLength; i++) {
202: for (uint256 i = 0; i < batchedOrdersLength; i++) {
262: for (uint256 i = 0; i < tokensLength; i++) {
321: for (uint256 i = 0; i < batchedOrdersLength; i++) {
339: for (uint256 i = 0; i < batchedOrdersLength; i++) {
375: for (uint256 i = 0; i < batchLength; i++) {
418: for (uint256 i = 0; i < batchLength; i++) {
OpertorResolver.sol:
40: for (uint256 i = 0; i < namesLength; i++) {
60: for (uint256 i = 0; i < names.length; i++) {
75: for (uint256 i = 0; i < destinations.length; i++) {
MixinOperatorResolver.sol:
37: for (uint256 i = 0; i < requiredOperators.length; i++) {
56: for (uint256 i = 0; i < requiredOperators.length; i++) {
TimelockControllerEmergency.sol: 84,89,234,324
Shortening revert strings to fit in 32 bytes will decrease deployment time gas and will decrease runtime gas when the revert condition is met. Revert strings that are longer than 32 bytes require at least one additional mstore, along with additional overhead for computing memory offset, etc. 1 byte for character instanaces: https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/abstracts/MixinOperatorResolver.sol#L77 https://github.com/code-423n4/2022-06-nested/blob/0dc44d779eaca8f40b7526aabdd81a098dcebf25/contracts/libraries/StakingLPVaultHelpers.sol#L138 https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/governance/scripts/OperatorScripts.sol#L19-L20 https://github.com/code-423n4/2022-06-nested/blob/b253ed80f67d1bb2a04e1702f5796fd96a7c521e/contracts/governance/scripts/OperatorScripts.sol#L54
#0 - obatirou
2022-06-24T12:57:01Z
Duplicate of point 2 from issue https://github.com/code-423n4/2022-06-nested-findings/issues/62
#1 - maximebrugel
2022-06-24T14:02:50Z
#62 (see comment)
#2 - Yashiru
2022-06-24T15:37:55Z
Duplicated of #2 at For loop optimizaion
#3 - Yashiru
2022-06-27T08:33:20Z
msgSender() should be used for intermediate, library-like contracts. That is why it is used in the NestedFactory.
Already surfaced in previous audits.