-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathRoulette.sol
185 lines (164 loc) · 5.58 KB
/
Roulette.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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import {Game} from "./Game.sol";
/// @title BetSwirl's Roulette game
/// @notice
/// @author Romuald Hog
contract Roulette is Game {
/// @notice Full roulette bet information struct.
/// @param bet The Bet struct information.
/// @param rouletteBet The Roulette bet struct information.
/// @dev Used to package bet information for the front-end.
struct FullRouletteBet {
Bet bet;
RouletteBet rouletteBet;
}
/// @notice Roulette bet information struct.
/// @param bet The Bet struct information.
/// @param numbers The chosen numbers.
struct RouletteBet {
uint40 numbers;
uint8 rolled;
}
uint8 private constant MODULO = 37;
uint256 private constant POPCNT_MULT =
0x0000000000002000000000100000000008000000000400000000020000000001;
uint256 private constant POPCNT_MASK =
0x0001041041041041041041041041041041041041041041041041041041041041;
uint256 private constant POPCNT_MODULO = 0x3F;
/// @notice Maps bets IDs to chosen numbers.
mapping(uint256 => RouletteBet) public rouletteBets;
/// @notice Emitted after a bet is placed.
/// @param id The bet ID.
/// @param user Address of the gamer.
/// @param token Address of the token.
/// @param amount The bet amount.
/// @param vrfCost The Chainlink VRF cost paid by player.
/// @param numbers The chosen numbers.
event PlaceBet(
uint256 id,
address indexed user,
address indexed token,
uint256 amount,
uint256 vrfCost,
uint40 numbers
);
/// @notice Emitted after a bet is rolled.
/// @param id The bet ID.
/// @param user Address of the gamer.
/// @param token Address of the token.
/// @param amount The bet amount.
/// @param numbers The chosen numbers.
/// @param rolled The rolled number.
/// @param payout The payout amount.
event Roll(
uint256 id,
address indexed user,
address indexed token,
uint256 amount,
uint40 numbers,
uint8 rolled,
uint256 payout
);
/// @notice Provided cap is under the minimum.
error NumbersNotInRange();
/// @notice Initialize the game base contract.
/// @param bankAddress The address of the bank.
/// @param chainlinkCoordinatorAddress Address of the Chainlink VRF Coordinator.
/// @param LINK_ETH_feedAddress Address of the Chainlink LINK/ETH price feed.
constructor(
address bankAddress,
address chainlinkCoordinatorAddress,
address LINK_ETH_feedAddress
) Game(bankAddress, chainlinkCoordinatorAddress, 1, LINK_ETH_feedAddress) {}
/// @notice Calculates the target payout amount.
/// @param betAmount Bet amount.
/// @param numbers The chosen numbers.
/// @return The target payout amount.
function _getPayout(uint256 betAmount, uint40 numbers)
private
pure
returns (uint256)
{
return
(betAmount * MODULO) /
(((numbers * POPCNT_MULT) & POPCNT_MASK) % POPCNT_MODULO);
}
/// @notice Creates a new bet and stores the chosen bet mask.
/// @param numbers The chosen numbers.
/// @param token Address of the token.
/// @param tokenAmount The number of tokens bet.
function wager(
uint40 numbers,
address token,
uint256 tokenAmount
) external payable whenNotPaused {
if (numbers == 0 || numbers >= 2**MODULO - 1) {
revert NumbersNotInRange();
}
Bet memory bet = _newBet(
token,
tokenAmount,
_getPayout(10000, numbers)
);
rouletteBets[bet.id].numbers = numbers;
emit PlaceBet(
bet.id,
bet.user,
bet.token,
bet.amount,
bet.vrfCost,
numbers
);
}
/// @notice Resolves the bet using the Chainlink randomness.
/// @param id The bet ID.
/// @param randomWords Random words list. Contains only one for this game.
// solhint-disable-next-line private-vars-leading-underscore
function fulfillRandomWords(uint256 id, uint256[] memory randomWords)
internal
override
{
uint256 startGas = gasleft();
RouletteBet storage rouletteBet = rouletteBets[id];
Bet storage bet = bets[id];
uint8 rolled = uint8(randomWords[0] % MODULO);
rouletteBet.rolled = rolled;
uint256 payout = _resolveBet(
bet,
(2**rolled) & rouletteBet.numbers != 0 ?
_getPayout(bet.amount, rouletteBet.numbers) : 0
);
emit Roll(
bet.id,
bet.user,
bet.token,
bet.amount,
rouletteBet.numbers,
rolled,
payout
);
_accountVRFCost(bet, startGas);
}
/// @notice Gets the list of the last user bets.
/// @param user Address of the gamer.
/// @param dataLength The amount of bets to return.
/// @return A list of Roulette bet.
function getLastUserBets(address user, uint256 dataLength)
external
view
returns (FullRouletteBet[] memory)
{
Bet[] memory lastBets = _getLastUserBets(user, dataLength);
FullRouletteBet[] memory lastRouletteBets = new FullRouletteBet[](
lastBets.length
);
for (uint256 i; i < lastBets.length; i++) {
lastRouletteBets[i] = FullRouletteBet(
lastBets[i],
rouletteBets[lastBets[i].id]
);
}
return lastRouletteBets;
}
}