Pinkslip Finance - Smart Contract Audit Report

Summary

 PinkslipFinance Audit Report Pinkslip Finance is building a new ERC-20 token with a crowdsale platform, a racing game, and a yield farming platform that ties it all together.

We reviewed Pinkslip Finance's PinkslipToken, PinkslipSale, PinkslipNFT, PinkslipRacing, PinkslipTicket, and PinkslipStake contracts using code provided to us by the project team.

Notes on Individual Contracts:
PinkslipToken contract:
  • The total supply of the Pinkslip token is set to 30 million tokens, and is minted to the owner on initialization.
  • No mint functions are present, but any user may burn their own tokens or those for which they are given approval.
  • Transfers are initially locked and must be unlocked by the owner; users on the lock whitelist are exempt.
  • The owner is able to release the lock to enable transfers at any time; once unlocked, transfers may not be locked again.
  • The owner can enforce a max transaction amount only once for a period of 24 hours; whitelisted users are exempt from the max transaction amount.
  • The owner is able to add or remove any address from the whitelist and the lock whitelist at any time.
PinkslipSale contract:
  • The crowdsale is active until the hard cap of 500 ETH has been met, or unless the owner has manually paused the system.
  • While the crowdsale is active, users must deposit at least 0.1 ETH (up to a total contribution limit of 3 ETH per user) and in return will receive 10,909 tokens per ETH deposited.
  • Any amount of ETH deposited over the hard cap is returned to the user, and the remaining amount is transferred to the funding address controlled by the team.
  • The owner can pause or unpause the crowdsale at any time.
  • The owner can transfer all of the crowdsale tokens in the contract to the funding address controlled by the team at any time.
PinkslipNFT contract:
  • Anyone can use the PinkslipNFT contract to purchase up to 3 NFTs representing a car that can be used in the PinkslipRacing contract.
  • Alternatively, any wallet or contract address with the Minter role can mint any valid car to any wallet address.
  • There are 3 types of cars that users can purchase; prices vary depending on car type and are paid in the fee token defined on initialization.
  • Users can purchase an unlimited amount of cars of type 1 or 2, but there is a limited supply of 1,000 cars of type 3 can ever be minted.
  • A portion of the fee token is transferred to the staking fees wallet and the remainder is sent to the platform fees wallet; both wallets are controlled by the team.
  • The owner has the default Admin role and the Minter role.
  • The owner can set the prices for the car types to any value at any time.
PinkslipRacing contract:
  • Anyone can create a proposal for a race in at most 1 of 50 slots, given the slot is available and the user is not currently in a slot.
  • The race creator must provide the ID of the Pinkslip NFT car they wish to use and wager in the race and the amount they wish to wager as a reward for winning the race; the wager amount must be at least 5 tokens.
  • The race creator must ensure they have enough balance to cover the wager amount, the contract address is approved for at least the wager amount, they are the owner of the Pinkslip NFT car, the contract address is approved for the Pinkslip NFT car, and the end date of the race (24 hours from creation) has not passed in order to secure the race slot.
  • If the race slot has not been secured, it can be overwritten by another user.
  • Only one user can accept another user's race proposal as long as the end time of the race has not passed and the proper approvals are in place.
  • On acceptance, the winner is randomly selected and will receive the wagered amount and Pinkslip NFT car.
  • The randomness function used to determine the winner relies on some predictable variables that can be manipulated by miners to some extent. This is common, albiet not best practice, but the probability of miners maliciously changing these variables is extremley low.
  • Odds of winning the race also varies depending on the cars chosen by both players; car type 1 grants the user 3 points, car type 2 grants 5 points, and car type 3 grants the user 7 points.
  • Users are able to check the car type of the race creator prior to accepting a race.
  • The race creator is able to cancel their race proposal as long as the end time has not passed and the race has not been accepted yet.
PinkslipTicket contract:
  • Users can exchange 20 Pinkslip NFT cars for 1 Pinkslip Staking Pass NFT that is needed in order to participate in the PinkslipStake staking contract.
  • Alternatively, a user can purchase a Pinkslip Staking Pass NFT for 5 ETH; the ETH is sent to the fee wallet controlled by the team.
  • Any wallet or contract address with the Minter role can mint a Pinkslip Staking Pass NFT to any wallet address at any time.
  • The owner has the default Admin role and the minter role.
  • The owner can set the price for a Pinkslip Staking Pass NFT to any value at any time.
PinkslipStake contract:
  • Users must deposit at most 1 Pinkslip Staking Pass NFT and will recieve 1000 shares in the staking pool in return.
  • On withdrawals, the user forfeits their shares in the staking pool and receives rewards in Pinkslip Token.
  • There is a minimum stake time enforced by the contract in order to receive all accrued rewards. In the event that the user chooses to withdraw before the minimum stake time has elapsed, half of the reward amount is burned and the remaining half is transferred to the user.
  • Rewards are recalculated during any function call and can also be kicked off manually at any time.
  • The owner can set the minimum stake time to any value up to 365 days at any time; initially, it is set to 30 days.
  • SafeMath is utilized to prevent overflows.

Audit Findings Summary:
  • No security issues from outside attackers were identified.
  • Ensure trust in the team as they have notable control in the ecosystem.
  • Date: August 16th, 2021.
  • Updated: November 7th, 2021 to include PinkslipStaking minimum stake time requirement.

External Threat Results

Vulnerability CategoryNotesResult
Arbitrary Storage WriteN/APASS
Arbitrary JumpN/APASS
Delegate Call to Untrusted ContractN/APASS
Dependence on Predictable VariablesDecisions are made based on the block.number
and block.difficulty environment variables
which can be manipulated by a malicious miner.
This is extremley unlikely to occur.
WARNING
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

Pinkslip Token Contract

Smart Contract Graph

Contract Inheritance


 ($) = payable function
 # = non-constant function
 
 Int = Internal
 Ext = External
 Pub = Public
 
 + [Int] IERC20 
    - [Ext] totalSupply
    - [Ext] balanceOf
    - [Ext] transfer #
    - [Ext] allowance
    - [Ext] approve #
    - [Ext] transferFrom #

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

 + [Lib] SafeMath 
    - [Int] tryAdd
    - [Int] trySub
    - [Int] tryMul
    - [Int] tryDiv
    - [Int] tryMod
    - [Int] add
    - [Int] sub
    - [Int] mul
    - [Int] div
    - [Int] mod
    - [Int] sub
    - [Int] div
    - [Int] mod

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

 +  PinkslipToken (Context, IERC20, Ownable)
    - [Pub]  #
    - [Pub] name
    - [Pub] symbol
    - [Pub] decimals
    - [Pub] totalSupply
    - [Pub] balanceOf
    - [Pub] transfer #
    - [Pub] allowance
    - [Pub] approve #
    - [Pub] transferFrom #
    - [Pub] increaseAllowance #
    - [Pub] decreaseAllowance #
    - [Pub] burn #
    - [Pub] burnFrom #
    - [Ext] addToWhitelist #
       - modifiers: onlyOwner
    - [Ext] removeFromWhitelist #
       - modifiers: onlyOwner
    - [Ext] setMaxTxDate #
       - modifiers: onlyOwner
    - [Int] _transfer #
    - [Int] _burn #
    - [Int] _approve #
    - [Ext] addToLockWhitelist #
       - modifiers: onlyOwner
    - [Ext] removeFromLockWhitelist #
       - modifiers: onlyOwner
    - [Ext] release #
       - modifiers: onlyOwner

Pinkslip Sale Contract

Smart Contract Graph

Contract Inheritance


 ($) = payable function
 # = non-constant function
 
 Int = Internal
 Ext = External
 Pub = Public
 
 + [Lib] SafeMath 
    - [Int] tryAdd
    - [Int] trySub
    - [Int] tryMul
    - [Int] tryDiv
    - [Int] tryMod
    - [Int] add
    - [Int] sub
    - [Int] mul
    - [Int] div
    - [Int] mod
    - [Int] sub
    - [Int] div
    - [Int] mod

 +  ReentrancyGuard 
    - [Int]  #

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

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

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

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

 +  PinkslipSale (ReentrancyGuard, Ownable)
    - [Pub]  #
    - [Ext] getToken
    - [Ext]  ($)
    - [Int] sell #
       - modifiers: nonReentrant,whenCrowdsaleAlive
    - [Ext] totalTokensNeeded
    - [Ext] stop #
       - modifiers: onlyOwner
    - [Ext] unstop #
       - modifiers: onlyOwner
    - [Ext] returnUnsold #
       - modifiers: nonReentrant,onlyOwner
    - [Pub] getTime
    - [Pub] isActive
    - [Pub] isSuccessful

Pinkslip NFT and Racing Contracts

Smart Contract Graph

Contract Inheritance


 ($) = payable function
 # = non-constant function
 
 Int = Internal
 Ext = External
 Pub = Public
 
 +  Context 
    - [Int] _msgSender
    - [Int] _msgData

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

 + [Lib] SafeMath 
    - [Int] tryAdd
    - [Int] trySub
    - [Int] tryMul
    - [Int] tryDiv
    - [Int] tryMod
    - [Int] add
    - [Int] sub
    - [Int] mul
    - [Int] div
    - [Int] mod
    - [Int] sub
    - [Int] div
    - [Int] mod

 +  ReentrancyGuard 
    - [Int]  #

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

 + [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] IERC721Metadata (IERC721)
    - [Ext] name
    - [Ext] symbol
    - [Ext] tokenURI

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

 + [Int] IERC721Receiver 
    - [Ext] onERC721Received #

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

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

 + [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

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

 + [Lib] Strings 
    - [Int] toString

 +  ERC721 (Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable)
    - [Pub]  #
    - [Pub] balanceOf
    - [Pub] ownerOf
    - [Pub] name
    - [Pub] symbol
    - [Pub] tokenURI
    - [Pub] baseURI
    - [Pub] tokenOfOwnerByIndex
    - [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] _mint #
    - [Int] _burn #
    - [Int] _transfer #
    - [Int] _setTokenURI #
    - [Int] _setBaseURI #
    - [Prv] _checkOnERC721Received #
    - [Int] _approve #
    - [Int] _beforeTokenTransfer #

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

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

 +  PinkslipNFT (ERC721, AccessControl, Ownable)
    - [Pub]  #
       - modifiers: ERC721
    - [Pub] mint #
    - [Pub] buy #
    - [Pub] carType
    - [Int] _setCarType #
    - [Pub] setFeesDestinators #
       - modifiers: onlyOwner
    - [Pub] setFeesPercentages #
       - modifiers: onlyOwner
    - [Pub] setFeesAmounts #
       - modifiers: onlyOwner

 +  PinkslipRacing (Ownable, ReentrancyGuard)
    - [Pub]  #
    - [Pub] createRace #
       - modifiers: slotAvailable
    - [Pub] cancel #
       - modifiers: inProgress
    - [Pub] accept #
       - modifiers: inProgress
    - [Pub] isSlotAvailable
    - [Pub] allSlotsStatus
    - [Int] _getTime
    - [Int] _randomNumber
    - [Int] _chancesByType

Pinkslip NFT, Ticket, and Stake Contracts

Smart Contract Graph

Contract Inheritance


 ($) = payable function
 # = non-constant function
 
 Int = Internal
 Ext = External
 Pub = Public
 
 + [Lib] SafeMath 
    - [Int] tryAdd
    - [Int] trySub
    - [Int] tryMul
    - [Int] tryDiv
    - [Int] tryMod
    - [Int] add
    - [Int] sub
    - [Int] mul
    - [Int] div
    - [Int] mod
    - [Int] sub
    - [Int] div
    - [Int] mod

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

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

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

 + [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] IERC721Metadata (IERC721)
    - [Ext] name
    - [Ext] symbol
    - [Ext] tokenURI

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

 + [Int] IERC721Receiver 
    - [Ext] onERC721Received #

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

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

 + [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

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

 + [Lib] Strings 
    - [Int] toString

 +  ERC721 (Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable)
    - [Pub]  #
    - [Pub] balanceOf
    - [Pub] ownerOf
    - [Pub] name
    - [Pub] symbol
    - [Pub] tokenURI
    - [Pub] baseURI
    - [Pub] tokenOfOwnerByIndex
    - [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] _mint #
    - [Int] _burn #
    - [Int] _transfer #
    - [Int] _setTokenURI #
    - [Int] _setBaseURI #
    - [Prv] _checkOnERC721Received #
    - [Int] _approve #
    - [Int] _beforeTokenTransfer #

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

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

 +  PinkslipNFT (ERC721, AccessControl, Ownable)
    - [Pub]  #
       - modifiers: ERC721
    - [Pub] mint #
    - [Pub] buy #
    - [Pub] carType
    - [Int] _setCarType #
    - [Pub] setFeesDestinators #
       - modifiers: onlyOwner
    - [Pub] setFeesPercentages #
       - modifiers: onlyOwner
    - [Pub] setFeesAmounts #
       - modifiers: onlyOwner

 +  PinkslipTicket (ERC721, AccessControl, Ownable)
    - [Pub]  #
       - modifiers: ERC721
    - [Pub] mint #
    - [Pub] buy ($)
    - [Pub] exchange #
    - [Pub] setFeeAddress #
       - modifiers: onlyOwner
    - [Pub] setFeeAmount #
       - modifiers: onlyOwner

 +  PinkslipStake (Ownable)
    - [Pub]  #
    - [Ext] pendingReward
    - [Pub] updatePool #
    - [Pub] deposit #
    - [Pub] withdraw #