-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathFlipCoin.sol
167 lines (141 loc) · 4.81 KB
/
FlipCoin.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Ownable} from "openzeppelin-solidity/contracts/access/Ownable.sol";
import {VRFConsumerBase} from "@bisonai/orakl-contracts/src/v0.1/VRFConsumerBase.sol";
import {IVRFCoordinator} from "@bisonai/orakl-contracts/src/v0.1/interfaces/IVRFCoordinator.sol";
contract FlipCoin is VRFConsumerBase, Ownable {
IVRFCoordinator COORDINATOR;
uint64 public accId;
bytes32 public keyHash;
uint32 public callbackGasLimit = 300_000;
uint256 public tax = 350; // basis points (3.5%)
uint256 public taxMax = 10_000; // basis points (100%)
uint256 public unclaimed = 0;
struct Player {
uint256 winCount;
uint256 totalCount;
uint256 balance;
}
struct Request {
address player;
uint256 bet;
uint256 betAmount;
uint result;
bool hasResult;
}
mapping(uint256 => Request) public requests;
mapping(address => Player) public players;
mapping(address => uint256[]) public bets;
event SetCoordinator(address setter, address newCoordinator);
event SetTax(address setter, uint256 tax);
event SetAccountId(uint64 accId);
event SetKeyHash(bytes32 keyHash);
event SetGasLimit(uint32 callbackGasLimit);
event Flip(
address player,
uint256 bet,
uint256 betAmount,
uint256 requestId
);
event Result(
address player,
uint256 requestId,
uint256 result,
uint256 randomResult
);
event Claim(address player, uint256 amount);
constructor(
uint64 _accountId,
address _coordinator,
bytes32 _keyHash
) VRFConsumerBase(_coordinator) {
COORDINATOR = IVRFCoordinator(_coordinator);
accId = _accountId;
keyHash = _keyHash;
}
function setAccountId(uint64 _accId) public onlyOwner {
accId = _accId;
emit SetAccountId(_accId);
}
function setTax(uint256 _tax) public onlyOwner {
require(_tax <= taxMax, "FlipCoin: Tax fee out of range");
tax = _tax;
emit SetTax(msg.sender, _tax);
}
function setKeyHash(bytes32 _keyHash) public onlyOwner {
keyHash = _keyHash;
emit SetKeyHash(_keyHash);
}
function setGasLimit(uint32 _callbackGasLimit) public onlyOwner {
callbackGasLimit = _callbackGasLimit;
emit SetGasLimit(_callbackGasLimit);
}
function flip(uint256 _bet) public payable {
uint256 fee_ = (msg.value * tax) / taxMax;
uint256 betAmount_ = msg.value - fee_;
unclaimed += betAmount_ * 2;
uint256 requiredBalance_ = unclaimed + fee_;
require(
address(this).balance >= requiredBalance_,
"FlipCoin: Insufficient contract balance"
);
uint256 requestId_ = requestRandomWords();
requests[requestId_].player = msg.sender;
requests[requestId_].bet = _bet;
requests[requestId_].betAmount = betAmount_;
players[msg.sender].totalCount += 1;
bets[msg.sender].push(requestId_);
emit Flip(msg.sender, _bet, betAmount_, requestId_);
}
function requestRandomWords() internal returns (uint256) {
return COORDINATOR.requestRandomWords(
keyHash,
accId,
callbackGasLimit,
1
);
}
function fulfillRandomWords(
uint256 _requestId,
uint256[] memory _randomWords
) internal override {
uint256 result_ = _randomWords[0] % 2;
requests[_requestId].result = result_;
requests[_requestId].hasResult = true;
uint256 bet_ = requests[_requestId].bet;
uint256 betAmount_ = requests[_requestId].betAmount;
address player_ = requests[_requestId].player;
if (bet_ == result_) {
// won
players[player_].winCount += 1;
players[player_].balance += betAmount_ * 2;
} else {
// lost
unclaimed -= betAmount_;
}
emit Result(player_, _requestId, result_, _randomWords[0]);
}
function claim() public {
Player storage player_ = players[msg.sender];
uint256 amount_ = player_.balance;
require(amount_ > 0, "FlipCoin: Insufficient player balance");
require(
unclaimed >= amount_,
"FlipCoin: Insufficient contract balance"
);
unclaimed -= amount_;
player_.balance = 0;
emit Claim(msg.sender, amount_);
payable(msg.sender).transfer(amount_);
}
function withdraw(uint256 _amount) public onlyOwner {
uint256 treasuryBalance_ = address(this).balance - unclaimed;
require(
treasuryBalance_ >= _amount,
"FlipCoin: Insufficient balance in contract"
);
payable(msg.sender).transfer(_amount);
}
// Receive remaining payment from requestRandomWords
receive() external payable {}
}