Platform: Code4rena
Start Date: 04/05/2022
Pot Size: $50,000 DAI
Total HM: 24
Participants: 71
Period: 5 days
Judge: Justin Goro
Total Solo HM: 14
Id: 119
League: ETH
Rank: 12/71
Findings: 6
Award: $680.69
🌟 Selected for report: 1
🚀 Solo Findings: 0
🌟 Selected for report: cccz
Also found by: 0x52, 0xYamiDancho, GimelSec, IllIllI, PPrieditis, WatchPug, csanuragjain, danb, gzeon, hickuphh3, horsefacts, hyh, kenzo, leastwood, reassor, unforgiven
63.9296 DAI - $63.93
https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/FixedPricePassThruGate.sol#L48 https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/FixedPricePassThruGate.sol#L53
Contract FixedPricePassThruGate
is a pass thru gate that is passing funds to the gate's beneficiary. Function passThruGate
requires to send ether
that is equal or more than gate.ethCost
. In the case of receiving more ether
than gate.ethCost
, passThruGate
passes to the beneficiary only amount of gate.ethCost
:
(bool sent, bytes memory data) = gate.beneficiary.call{value: gate.ethCost}("");
Since there is no way to withdraw ether
it ends up with ether
being locked forever in the contract and effectively loss of funds for the user(s).
FixedPricePassThruGate.sol
:
Manual Review / VSCode
It is recommended to either pass msg.value
to beneficiary:
(bool sent, bytes memory data) = gate.beneficiary.call{value: msg.value}("");
or make sure that exact amount of ether
is sent:
require(msg.value == gate.ethCost, 'Please send exact amount of ETH');
#0 - illuzen
2022-05-11T09:33:26Z
Duplicate #49
#1 - gititGoro
2022-06-14T02:52:12Z
Upgraded severity: lost user funds.
#2 - gititGoro
2022-06-14T02:53:23Z
Duplicate of #48
🌟 Selected for report: MaratCerby
Also found by: 0x1337, 0x52, 0xYamiDancho, AuditsAreUS, CertoraInc, Dravee, GimelSec, IllIllI, PPrieditis, Ruhum, TrungOre, VAD37, berndartmueller, cccz, csanuragjain, defsec, hickuphh3, horsefacts, hyh, jayjonah8, kenzo, leastwood, mtz, p4st13r4, reassor, throttle, wuwe1, ych18
3.1753 DAI - $3.18
https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/PermissionlessBasicPoolFactory.sol#L144-L146 https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/PermissionlessBasicPoolFactory.sol#L194-L198 https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleDropFactory.sol#L73-L77 https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleResistor.sol#L112-L121 https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleVesting.sol#L85-L89
FactoryDAO is providing multiple tools for DAOs to launch tokens and manage their economies. Multiple contracts that are handling tokens are not supporting ERC20 tokens with fee. This leads to incorrect accounting for depositing tokens for all ERC20 tokens with fee and potentially the one that can such a fee enable. One of the popular tokens that implements such a fee (but currently is set to 0
) is USDT
.
Example for PermissionlessBasicPoolFactory.deposit
:
(..) receipt.amountDepositedWei = amount; receipt.timeDeposited = block.timestamp; receipt.owner = msg.sender; bool success = IERC20(pool.depositToken).transferFrom(msg.sender, address(this), amount); (..)
transferFrom
transferred 999 tokens to the contract and took 0.1% as a feeThe severity was increased to medium since the FactoryDAO protocol is expected to be used by DAOs and managing the variety of ERC20 tokens.
PermissionlessBasicPoolFactory.sol
:
MerkleDropFactory.sol
:
MerkleResistor.sol
:
MerkleVesting.sol
:
Manual Review / VSCode
It is recommended to add support for ERC20 tokens with built-in fees. Example of the implementation:
(..) uint256 _beforeBalance = IERC20(pool.depositToken).balanceOf(address(this)); bool success = IERC20(pool.depositToken).transferFrom(msg.sender, address(this), amount); require(success, 'Token transfer failed'); uint256 _afterBalance = IERC20(pool.depositToken).balanceOf(address(this)); receipt.amountDepositedWei = _afterBalance - _beforeBalance (..)
#0 - illuzen
2022-05-10T07:00:06Z
Duplicate, but this mitigation is better.
105.1961 DAI - $105.20
https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/PermissionlessBasicPoolFactory.sol#L169 https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/PermissionlessBasicPoolFactory.sol#L282
Contract PermissionlessBasicPoolFactory
calculates rewards by using hardcoded value of decimals 18
(1e18) for ERC20 tokens. This leads to wrong rewards calculations and effectively loss of funds for all pools that will be using ERC20 tokens with different decimals than 18
. Example of such a token is USDC that has 6 decimals only.
Manual Review / VSCode
It is recommended to add support for different number of decimals than 18
by dynamically checking decimals()
for the tokens that are part of the rewards calculations. Alternatively if such a support is not needed, new require statements should be added to addPool
that will be checking that the number of decimals for all ERC20 tokens is 18
.
#0 - illuzen
2022-05-10T07:00:24Z
Valid
🌟 Selected for report: AuditsAreUS
320.671 DAI - $320.67
https://github.com/code-423n4/2022-05-factorydao/blob/e22a562c01c533b8765229387894cc0cb9bed116/contracts/PermissionlessBasicPoolFactory.sol#L110 https://github.com/code-423n4/2022-05-factorydao/blob/e22a562c01c533b8765229387894cc0cb9bed116/contracts/PermissionlessBasicPoolFactory.sol#L314-L318
Contract PermissionlessBasicPoolFactory
allows creating new permissionless pools. One of the parameters of the new pool is pool.taxPerCapita
that is set to the value of globalTaxPerCapita
and represents tax on that specific pool. Account globalBeneficiary
is able to change globalTaxPerCapita
at any time via setGlobalTax
and he can set it up as high as 99%
. He is able to run front-running attack that will monitor mempool and once the creation of the new pool with significant amount of rewards gets detected he will change the globalTaxPerCapita
to 99%
.
Exploit Scenario:
addPool
and transfers 1000 WETH tokens (global tax is set to 0.1%
)globalBeneficiary
monitors mempool and launches front-running attack which increases globalTaxPerCapita
to 99%
via setGlobalTax
functionsetGlobalTax
is being included in the block before user's addPool99%
and significant amount of tokens locked as reward that he cannot withdraw99%
of the pool rewards as a taxManual Review / VSCode
It is recommended to add timelock for changing globalTaxPerCapita
via setGlobalTax
.
#0 - illuzen
2022-05-10T06:05:37Z
Valid, but probably tax should be passed into function and checked to match, instead of timelock
#1 - illuzen
2022-05-10T07:18:51Z
Closing since https://github.com/code-423n4/2022-05-factorydao-findings/issues/56 has a better mitigation
#2 - illuzen
2022-06-03T02:40:15Z
#3 - gititGoro
2022-06-12T04:10:58Z
🌟 Selected for report: horsefacts
Also found by: 0x1f8b, 0xYamiDancho, 0xf15ers, 0xkatana, ACai, AlleyCat, Bruhhh, Dravee, Funen, GimelSec, Hawkeye, IllIllI, MaratCerby, PPrieditis, Picodes, Ruhum, TerrierLover, VAD37, berndartmueller, csanuragjain, defsec, delfin454000, eccentricexit, ellahi, fatherOfBlocks, gzeon, hansfriese, hickuphh3, hyh, ilan, joestakey, juicy, kebabsec, oyc_109, rajatbeladiya, reassor, rfa, robee, samruna, simon135, sorrynotsorry, throttle
127.9429 DAI - $127.94
Low
FactoryDAO's contracts do not check for zero addresses which might lead to loss of funds, failed transactions and can break the protocol functionality
MerkleDropFactory.sol
:
tokenAddress
address - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleDropFactory.sol#L49destination
address - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleDropFactory.sol#L88MerkleResistor.sol
:
tokenAddress
address - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleResistor.sol#L80MerkleVesting.sol
:
tokenAddress
address - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleVesting.sol#L62MerkleIdentity.sol
:
_mgmt
address - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleIdentity.sol#L52newMgmt
address - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleIdentity.sol#L60newAdder
address - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleIdentity.sol#L67nftAddress
, priceGateAddress
, eligibilityAddress
addresses - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleIdentity.sol#L92-L94MerkleEligibility.sol
:
_gateMaster
address - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleEligibility.sol#L35FixedPricePassThruGate.sol
:
_beneficiary
address - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/FixedPricePassThruGate.sol#L28
SpeedBumpPriceGate.sol
:beneficiary
address - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/SpeedBumpPriceGate.sol#L37VoterID.sol
:
ooner
and minter
addresses - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/VoterID.sol#L108thisOwner
address - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/VoterID.sol#L122newOwner
address - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/VoterID.sol#L151PermissionlessBasicPoolFactory.sol
:
_globalBeneficiary
address - https://github.com/code-423n4/2022-05-factorydao/blob/e22a562c01c533b8765229387894cc0cb9bed116/contracts/PermissionlessBasicPoolFactory.sol#L75depositTokenAddress
address - https://github.com/code-423n4/2022-05-factorydao/blob/e22a562c01c533b8765229387894cc0cb9bed116/contracts/PermissionlessBasicPoolFactory.sol#L97excessBeneficiary
address - https://github.com/code-423n4/2022-05-factorydao/blob/e22a562c01c533b8765229387894cc0cb9bed116/contracts/PermissionlessBasicPoolFactory.sol#L98rewardTokenAddresses
addresses - https://github.com/code-423n4/2022-05-factorydao/blob/e22a562c01c533b8765229387894cc0cb9bed116/contracts/PermissionlessBasicPoolFactory.sol#L116Manual Review / VSCode
It is recommended to add zero address checks for listed parameters.
Low
Multiple contracts are not implementing events for critical functions. Lack of events makes it difficult for off-chain applications to monitor the protocol.
MerkleIdentity.sol
:
MerkleEligibility.sol
:
FixedPricePassThruGate.sol
:
SpeedBumpPriceGate.sol
:
PermissionlessBasicPoolFactory.sol
:
Manual Review / VSCode
It is recommended to add missing events to listed functions.
Low
The IERC20.transfer()
function returns a boolean value indicating success. This parameter needs to be checked for success. Some tokens do not revert if the transfer failed but return false instead.
Tokens that don't actually perform the transfer and return false are still counted as a correct transfer. Furthermore, tokens that do not correctly implement the EIP20 standard, like USDT which does not return a success boolean, will revert.
MerkleVesting.sol
:
Manual Review / VSCode
It is recommended to use OpenZeppelin's SafeERC20 with the safeTransfer
function that handles the return value check as well as non-standard-compliant tokens.
Low
Function PermissionlessBasicPoolFactory.fundPool
does not follow checks-effects-interactions pattern that might lead to reentrancy attacks.
success = success && IERC20(pool.rewardTokens[i]).transferFrom(msg.sender, address(this), amount); // bookkeeping to make sure pools don't share tokens pool.rewardFunding[i] += amount;
PermissionlessBasicPoolFactory.sol
Manual Review / VSCode
It is recommended to first set the effects and then perform interactions such as external calls.
Changing critical addresses such as ownership should be a two-step process where the first transaction (from the old/current address) registers the new address (i.e. grants ownership) and the second transaction (from the new address) replaces the old address with the new one. This gives an opportunity to recover from incorrect addresses mistakenly used in the first step. If not, contract functionality might become inaccessible.
MerkleIdentity.sol
:
VoterID.sol
:
Manual Review / VSCode
It is recommended to implement two-step process for passing ownership for HolyPaladinToken.sol and PaladinRewardReserve.sol contracts.
Low
Missing check for _globalTaxPerCapita
that should not exceeds 1000
.
Manual Review / VSCode
It is recommended to add check for _globalTaxPerCapita
to make sure that the value cannot be bigger than 1000
.
Non-Critical
Function VoterID.tokenURI
that implements ERC721 standard should revert in case of non existent tokens.
Manual Review / VSCode
It is recommended to revert for non existent tokens.
Non-Critical
Using different compiler versions across contracts of the same project might lead to confusion and accidental errors.
Examples:
0.8.12
- https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/PermissionlessBasicPoolFactory.sol#L30.8.9
- https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/FixedPricePassThruGate.sol#L30.8.9
- https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/SpeedBumpPriceGate.sol#L30.8.9
- https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleIdentity.sol#L30.8.9
- https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleEligibility.sol#L30.8.9
- https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/VoterID.sol#L30.8.9
- https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleDropFactory.sol#L30.8.9
- https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleResistor.sol#L3Manual Review / VS Code
Consider using a single compiler version for compiling both contracts, for example 0.8.12.
#0 - illuzen
2022-05-12T08:49:30Z
all duplicates
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0xNazgul, 0xYamiDancho, 0xf15ers, 0xkatana, ACai, CertoraInc, Dravee, Funen, GimelSec, Hawkeye, PPrieditis, Picodes, Ruhum, TerrierLover, Tomio, VAD37, Waze, csanuragjain, defsec, delfin454000, eccentricexit, ellahi, fatherOfBlocks, gzeon, hansfriese, horsefacts, ilan, joestakey, juicy, minhquanym, oyc_109, rajatbeladiya, reassor, rfa, robee, samruna, simon135, z3s
59.7678 DAI - $59.77
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.
PermissionlessBasicPoolFactory
MerkleLib.sol
:
Manual Review / VSCode
It is recommended to cache the array length outside of for loop.
Shortening revert error messages to fit in 32 bytes will decrease gas costs for deployment and gas costs when the revert condition has been met.
PermissionlessBasicPoolFactory.sol
:
MerkleDropFactory.sol
:
MerkleResistor.sol
:
MerkleVesting.sol
:
MerkleIdentity.sol
:
VoterID.sol
:
Manual Review / VSCode
It is recommended to decrease revert messages to maximum 32 bytes. Alternatively custom error types should be used.
Usage of Custom Errors reduces the gas cost.
PermissionlessBasicPoolFactory.sol
:
require(rewardsWeiPerSecondPerToken.length == rewardTokenAddresses.length, 'Rewards and reward token arrays must be same length'); require(success, 'Token deposits failed'); require(pool.id == poolId, 'Uninitialized pool'); require(receipt.id == receiptId, 'Uninitialized receipt'); require(pool.id == poolId, 'Uninitialized pool'); require(block.timestamp > pool.startTime, 'Cannot deposit before pool start'); require(block.timestamp < pool.endTime, 'Cannot deposit after pool ends'); require(pool.totalDepositsWei < pool.maximumDepositWei, 'Maximum deposit already reached'); require(success, 'Token transfer failed'); require(pool.id == poolId, 'Uninitialized pool'); require(receipt.id == receiptId, 'Can only withdraw real receipts'); require(receipt.owner == msg.sender || block.timestamp > pool.endTime, 'Can only withdraw your own deposit'); require(receipt.timeWithdrawn == 0, 'Can only withdraw once per receipt'); require(success, 'Token transfer failed'); require(pool.id == poolId, 'Uninitialized pool'); require(pool.totalDepositsWei == 0, 'Cannot withdraw until all deposits are withdrawn'); require(block.timestamp > pool.endTime, 'Contract must reach maturity'); require(success, 'Token transfer failed'); require(pool.id == poolId, 'Uninitialized pool'); require(success, 'Token transfer failed'); require(msg.sender == globalBeneficiary, 'Only globalBeneficiary can set tax'); require(newTaxPerCapita < 1000, 'Tax too high');
MerkleDropFactory.sol
:
require(IERC20(merkleTree.tokenAddress).transferFrom(msg.sender, address(this), value), "ERC20 transfer failed"); require(treeIndex <= numTrees, "Provided merkle index doesn't exist"); require(!withdrawn[destination][treeIndex], "You have already withdrawn your entitled token."); require(tree.merkleRoot.verifyProof(leaf, proof), "The proof could not be verified."); require(IERC20(tree.tokenAddress).transfer(destination, value), "ERC20 transfer failed");
MerkleVesting.sol
:
require(IERC20(merkleTree.tokenAddress).transferFrom(msg.sender, address(this), value), "ERC20 transfer failed"); require(!initialized[destination][treeIndex], "Already initialized"); require(tree.rootHash.verifyProof(leaf, proof), "The proof could not be verified."); require(initialized[destination][treeIndex], "You must initialize your account first."); require(block.timestamp > tranche.lockPeriodEndTime, 'Must wait until after lock period'); require(tranche.currentCoins > 0, 'No coins left to withdraw');
MerkleResistor.sol
:
require(pctUpFront < 100, 'pctUpFront >= 100'); require(minEndTime < maxEndTime, 'minEndTime must be less than maxEndTime'); require(IERC20(merkleTree.tokenAddress).transferFrom(msg.sender, address(this), value), "ERC20 transfer failed"); require(msg.sender == destination, 'Can only initialize your own tranche'); require(!initialized[destination][treeIndex], "Already initialized"); require(tree.merkleRoot.verifyProof(leaf, proof), "The proof could not be verified."); require(valid, 'Invalid vesting schedule'); require(initialized[destination][treeIndex], "You must initialize your account first."); require(tranche.currentCoins > 0, 'No coins left to withdraw'); require(IERC20(tree.tokenAddress).transfer(destination, currentWithdrawal), 'Token transfer failed');
FixedPricePassThruGate.sol
:
require(msg.value >= gate.ethCost, 'Please send more ETH'); require(sent, 'ETH transfer failed')
SpeedBumpPriceGate.sol
:
require(msg.value >= price, 'Please send more ETH'); require(sent, 'ETH transfer failed');
MerkleEligibility.sol
:
require(msg.sender == gateMaster, "Only gatemaster may call this."); require(isEligible(index, recipient, proof), "Address is not eligible");
MerkleIdentity.sol
:
require (msg.sender == management, 'Only management may call this'); require(msg.sender == treeAdder, 'Only treeAdder can add trees'); require(merkleIndex <= numTrees, 'merkleIndex out of range'); require(verifyMetadata(tree.metadataMerkleRoot, tokenId, uri, metadataProof), "The metadata proof could not be verified");
VoterID.sol
:
require (msg.sender == _owner_, 'Identity: Only owner may call this'); require(msg.sender == _minter, 'Only minter may create identity'); require(owners[thisToken] == address(0), 'Token already exists'); require(ooner != address(0), 'No such token'); require(isApproved(msg.sender, tokenId), 'Identity: Unapproved transfer'); require(checkOnERC721Received(from, to, tokenId, data), "Identity: transfer to non ERC721Receiver implementer"); require(isApproved(msg.sender, tokenId), 'Identity: Not authorized to approve'); require(holder != approved, 'Identity: Approving self not allowed'); require(holder != address(0), 'Identity: Invalid tokenId'); require(owners[tokenId] == from, "Identity: Transfer of token that is not own"); require(to != address(0), "Identity: transfer to the zero address"); require(_index < numIdentities, 'Invalid token index'); require(_index < balances[_address], 'Index out of range'); require(_address != address(0), 'Cannot query zero address');
Manual Review / VSCode
It is recommended to add Custom Errors.
++i
or --i
costs less gas compared to i++
, i += 1
, i--
or i -= 1
for unsigned integer as pre-increment/pre-decrement is cheaper (about 5 gas per iteration).
PermissionlessBasicPoolFactory.sol
:
MerkleLib.sol
:
MerkleEligibility.sol
:
VoterID.sol
:
Manual Review / VSCode
It is recommended to use ++i
or --i
instead of i++
, i += 1
, i--
or i -= 1
to increment value of an unsigned integer variable.
Starting from solidity 0.8.0
there is built-in check for overflows/underflows. This mechanism automatically checks if the variable overflows or underflows and throws an error. Multiple contracts use increments that cannot overflow but consume additional gas for checks.
PermissionlessBasicPoolFactory.sol
:
MerkleLib.sol
:
i += 1
can be unchecked - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleLib.sol#L22MerkleDropFactory.sol
:
++numTrees
can be unchecked - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleDropFactory.sol#L51MerkleResistor.sol
:
++numTrees
can be unchecked - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleResistor.sol#L86MerkleVesting.sol
:
++numTrees
can be unchecked - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleVesting.sol#L64FixedPricePassThruGate.sol
:
++numGates
can be unchecked - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/FixedPricePassThruGate.sol#L30SpeedBumpPriceGate.sol
:
++numGates
can be unchecked - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/SpeedBumpPriceGate.sol#L39MerkleEligibility.sol
:
++numGates
can be unchecked - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleEligibility.sol#L47++timesWithdrawn[index][recipient]
can be unchecked - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleEligibility.sol#L91++gate.totalWithdrawals
can be unchecked - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleEligibility.sol#L93MerkleIdentity.sol
:
++numTrees
can be unchecked - https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleIdentity.sol#L98Manual Review / VSCode
It is recommended wrap incrementing of i
with unchecked
block:
for (uint256 i; i < numWarriors; ) { _mint(msg.sender); unchecked { ++i }; }
If a variable is not set/initialized, it is assumed to have the default value (0
for uint, false
for bool, address(0)
for addresses). Explicitly initializing it with its default value is an anti-pattern and waste of gas.
PermissionlessBasicPoolFactory.sol
MerkleLib.sol
:
MerkleDropFactory.sol
:
MerkleResistor.sol
:
MerkleVesting.sol
:
MerkleEligibility.sol
:
VoterID.sol
:
Manual Review / VSCode
It is recommended to remove explicit initializations with default values.
PermissionlessBasicPoolFactory.sol
:
timeDeposited
and timeWithdrawn
as uint64
- https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/PermissionlessBasicPoolFactory.sol#L18-L19startTime
and endTime
as uint64
- https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/PermissionlessBasicPoolFactory.sol#L32-L33taxPerCapita
as uint16
- https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/PermissionlessBasicPoolFactory.sol#L34MerkleResistor.sol
:
startTime
, endTime
, lastWithdrawalTime
as uint64
- https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleResistor.sol#L27-L34minEndTime
, maxEndTime
as uint64
- https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleResistor.sol#L37-L45pctUpFron
as uint8
- https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleResistor.sol#L42MerkleVesting.sol
:
startTime
, endTime
, lastWithdrawalTime
, lockPeriodEndTime
as uint64
- https://github.com/code-423n4/2022-05-factorydao/blob/db415804c06143d8af6880bc4cda7222e5463c0e/contracts/MerkleVesting.sol#L22-L23Manual Review / VSCode
It is recommended to pack listed values in order to consume less storage and thus gas.
#0 - illuzen
2022-05-12T08:48:08Z
all duplicates