// ╔══╗╔═══╗╔╗╔╗╔═══╗╔════╗╔══╗╔═══╗╔══╗╔╗──╔╗╔═══╗──╔══╗─╔═══╗╔════╗
// ║╔═╝║╔═╗║║║║║║╔═╗║╚═╗╔═╝║╔╗║║╔══╝║╔╗║║║──║║║╔══╝──║╔╗║─║╔══╝╚═╗╔═╝
// ║║──║╚═╝║║╚╝║║╚═╝║──║║──║║║║║║╔═╗║╚╝║║╚╗╔╝║║╚══╗──║╚╝╚╗║╚══╗──║║
// ║║──║╔╗╔╝╚═╗║║╔══╝──║║──║║║║║║╚╗║║╔╗║║╔╗╔╗║║╔══╝──║╔═╗║║╔══╝──║║
// ║╚═╗║║║║──╔╝║║║─────║║──║╚╝║║╚═╝║║║║║║║╚╝║║║╚══╗╔╗║╚═╝║║╚══╗──║║
// ╚══╝╚╝╚╝──╚═╝╚╝─────╚╝──╚══╝╚═══╝╚╝╚╝╚╝──╚╝╚═══╝╚╝╚═══╝╚═══╝──╚╝
//By playing platform games you agree that your age is over 21 and you clearly understand that you can lose your coins
//The platform is not responsible for all Ethereum cryptocurrency losses during the game.
//The contract uses the entropy algorithm Signidice
//https://github.com/gluk256/misc/blob/master/rng4ethereum/signidice.md
pragma solidity 0.5.16;
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a / b;
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b; assert(c >= a);
return c;
}
}
contract CryptoGames {
using SafeMath for uint;
address payable public owner = 0x333333e25F2176e2e165Aeb1b933cE10Cf315b47;
address public CROUPIER_BOB = 0xB0B3336c83A4c86FBd4f804BB8D410B23F181b05;
uint public minStake = 0.01 ether;
uint public maxStake = 15 ether;
uint public constant WIN_COEFFICIENT = 198;
uint public constant DICE_COEFFICIENT = 600;
mapping(address => uint) public deposit;
mapping(address => uint) public withdrawal;
bool status = true;
enum GameState {
Pending,
Win,
Lose,
Draw
}
enum Games {
CoinFlip,
KNB,
Dice
}
struct Game {
Games game_title;
address payable player;
uint bet;
bytes32 seed;
GameState state;
uint result;
bytes choice;
uint profit;
}
event NewGame(address indexed player, bytes32 seed, uint bet, bytes choice, string game);
event DemoGame(address indexed player, bytes32 seed, uint bet, bytes choice, string game);
event ConfirmGame(address indexed player, string game, uint profit, bytes choice, uint game_choice, bytes32 seed, bool status, bool draw, uint timestamp);
event Deposit(address indexed from, uint indexed block, uint value, uint time);
event Withdrawal(address indexed from, uint indexed block, uint value, uint ident,uint time);
mapping(bytes32 => Game) public listGames;
// Only our croupier and no one else can open the bet
modifier onlyCroupier() {
require(msg.sender == CROUPIER_BOB);
_;
}
// Check that the rate is between 0.01 - 15 ether
modifier betInRange() {
require(minStake <= msg.value && msg.value <= maxStake);
_;
}
modifier onlyOwner {
require(msg.sender == owner); _;
}
modifier isNotContract() {
uint size;
address addr = msg.sender;
assembly { size := extcodesize(addr) }
require(size == 0 && tx.origin == msg.sender);
_;
}
modifier contractIsOn() {
require(status);
_;
}
// Game CoinFlip
// The game of tossing a coin, the coin has 2 sides,
// an eagle and a tails, which one is up to you to choose
function game_coin(bytes memory _choice, bytes32 seed) public betInRange payable returns(uint8) {
string memory game_title = 'CoinFlip';
uint8 user_choice;
assembly {user_choice := mload(add(0x1, _choice))}
require(listGames[seed].bet == 0x0);
require(_choice.length == 1);
require(user_choice == 0 || user_choice == 1);
listGames[seed] = Game({
game_title: Games.CoinFlip,
player: msg.sender,
bet: msg.value,
seed: seed,
state: GameState.Pending,
choice: _choice,
result: 0,
profit: 0
});
emit NewGame(msg.sender, seed, msg.value, _choice, game_title);
return user_choice;
}
// Game KNB
// Game of stone, scissors, paper
// The stone breaks the scissors, the scissors cut the paper, the paper wraps the stone.
// Everything is just kk in childhood, it remains only to try to play
function game_knb(bytes memory _choice, bytes32 seed) public betInRange payable {
string memory game_title = 'KNB';
uint8 user_choice;
assembly {user_choice := mload(add(0x1, _choice))}
require(listGames[seed].bet == 0x0);
require(_choice.length == 1);
//Checking that bids are in the right range
//1 - stone, 2 - scissors, 3 - paper
require(user_choice >=1 && user_choice <=3);
listGames[seed] = Game({
game_title: Games.KNB,
player: msg.sender,
bet: msg.value,
seed: seed,
state: GameState.Pending,
choice: _choice,
result: 0,
profit: 0
});
emit NewGame(msg.sender, seed, msg.value, _choice, game_title);
}
// Game Dice
// Playing dice, the player can select up to 5 dice values at a time. The more dice a player chooses, the less his final reward.
// The reward is calculated according to the formula: (6 / number of selected cubes) * bet
function game_dice(bytes memory _choice, bytes32 seed) public betInRange payable {
string memory game_title = 'Dice';
require(listGames[seed].bet == 0x0);
//Checking that bids are in the right range, and no more than 5 cubes are selected
require(_choice.length >= 1 && _choice.length <= 5);
// for(uint i=0; i< _choice.length; i++){
// require(_choice[i] > 0 && _choice[i] < 7);
// }
listGames[seed] = Game({
game_title: Games.Dice,
player: msg.sender,
bet: msg.value,
seed: seed,
state: GameState.Pending,
choice: _choice,
result: 0,
profit: 0
});
emit NewGame(msg.sender, seed, msg.value, _choice, game_title);
}
//Casino must sign the resulting value V with its PrivKey, thus producing the digital signature S = sign(PrivKey, V), and send the corresponding TX, containing S.
//The contract recovers the actual public key (K) from the digital signature S, and verifies that it is equal to the previously published PubKey (K == PubKey).
//If APK does not match PubKey, it is tantamount to cheating. In this case, the contract simply rejects the transaction.
//The contract uses S as a seed for the predefined PRNG algorithm (e.g. SHA-3 based), which produces the lucky number (L), e.g. between 1 and 6.
function confirm(bytes32 seed, uint8 _v, bytes32 _r, bytes32 _s) public onlyCroupier {
// Checking that it was Uncle Bob who signed the transaction, otherwise we reject the impostor transaction
require (ecrecover(seed, _v, _r, _s) == CROUPIER_BOB);
Game storage game = listGames[seed];
bytes memory choice = game.choice;
game.result = uint256(_s) % 12;
uint profit = 0;
uint8 user_choice;
//Our algorithms are very simple and understandable even to the average Internet user and do not need additional explanation
//Coin game algorithm
if (game.game_title == Games.CoinFlip){
assembly {user_choice := mload(add(0x1, choice))}
if(game.result == user_choice){
profit = game.bet.mul(WIN_COEFFICIENT).div(100);
game.state = GameState.Win;
game.profit = profit;
game.player.transfer(profit);
emit ConfirmGame(game.player, 'CoinFlip', profit, game.choice, game.result, game.seed, true, false, now);
}else{
game.state = GameState.Lose;
emit ConfirmGame(game.player, 'CoinFlip', 0, game.choice, game.result, game.seed, false, false, now);
}
//KNB game algorithm
}else if(game.game_title == Games.KNB){
assembly {user_choice := mload(add(0x1, choice))}
if(game.result != user_choice){
if (user_choice == 1 && game.result == 2 || user_choice == 2 && game.result == 3 || user_choice == 3 && game.result == 1) {
profit = game.bet.mul(WIN_COEFFICIENT).div(100);
game.state = GameState.Win;
game.profit = profit;
game.player.transfer(profit);
emit ConfirmGame(game.player, 'KNB', profit, game.choice, game.result, game.seed, true, false, now);
}else{
game.state = GameState.Lose;
emit ConfirmGame(game.player, 'KNB', 0, game.choice, game.result, game.seed, false, false, now);
}
}else{
profit = game.bet.sub(0.001 ether);
game.player.transfer(profit);
game.state = GameState.Draw;
emit ConfirmGame(game.player, 'KNB', profit, game.choice, game.result, game.seed, false, true, now);
}
//Dice game algorithm
}else if(game.game_title == Games.Dice){
uint length = game.choice.length + 1;
for(uint8 i=1; i< length; i++){
assembly {user_choice := mload(add(i, choice))}
if (user_choice == game.result){
profit = game.bet.mul(DICE_COEFFICIENT.div(game.choice.length)).div(100);
}
}
if(profit > 0){
game.state = GameState.Win;
game.profit = profit;
game.player.transfer(profit);
emit ConfirmGame(game.player, 'Dice', profit, game.choice, game.result, game.seed, true, false, now);
}else{
game.state = GameState.Lose;
emit ConfirmGame(game.player, 'Dice', 0, game.choice, game.result, game.seed, false, false, now);
}
}
}
// Demo game, 0 ether value. To reduce the cost of the game, we calculate a random result on the server
function demo_game(string memory game, bytes memory _choice, bytes32 seed, uint bet) public {
emit DemoGame(msg.sender, seed, bet, _choice, game);
}
function get_player_choice(bytes32 seed) public view returns(bytes memory) {
Game storage game = listGames[seed];
return game.choice;
}
//The casino has its own expenses for maintaining the servers, paying for them, each signature by our bot Bob costs 0.00135 ether
//and we honestly believe that the money that players own is ours, everyone can try their luck and play with us
function pay_royalty (uint _value) onlyOwner public {
owner.transfer(_value * 1 ether);
}
//automatic withdrawal using server bot
function multisend(address payable[] memory dests, uint256[] memory values, uint256[] memory ident) onlyOwner contractIsOn public returns(uint) {
uint256 i = 0;
while (i < dests.length) {
uint transfer_value = values[i].sub(values[i].mul(3).div(100));
dests[i].transfer(transfer_value);
withdrawal[dests[i]]+=values[i];
emit Withdrawal(dests[i], block.number, values[i], ident[i], now);
i += 1;
}
return(i);
}
function startProphylaxy()onlyOwner public {
status = false;
}
function stopProphylaxy()onlyOwner public {
status = true;
}
// recharge function for games
function() external isNotContract contractIsOn betInRange payable {
deposit[msg.sender]+= msg.value;
emit Deposit(msg.sender, block.number, msg.value, now);
}
}
//P̴̩͖͈̳o̷̡̳̭̞͔̺̩̩w̸̡̡̡̤̹͙͔̜̮̟̺̬̰͔͉͉͎͉̠̝͜ͅe̵̜̤̹ŗ̶̹̞̰̭̹̭̻̤͔͈͓͉ę̵̡͉͚̲̞̘͙̥̳͇͓̭ḑ̷̞̰̯̭͚͎̣͔̜̝̬͜ͅͅ ̵̣̲b̷̢͙͈̣̝̩͔͉͖y̷̢̱̠̙̘̹̟̠̙͖͍̹̦͍ͅ ̵̡̢̠̗͎͍͕̯̹͈͈̬̹c̷̢̪̪͎̺̠̤̮̙̜̞͈̞̝̭̭r̸̥̯̩̩̝̟͉̲̪̣̬̟̮̤̲̜y̵̗̬͓͎̻̱̝̗͕̟͙̯͇̜̤̲͔̭̫͓p̸̢͇͇̠̪t̵̹̳̮͇͜ǫ̸̙̬ͅͅģ̵̹̬͉̫̣͔̝̳̘̰̘̤̮a̸̡͖̮͙̯̬̰̫̫̘͎͎̰͇̹̜̼̥͚͇͉͔͚͓m̸̢̫̙̫̮̪͕̭̟̬̣̟̫̦͙̖ȩ̸̡̧̟̰̯͖̲͍̳͚̘̦͎̙̥̫͎̺̤̮͜ͅ.̴̨̱̲͚b̸͍͔e̶̡̡̡̜̬͓̤̣͍̝͚͖̘͈̱̘̲̠͓͍͙͉̯͍t̵̻̮
//
//
{
"compilationTarget": {
"CryptoGames.sol": "CryptoGames"
},
"evmVersion": "istanbul",
"libraries": {},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"string","name":"game","type":"string"},{"indexed":false,"internalType":"uint256","name":"profit","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"choice","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"game_choice","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"seed","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"},{"indexed":false,"internalType":"bool","name":"draw","type":"bool"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"ConfirmGame","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"bytes32","name":"seed","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"bet","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"choice","type":"bytes"},{"indexed":false,"internalType":"string","name":"game","type":"string"}],"name":"DemoGame","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"uint256","name":"block","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"bytes32","name":"seed","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"bet","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"choice","type":"bytes"},{"indexed":false,"internalType":"string","name":"game","type":"string"}],"name":"NewGame","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"uint256","name":"block","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ident","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"Withdrawal","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[],"name":"CROUPIER_BOB","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DICE_COEFFICIENT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"WIN_COEFFICIENT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"seed","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"confirm","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"game","type":"string"},{"internalType":"bytes","name":"_choice","type":"bytes"},{"internalType":"bytes32","name":"seed","type":"bytes32"},{"internalType":"uint256","name":"bet","type":"uint256"}],"name":"demo_game","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"_choice","type":"bytes"},{"internalType":"bytes32","name":"seed","type":"bytes32"}],"name":"game_coin","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"_choice","type":"bytes"},{"internalType":"bytes32","name":"seed","type":"bytes32"}],"name":"game_dice","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"_choice","type":"bytes"},{"internalType":"bytes32","name":"seed","type":"bytes32"}],"name":"game_knb","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"seed","type":"bytes32"}],"name":"get_player_choice","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"listGames","outputs":[{"internalType":"enum CryptoGames.Games","name":"game_title","type":"uint8"},{"internalType":"address payable","name":"player","type":"address"},{"internalType":"uint256","name":"bet","type":"uint256"},{"internalType":"bytes32","name":"seed","type":"bytes32"},{"internalType":"enum CryptoGames.GameState","name":"state","type":"uint8"},{"internalType":"uint256","name":"result","type":"uint256"},{"internalType":"bytes","name":"choice","type":"bytes"},{"internalType":"uint256","name":"profit","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable[]","name":"dests","type":"address[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"uint256[]","name":"ident","type":"uint256[]"}],"name":"multisend","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"pay_royalty","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"startProphylaxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"stopProphylaxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"withdrawal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]