RabbitHole Quest Protocol contest - 0xackermann's results

A protocol to distribute token rewards for completing on-chain tasks.

General Information

Platform: Code4rena

Start Date: 25/01/2023

Pot Size: $36,500 USDC

Total HM: 11

Participants: 173

Period: 5 days

Judge: kirk-baird

Total Solo HM: 1

Id: 208

League: ETH

RabbitHole

Findings Distribution

Researcher Performance

Rank: 40/173

Findings: 1

Award: $119.60

QA:
grade-a

🌟 Selected for report: 0

🚀 Solo Findings: 0

QA Report

Low Risk Issues

Non Critical Risk Issues


[L-01] Missing calls to __ReentrancyGuard_init functions of inherited contracts


Description:

Most contracts use the delegateCall proxy pattern and hence their implementations require the use of initialize() functions instead of constructors. This requires derived contracts to call the corresponding init functions of their inherited base contracts. This is done in most places except a few.

Impact: The inherited base classes do not get initialized which may lead to undefined behavior.

Lines of Code:

Recommended Mitigation Steps Add missing calls to init functions of inherited contracts.

 ) public initializer {
    __Ownable_init();
    __AccessControl_init();
+   __ReentrancyGuard_init();
    grantDefaultAdminAndCreateQuestRole(msg.sender);
    claimSignerAddress = claimSignerAddress_;
    rabbitholeReceiptContract = RabbitHoleReceipt(rabbitholeReceiptContract_);
    setProtocolFeeRecipient(protocolFeeRecipient_);
    setQuestFee(2_000);
    questIdCount = 1;
}

[L-02] Royalty Fee upper limit


Description:

The idea is the same for questFee which has a upper limit of 10000, which can be found at QuestFactory.sol#L187. This is to avoid to have high royalty fees.

function setQuestFee(uint256 questFee_) public onlyOwner {
    if (questFee_ > 10_000) revert QuestFeeTooHigh();
    questFee = questFee_;
}

Recommendation:

function setRoyaltyFee(uint256 royaltyFee_) public onlyOwner {
    if (royaltyFee_ > 10_000) revert RoyaltyFeeTooHigh(); 
    royaltyFee = royaltyFee_;
    emit RoyaltyFeeSet(royaltyFee_);
}

Lines of Code:


[L-03] Owner can renounce Ownership


Description:

Typically, the contract’s owner is the account that deploys the contract. As a result, the owner is able to perform certain privileged activities.

The non-fungible Ownable used in this project contract implements renounceOwnership. This can represent a certain risk if the ownership is renounced for any other reason than by design. Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.

Lines of Code:

onlyOwner functions:


[L-04] Loss of precision due to rounding


return (maxTotalRewards() * questFee) / 10_000;

Lines of Code:


[L-05] Use safeTransferOwnership instead of transferOwnership function


Description: transferOwnership function is used to change Ownership from Ownable.sol.

Use a 2 structure transferOwnership which is safer. safeTransferOwnership, use it is more secure due to 2-stage ownership transfer.

Recommendation: Use Ownable2Step.sol Ownable2Step.sol

Lines of Code:


[NC-01] For modern and more readable code; update import usages


Description:

Our Solidity code is also cleaner in another way that might not be noticeable: the struct Point. We were importing it previously with global import but not using it. The Point struct polluted the source code with an unnecessary object we were not using because we did not need it. This was breaking the rule of modularity and modular programming: only import what you need Specific imports with curly braces allow us to apply this rule better.

Recommendation:

import {contract1 , contract2} from "filename.sol";

Lines of Code:


[NC-02] Include return parameters in NatSpec comments


Description:

https://docs.soliditylang.org/en/v0.8.15/natspec-format.html

If Return parameters are declared, you must prefix them with "/// @return".

Some code analysis programs do analysis by reading NatSpec details, if they can't see the "@return" tag, they do incomplete analysis.

Recommendation: Include return parameters in NatSpec comments

Recommendation Code Style: (from Uniswap3)

    /// @notice Adds liquidity for the given recipient/tickLower/tickUpper position
    /// @dev The caller of this method receives a callback in the form of IUniswapV3MintCallback#uniswapV3MintCallback
    /// in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends
    /// on tickLower, tickUpper, the amount of liquidity, and the current price.
    /// @param recipient The address for which the liquidity will be created
    /// @param tickLower The lower tick of the position in which to add liquidity
    /// @param tickUpper The upper tick of the position in which to add liquidity
    /// @param amount The amount of liquidity to mint
    /// @param data Any data that should be passed through to the callback
    /// @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback
    /// @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback
    function mint(
        address recipient,
        int24 tickLower,
        int24 tickUpper,
        uint128 amount,
        bytes calldata data
    ) external returns (uint256 amount0, uint256 amount1);

Lines of Code:


[NC-03] Return parameters are declared but not used


Recommendation:

  address receiver, uint256 royaltyAmount) {
    require(_exists(tokenId_), 'Nonexistent token');

-    uint256 royaltyPayment = (salePrice_ * royaltyFee) / 10_000;
-    return (royaltyRecipient, royaltyPayment);

+    receiver = royaltyRecipient;
+    royaltyAmount = (salePrice_ * royaltyFee) / 10_000;
  }

Lines of Code:


[NC-04] Parameter is not used in the function


tokenId_ from RabbitHoleTickets.sol#L110 is not used in the function.

function royaltyInfo(
    uint256 tokenId_,
    uint256 salePrice_
) external view override returns (address receiver, uint256 royaltyAmount) {
    uint256 royaltyPayment = (salePrice_ * royaltyFee) / 10_000;
    return (royaltyRecipient, royaltyPayment);
}

[NC-05] Use a more recent version of Solidity


Description:

For security, it is best practice to use the latest Solidity version. For the security fix list in the versions; https://github.com/ethereum/solidity/blob/develop/Changelog.md

Recommendation:

Old version of Solidity is used , newer version can be used (0.8.17)

Lines of Code: All contracts


[NC-06] Constant values such as a call to keccak256(), should used to immutable rather than constant


Description:

There is a difference between constant variables and immutable variables, and they should each be used in their appropriate contexts.

While it doesn't save any gas because the compiler knows that developers often make this mistake, it's still best to use the right tool for the task at hand.

Constants should be used for literal values written into the code, and immutable variables should be used for expressions, or values calculated in, or passed into the constructor.

Lines of Code:

bytes32 public constant CREATE_QUEST_ROLE = keccak256('CREATE_QUEST_ROLE');

[NC-07] Floating pragma


Description:

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

Recommendation:

Lock the pragma version and also consider known bugs (https://github.com/ethereum/solidity/releases) for the compiler version that is chosen.

Floating Pragma List: pragma solidity ^0.8.15; (all contracts)


[NC-08] Open TODOs


Recommendation: Use temporary TODOs as you work on a feature, but make sure to treat them before merging. Either add a link to a proper issue in your TODO, or remove it from the code.

Lines of code:


[NC-09] Long lines are not suitable for the ‘Solidity Style Guide’


Description:

It is generally recommended that lines in the source code should not exceed 80-120 characters. Today's screens are much larger, so in some cases it makes sense to expand that. The lines above should be split when they reach that length, as the files will most likely be on GitHub and GitHub always uses a scrollbar when the length is more than 164 characters.

(why-is-80-characters-the-standard-limit-for-code-width)[https://softwareengineering.stackexchange.com/questions/148677/why-is-80-characters-the-standard-limit-for-code-width]

Recommendation:

Multiline output parameters and return statements should follow the same style recommended for wrapping long lines found in the Maximum Line Length section.

https://docs.soliditylang.org/en/v0.8.17/style-guide.html#introduction

Lines of code:


[NC-10] Signature scheme does not support smart contracts


Description:

Non-Fungible does not support EIP 1271 and therefore no signatures that are validated by smart contracts. This limits the applicability for protocols that want to build on top of it and persons that use smart contract wallets. Consider implementing support for it https://eips.ethereum.org/EIPS/eip-1271


[NC-11] Omissions in Events


Descriptions:

Throughout the codebase, events are generally emitted when sensitive changes are made to the contracts. However, some events are missing important parameters

Recommendation:

The events should include the new value and old value where possible: Events with no old value;;

Lines of Code:

#0 - c4-judge

2023-02-05T07:46:31Z

kirk-baird marked the issue as grade-a

#1 - c4-sponsor

2023-02-08T00:11:17Z

jonathandiep marked the issue as sponsor acknowledged

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