1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.6.6 ;
3
+
4
+ import "smartcontractkit/[email protected] /contracts/src/v0.6/VRFConsumerBase.sol " ;
5
+
6
+ /* Contract Guess Number
7
+ Contract should support multiple guess the number games.
8
+ Creator of games should risk an ammounts of tokens to start a new game.
9
+ A secret number is established during game creation by calling chainlink
10
+ The secret number should be between 1-100.
11
+ Each guess of the number in a game will cost an amount of tokens
12
+ Each game should allow only 10 guesses, once the tenth guess is made
13
+ the game will expire and the funds will go to the game creator.
14
+ Whoever makes the right guess will win the balance of the game.
15
+ Once the right guess is made a game should not allow people to play.
16
+ Once a game makes a payment 1% of the amount will go to the contract creator as a fee. */
17
+
18
+ contract GuessNumber is VRFConsumerBase {
19
+ using SafeMathChainlink for uint256 ;
20
+
21
+ uint256 private constant ROLL_IN_PROGRESS = 1000 ;
22
+ bytes32 private s_keyHash;
23
+ uint256 private s_fee;
24
+
25
+ event Dice_rolled (bytes32 indexed requestId , uint256 indexed roller );
26
+ event Game_created (address indexed owner , uint256 game_index , uint256 time );
27
+ event Game_served (bytes32 indexed requestId , uint256 indexed game_id );
28
+ event Game_solved (address indexed solver , uint256 game_index , uint256 time );
29
+ event Game_expired (address indexed creator , uint256 game_index , uint256 time );
30
+
31
+ struct game {
32
+ address game_owner;
33
+ uint256 secret_number;
34
+ uint256 game_balance;
35
+ uint256 guess_count;
36
+ bool is_active;
37
+ }
38
+
39
+ uint256 curr_id;
40
+
41
+ mapping (bytes32 => uint256 ) private rolls;
42
+ mapping (uint256 => game) game_index;
43
+
44
+ address payable contract_owner;
45
+
46
+ constructor (address vrfCoordinator , address link , bytes32 keyHash , uint256 fee )
47
+ public
48
+ VRFConsumerBase (vrfCoordinator, link)
49
+ {
50
+ s_keyHash = keyHash;
51
+ s_fee = fee;
52
+ contract_owner = msg .sender ;
53
+ curr_id = 0 ;
54
+ }
55
+
56
+ function create_game () public payable returns (bool ){
57
+ require (msg .value == 0.0001 * (10 ** 18 ), "You should pay 0.0001 tokens to create game " );
58
+ game_index[curr_id].game_owner = msg .sender ;
59
+ game_index[curr_id].game_balance = msg .value ;
60
+ game_index[curr_id].guess_count = 0 ;
61
+ rollDice (curr_id, curr_id+10 );
62
+ curr_id = curr_id + 1 ;
63
+ emit Game_created (msg .sender ,curr_id-1 , block .timestamp );
64
+ }
65
+
66
+ function rollDice (uint256 game_id , uint256 seed ) public returns (bytes32 requestId ) {
67
+ require (LINK.balanceOf (address (this )) >= s_fee, "Not enough LINK to pay fee " );
68
+ require (game_index[game_id].secret_number == 0 , "Already served " );
69
+ requestId = requestRandomness (s_keyHash, s_fee, seed);
70
+ rolls[requestId] = game_id;
71
+ game_index[game_id].secret_number = ROLL_IN_PROGRESS;
72
+ emit Dice_rolled (requestId, game_id);
73
+ }
74
+
75
+ function fulfillRandomness (bytes32 requestId , uint256 randomness ) internal override {
76
+ uint256 served_game = rolls[requestId];
77
+ uint256 d10Value = randomness.mod (100 ).add (1 );
78
+ game_index[served_game].secret_number = d10Value;
79
+ game_index[served_game].is_active = true ;
80
+ emit Game_served (requestId, served_game);
81
+ }
82
+
83
+ function play_game (uint256 game_id , uint256 guessed_number ) public payable returns (bool ) {
84
+ require (msg .value == 0.00001 * (10 ** 18 ), "you must payh 0.00001 tokens to play " );
85
+ require (guessed_number >= 1 && guessed_number<= 100 , "Guessed number should be within 1 to 100 " );
86
+ require (game_index[game_id].is_active == true );
87
+ game_index[game_id].game_balance = game_index[game_id].game_balance + msg .value ;
88
+ game_index[game_id].guess_count = game_index[game_id].guess_count + 1 ;
89
+ address payable player = payable (msg .sender );
90
+ address payable creator = payable (game_index[game_id].game_owner);
91
+ if (guessed_number == game_index[game_id].secret_number) {
92
+ player.transfer ((game_index[game_id].game_balance * 99 ) / 100 );
93
+ contract_owner.transfer (game_index[game_id].game_balance / 100 );
94
+ game_index[game_id].game_balance = 0 ;
95
+ game_index[game_id].is_active = false ;
96
+ emit Game_solved (msg .sender , game_id, block .timestamp );
97
+ }
98
+ else {
99
+ if (game_index[game_id].guess_count == 10 ){
100
+ creator.transfer ((game_index[game_id].game_balance * 99 ) / 100 );
101
+ contract_owner.transfer (game_index[game_id].game_balance / 100 );
102
+ game_index[game_id].game_balance = 0 ;
103
+ game_index[game_id].is_active = false ;
104
+ emit Game_expired (game_index[game_id].game_owner, game_id, block .timestamp );
105
+ }
106
+ }
107
+ }
108
+
109
+ function get_game_balance (uint256 game_id ) public view returns (uint256 ) {
110
+ return game_index[game_id].game_balance;
111
+ }
112
+
113
+ function get_game_guesses (uint256 game_id ) public view returns (uint256 ) {
114
+ return game_index[game_id].guess_count;
115
+ }
116
+
117
+ function is_game_active (uint game_id ) public view returns (bool ) {
118
+ return game_index[game_id].is_active;
119
+ }
120
+
121
+
122
+ // the functions below are for pure testing purposes these should be deleted to actually make this a dApp
123
+ function get_game_number_test (uint256 game_id ) public view returns (uint256 ) {
124
+ return game_index[game_id].secret_number;
125
+ }
126
+
127
+ function cancelGame (uint256 game_id ) public returns (bool ){
128
+ require (msg .sender == game_index[game_id].game_owner);
129
+ address payable creator = payable (msg .sender );
130
+ creator.transfer (game_index[game_id].game_balance);
131
+ game_index[game_id].game_balance = 0 ;
132
+ return true ;
133
+ }
134
+ }
0 commit comments