Forgotten Runes Warrior Guild contest - 0x1f8b's results

16,000 Warrior NFTs sold in a phased Dutch Auction.

General Information

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

Forgotten Runes

Findings Distribution

Researcher Performance

Rank: 25/93

Findings: 3

Award: $292.31

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: Kulk0

Also found by: 0x1f8b, 0xDjango, BowTiedWardens, Dinddle, broccolirob, defsec, dirk_y, hyh, rajatbeladiya, throttle, unforgiven

Labels

bug
duplicate
2 (Med Risk)

Awards

246.5367 USDC - $246.54

External Links

Lines of code

https://github.com/code-423n4/2022-05-runes/blob/060b4f82b79c8308fe65674a39a07c44fa586cd3/contracts/ForgottenRunesWarriorsMinter.sol#L257

Vulnerability details

Impact

The teamSummon method is too centralized.

Proof of Concept

Using the teamSummon function of ForgottenRunesWarriorsMinter, the owner address can mint arbitrary amount of warriors.

If the private key of the owner or minter address is compromised, the attacker will be able to mint an unlimited amount of warriors.

I believe this is unnecessary and poses a serious centralization risk.

Consider reduce centralization risks with timelock contracts.

#0 - KenzoAgada

2022-06-06T05:43:45Z

Duplicate of #104.

  1. METADATA_PROVENANCE_HASH is not restricted to be a hash. It could be any kind of string.

  2. It was found some transfer without checking the boolean result, ERC20 standard specify that the token can return false if this call was not made, so it's mandatory to check the result of these calls.

  1. The setXX methods of ForgottenRunesWarriorsMinter must emit an event in order to be detected by dapps.
  1. The contract ForgottenRunesWarriorsMinter is Ownable and Pausable, so the owner could resign while the contract is paused, causing a Denial of Service. Owner resignation while paused should be avoided.

  1. There are require messages bigger than 32 bytes. More than 32 bytes for message will incur an extra gas costs.
  1. Unused constant, the constant R is not used and could be removed
  1. Remove nonReentrant modifier from mint method.

It's possible to remove the modifier if the storage changes are produced before the _safeMint method.

function mint(address recipient) public override returns (uint256) { require(numMinted < MAX_WARRIORS, 'All warriors have been summoned'); require(_msgSender() == minter, 'Not a minter'); uint256 tokenId = numMinted++; _safeMint(recipient, tokenId); return tokenId; }
  1. Change the incremental logic from i++ to ++i in order to save some opcodes:
  1. Redundant require. the require(numSold + numWarriors <= maxDaSupply, 'Not enough remaining'); already checked the previous one.
  1. It's compared a boolean value using == false, instead of using the boolean value, or NOT opcode, it's cheaper to use NOT when the value it's false, or just the value without == true, when it's true, because it will use less opcode inside the VM.
AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter