PinkslipFlip - Smart Contract 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.
For this audit, we reviewed Pinkslip Finance's PinkslipFlip contract using code provided to us by the project team.
We previously reviewed the project team's PinkslipToken, PinkslipSale, PinkslipNFT, PinkslipRacing, PinkslipTicket, and PinkslipStake contracts here.
Notes on the Contract:
- Any user may create a game by calling the createGame() function and claiming an available slot.
- When creating a game, users must also wager at least one PinkSlip token, though funds do not need to be deposited.
- 12 slots will be available (0-11) and users can only utilize a single slot at once.
- Note that game creators who sell the tokens they have wagered will have been considere to abandon their game slot; allowing any other user to create a game in that slot.
- A user who created a game entry can elect to cancel that game entry as long as that game is still in progress.
- Any user can call accept() and pass in a game ID to wager on and and participate in that game.
- The contract will check the game creator's balance and allowance to ensure a successful transfer of tokens can occcur.
- Next, a pseudo-random number will be generated to determine the outcome of the game via the _randomNumber() function. The probability of each user winning is in theory 50%.
- The _randomNumber() function uses a weak source of randomness, potentially allowing outcomes to be determined by miners/flashbots while a block is being mined. The team has made the contract Pausable to address this and will pause its use if abuse is detected.
- If the value returned by the _randomNumber() function is 1-5 the game's creator shall be the winner. Otherwise, if the value returned is 6-10, the game's acceptor shall be the winner.
- At the end of the process, funds will be transferred to the winner and the game slot reset.
- Users cannot call accept() on their own game.
- Even with protection against smart contracts, the same logic could be applied to create a python script models the pseudo-randomness and then sends only winning transactions via flashbots.
- The owner of the contract can set the fee percentage to any value and the destination address for fees at any time.
- The owner of the contract can also pause the contract's usage. This is desired in case abuse of the game is detected.
- SafeMath is utilized to prevent overflows.
Audit Findings Summary:
- The source of pseudo-randomness could allow miners/flashbots to only conduct winning transactions; though the team can pause usage of the contract if abuse is detected.
- Ensure trust in the team as they have some control in the ecosystem.
- Date: September 23rd, 2021.
- Update Date: September 25th, 2021 - Resolution of issues and implementation of gas optimizations.
External Threat Results
|Arbitrary Storage Write||N/A||PASS|
|Delegate Call to Untrusted Contract||N/A||PASS|
|Dependence on Predictable Variables||Environment variables are used to determine a|
pseudo-random number, which could allow
miners to predict the result of the
|State Change External Calls||N/A||Pass|
|User Supplied Assertion||N/A||PASS|
|Critical Solidity Compiler||N/A||PASS|
|Overall Contract Safety||PASS|
Pinkslip Token Contract
($) = 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] add - [Int] sub - [Int] sub - [Int] mul - [Int] div - [Int] div - [Int] mod - [Int] mod + Pausable (Context) - [Int] # - [Pub] paused - [Int] _pause # - modifiers: whenNotPaused - [Int] _unpause # - modifiers: whenPaused + [Int] IERC20 - [Ext] totalSupply - [Ext] balanceOf - [Ext] transfer # - [Ext] allowance - [Ext] approve # - [Ext] transferFrom # + PinkslipFlip (Ownable, Pausable) - [Pub] # - [Ext] createGame # - modifiers: slotAvailable,whenNotPaused - [Ext] cancel # - modifiers: inProgress,whenNotPaused - [Ext] accept # - modifiers: inProgress,whenNotPaused - [Pub] isSlotAvailable - [Ext] allSlotsStatus - [Ext] setFeeAndDestinator # - modifiers: onlyOwner - [Int] _getTime - [Int] _randomNumber