An unofficial audit of a Solidity Game smart contract: Wizards & Dragons Game


Contracts on which the audit was based

Audit Finding

Slither Finding

WD-100: check gpToken.transferFrom return value

WD-101: check all divisions

WD-102: WNDGame stuck money?


WD-001: Floating pragma

WD-002: Hardhat console imported in deployed contract

WD-003: import not used in interfaces

WD-004: missing explanation about lastWrite mechanism

WD-005: Emission of events missing for critical actions

  • GP.sol: missing events for functions addAdmin, removeAdmin, updateOriginAccess
  • SacrificialAlter.sol: missing events for functions addAdmin, removeAdmin, updateOriginAccess, setContracts, setType, setExchangeAmt, updateOriginAccess
  • Tower.sol: missing events for functions setRescueEnabled, _payDragonTax
  • Traits.sol: missing events for functions setWnD, uploadTraits
  • WnD.sol: missing events for functions addAdmin, removeAdmin, updateOriginAccess, withdraw, setPaidTokens, setContracts
  • WNDGame.sol: missing events for functions setContracts, setTreasureChestId, addToWhitelist, setPublicSaleStart, setMaxGpCost, payTribute, makeTreasureChests, sellTreasureChests, sacrifice

WD-006: Event does not have indexed parameters

WD-007: create an external contract for the lastWrite mechanism

WD-009: replace admins mechanism with AccessControl

WD-010: add admin mechanism should validate the address


WD-011: setContracts should revert if _gp address is 0 address

WD-012: maxSupply in setType can be == 0?

WD-013: exchangeAmt in setExchangeAmt can be == 0?

WD-014: possible reentrancy issue

WD-015: updateOriginAccess is updating incorrectly lastWrite[tx.origin].time


WD-016: unbound array

WD-017: setWnD wndNFT could be set 0x address

WD-018: BASE 64 code could be replaced by an external library


WD-019: check that _maxTokens respect what’s written in the comments

// max number of tokens that can be minted: 60000 in production
uint256 public maxTokens;

WD-020: add checks on setContracts parameters

WD-021: generate is an internal method that returns a WizardDragon but its return value is never used

WD-022: updateOriginAccess assign the incorrect value to lastWrite[tx.origin].time

WD-023: _paidTokens parameter of setPaidTokens should have the same int type of PAID_TOKENS

WD-024: check setPaidTokens parameter value

WD-025: be aware of modifier orders in setPaused


WD-026: define presalePrice as a constant if it never changes

WD-027: add param checks in setContracts

WD-028: startedTime can be reset multiple times.

WD-029: addToWhitelist can reset an account whitelisting allowing it to mint more than 2 tokens in a whitelisting period

  • addToWhitelist is called whitelisting Alice address addr1.
  • Alice mint 2 items in whitelist period
  • Admin call again addToWhitelist with Alice's address as a parameter. Alice whitelisting metadata gets reset and can mint again.

WD-030: add nonReentrancy on both makeTreasureChests and sellTreasureChests?

Update 1: an official GitHub repository



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store


#web3 dev + auditor | @SpearbitDAO security researcher, @yAcademyDAO resident auditor, @developer_dao #459, @TheSecureum bootcamp-0, @code4rena warden