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
Rank: 40/173
Findings: 1
Award: $119.60
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: CodingNameKiki
Also found by: 0x1f8b, 0x4non, 0x5rings, 0xAgro, 0xMirce, 0xRobocop, 0xSmartContract, 0xackermann, AkshaySrivastav, ArmedGoose, Aymen0909, BClabs, Breeje, Dewaxindo, Diana, HollaDieWaldfee, IceBear, IllIllI, Iurii3, Josiah, Krayt, PaludoX0, Phenomana, PrasadLak, RaymondFam, Rolezn, SaeedAlipoor01988, SaharDevep, SleepingBugs, adriro, arialblack14, bin2chen, brevis, btk, carlitox477, carrotsmuggler, catellatech, chaduke, chrisdior4, cryptonue, cryptostellar5, csanuragjain, ddimitrov22, fellows, glcanvas, halden, hl_, horsefacts, jat, joestakey, kenta, libratus, lukris02, luxartvinsec, manikantanynala97, martin, matrix_0wl, nadin, nicobevi, oberon, peanuts, prestoncodes, rbserver, sakshamguruji, sashik_eth, sayan, seeu, thekmj, tnevler, trustindistrust, tsvetanovv, xAriextz, zadaru13, zaskoh
119.6013 USDC - $119.60
__ReentrancyGuard_init
functions of inherited contractsDescription:
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; }
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:
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:
return (maxTotalRewards() * questFee) / 10_000;
Lines of Code:
safeTransferOwnership
instead of transferOwnership
functionDescription:
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:
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:
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:
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:
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); }
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
keccak256()
, should used to immutable rather than constantDescription:
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');
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)
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:
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:
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
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