Plant vs. Undead - Smart Contract Audit Report

Summary

Plant vs. Undead Audit Report Plant vs. Undead is building an NFT marketplace where users can buy and sell Plants to be used in their multiplayer game.

For this audit, we reviewed the PlantCore and SaleClockAuction contracts using code provided to us by the project team.

Notes on the Contracts:
  • Users can pay a price set by the owner to create a Plant at any time as long as there are plants available to be created.
  • Users can specify the address to where the Plant will be minted; this address will be known as the owner of the Plant.
  • The Bundle and Farm addresses can create Plants without paying the fee.
  • The owner of the Plant can burn the Plant at any time, as long as burning is enabled; the user will receive some amount of PVU tokens decided by the owner in return.
  • The owner of the Plant can create a sale auction for the Plant; on auction, the Plant will be transferred to the Sale Auction contract.
  • The owner of the Plant specifies the starting and ending prices as well as the auction duration.
  • The current price of the Plant increases linearly from the starting price to the ending price as time progresses.
  • Anyone can claim a Plant that is up for auction, as long as the bid amount meets or exceeds the current price of the Plant; users must bid in PVU tokens.
  • The winner of the auction will receive the Plant NFT and the excess bid amount, and a portion of the sale price is transferred to the seller in PVU tokens.
  • The remaining PVU tokens stay in the contract and are able to be withdrawn by the project team at any time.
  • The seller is able to cancel the auction at any time.

  • The owner is able to withdraw any ETH and PVU tokens in the contract at any time.
  • The owner is able to pause or unpause the system at any time.
  • The owner is able to cancel any auction when the system is paused.
  • The owner is able to change the owner's cut received during an auction sale to any percentage up to 100% at any time.
  • The owner is able to update the price to create a Plant to any PVU token amount at any time.
  • The owner is able to update the PVU return rate on a burn to any value at any time.
  • The owner can toggle the burn functionality at any time.
  • The owner is able to add plants and seed farms that can be created at any time.
  • The owner is able to set the Sale Auction, Farm, and Bundle addresses to any value at any time.

  • Some variables could have been declared constant for extra gas savings.
  • Some functions could have been declared external for extra gas savings.
  • The contract utilizes the SafeMath library to prevent overflows.
Audit Findings Summary
  • No security issues from outside attackers were identified.
  • Ensure trust in the team as they have some control in the ecosystem.
  • Date: July 29th, 2021

Audit 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
Flash LoansN/APASS
Integer Over/UnderflowN/APASS
Multiple SendsN/APASS
OraclesN/APASS
SuicideN/APASS
State Change External CallsN/APASS
Unchecked RetvalN/APASS
User Supplied AssertionN/APASS
Critical Solidity CompilerN/APASS
Overall Contract Safety PASS

PlantCore Contract

Smart Contract Graph

Contract Inheritance


 ($) = payable function
 # = non-constant function
 
 + [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

 + [Lib] Address 
    - [Int] isContract
    - [Int] sendValue #
    - [Int] functionCall #
    - [Int] functionCall #
    - [Int] functionCallWithValue #
    - [Int] functionCallWithValue #
    - [Prv] _functionCallWithValue #

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

 +  AccessControl (Context)
    - [Pub] hasRole
    - [Pub] getRoleMemberCount
    - [Pub] getRoleMember
    - [Pub] getRoleAdmin
    - [Pub] grantRole #
    - [Pub] revokeRole #
    - [Pub] renounceRole #
    - [Int] _setupRole #
    - [Int] _setRoleAdmin #
    - [Prv] _grantRole #
    - [Prv] _revokeRole #

 + [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] IERC721Enumerable (IERC721)
    - [Ext] totalSupply
    - [Ext] tokenOfOwnerByIndex
    - [Ext] tokenOfOwner
    - [Ext] tokenByIndex

 + [Int] IERC721Receiver 
    - [Ext] onERC721Received #

 + [Int] IERC20 
    - [Ext] balanceOf
    - [Ext] allowance
    - [Ext] approve #
    - [Ext] transfer #
    - [Ext] transferFrom #

 +  ERC165 (IERC165)
    - [Int]  #
    - [Pub] supportsInterface
    - [Int] _registerInterface #

 + [Lib] SafeMath 
    - [Int] add
    - [Int] sub
    - [Int] sub
    - [Int] mul
    - [Int] div
    - [Int] div
    - [Int] mod
    - [Int] mod

 + [Lib] EnumerableMap 
    - [Prv] _set #
    - [Prv] _remove #
    - [Prv] _contains
    - [Prv] _length
    - [Prv] _at
    - [Prv] _get
    - [Prv] _get
    - [Int] set #
    - [Int] remove #
    - [Int] contains
    - [Int] length
    - [Int] at
    - [Int] get
    - [Int] get

 +  ERC721 (Context, ERC165, IERC721, IERC721Enumerable)
    - [Pub]  #
    - [Pub] balanceOf
    - [Pub] ownerOf
    - [Pub] tokenOfOwnerByIndex
    - [Pub] tokenOfOwner
    - [Pub] totalSupply
    - [Pub] tokenByIndex
    - [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] _mintPlant #
    - [Int] _burn #
    - [Int] _transfer #
    - [Prv] _checkOnERC721Received #
    - [Int] _approve #
    - [Int] _beforeTokenTransfer #

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

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

 +  Ownable (Context)
    - [Int]  #
    - [Pub] owner
    - [Pub] renounceOwnership #
       - modifiers: onlyOwner
    - [Pub] transferOwnership #
       - modifiers: onlyOwner

 + [Int] IClockAuction 
    - [Ext] createAuction #

 + [Int] IPlantCore 
    - [Ext] createPlantFromFarm #
    - [Ext] createBundlePlant #

 +  PlantCore (ERC721Pausable, AccessControl, Ownable, IPlantCore)
    - [Pub]  #
       - modifiers: ERC721
    - [Ext] getRangeIdLength
    - [Ext] getRangeId
    - [Ext] getSeedFarmLength
    - [Ext] getSeedFarm
    - [Ext] addPlantId #
       - modifiers: onlyOwner
    - [Ext] addSeedFarm #
       - modifiers: onlyOwner
    - [Ext] updatePrice #
       - modifiers: onlyOwner
    - [Ext] createPlant #
    - [Ext] createBundlePlant #
       - modifiers: onlyBundle
    - [Ext] createPlantFromFarm #
       - modifiers: onlyFarm
    - [Ext] createSaleAuction #
       - modifiers: whenNotPaused
    - [Ext] burnPlant #
    - [Ext] setSaleAuctionAddress #
       - modifiers: onlyOwner
    - [Ext] setFarmAddress #
       - modifiers: onlyOwner
    - [Ext] setBundleAddress #
       - modifiers: onlyOwner
    - [Ext] setIsBurn #
       - modifiers: onlyOwner
    - [Ext] setRate #
       - modifiers: onlyOwner
    - [Pub] getPlant
    - [Int] _randomPlantId #
    - [Prv] _remove #
    - [Int] _randomSeedFarm #
    - [Prv] _removeSeedFarm #
    - [Pub] getBalance
    - [Ext] withdrawBalance #
       - modifiers: onlyOwner
    - [Pub] pause #
       - modifiers: whenNotPaused
    - [Pub] unpause #
       - modifiers: whenPaused
							

SaleClockAuction Contract

Smart Contract Graph

Contract Inheritance


 ($) = payable function
 # = non-constant function
 
 + [Lib] SafeMath 
    - [Int] add
    - [Int] sub
    - [Int] sub
    - [Int] mul
    - [Int] div
    - [Int] div
    - [Int] mod
    - [Int] mod

 + [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] IERC20 
    - [Ext] balanceOf
    - [Ext] allowance
    - [Ext] approve #
    - [Ext] transfer #
    - [Ext] transferFrom #

 +  ClockAuctionBase 
    - [Int] _owns
    - [Int] _escrow #
    - [Int] _transfer #
    - [Int] _addAuction #
    - [Int] _cancelAuction #
    - [Int] _bid #
    - [Int] _removeAuction #
    - [Int] _isOnAuction
    - [Int] _currentPrice
    - [Int] _computeCurrentPrice
    - [Int] _computeCut

 +  Ownable 
    - [Pub]  #
    - [Ext] transferOwnership #
       - modifiers: onlyOwner

 +  Pausable (Ownable)
    - [Ext] pause #
       - modifiers: onlyOwner,whenNotPaused
    - [Ext] unpause #
       - modifiers: onlyOwner,whenPaused

 + [Int] IClockAuction 
    - [Ext] createAuction #

 +  ClockAuction (Pausable, ClockAuctionBase, IClockAuction)
    - [Pub]  #
    - [Ext] withdrawBalance #
       - modifiers: onlyOwner
    - [Ext] changeCut #
       - modifiers: onlyOwner
    - [Pub] getBalance
    - [Ext] createAuction #
       - modifiers: whenNotPaused
    - [Ext] bid #
       - modifiers: whenNotPaused
    - [Ext] cancelAuction #
    - [Ext] cancelAuctionWhenPaused #
       - modifiers: whenPaused,onlyOwner
    - [Ext] getAuction
    - [Ext] getCurrentPrice

 +  SaleClockAuction (ClockAuction)
    - [Pub]  #
       - modifiers: ClockAuction
    - [Ext] createAuction #
    - [Ext] bid #
    - [Ext] averageGen0SalePrice