Hello Gophers - Smart Contract Audit Report

Audit Summary

Hello Gophers is creating new game featuring NFTs and a Staking platform on the Harmony One mainnet.

For this audit, we reviewed Hello Gophers' project at commit cdf8eee92c0583620f73336b021b7a51437a440b on the team's private GitHub repository.

Audit Findings

Please ensure trust in the team prior to investing as they have substantial control in the ecosystem.
Date: February 16th, 2022.
Updated: February 17th, 2022 to reflect changes from commit 73fdd6d426fcdc82c4ac8808a74ca339fd008323 to commit cdf8eee92c0583620f73336b021b7a51437a440b
Updated: February 22, 2022 to reflect changes from commit cdf8eee92c0583620f73336b021b7a51437a440b to commit af3c21374794c9b08c01b7bae3b081877cf089ad

Finding #1 - HelloGophers - Informational (Resolved)

Description: The contract inherits the PausableUpgradeable contract, however there is no function to enable the owner to pause the contract. Only the following function exists:
function _pause() override internal {
	super._pause();
}
Risk/Impact: The owner will not be able to pause the contract's functionality if they desire to.
Recommendation: If the team intends to make the HelloGophers contract pausable, an external onlyOwner pause function should be added.
Resolution: An external onlyOwner pause function has been implemented, allowing the owner to toggle minting and level up functionality.

Finding #2 - Staking - Informational (Resolved)

Description: The following functions are declared public, but are never called internally:
Staking.getPeasantPoolAtIndex(), Staking.getRoyalPoolAtIndex(), Staking.getStakedTokensInfo().
Recommendation: These functions can be declared external for additional gas savings on each call.
Resolution: The team has declared these functions external.

Contracts Overview

Shard Contract:
  • This contract is a fungible token used within the Hello Gophers ecosystem.
  • The maximum allowed supply of $SHARD is 100 billion tokens.
  • Authorized addresses can mint $SHARD tokens to any address at any time.
  • Authorized addresses can also burn any user's tokens at any time.
  • No custom transfer logic exists within the contract.
  • The owner can grant or revoke Authorized privileges from any address at any time.
  • This contract complies with the ERC-20 standard.
HelloGophers Contract:
  • This contract can be used to purchase and level up ERC-721 Gophers.
  • Each Gopher has its own Traits, made up of its Role, stats, and appearance.
  • Users can purchase Gophers for a specified price, either in USDC or $SHARD.
  • If less than 10,000 Gophers have been minted, users must pay in the USDC mint price; these Gophers are considered "Gen 0" Gophers.
  • After 10,000 Gophers have been minted, users will pay in $SHARD in a separate mint price; these Gophers are considered "Gen 1" Gophers.
  • Users can only purchase up to a certain number of Gophers at once.
  • When minting, a random number is generated using Harmony's VRF functionality and is used to determine the Gopher's Trait IDs.
  • Traits include whether a Gopher is a Peasant or Royal, appearance IDs, Role IDs, and stats.
  • A Gopher's Trait IDs are correlated to Traits defined in the corresponding Traits contract.
  • The owner has the ability to allocate a specified number of free Gophers to Whitelisted users as giveaways.
  • Only 2000 Gophers can be minted for giveaways.
  • For each mint, there is a 1 in 10 chance for a Gopher to be minted to the owner of a randomly selected staked Royal Gopher.
  • Minting is only permitted once the contract's specified start time has passed.
  • Users can level up their Gophers by paying a price per level in $SHARD.
  • Users cannot level their Gopher higher than the maximum level.
  • Contracts are not permitted to mint Gophers.
  • The owner can update the Whitelist and the number of free Gophers that any Whitelisted user can mint at any time.
  • The owner can update the maximum number of Gophers that can be minted at once at any time.
  • The owner can update the USDC mint price, Shard mint price, and level up price at any time.
  • The owner can add new Roles, update the number or appearances, and update the maximum level at any time.
  • The owner can update the Staking or Traits contracts at any time.
  • The owner can pause the contract at any time, disabling minting and leveling up functionality.
  • This contract can be upgraded by the owner at any time.
Traits Contract:
  • This contract defines the Traits corresponding to Gophers' Trait IDs.
  • The owner can update Gopher appearance names and any image corresponding to an appearance hash at any time.
  • The owner can update the metadata corresponding to a Role ID at any time.
  • The owner can update the global image prefix and image suffix at any time.
  • A Gopher's token URI is determined from this contract and is composed of a Gopher's Peasant or Royal status, token ID, role name and description, image, stats, appearance, and generation.
  • The owner can update the associated HelloGophers contract used to fetch token attributes at any time.
Staking Contract:
  • Users can use this contract to stake their Gophers into specified pools in order to earn rewards in the form of $SHARD.
  • Users can stake any of their Peasant or Royal Gophers after a defined start timestamp has passed, transferring them to this contract and adding them to the appropriate Peasant or Royal pool.
  • Multiple Peasant and Royal pools are intended to exist.
  • A Gopher's Role ID must exist in the pool's list of accepted Role IDs in order to be added.
  • Staked Gen 0 Gophers will additionally be added to the Gen 0 pool.
  • Users can attempt to claim rewards at any time and can unstake if their Gopher has been staked for at least the pool's "minimum time to exit".
  • If claiming before the contract's unlock time, a percentage of claimed rewards will remain locked.
  • The unlocked percentage of rewards will increase at a rate of 2% per week over the course of 49 weeks (2% begins unlocked).
  • After the unlock time has passed, users can claim all of their previously locked rewards.
  • Peasant rewards are accrued daily based on the pool's reward rate and are multiplied by the level of the Gopher staked.
  • A user cannot earn any further Peasant rewards if they have accrued more than 34000000000 $ONE in total rewards.
  • When unstaking a Peasant, there is a chance that the users earned rewards will not be transferred to them and instead be taken as a "Royal Tax".
  • This probability is dependent on the pool's "stolen rate" and the contract's stolen rate deduction per level.
  • A random number is generated for this chance using Harmony's VRF.
  • The probability to lose rewards when unstaking is decreased for higher level Gophers.
  • If claiming Peasant rewards without unstaking, users will always pay a Royal Tax based on the pool's tax rate, decreased by the Gopher's level and the contract's "tax rate deduction per level".
  • The Royal Tax is distributed to Royal pools based on their number of accepted Role IDs.
  • When claiming Royal rewards, users will earn based on their Royal Gopher's level and the pool's accumulated Royal Tax.
  • Users can unstake their Royal Gophers at any time.
  • Rewards earned by Gen 1 tokens will have an additional tax taken and sent to the Gen 0 pool based on the Gen 0 pool's tax rate.
  • Accumulated Gen 0 pool rewards will be added to Gen 0 token rewards at the time of claiming.
  • Contracts are not permitted to stake or claim rewards.
  • The owner can add new Peasant or Royal pools at any time.
  • The owner can update the Gen 0 pool tax rate, tax rate deduction per level, and stolen rate deduction per level at any time.
  • The owner can pause the contract at any time, disabling claiming and staking functionality.
  • ReentrancyGuard is used where applicable to prevent reentrancy attacks.
  • The owner must be careful to not accept the same Role ID in multiple different Royal pools.
  • This contract can be upgraded by the owner at any time.

External Threat Results

Vulnerability CategoryNotesResult
Arbitrary Storage WriteN/APASS
Arbitrary JumpN/APASS
Centralization of Control
  • The owner and defined roles have the permissions mentioned above.
  • Authorized users can mint or burn $SHARD from any address at any time.
  • The owner can update taxes to any percentages at any time.
  • The owner can upgrade the HelloGophers and Staking contracts at any time.
  • The owner can pause the HelloGophers or Staking contract functionality at any time.
  • WARNING
    Delegate Call to Untrusted ContractN/APASS
    Dependence on Predictable VariablesN/APASS
    Deprecated OpcodesN/APASS
    Ether ThiefN/APASS
    ExceptionsN/APASS
    External CallsN/APASS
    Flash LoansN/APASS
    Integer Over/UnderflowN/APASS
    Logical IssuesN/APASS
    Multiple SendsN/APASS
    OraclesN/APASS
    SuicideN/APASS
    State Change External CallsN/APASS
    Unbounded LoopN/APASS
    Unchecked RetvalN/APASS
    User Supplied AssertionN/APASS
    Critical Solidity CompilerN/APASS
    Overall Contract Safety PASS


    Details: HelloGophers Contract

    ERC20 Token Graph

    Multi-file Token

    												
    ($) = payable function
     # = non-constant function
    
       + [Lib] AddressUpgradeable 
        - [Int] isContract
        - [Int] sendValue #
        - [Int] functionCall #
        - [Int] functionCall #
        - [Int] functionCallWithValue #
        - [Int] functionCallWithValue #
        - [Int] functionStaticCall
        - [Int] functionStaticCall
        - [Int] verifyCallResult
    
     +  Initializable 
        - [Prv] _isConstructor
    
     + [Int] IERC20Upgradeable 
        - [Ext] totalSupply
        - [Ext] balanceOf
        - [Ext] transfer #
        - [Ext] allowance
        - [Ext] approve #
        - [Ext] transferFrom #
    
     +  ContextUpgradeable (Initializable)
        - [Int] __Context_init #
           - modifiers: onlyInitializing
        - [Int] __Context_init_unchained #
           - modifiers: onlyInitializing
        - [Int] _msgSender
        - [Int] _msgData
    
     +  OwnableUpgradeable (Initializable, ContextUpgradeable)
        - [Int] __Ownable_init #
           - modifiers: onlyInitializing
        - [Int] __Ownable_init_unchained #
           - modifiers: onlyInitializing
        - [Pub] owner
        - [Pub] renounceOwnership #
           - modifiers: onlyOwner
        - [Pub] transferOwnership #
           - modifiers: onlyOwner
        - [Int] _transferOwnership #
    
     +  PausableUpgradeable (Initializable, ContextUpgradeable)
        - [Int] __Pausable_init #
           - modifiers: onlyInitializing
        - [Int] __Pausable_init_unchained #
           - modifiers: onlyInitializing
        - [Pub] paused
        - [Int] _pause #
           - modifiers: whenNotPaused
        - [Int] _unpause #
           - modifiers: whenPaused
    
     + [Int] IERC165Upgradeable 
        - [Ext] supportsInterface
    
     + [Int] IERC721Upgradeable (IERC165Upgradeable)
        - [Ext] balanceOf
        - [Ext] ownerOf
        - [Ext] safeTransferFrom #
        - [Ext] transferFrom #
        - [Ext] approve #
        - [Ext] getApproved
        - [Ext] setApprovalForAll #
        - [Ext] isApprovedForAll
        - [Ext] safeTransferFrom #
    
     + [Int] IERC721ReceiverUpgradeable 
        - [Ext] onERC721Received #
    
     + [Int] IERC721MetadataUpgradeable (IERC721Upgradeable)
        - [Ext] name
        - [Ext] symbol
        - [Ext] tokenURI
    
     + [Lib] StringsUpgradeable 
        - [Int] toString
        - [Int] toHexString
        - [Int] toHexString
    
     +  ERC165Upgradeable (Initializable, IERC165Upgradeable)
        - [Int] __ERC165_init #
           - modifiers: onlyInitializing
        - [Int] __ERC165_init_unchained #
           - modifiers: onlyInitializing
        - [Pub] supportsInterface
    
     +  ERC721Upgradeable (Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721Upgradeable, IERC721MetadataUpgradeable)
        - [Int] __ERC721_init #
           - modifiers: onlyInitializing
        - [Int] __ERC721_init_unchained #
           - modifiers: onlyInitializing
        - [Pub] supportsInterface
        - [Pub] balanceOf
        - [Pub] ownerOf
        - [Pub] name
        - [Pub] symbol
        - [Pub] tokenURI
        - [Int] _baseURI
        - [Pub] approve #
        - [Pub] getApproved
        - [Pub] setApprovalForAll #
        - [Pub] isApprovedForAll
        - [Pub] transferFrom #
        - [Pub] safeTransferFrom #
        - [Pub] safeTransferFrom #
        - [Int] _safeTransfer #
        - [Int] _exists
        - [Int] _isApprovedOrOwner
        - [Int] _safeMint #
        - [Int] _safeMint #
        - [Int] _mint #
        - [Int] _burn #
        - [Int] _transfer #
        - [Int] _approve #
        - [Int] _setApprovalForAll #
        - [Prv] _checkOnERC721Received #
        - [Int] _beforeTokenTransfer #
        - [Int] _afterTokenTransfer #
    
     + [Int] IERC721EnumerableUpgradeable (IERC721Upgradeable)
        - [Ext] totalSupply
        - [Ext] tokenOfOwnerByIndex
        - [Ext] tokenByIndex
    
     +  ERC721EnumerableUpgradeable (ERC721Upgradeable, IERC721EnumerableUpgradeable)
        - [Int] __ERC721Enumerable_init #
           - modifiers: onlyInitializing
        - [Int] __ERC721Enumerable_init_unchained #
           - modifiers: onlyInitializing
        - [Pub] supportsInterface
        - [Pub] tokenOfOwnerByIndex
        - [Pub] totalSupply
        - [Pub] tokenByIndex
        - [Int] _beforeTokenTransfer #
        - [Prv] _addTokenToOwnerEnumeration #
        - [Prv] _addTokenToAllTokensEnumeration #
        - [Prv] _removeTokenFromOwnerEnumeration #
        - [Prv] _removeTokenFromAllTokensEnumeration #
    
     + [Int] IStaking 
        - [Ext] randomRoyalOwner
    
     + [Int] ITraits 
        - [Ext] tokenURI
    
     + [Int] IHelloGophers 
        - [Ext] getMaxGen0Tokens
        - [Ext] getTokenTraits
        - [Ext] getAppearanceHash
    
    
     +  RandomBase 
        - [Prv] vrf
        - [Int] random #
    
     +  HelloGophers (IHelloGophers, RandomBase, Initializable, ERC721EnumerableUpgradeable, OwnableUpgradeable, PausableUpgradeable)
        - [Pub] initialize #
           - modifiers: initializer
        - [Ext] mintGophers #
           - modifiers: whenNotPaused
        - [Ext] mintGiveawayGophers #
           - modifiers: whenNotPaused
        - [Ext] mintCustomGopher #
           - modifiers: whenNotPaused,onlyOwner
        - [Int] _mint #
        - [Ext] levelUpGopher #
           - modifiers: whenNotPaused
        - [Ext] getMaxGen0Tokens
        - [Ext] getTokenTraits
        - [Ext] getAppearanceHash
        - [Ext] tokensOfOwner
        - [Pub] tokensOfOwner
        - [Ext] setStaking #
           - modifiers: onlyOwner
        - [Ext] setTraits #
           - modifiers: onlyOwner
        - [Ext] setMintCost #
           - modifiers: onlyOwner
        - [Ext] setUsdcMintCost #
           - modifiers: onlyOwner
        - [Ext] setCostPerLevel #
           - modifiers: onlyOwner
        - [Ext] setMaxPerMint #
           - modifiers: onlyOwner
        - [Ext] setMaxLevel #
           - modifiers: onlyOwner
        - [Ext] addRoles #
           - modifiers: onlyOwner
        - [Ext] editRoleMaxAppearances #
           - modifiers: onlyOwner
        - [Pub] setWhitelist #
           - modifiers: onlyOwner
        - [Ext] setWhitelistBulk #
           - modifiers: onlyOwner
        - [Int] hashRoleAndAppearance
        - [Int] _generateTrait
        - [Int] _selectRole
        - [Int] _selectRandomUintFromRange
        - [Int] _selectRecipient
        - [Int] _pause #
        - [Pub] tokenURI
    
    
    
     

    Details: Traits Contract

    ERC20 Token Graph

    Multi-file Token

    												
    ($) = payable function
     # = non-constant function
     +  Context 
        - [Int] _msgSender
        - [Int] _msgData
    
     +  Ownable (Context)
        - [Pub]  #
        - [Pub] owner
        - [Pub] renounceOwnership #
           - modifiers: onlyOwner
        - [Pub] transferOwnership #
           - modifiers: onlyOwner
        - [Int] _transferOwnership #
    
     + [Lib] Strings 
        - [Int] toString
        - [Int] toHexString
        - [Int] toHexString
    
     + [Int] ITraits 
        - [Ext] tokenURI
    
     + [Int] IHelloGophers 
        - [Ext] getMaxGen0Tokens
        - [Ext] getTokenTraits
        - [Ext] getAppearanceHash
        - [Ext] isCustomGopher
    
     +  Traits (Ownable, ITraits)
        - [Ext] setHelloGophers #
           - modifiers: onlyOwner
        - [Ext] setImagePrefix #
           - modifiers: onlyOwner
        - [Ext] setImageSuffix #
           - modifiers: onlyOwner
        - [Ext] uploadAppearanceVariations #
           - modifiers: onlyOwner
        - [Ext] uploadCustomGopherAppearanceVariations #
           - modifiers: onlyOwner
        - [Ext] uploadRoles #
           - modifiers: onlyOwner
        - [Ext] uploadImage #
           - modifiers: onlyOwner
        - [Ext] uploadCustomGopherImage #
           - modifiers: onlyOwner
        - [Int] attributeForTypeAndValue
        - [Int] attributeForTypeAndValue
        - [Pub] compileAttributes
        - [Pub] getImage
        - [Pub] tokenURI
        - [Int] base64
    
    
     
     

    Details: Staking Contract

    ERC20 Token Graph

    Multi-file Token

    												
    ($) = payable function
     # = non-constant function
    
     
     + [Lib] AddressUpgradeable 
        - [Int] isContract
        - [Int] sendValue #
        - [Int] functionCall #
        - [Int] functionCall #
        - [Int] functionCallWithValue #
        - [Int] functionCallWithValue #
        - [Int] functionStaticCall
        - [Int] functionStaticCall
        - [Int] verifyCallResult
    
     +  Initializable 
        - [Prv] _isConstructor
    
     + [Int] IERC721ReceiverUpgradeable 
        - [Ext] onERC721Received #
    
     +  ContextUpgradeable (Initializable)
        - [Int] __Context_init #
           - modifiers: onlyInitializing
        - [Int] __Context_init_unchained #
           - modifiers: onlyInitializing
        - [Int] _msgSender
        - [Int] _msgData
    
     +  OwnableUpgradeable (Initializable, ContextUpgradeable)
        - [Int] __Ownable_init #
           - modifiers: onlyInitializing
        - [Int] __Ownable_init_unchained #
           - modifiers: onlyInitializing
        - [Pub] owner
        - [Pub] renounceOwnership #
           - modifiers: onlyOwner
        - [Pub] transferOwnership #
           - modifiers: onlyOwner
        - [Int] _transferOwnership #
    
     +  PausableUpgradeable (Initializable, ContextUpgradeable)
        - [Int] __Pausable_init #
           - modifiers: onlyInitializing
        - [Int] __Pausable_init_unchained #
           - modifiers: onlyInitializing
        - [Pub] paused
        - [Int] _pause #
           - modifiers: whenNotPaused
        - [Int] _unpause #
           - modifiers: whenPaused
    
     +  ReentrancyGuardUpgradeable (Initializable)
        - [Int] __ReentrancyGuard_init #
           - modifiers: onlyInitializing
        - [Int] __ReentrancyGuard_init_unchained #
           - modifiers: onlyInitializing
    
     + [Lib] EnumerableSetUpgradeable 
        - [Prv] _add #
        - [Prv] _remove #
        - [Prv] _contains
        - [Prv] _length
        - [Prv] _at
        - [Prv] _values
        - [Int] add #
        - [Int] remove #
        - [Int] contains
        - [Int] length
        - [Int] at
        - [Int] values
        - [Int] add #
        - [Int] remove #
        - [Int] contains
        - [Int] length
        - [Int] at
        - [Int] values
        - [Int] add #
        - [Int] remove #
        - [Int] contains
        - [Int] length
        - [Int] at
        - [Int] values
    
     + [Int] IERC20Upgradeable 
        - [Ext] totalSupply
        - [Ext] balanceOf
        - [Ext] transfer #
        - [Ext] allowance
        - [Ext] approve #
        - [Ext] transferFrom #
    
     + [Int] IERC165Upgradeable 
        - [Ext] supportsInterface
    
     + [Int] IERC721Upgradeable (IERC165Upgradeable)
        - [Ext] balanceOf
        - [Ext] ownerOf
        - [Ext] safeTransferFrom #
        - [Ext] transferFrom #
        - [Ext] approve #
        - [Ext] getApproved
        - [Ext] setApprovalForAll #
        - [Ext] isApprovedForAll
        - [Ext] safeTransferFrom #
    
     + [Int] IERC721MetadataUpgradeable (IERC721Upgradeable)
        - [Ext] name
        - [Ext] symbol
        - [Ext] tokenURI
    
     + [Lib] StringsUpgradeable 
        - [Int] toString
        - [Int] toHexString
        - [Int] toHexString
    
     +  ERC165Upgradeable (Initializable, IERC165Upgradeable)
        - [Int] __ERC165_init #
           - modifiers: onlyInitializing
        - [Int] __ERC165_init_unchained #
           - modifiers: onlyInitializing
        - [Pub] supportsInterface
    
     +  ERC721Upgradeable (Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721Upgradeable, IERC721MetadataUpgradeable)
        - [Int] __ERC721_init #
           - modifiers: onlyInitializing
        - [Int] __ERC721_init_unchained #
           - modifiers: onlyInitializing
        - [Pub] supportsInterface
        - [Pub] balanceOf
        - [Pub] ownerOf
        - [Pub] name
        - [Pub] symbol
        - [Pub] tokenURI
        - [Int] _baseURI
        - [Pub] approve #
        - [Pub] getApproved
        - [Pub] setApprovalForAll #
        - [Pub] isApprovedForAll
        - [Pub] transferFrom #
        - [Pub] safeTransferFrom #
        - [Pub] safeTransferFrom #
        - [Int] _safeTransfer #
        - [Int] _exists
        - [Int] _isApprovedOrOwner
        - [Int] _safeMint #
        - [Int] _safeMint #
        - [Int] _mint #
        - [Int] _burn #
        - [Int] _transfer #
        - [Int] _approve #
        - [Int] _setApprovalForAll #
        - [Prv] _checkOnERC721Received #
        - [Int] _beforeTokenTransfer #
        - [Int] _afterTokenTransfer #
    
     + [Int] IERC721EnumerableUpgradeable (IERC721Upgradeable)
        - [Ext] totalSupply
        - [Ext] tokenOfOwnerByIndex
        - [Ext] tokenByIndex
    
     +  ERC721EnumerableUpgradeable (ERC721Upgradeable, IERC721EnumerableUpgradeable)
        - [Int] __ERC721Enumerable_init #
           - modifiers: onlyInitializing
        - [Int] __ERC721Enumerable_init_unchained #
           - modifiers: onlyInitializing
        - [Pub] supportsInterface
        - [Pub] tokenOfOwnerByIndex
        - [Pub] totalSupply
        - [Pub] tokenByIndex
        - [Int] _beforeTokenTransfer #
        - [Prv] _addTokenToOwnerEnumeration #
        - [Prv] _addTokenToAllTokensEnumeration #
        - [Prv] _removeTokenFromOwnerEnumeration #
        - [Prv] _removeTokenFromAllTokensEnumeration #
    
     + [Int] IStaking 
        - [Ext] randomRoyalOwner
    
     + [Int] ITraits 
        - [Ext] tokenURI
    
     + [Int] IHelloGophers 
        - [Ext] getMaxGen0Tokens
        - [Ext] getTokenTraits
        - [Ext] getAppearanceHash
        - [Ext] isCustomGopher
    
     +  RandomBase 
        - [Prv] vrf
        - [Int] random #
    
     +  HelloGophers (IHelloGophers, RandomBase, Initializable, ERC721EnumerableUpgradeable, OwnableUpgradeable, PausableUpgradeable)
        - [Pub] initialize #
           - modifiers: initializer
        - [Ext] mintGophers #
           - modifiers: whenNotPaused
        - [Ext] mintGiveawayGophers #
           - modifiers: whenNotPaused
        - [Ext] mintCustomGopher #
           - modifiers: whenNotPaused,onlyOwner
        - [Int] _mint #
        - [Ext] levelUpGopher #
           - modifiers: whenNotPaused
        - [Ext] getMaxGen0Tokens
        - [Ext] getTokenTraits
        - [Ext] getAppearanceHash
        - [Ext] tokensOfOwner
        - [Pub] tokensOfOwner
        - [Ext] setStaking #
           - modifiers: onlyOwner
        - [Ext] setTraits #
           - modifiers: onlyOwner
        - [Ext] setMintCost #
           - modifiers: onlyOwner
        - [Ext] setUsdcMintCost #
           - modifiers: onlyOwner
        - [Ext] setCostPerLevel #
           - modifiers: onlyOwner
        - [Ext] setMaxPerMint #
           - modifiers: onlyOwner
        - [Ext] setMaxLevel #
           - modifiers: onlyOwner
        - [Ext] addRoles #
           - modifiers: onlyOwner
        - [Ext] editRoleMaxAppearances #
           - modifiers: onlyOwner
        - [Pub] setWhitelist #
           - modifiers: onlyOwner
        - [Ext] setWhitelistBulk #
           - modifiers: onlyOwner
        - [Int] hashRoleAndAppearance
        - [Int] _generateTrait
        - [Int] _selectRole
        - [Int] _selectRandomUintFromRange
        - [Int] _selectRecipient
        - [Int] _pause #
        - [Pub] tokenURI
    
     + [Int] IERC20 
        - [Ext] totalSupply
        - [Ext] balanceOf
        - [Ext] transfer #
        - [Ext] allowance
        - [Ext] approve #
        - [Ext] transferFrom #
    
     + [Int] IERC20Metadata (IERC20)
        - [Ext] name
        - [Ext] symbol
        - [Ext] decimals
    
     +  Context 
        - [Int] _msgSender
        - [Int] _msgData
    
     +  ERC20 (Context, IERC20, IERC20Metadata)
        - [Pub]  #
        - [Pub] name
        - [Pub] symbol
        - [Pub] decimals
        - [Pub] totalSupply
        - [Pub] balanceOf
        - [Pub] transfer #
        - [Pub] allowance
        - [Pub] approve #
        - [Pub] transferFrom #
        - [Pub] increaseAllowance #
        - [Pub] decreaseAllowance #
        - [Int] _transfer #
        - [Int] _mint #
        - [Int] _burn #
        - [Int] _approve #
        - [Int] _spendAllowance #
        - [Int] _beforeTokenTransfer #
        - [Int] _afterTokenTransfer #
    
     +  Ownable (Context)
        - [Pub]  #
        - [Pub] owner
        - [Pub] renounceOwnership #
           - modifiers: onlyOwner
        - [Pub] transferOwnership #
           - modifiers: onlyOwner
        - [Int] _transferOwnership #
    
     +  Shard (ERC20, Ownable)
        - [Pub]  #
           - modifiers: ERC20
        - [Ext] mint #
        - [Ext] burn #
        - [Ext] addController #
           - modifiers: onlyOwner
        - [Ext] removeController #
           - modifiers: onlyOwner
    
     +  Staking (IStaking, RandomBase, Initializable, IERC721ReceiverUpgradeable, OwnableUpgradeable, PausableUpgradeable, ReentrancyGuardUpgradeable)
        - [Pub] initialize #
           - modifiers: initializer
        - [Ext] stakeManyRoyalAndPeasant #
           - modifiers: nonReentrant
        - [Int] _addPeasentToPool #
           - modifiers: whenNotPaused
        - [Int] _addRoyalToPool #
           - modifiers: whenNotPaused
        - [Int] _addTokenToGen0Pool #
           - modifiers: whenNotPaused
        - [Ext] claimManyRoyalAndPeasant #
           - modifiers: whenNotPaused,nonReentrant
        - [Int] _claimPeasentFromPool #
        - [Int] _claimRoyalFromPool #
        - [Int] _claimGen0FromPool #
        - [Ext] claimLockedRewards #
        - [Int] _payRoyalTax #
        - [Int] _payGen0Tax #
        - [Int] _handleGen1Tax #
        - [Pub] getPeasantPoolAtIndex
        - [Pub] getRoyalPoolAtIndex
        - [Pub] isPeasant
        - [Pub] getLockPercentage
        - [Pub] pendingPeasantRewards
        - [Pub] pendingRoyalRewards
        - [Ext] randomRoyalOwner
        - [Pub] getStakedTokenIds
        - [Pub] getStakedTokensInfo
        - [Ext] onERC721Received
        - [Ext] setPaused #
           - modifiers: onlyOwner
        - [Ext] setStolenRateDeductionPerLevel #
           - modifiers: onlyOwner
        - [Ext] setTaxRateDeductionPerLevel #
           - modifiers: onlyOwner
        - [Ext] setGen0PoolTaxRate #
           - modifiers: onlyOwner
        - [Ext] addPeasentPools #
           - modifiers: onlyOwner
        - [Ext] addRoyalPools #
           - modifiers: onlyOwner