Volume Wars - Smart Contract Audit Report

Summary

 VolumeWars Audit Report PiggyBankToken is building Volume Wars, a game in which teams representing various tokens battle each other in order to win rewards in the form of Piggy NFTs.

We reviewed PiggyBankToken's PiggyNFT, PiggyGame, and TransparentUpgradeableProxy contracts at commit 0b6583867a72f6d98fa506780575e0e425712cb0 on the team's GitHub repository.

Notes on Individual Contracts:
PiggyNFT Contract:
  • Any address with the Minter role can use the PiggyNFT contract to mint or burn Piggy NFTs at any time.
  • The Minter role is able to define card sets; each Piggy NFT represents one card in a set.
  • The Minter role can burn any Piggy NFT from any user at any time without any prior approval.
  • The owner is able to grant or revoke the Minter role from any address at any time.
  • Initially, the owner has the Admin role, the Minter role, and the Pauser role. The Piggy Game contract has the Minter role.
  • The owner is able to set the base token URI to any value at any time.
PiggyGame Contract:
  • There are two teams created upon initialization; one representing the Piggy token, and another representing a second token determined by the project team.
  • There is an unlimited number of rounds in this game; rounds are referred to as 'seasons' in the contract.
  • Users are able to join any team that is active in the current season.
  • After joining a team, a user may not switch over to a different team at any time; this applies even across seasons.
  • Users can carry out an "attack" on another team, which will swap half of the BNB provided by the user for their team's tokens. The received tokens are deposited into the 0x..dead wallet address, which removes them from the token's circulating supply.
  • The remaining BNB is split between the project team and the current season's reward pool.
  • The BNB value is added as experience points to the user and added as damage points to the team being attacked.
  • The attacker is eligible to receive reward booster packs based on the amount used in the attack.
  • The user must pay a redeem fee in order to claim reward booster packs; half of the redeem fee is allocated for the project team and the other half is deposited into the current season's reward pool.
  • The booster packs can be claimed and exchanged for Piggy NFT cards that are randomly chosen based on the grade of the booster pack.
  • Chainlink VRF is used to generate random data securely from off-chain to select Piggy NFT cards. This is the industry standard and is resistant to manipulation.
  • Note that the team must fund the contract with LINK tokens; otherwise no one will be able to claim any booster packs.
  • Once a user has received all cards in a set, they can be exchanged for the Legendary card NFT.
  • When the season is closed, the damage points for each team will be reset, and the team with the least amount of damage will be declared the winner.
  • The winning team will have access to the rewards pool where they will be eligible to receive the rarest Rare cards.
  • The Fee Destination address is able to withdraw all BNB taken as fees at any time.
  • The Fee Destination address is able to chnage the Fee Destination address at any time.
  • The owner is able to open or close the game at any time; the game must be open in order for a user to join, attack, and claim/unpack booster packs.
  • The owner is able to set the season to any value at any time, including seasons that have already passed.
  • The owner is able to open and close a season at will.
  • The owner is able to create a new team at any time; teams are represented by a token address.
  • The owner is able to disable any team at any time; disabled teams are not able to use the platform and are not able to withdraw any funds.
  • The owner is able to withdraw all LINK tokens from the contract at any time.
  • The owner is able to set the join fee to any value at any time.
  • The owner is able to set the minimum amount of Piggy tokens in order to join to any value at any time.
  • The owner is able to set the fee for redeeming booster packs to any value at any time.
  • The owner is able to transfer pool funds to future pools at any time.
  • The owner is able to set the thresholds for reward types to any values at any time.
  • The owner is able to set the odds for receiving Rare cards to any value at any time.
General Notes Across All Contracts:
  • The team has worked with us to resolve logical issues and optimize these contracts for gas efficiency.
  • The platform should not be used with ERC-777 tokens to prevent re-entrancy issues. This is uncommon.
  • As the contracts are implemented with Solidity v0.8.x, they are protected from overflows.

Audit Findings Summary:

External Threat Results

Vulnerability CategoryNotesResult
Arbitrary Storage WriteN/APASS
Arbitrary JumpN/APASS
Delegate Call to Untrusted ContractN/APASS
Dependence on Predictable VariablesN/APASS
Deprecated OpcodesN/APASS
Ether ThiefN/APASS
ExceptionsN/APASS
External CallsN/APASS
Integer Over/UnderflowN/APASS
Multiple SendsN/APASS
SuicideN/APASS
State Change External CallsN/APASS
Unchecked RetvalN/APASS
User Supplied AssertionN/APASS
Critical Solidity CompilerN/APASS
Overall Contract Safety PASS

Piggy NFT Contract

Smart Contract Graph

Contract Inheritance


 ($) = payable function
 # = non-constant function
 
 Int = Internal
 Ext = External
 Pub = Public
 
 + [Int] IERC165 
    - [Ext] supportsInterface

 + [Int] IERC721 (IERC165)
    - [Ext] balanceOf
    - [Ext] ownerOf
    - [Ext] safeTransferFrom #
    - [Ext] transferFrom #
    - [Ext] approve #
    - [Ext] getApproved
    - [Ext] setApprovalForAll #
    - [Ext] isApprovedForAll
    - [Ext] safeTransferFrom #

 + [Int] IERC721Receiver 
    - [Ext] onERC721Received #

 + [Int] IERC721Metadata (IERC721)
    - [Ext] name
    - [Ext] symbol
    - [Ext] tokenURI

 + [Lib] Address 
    - [Int] isContract
    - [Int] sendValue #
    - [Int] functionCall #
    - [Int] functionCall #
    - [Int] functionCallWithValue #
    - [Int] functionCallWithValue #
    - [Int] functionStaticCall
    - [Int] functionStaticCall
    - [Int] functionDelegateCall #
    - [Int] functionDelegateCall #
    - [Prv] _verifyCallResult

 +  Context 
    - [Int] _msgSender
    - [Int] _msgData

 + [Lib] Strings 
    - [Int] toString
    - [Int] toHexString
    - [Int] toHexString

 +  ERC165 (IERC165)
    - [Pub] supportsInterface

 +  ERC721 (Context, ERC165, IERC721, IERC721Metadata)
    - [Pub]  #
    - [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 #
    - [Prv] _checkOnERC721Received #
    - [Int] _beforeTokenTransfer #

 + [Int] IERC721Enumerable (IERC721)
    - [Ext] totalSupply
    - [Ext] tokenOfOwnerByIndex
    - [Ext] tokenByIndex

 +  ERC721Enumerable (ERC721, IERC721Enumerable)
    - [Pub] supportsInterface
    - [Pub] tokenOfOwnerByIndex
    - [Pub] totalSupply
    - [Pub] tokenByIndex
    - [Int] _beforeTokenTransfer #
    - [Prv] _addTokenToOwnerEnumeration #
    - [Prv] _addTokenToAllTokensEnumeration #
    - [Prv] _removeTokenFromOwnerEnumeration #
    - [Prv] _removeTokenFromAllTokensEnumeration #

 +  ERC721Burnable (Context, ERC721)
    - [Pub] burn #

 +  Pausable (Context)
    - [Pub]  #
    - [Pub] paused
    - [Int] _pause #
       - modifiers: whenNotPaused
    - [Int] _unpause #
       - modifiers: whenPaused

 +  ERC721Pausable (ERC721, Pausable)
    - [Int] _beforeTokenTransfer #

 + [Int] IAccessControl 
    - [Ext] hasRole
    - [Ext] getRoleAdmin
    - [Ext] grantRole #
    - [Ext] revokeRole #
    - [Ext] renounceRole #

 +  AccessControl (Context, IAccessControl, ERC165)
    - [Pub] supportsInterface
    - [Pub] hasRole
    - [Int] _checkRole
    - [Pub] getRoleAdmin
    - [Pub] grantRole #
       - modifiers: onlyRole
    - [Pub] revokeRole #
       - modifiers: onlyRole
    - [Pub] renounceRole #
    - [Int] _setupRole #
    - [Int] _setRoleAdmin #
    - [Prv] _grantRole #
    - [Prv] _revokeRole #

 + [Lib] EnumerableSet 
    - [Prv] _add #
    - [Prv] _remove #
    - [Prv] _contains
    - [Prv] _length
    - [Prv] _at
    - [Int] add #
    - [Int] remove #
    - [Int] contains
    - [Int] length
    - [Int] at
    - [Int] add #
    - [Int] remove #
    - [Int] contains
    - [Int] length
    - [Int] at
    - [Int] add #
    - [Int] remove #
    - [Int] contains
    - [Int] length
    - [Int] at

 + [Int] IAccessControlEnumerable 
    - [Ext] getRoleMember
    - [Ext] getRoleMemberCount

 +  AccessControlEnumerable (IAccessControlEnumerable, AccessControl)
    - [Pub] supportsInterface
    - [Pub] getRoleMember
    - [Pub] getRoleMemberCount
    - [Pub] grantRole #
    - [Pub] revokeRole #
    - [Pub] renounceRole #
    - [Int] _setupRole #

 + [Lib] Counters 
    - [Int] current
    - [Int] increment #
    - [Int] decrement #
    - [Int] reset #

 +  ERC721PresetMinterPauserAutoId (Context, AccessControlEnumerable, ERC721Enumerable, ERC721Burnable, ERC721Pausable)
    - [Pub]  #
       - modifiers: ERC721
    - [Int] _baseURI
    - [Pub] mint #
    - [Pub] pause #
    - [Pub] unpause #
    - [Int] _beforeTokenTransfer #
    - [Pub] supportsInterface

 +  piggyNFT (Context, AccessControlEnumerable, ERC721Enumerable, ERC721Burnable, ERC721Pausable)
    - [Pub]  #
       - modifiers: ERC721
    - [Pub] metadataOf
    - [Pub] dataOfTokenOfOwnerByIndex
    - [Pub] totalCardsOf
    - [Pub] addSet #
    - [Int] _baseURI
    - [Pub] forgeBurn #
    - [Pub] mint #
    - [Pub] pause #
    - [Pub] unpause #
    - [Int] _beforeTokenTransfer #
    - [Pub] supportsInterface

Piggy Game Contract

Smart Contract Graph

Contract Inheritance


 ($) = payable function
 # = non-constant function
 
 Int = Internal
 Ext = External
 Pub = Public
 
 +  Initializable 

 + [Int] LinkTokenInterface 
    - [Ext] allowance
    - [Ext] approve #
    - [Ext] balanceOf
    - [Ext] decimals
    - [Ext] decreaseApproval #
    - [Ext] increaseApproval #
    - [Ext] name
    - [Ext] symbol
    - [Ext] totalSupply
    - [Ext] transfer #
    - [Ext] transferAndCall #
    - [Ext] transferFrom #

 + [Int] IERC165 
    - [Ext] supportsInterface

 + [Int] IUniswapV2Router01 
    - [Ext] factory
    - [Ext] WETH
    - [Ext] addLiquidity #
    - [Ext] addLiquidityETH ($)
    - [Ext] removeLiquidity #
    - [Ext] removeLiquidityETH #
    - [Ext] removeLiquidityWithPermit #
    - [Ext] removeLiquidityETHWithPermit #
    - [Ext] swapExactTokensForTokens #
    - [Ext] swapTokensForExactTokens #
    - [Ext] swapExactETHForTokens ($)
    - [Ext] swapTokensForExactETH #
    - [Ext] swapExactTokensForETH #
    - [Ext] swapETHForExactTokens ($)
    - [Ext] quote
    - [Ext] getAmountOut
    - [Ext] getAmountIn
    - [Ext] getAmountsOut
    - [Ext] getAmountsIn

 + [Int] IUniswapV2Router02 (IUniswapV2Router01)
    - [Ext] removeLiquidityETHSupportingFeeOnTransferTokens #
    - [Ext] removeLiquidityETHWithPermitSupportingFeeOnTransferTokens #
    - [Ext] swapExactTokensForTokensSupportingFeeOnTransferTokens #
    - [Ext] swapExactETHForTokensSupportingFeeOnTransferTokens ($)
    - [Ext] swapExactTokensForETHSupportingFeeOnTransferTokens #

 + [Int] IERC721 (IERC165)
    - [Ext] balanceOf
    - [Ext] ownerOf
    - [Ext] safeTransferFrom #
    - [Ext] transferFrom #
    - [Ext] approve #
    - [Ext] getApproved
    - [Ext] setApprovalForAll #
    - [Ext] isApprovedForAll
    - [Ext] safeTransferFrom #

 +  ContextUpgradeable (Initializable)
    - [Int] __Context_init #
       - modifiers: initializer
    - [Int] __Context_init_unchained #
       - modifiers: initializer
    - [Int] _msgSender
    - [Int] _msgData

 +  OwnableUpgradeable (Initializable, ContextUpgradeable)
    - [Int] __Ownable_init #
       - modifiers: initializer
    - [Int] __Ownable_init_unchained #
       - modifiers: initializer
    - [Pub] owner
    - [Pub] renounceOwnership #
       - modifiers: onlyOwner
    - [Pub] transferOwnership #
       - modifiers: onlyOwner
    - [Prv] _setOwner #

 + [Int] IBEP20 
    - [Ext] totalSupply
    - [Ext] decimals
    - [Ext] symbol
    - [Ext] name
    - [Ext] getOwner
    - [Ext] balanceOf
    - [Ext] transfer #
    - [Ext] allowance
    - [Ext] approve #
    - [Ext] transferFrom #

 +  VRFRequestIDBase 
    - [Int] makeVRFInputSeed
    - [Int] makeRequestId

 +  ProxySafeVRFConsumerBase (VRFRequestIDBase)
    - [Int] fulfillRandomness #
    - [Int] requestRandomness #
    - [Ext] rawFulfillRandomness #

 + [Int] IRewardNFT (IERC721)
    - [Ext] mint #
    - [Ext] metadataOf #
    - [Ext] totalCardsOf #
    - [Ext] forgeBurn #
    - [Ext] addSet #

 +  piggyGame (OwnableUpgradeable, ProxySafeVRFConsumerBase)
    - [Pub] initialize #
       - modifiers: initializer
    - [Ext]  ($)
    - [Pub] getJoinFee
    - [Pub] isGameOpen
    - [Pub] currentSeason
    - [Pub] balanceOf
    - [Pub] boosterPackBalanceOf
    - [Pub] totalGamesPlayedOf
    - [Pub] teamOf
    - [Pub] getThresholds
    - [Pub] hasPlayerJoined
    - [Pub] getRareChances
    - [Pub] teamDamageOf
    - [Pub] teamWinsOf
    - [Pub] getActiveTeams
    - [Pub] playerWins
    - [Pub] tokenInfo
    - [Pub] tokenBalanceOf
    - [Pub] unclaimedBoosterPacksOf
    - [Pub] isNFTRedeemable
    - [Pub] setOpen #
       - modifiers: onlyOwner
    - [Pub] setSeason #
       - modifiers: onlyOwner
    - [Pub] openSeason #
       - modifiers: onlyOwner
    - [Pub] closeSeason #
       - modifiers: onlyOwner
    - [Pub] addTeam #
       - modifiers: onlyOwner
    - [Pub] withdrawAllDevETH #
       - modifiers: onlyOwner
    - [Pub] withdrawLink #
       - modifiers: onlyOwner
    - [Pub] setJoinFee #
       - modifiers: onlyOwner
    - [Pub] setJoinPiggy #
       - modifiers: onlyOwner
    - [Pub] setRedeemFee #
       - modifiers: onlyOwner
    - [Pub] updatePancakeSwapRouter #
       - modifiers: onlyOwner
    - [Pub] updateNFTAddress #
       - modifiers: onlyOwner
    - [Pub] join ($)
    - [Pub] buyTokens ($)
    - [Pub] deposit #
    - [Pub] withdraw #
    - [Pub] attack #
    - [Prv] getRandomNumber #
    - [Prv] requestReward #
    - [Int] fulfillRandomness #
    - [Pub] claimBoosterPacks ($)
    - [Pub] unpackBoosterPack #
    - [Pub] getNumRewards
    - [Prv] assignNFTs #
    - [Prv] getRandomInt
    - [Pub] forgeLegendary #
    - [Prv] openPool #
    - [Pub] claimLegendaryReward #
    - [Pub] transferPoolFunds #
       - modifiers: onlyOwner
    - [Pub] setThresholds #
       - modifiers: onlyOwner
    - [Pub] setRareChance #
       - modifiers: onlyOwner
    - [Prv] swapTokensForEth #
    - [Prv] swapEthForTokens #
    - [Prv] swapEthForExactTokens #
    - [Pub] mintNFT #
       - modifiers: onlyOwner