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: 43/93
Findings: 2
Award: $83.61
🌟 Selected for report: 0
🚀 Solo Findings: 0
48.5872 USDC - $48.59
https://github.com/code-423n4/2022-05-runes/blob/060b4f82b79c8308fe65674a39a07c44fa586cd3/contracts/ForgottenRunesWarriorsGuild.sol#L164 https://github.com/code-423n4/2022-05-runes/blob/060b4f82b79c8308fe65674a39a07c44fa586cd3/contracts/ForgottenRunesWarriorsMinter.sol#L610 https://github.com/code-423n4/2022-05-runes/blob/060b4f82b79c8308fe65674a39a07c44fa586cd3/contracts/ForgottenRunesWarriorsMinter.sol#L618
Using Solidity's transfer
function has some notable shortcomings when the withdrawer is a smart contract, which can render ETH deposits impossible to withdraw. Specifically, the withdrawal will inevitably fail when:
The sendValue
function available in OpenZeppelin Contract’s Address library can be used to transfer the withdrawn Ether without being limited to 2300 gas units. Risks of reentrancy stemming from the use of this function can be mitigated by tightly following the "Check-effects-interactions" pattern and using OpenZeppelin Contract’s ReentrancyGuard contract. For further reference on why using Solidity’s transfer is no longer recommended, refer to these articles:
ForgottenRunesWarriorsGuild.sol#L164
ForgottenRunesWarriorsMinter.sol#L610
ForgottenRunesWarriorsMinter.sol#L618
Manual review
Use Solidity's low-level call()
function or the sendValue
function available in OpenZeppelin Contract’s Address library to send Ether.
#0 - KenzoAgada
2022-06-06T12:48:49Z
Duplicate of #254
#1 - gzeoneth
2022-06-18T17:23:28Z
This is true but also these are onlyOwner
function where the owner have full control of the destination address to mitigate any issue in production. Downgrading to Low / QA.
🌟 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
35.025 USDC - $35.02
Spelling mistakes found.
* @param newMintlistStartTime uint256 the mintlst phase start time
mintlst
Fix spelling mistakes.
Contracts should be deployed with the same compiler version and flags that they have been tested with thoroughly. Locking the pragma helps to ensure that contracts do not accidentally get deployed using, for example, an outdated compiler version that might introduce bugs that affect the contract system negatively.
https://swcregistry.io/docs/SWC-103
ForgottenRunesWarriorsGuild.sol#L1
ForgottenRunesWarriorsMinter.sol#L1
Lock the pragma version and also consider known bugs (https://github.com/ethereum/solidity/releases) for the compiler version that is chosen.
Pragma statements can be allowed to float when a contract is intended for consumption by other developers, as in the case with contracts in a library or EthPM package. Otherwise, the developer would need to manually update the pragma in order to compile locally.
When changing state variables events are not emitted. Emitting events allows monitoring activities with off-chain monitoring tools.
ForgottenRunesWarriorsMinter.sol#L441
ForgottenRunesWarriorsMinter.sol#L448
ForgottenRunesWarriorsMinter.sol#L455
ForgottenRunesWarriorsMinter.sol#L462
ForgottenRunesWarriorsMinter.sol#L469
ForgottenRunesWarriorsMinter.sol#L505
ForgottenRunesWarriorsMinter.sol#L513
ForgottenRunesWarriorsMinter.sol#L520
ForgottenRunesWarriorsMinter.sol#L550
ForgottenRunesWarriorsMinter.sol#L557
ForgottenRunesWarriorsMinter.sol#L564
ForgottenRunesWarriorsMinter.sol#L571
ForgottenRunesWarriorsMinter.sol#L579
ForgottenRunesWarriorsMinter.sol#L586
ForgottenRunesWarriorsMinter.sol#L593
ForgottenRunesWarriorsMinter.sol#L600
Emit events for state variable changes.
payable
Functions which do not use msg.value
do not need payable
modifier.
ForgottenRunesWarriorsGuild.sol#L163
ForgottenRunesWarriorsMinter.sol#L616
Remove payable
modifier.
Zero-address checks are a best-practice for input validation of critical address parameters. While the codebase applies this to most most cases, there are many places where this is missing in constructors and setters.
Impact: Accidental use of zero-addresses may result in exceptions, burn fees/tokens or force redeployment of contracts.
ForgottenRunesWarriorsMinter.sol#L528
vault = _newVaultAddress;
ForgottenRunesWarriorsMinter.sol#L537
warriors = _newWarriorsAddress;
ForgottenRunesWarriorsMinter.sol#L544
weth = _newWethAddress;
ForgottenRunesWarriorsGuild.sol#L138
minter = newMinter;
Add zero-address checks, e.g.:
require(_newVaultAddress != address(0), "Zero-address");
daDropInterval
in setDaDropInterval()
Setting daDropInterval
to a value of 0
results in division by zero in following cases:
ForgottenRunesWarriorsMinter.sol#L285
uint256 dropPerStep = (startPrice - lowestPrice) / (daPriceCurveLength / daDropInterval);
ForgottenRunesWarriorsMinter.sol#L288
uint256 steps = elapsed / daDropInterval;
ForgottenRunesWarriorsMinter.sol#L572
Validate _newTime
to make sure value is != 0
:
require(_newTime != 0, "Zero");
finalPrice
in setFinalPrice()
As the dutch auction start price is defined as 2.5 ether
, this should be used as an upper bound for finalPrice
to prevent setting an arbitrary high price.
ForgottenRunesWarriorsMinter.sol#L580
Validate _newPrice
to be < 2.5 ether
:
require(_newPrice <= 2.5 ether, "Limit reached");