-
Notifications
You must be signed in to change notification settings - Fork 0
/
CoinFlip.sol
125 lines (98 loc) · 3.41 KB
/
CoinFlip.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.6.0;
/**
* @title - CoinFlip.sol - ETHDenver 2021 POC
* @author - Zachary Wolff - @WolfDeFi
* @notice - non-profit Web3 game of chance feeds $$-> Public Goods Pool
**/
// TODO add safemath.sol
/**
* @notice interface for interacting with GamingLicenseToken contract
*/
interface GamingLicenseToken {
function balanceOf(address) external returns (uint256);
}
contract CoinFlip{
/// @notice Address for the gamingTokenLicense contract
address public gamingTokenContract;
/// @notice Max Bet Size in WEI
uint256 public maxBet;
/// @notice map gaming license to balance
mapping(address => uint) public game_balances;
/// @notice Win/loss events
event Winner(string congratulations);
event Loser(string sorry);
/// @dev debug events
event BalanceOf(uint256 balanceOfNFTs);
/**
* @param _gamingTokenContract - Gaming License Token Contract Address
* @param _maxBet - Max Bet Size
**/
constructor(address _gamingTokenContract, uint256 _maxBet) public {
gamingTokenContract = _gamingTokenContract;
maxBet = _maxBet;
}
function placeBet() public payable {
// Reject bets from accounts that don't hold a valid gaming license
require(isLicensed(msg.sender) == true, "CF :: A valid gaming license is required");
// Reject bets that are too large
require(msg.value <= maxBet, "CF :: Bet size exceeds max");
// Reject empty bets
require(msg.value > 0, "CF :: Wager is required to play");
// settle the bet
if (_isWinner() == true) {
emit Winner("CF :: Nice bet! You won.");
} else {
emit Loser("CF :: Sorry! you lost");
}
}
/**
* @notice check if msg.sender has a valid license token
* @param _player address
*/
function isLicensed(address _player) private returns (bool) {
if (_getBalanceOf(_player) > 0) {
return true;
}
}
/**
* @notice gets a sudo random number and checks if it's even (winner) or odd (loser)
*/
function _isWinner() internal returns (bool) {
uint bad_random = _thisIsNotRandom();
uint value = bad_random / 2;
if (2 * value == bad_random) {
// Update user balance
uint256 payout = _calculatePayout();
uint256 current_balance = game_balances[msg.sender];
game_balances[msg.sender] = payout + current_balance;
return true; // even wins
} else {
return false; // odd lose
}
}
// Coming soon - placholder for now
function _calculatePayout() internal returns (uint256) {
// TODO - deduct a house edge of x% and return bet minus house edge
return msg.value;
}
/**
* @notice get balanceOf from gaming license token contract for a given address
* @param _player address
* @return number of tokens provided address has
* @dev this needs to be strenghtened - 1) check token registry for token expiration
*/
function _getBalanceOf(address _player) private returns (uint256){
GamingLicenseToken GT = GamingLicenseToken(gamingTokenContract);
uint256 balance = GT.balanceOf(_player);
// emit BalanceOf(balance);
return balance;
}
/**
* @notice this is not random - used for POC purposes, not safe for production!
* @dev https://medium.com/better-programming/how-to-generate-truly-random-numbers-in-solidity-and-blockchain-9ced6472dbdf
*/
function _thisIsNotRandom() private returns(uint){
return uint(keccak256(abi.encodePacked(block.difficulty, now)));
}
}