GeoPoly - Smart Contract Audit Report

Summary

GeoPoly Audit Report GeoPoly is building a new token, vesting contract, and game which features NFTs which correspond to locations around the world.

For this audit, we reviewed the Geos20Vesting contract using code provided by the project team, and the GEO20 and GeoPoly contracts at addresses 0xf1428850f92B87e629c6f3A3B75BffBC496F7Ba6on and 0x0b72a80C151DeC838Cb6fBCE002c09eD35897345, respectively, the Polygon mainnet.

Notes on the Contracts:
GEO20 Contract:
  • 100% of a specified max supply is sent to the owner upon deployment.
  • No mint or burn functions are present; though the circulating supply can be reduced by sending tokens to the 0x..dead address, if desired.
  • Transferring is not permitted until the owner sets the contract to a 'live' state.
  • While 'EarlyBird' mode is enabled, users on the 'EarlyBird' list can buy and sell up to a maximum transaction amount of the token.
  • No other transferring is permitted while 'EarlyBird' mode is enabled.
  • If the sender or recipient of a transfer is present in the whitelist, no transaction fees are paid.
  • The owner can update the maximum 'EarlyBird' transaction amount at any time.
  • One of three transaction fees are taken from the amount received by the recipient upon transfer, depenending on whether a user is buying, selling, or transferring.
  • Fees are stored in this contract.
  • The owner can update the maximum 'EarlyBird' transaction amount at any time.
  • The owner can only enable 'EarlyBird' mode one time, and can disable this mode at any time.
  • The owner can add or remove a liquidity pool at any time.
  • The owner can add or remove any address from the whitelist at any time.
  • The owner can add or remove any non-contract address from the 'EarlyBird' list at any time.
  • The owner can update fees to any value below 3% at any time.
  • The owner can withdraw any amount of tokens from the contract at any time.
  • This contract follows the ERC20 standard.
Geos20Vesting Contract:
  • This contract allows users to receive vesting token amounts over a specified period of time.
  • When adding a vesting schedule for an address, the owner will specify a total vesting time and different amounts which can be scheduled to release at varying points in time.
  • Vesting only begins after a specified global launch time has passed.
  • The total vesting amount must equal a multiple of 1000 tokens.
  • The owner can add an address to receive vesting funds at any time.
  • An address cannot be added more than once.
  • If the specified token is GEOS20 or another fee-on-transfer token, the project team should exercise caution and whitelist users in order for them to receive the full vesting amount.
  • The team should avoid using ERC-777 compliant tokens with this contract.
  • The owner can update the launch time at any time. If a user have been added to the vesting schedule before the launch time is updated, the launch time update will not affect their vesting schedule.
GeoPoly Contract:
  • This contract includes NFTs of different categories; each category can have multiple tiers which an NFT can be upgraded to.
  • The owner is given the Admin role, and can grant/revoke the Admin role to/from any address at any time.
  • A user can purchase NFTs which have been added as 'mintable' by an Admin, with pricing dependent on category and tier. An Admin can also remove an NFT from being 'mintable' at any time.
  • A user can choose to purchase tier upgrades for their NFTs by using a token specified by the project team. The upgrade price of an NFT is based on the category's tier upgrade cost, the number of tiers being upgraded, and the global upgrade price.
  • The project team should exercise caution and whitelist this contract when using fee-on-transfer tokens for tier upgrade purchases.
  • Users can also reserve an NFT that has not been added as 'mintable'. A maximum of 100 total NFTs can be reserved.
  • An Admin can mint all NFTs which have been reserved at any time.
  • Users are able to reserve an NFT and specify any price; however, off-chain logic is intended to filter out reservations priced which are priced incorrectly. This will result in the user losing their reservation payment.
  • If an NFT is added as 'mintable' before reserves are minted, it is possible that two NFTs with the same properties and different token IDs could enter circulation. Off-chain logic is intended to prevent this from occurring.
  • We have not reviewed any off-chain logic in the scope of this audit, so we are unable to provide an assessment of the off-chain logic with regards to security.
  • User can pay for mints or reservations in USDT or MATIC. MATIC will take priority if any is passed.
  • Users should exercise caution when minting or reserving as to not give a USDT allowance when paying with MATIC, and to not provide MATIC when intending to pay in USDT; if a user attempts to pay in MATIC but it is under the required price, the contract will accept the MATIC and also attempt to transfer the entire price in USDT.
  • Minting and reservation prices are defined in USDT; the contract uses a GeosOracle contract to calculate the equivalent amount in MATIC during payment.
  • The GeosOracle contract was not provided in the scope of this audit, so we are unable to provide an assessment of this contract with regards to security.

  • An Admin can enable or disable NFT sales at any time. This prevents users from upgrading, buying, or reserving NFTs unless a private sale is in progress.
  • An Admin can enable or disable a private sale at any time. If NFT sales are disabled during a private sale, only whitelisted users will be able to upgrade, buy, or reserve NFTs.
  • The owner can mint any amount of NFTs to any address at any time at no cost.
  • When a new season begins, the mint count for the owner is reset to 0.
  • An Admin can add/remove users to/from the whitelist at any time.
  • An Admin can update the 'private sale version' at any time. This will remove all users from the whitelist.
  • An Admin can update the reserved NFT list at any time.
  • An Admin can update any reserved NFT's owner at any time.
  • An Admin can add a new category at any time.
  • An Admin can add a new tier to a category at any time.
  • An Admin can update the upgrade cost of any NFT category and global upgrade multiplier to any amount at any time.
  • An Admin can update the upgrade price multiplier at any time.
  • An Admin can update the token used to purchase upgrades at any time.
  • An Admin can update the GeosOracle contract used to calculate MATIC price at any time.
  • The owner can withdraw any amount of MATIC, USDT, or any other tokens from the contract at any time.
General Notes Across Contracts:
  • Many functions can be declared external for gas saving purposes.
  • The GEO20 and Geos20Vesting contracts should be deployed with Solidity 0.8.x in order to prevent overflows.
Audit Findings Summary
  • Please ensure trust in the team prior to investing as they have substantial control in the ecosystem. The owner can mint an unlimited amount of NFTs at any time.
  • The GeoPoly contract uses off-chain logic to prevent incorrect NFT reservations and minting of multiple NFTs with the same properties.
  • Date: December 3rd, 2021

Audit Results

Vulnerability CategoryNotesResult
Arbitrary Storage WriteN/APASS
Arbitrary JumpN/APASS
Centralization of ControlThe owner has the permissions listed above. Off-chain logic is also implemented as described above.WARNING
Critical Solidity CompilerN/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
State Change External CallsN/APASS
SuicideN/APASS
Unbounded LoopN/APASS
Unchecked RetvalN/APASS
User Supplied AssertionN/APASS
Overall Contract Safety PASS

Details: GEO20 Contract

ERC20 Token Graph

Multi-file Token

	

($) = payable function
 # = non-constant function
							
 +  Context 
    - [Int] _msgSender
    - [Int] _msgData

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

 + [Int] GEOS20Metadata (GEOS20)
    - [Ext] name
    - [Ext] symbol
    - [Ext] decimals

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

 +  GEO20 (Context, GEOS20, GEOS20Metadata, Ownable)
    - [Int] checkFees
    - [Int] initFees #
    - [Int] isContract
    - [Pub] setMaxEarlyBirdsAmount #
       - modifiers: onlyOwner
    - [Pub] addLiquidityPool #
       - modifiers: onlyOwner
    - [Pub] removeLiquidityPool #
       - modifiers: onlyOwner
    - [Pub] removeWhitelist #
       - modifiers: onlyOwner
    - [Pub] removeEarlyBird #
       - modifiers: onlyOwner
    - [Pub] changeFee #
       - modifiers: onlyOwner
    - [Pub] addToWhitelist #
       - modifiers: onlyOwner
    - [Pub] addToEarlyBirds #
       - modifiers: onlyOwner
    - [Pub] addBatchToEarlyBirds #
       - modifiers: onlyOwner
    - [Pub]  #
    - [Pub] name
    - [Pub] symbol
    - [Pub] decimals
    - [Pub] totalSupply
    - [Pub] balanceOf
    - [Pub] transfer #
    - [Pub] allowance
    - [Pub] approve #
    - [Pub] transferFrom #
    - [Pub] increaseAllowance #
    - [Pub] decreaseAllowance #
    - [Pub] taxOnTxns
    - [Pub] calculateAmount
    - [Pub] arrangeTxn
    - [Int] _transfer #
    - [Int] _mint #
    - [Int] _burn #
    - [Int] _approve #
    - [Int] _beforeTokenTransfer #
    - [Int] _afterTokenTransfer #
    - [Pub] goLiveGeoS #
       - modifiers: onlyOwner
    - [Pub] deActivateEarlyBirds #
       - modifiers: onlyOwner
    - [Pub] withdrawGeos #
       - modifiers: onlyOwner

							

Details: Geos20Vesting 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 #

 + [Int] GEOS20 
    - [Ext] transfer #

 +  Geos20Vesting (Ownable)
    - [Pub]  #
    - [Pub] setLaunchTime #
       - modifiers: onlyOwner
    - [Pub] getVestingSchedule
    - [Pub] canVest
    - [Pub] isVestor
    - [Pub] getMaxVestingNative
    - [Int] transfromArrDS
    - [Int] checkVestingSch
    - [Pub] getDaysInSecondsFrom
    - [Pub] checkWithdrawAmount
    - [Int] calculateReturn
    - [Pub] getReturnFromVesting #
    - [Pub] addTeamVesting #
       - modifiers: onlyOwner
    - [Pub] getAllVestors
       - modifiers: onlyOwner
    - [Pub] getTotalVesting

							

							
							

Details: GeoPoly Contract

ERC20 Token Graph

Multi-file Token

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

 + [Int] IERC1155 (IERC165)
    - [Ext] balanceOf
    - [Ext] balanceOfBatch
    - [Ext] setApprovalForAll #
    - [Ext] isApprovedForAll
    - [Ext] safeTransferFrom #
    - [Ext] safeBatchTransferFrom #

 + [Int] IERC1155Receiver (IERC165)
    - [Ext] onERC1155Received #
    - [Ext] onERC1155BatchReceived #

 + [Int] IERC1155MetadataURI (IERC1155)
    - [Ext] uri

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

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

 +  ERC165 (IERC165)
    - [Pub] supportsInterface

 +  ERC1155 (Context, ERC165, IERC1155, IERC1155MetadataURI)
    - [Pub]  #
    - [Pub] supportsInterface
    - [Pub] uri
    - [Pub] balanceOf
    - [Pub] balanceOfBatch
    - [Pub] setApprovalForAll #
    - [Pub] isApprovedForAll
    - [Pub] safeTransferFrom #
    - [Pub] safeBatchTransferFrom #
    - [Int] _safeTransferFrom #
    - [Int] _safeBatchTransferFrom #
    - [Int] _setURI #
    - [Int] _mint #
    - [Int] _mintBatch #
    - [Int] _burn #
    - [Int] _burnBatch #
    - [Int] _setApprovalForAll #
    - [Int] _beforeTokenTransfer #
    - [Prv] _doSafeTransferAcceptanceCheck #
    - [Prv] _doSafeBatchTransferAcceptanceCheck #
    - [Prv] _asSingletonArray

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

 + [Lib] GeoSpecial 
    - [Pub] disect
    - [Pub] format
    - [Pub] convertStringToByes
    - [Pub] bytes32ToString
    - [Pub] asciiToInteger
    - [Pub] doAll
    - [Pub] compareStrings

 + [Int] GEOS20 
    - [Ext] transfer #
    - [Ext] decimals
    - [Ext] balanceOf #
    - [Ext] transferFrom #
    - [Ext] allowance

 + [Int] GeosOracle 
    - [Ext] getExchangeRate

 +  ReentrancyGuard 
    - [Pub]  #

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

 +  Roles (Ownable)
    - [Pub]  #
    - [Pub] addToAdmins #
       - modifiers: onlyOwner
    - [Pub] removeFromAdmins #
       - modifiers: onlyOwner

 +  GeoPoly (ERC1155, ReentrancyGuard, Ownable, Roles)
    - [Pub]  #
       - modifiers: ERC1155
    - [Pub] getCategory
    - [Ext] getAllCategories
    - [Pub] categoryExists
    - [Ext] getCategoryName
    - [Pub] getAvaliableTiers
    - [Pub] getTierPrices
    - [Ext] getTokenId
    - [Pub] getTokenVars
    - [Ext] getMintingString
    - [Pub] getNumOfNFTs
    - [Ext] getWalletNFTs
    - [Pub] getNFTVars
    - [Pub] deserilazeNFTProps
    - [Ext] getNFTTier
    - [Pub] oracleUSDTcalc
    - [Pub] calcUpgradeCost
    - [Pub] isWhitelisted
    - [Ext] upgradeNFT #
       - modifiers: nonReentrant
    - [Ext] geoMint ($)
       - modifiers: nonReentrant
    - [Ext] reserveNFT ($)
       - modifiers: nonReentrant
    - [Int] getKec
    - [Int] changeNFTTier #
    - [Int] checkPayment #
    - [Int] checkGeosPayment #
    - [Int] addMint #
    - [Int] genericMint #
    - [Ext] getReservedNFTs
       - modifiers: isAdmin
    - [Ext] addCategory #
       - modifiers: isAdmin
    - [Ext] addTier #
       - modifiers: isAdmin
    - [Ext] changeUpgradePerTier #
       - modifiers: isAdmin
    - [Ext] changeUpgradePrice #
       - modifiers: isAdmin
    - [Ext] nftSalePaused #
       - modifiers: isAdmin
    - [Ext] pausePrivatePresale #
       - modifiers: isAdmin
    - [Ext] changeSeason #
       - modifiers: isAdmin
    - [Ext] mintReserved #
       - modifiers: isAdmin
    - [Ext] addToMints #
       - modifiers: isAdmin
    - [Ext] resetReservedNFTs #
       - modifiers: isAdmin
    - [Ext] addToWhitelist #
       - modifiers: isAdmin
    - [Ext] removeFromWhitelist #
       - modifiers: isAdmin
    - [Ext] addBatchWhitelist #
       - modifiers: isAdmin
    - [Ext] nextPrivateSaleV #
       - modifiers: isAdmin
    - [Ext] setGeosToken #
       - modifiers: onlyOwner
    - [Ext] setgOracle #
       - modifiers: onlyOwner
    - [Ext] withdraw #
       - modifiers: onlyOwner
    - [Ext] withdrawGeos #
       - modifiers: onlyOwner
    - [Ext] withdrawUSDT #
       - modifiers: onlyOwner
    - [Ext] withdrawTokens #
       - modifiers: onlyOwner
    - [Ext] withdrawAll #
       - modifiers: onlyOwner