Platform: Code4rena
Start Date: 03/05/2022
Pot Size: $30,000 USDC
Total HM: 6
Participants: 93
Period: 3 days
Judge: gzeon
Id: 118
League: ETH
Rank: 42/93
Findings: 1
Award: $89.96
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: defsec
Also found by: 0v3rf10w, 0x1f8b, 0x4non, 0x52, 0xDjango, 0xf15ers, 0xkatana, 0xliumin, AuditsAreUS, BowTiedWardens, CertoraInc, Cr4ckM3, Funen, GimelSec, Hawkeye, IllIllI, Kulk0, M0ndoHEHE, MaratCerby, Picodes, Ruhum, TerrierLover, TrungOre, VAD37, WatchPug, berndartmueller, broccolirob, catchup, cccz, cryptphi, csanuragjain, delfin454000, dirk_y, eccentricexit, ellahi, fatherOfBlocks, gzeon, hake, hansfriese, hickuphh3, horsefacts, hubble, hyh, ilan, joestakey, kebabsec, kenta, kenzo, leastwood, m9800, marximimus, minhquanym, oyc_109, p4st13r4, pauliax, pedroais, peritoflores, plotchy, rajatbeladiya, reassor, rfa, robee, rotcivegaf, samruna, shenwilly, shung, simon135, sorrynotsorry, sseefried, teddav, throttle, tintin, unforgiven, z3s
89.9579 USDC - $89.96
L-01 : Event messages missing for critical functions
L-02 : Owner can set the minter to any new address anytime
L-03 : Missing input validation in set MerkleRoot functions
L-04 : Null check in constructor parameters missing
L-05 : Null check in all the set values for price missing
L-06 : Input validation missing while setting max values for maxDaSupply, maxForSale & maxForClaim
L-07 : Missing input validation in function setPhaseTimes
NC-01 : require statement always true in function forwardERC20s()
NC-02 : Redundant require statement in bidSummon and publicSummon
NC-03 : withdrawAll does not need payable keyword
There are no events generated in any of the functions. Some critical functions may need some events to be emitted.
Tracking of any protocol changes is not possible, and transparency missing.
Contract : ForgottenRunesWarriorsMinter.sol Function : setFinalPrice(), setPhaseTimes(), etc.,
Add relevant event messages to critical functions required for tracking, or transparency
The initialize function is not protected by any modifier like initializer, so its possible to call this function multiple times, and setting the minter address to different values.
Setting the new minter to a new address may cause duplicate or redundant issuance of NFTs.
Contract : ForgottenRunesWarriorsGuild.sol
Function : initialize and setMinter functions
Protect the initialize function by an initializer modifier from Openzeppelin, and set the minter state variable in the initialize function. Along with this remove the setMinter function.
Contract : ForgottenRunesWarriorsMinter.sol Function : setMintlist1MerkleRoot(), setMintlist2MerkleRoot() & setClaimlistMerkleRoot()
Add below validation in the above set functions require(newMerkleRoot != bytes32(0), 'Not valid root');
Contract : ForgottenRunesWarriorsMinter.sol
Function : constructor()
constructor(IForgottenRunesWarriorsGuild _warriors, address _weth) { setWarriorsAddress(_warriors); setWethAddress(_weth); setVaultAddress(msg.sender); }
Add null check for the _warriors and _weth address parameters. Alternately add null check in respective functions called in the constructor
Wrongly setting the price value to 0 may cause loss of value of the NFT minted.
Contract : ForgottenRunesWarriorsMinter.sol
Functions : setFinalPrice(), setLowestPrice() & setStartPrice()
Add require statement to each of the set functions with appropriate min values.
Wrongly setting the values can cause minting of more number of NFTs than planned
Contract : ForgottenRunesWarriorsMinter.sol Function : maxDaSupply, maxForSale & maxForClaim
Define a new max value and add appropriate require statements as input validation in each of the functions
uint256 public maxTotal = 8000+6190+1100; require(_newSupply+maxForSale+maxForClaim <= maxTotal, "Minting more than permissible Supply")
There is a possibility of setting the phase times wrongly.
Mixing up the phase times may cause problems for minting for various groups/entities.
Contract : ForgottenRunesWarriorsMinter.sol Function : setPhaseTimes()
Check for null values and all values should be in future timestamp Also add check for newDaStartTime < newMintlistStartTime < newPublicStartTime < newClaimsStartTime
Contract : ForgottenRunesWarriorsGuild.sol
Function : forwardERC20s
below line in the function is always true, so unnecessary line 173 , require(address(msg.sender) != address(0));
Remove the above mentioned require statement
The line 136 require statement below is made redundant due to line 137 require statement. The line 207 require statement below is made redundant due to line 208 require statement.
Contract : ForgottenRunesWarriorsMinter.sol Function : function bidSummon()
line 136 require(numSold < maxDaSupply, 'Auction sold out'); line 137 require(numSold + numWarriors <= maxDaSupply, 'Not enough remaining');
Function : function publicSummon()
line 207 require(numSold < maxForSale, 'Sold out'); line 208 require(numSold + numWarriors <= maxForSale, 'Not enough remaining');
remove the redundant require statements in both the functions
Contract : ForgottenRunesWarriorsMinter.sol Function : line 616 function withdrawAll() public payable onlyOwner { ... }
remove the payable keyword