pragma solidity ^0.4.24;
/*
* ZETHR PRESENTS: SLOTS
*
* Written August 2018 by the Zethr team for zethr.io.
*
* Code framework written by Norsefire.
* EV calculations written by TropicalRogue.
* Audit and edits written by Klob.
* Multiroll framework written by Etherguy.
*
* Rolling Odds:
* 49.31% Lose / 50.69% Win
* 35.64% Two Matching Icons
* - 10.00% : 2.50x Multiplier [Two Rockets]
* - 15.00% : 1.33x Multiplier [Two Gold Pyramids]
* - 15.00% : 1.00x Multiplier [Two 'Z' Symbols]
* - 15.00% : 1.00x Multiplier [Two 'T' Symbols]
* - 15.00% : 1.00x Multiplier [Two 'H' Symbols]
* - 15.00% : 1.25x Multiplier [Two Purple Pyramids]
* - 15.00% : 2.00x Multiplier [Two Ether Icons]
* 6.79% One Of Each Pyramid
* - 1.50x Multiplier
* 2.94% One Moon Icon
* - 2.50x Multiplier
* 5.00% Three Matching Icons
* - 03.00% : 13.00x Multiplier [Three Rockets]
* - 05.00% : 09.00x Multiplier [Three Gold Pyramids]
* - 27.67% : 03.00x Multiplier [Three 'Z' Symbols]
* - 27.67% : 03.00x Multiplier [Three 'T' Symbols]
* - 27.67% : 03.00x Multiplier [Three 'H' Symbols]
* - 05.00% : 07.50x Multiplier [Three Purple Pyramids]
* - 04.00% : 11.00x Multiplier [Three Ether Icons]
* 0.28% Z T H Prize
* - 20x Multiplier
* 0.03% Two Moon Icons
* - 50x Multiplier
* 0.0001% Three Moon Grand Jackpot
* - Jackpot Amount (variable)
*
* From all of us at Zethr, thank you for playing!
*
*/
// Zethr Token Bankroll interface
contract ZethrTokenBankroll{
// Game request token transfer to player
function gameRequestTokens(address target, uint tokens) public;
function gameTokenAmount(address what) public returns (uint);
}
// Zether Main Bankroll interface
contract ZethrMainBankroll{
function gameGetTokenBankrollList() public view returns (address[7]);
}
// Zethr main contract interface
contract ZethrInterface{
function withdraw() public;
}
// Library for figuring out the "tier" (1-7) of a dividend rate
library ZethrTierLibrary{
function getTier(uint divRate)
internal
pure
returns (uint)
{
// Tier logic
// Returns the index of the UsedBankrollAddresses which should be used to call into to withdraw tokens
// We can divide by magnitude
// Remainder is removed so we only get the actual number we want
uint actualDiv = divRate;
if (actualDiv >= 30){
return 6;
} else if (actualDiv >= 25){
return 5;
} else if (actualDiv >= 20){
return 4;
} else if (actualDiv >= 15){
return 3;
} else if (actualDiv >= 10){
return 2;
} else if (actualDiv >= 5){
return 1;
} else if (actualDiv >= 2){
return 0;
} else{
// Impossible
revert();
}
}
}
// Contract that contains the functions to interact with the ZlotsJackpotHoldingContract
contract ZlotsJackpotHoldingContract {
function payOutWinner(address winner) public;
function getJackpot() public view returns (uint);
}
// Contract that contains the functions to interact with the bankroll system
contract ZethrBankrollBridge {
// Must have an interface with the main Zethr token contract
ZethrInterface Zethr;
// Store the bankroll addresses
// address[0] is tier1: 2-5%
// address[1] is tier2: 5-10, etc
address[7] UsedBankrollAddresses;
// Mapping for easy checking
mapping(address => bool) ValidBankrollAddress;
// Set up the tokenbankroll stuff
function setupBankrollInterface(address ZethrMainBankrollAddress)
internal
{
// Instantiate Zethr
Zethr = ZethrInterface(0xD48B633045af65fF636F3c6edd744748351E020D);
// Get the bankroll addresses from the main bankroll
UsedBankrollAddresses = ZethrMainBankroll(ZethrMainBankrollAddress).gameGetTokenBankrollList();
for(uint i=0; i<7; i++){
ValidBankrollAddress[UsedBankrollAddresses[i]] = true;
}
}
// Require a function to be called from a *token* bankroll
modifier fromBankroll() {
require(ValidBankrollAddress[msg.sender], "msg.sender should be a valid bankroll");
_;
}
// Request a payment in tokens to a user FROM the appropriate tokenBankroll
// Figure out the right bankroll via divRate
function RequestBankrollPayment(address to, uint tokens, uint tier)
internal
{
address tokenBankrollAddress = UsedBankrollAddresses[tier];
ZethrTokenBankroll(tokenBankrollAddress).gameRequestTokens(to, tokens);
}
function getZethrTokenBankroll(uint divRate)
public
constant
returns (ZethrTokenBankroll)
{
return ZethrTokenBankroll(UsedBankrollAddresses[ZethrTierLibrary.getTier(divRate)]);
}
}
// Contract that contains functions to move divs to the main bankroll
contract ZethrShell is ZethrBankrollBridge {
// Dump ETH balance to main bankroll
function WithdrawToBankroll()
public
{
address(UsedBankrollAddresses[0]).transfer(address(this).balance);
}
// Dump divs and dump ETH into bankroll
function WithdrawAndTransferToBankroll()
public
{
Zethr.withdraw();
WithdrawToBankroll();
}
}
// Zethr game data setup
// Includes all necessary to run with Zethr
contract ZlotsMulti is ZethrShell {
using SafeMath for uint;
// ---------------------- Events
// Might as well notify everyone when the house takes its cut out.
event HouseRetrievedTake(
uint timeTaken,
uint tokensWithdrawn
);
// Fire an event whenever someone places a bet.
event TokensWagered(
address _wagerer,
uint _wagered
);
event LogResult(
address _wagerer,
uint _result,
uint _profit,
uint _wagered,
uint _category,
bool _win
);
// Result announcement events (to dictate UI output!)
event Loss(address _wagerer, uint _block); // Category 0
event ThreeMoonJackpot(address _wagerer, uint _block); // Category 1
event TwoMoonPrize(address _wagerer, uint _block); // Category 2
event ZTHPrize(address _wagerer, uint _block); // Category 3
event ThreeZSymbols(address _wagerer, uint _block); // Category 4
event ThreeTSymbols(address _wagerer, uint _block); // Category 5
event ThreeHSymbols(address _wagerer, uint _block); // Category 6
event ThreeEtherIcons(address _wagerer, uint _block); // Category 7
event ThreePurplePyramids(address _wagerer, uint _block); // Category 8
event ThreeGoldPyramids(address _wagerer, uint _block); // Category 9
event ThreeRockets(address _wagerer, uint _block); // Category 10
event OneMoonPrize(address _wagerer, uint _block); // Category 11
event OneOfEachPyramidPrize(address _wagerer, uint _block); // Category 12
event TwoZSymbols(address _wagerer, uint _block); // Category 13
event TwoTSymbols(address _wagerer, uint _block); // Category 14
event TwoHSymbols(address _wagerer, uint _block); // Category 15
event TwoEtherIcons(address _wagerer, uint _block); // Category 16
event TwoPurplePyramids(address _wagerer, uint _block); // Category 17
event TwoGoldPyramids(address _wagerer, uint _block); // Category 18
event TwoRockets(address _wagerer, uint _block); // Category 19
event SpinConcluded(address _wagerer, uint _block); // Debug event
// ---------------------- Modifiers
// Makes sure that player porfit can't exceed a maximum amount
// We use the max win here - 50x
modifier betIsValid(uint _betSize, uint divRate, uint8 spins) {
require(_betSize.div(spins).mul(50) <= getMaxProfit(divRate));
require(_betSize.div(spins) >= minBet);
_;
}
// Requires the game to be currently active
modifier gameIsActive {
require(gamePaused == false);
_;
}
// Require msg.sender to be owner
modifier onlyOwner {
require(msg.sender == owner);
_;
}
// Requires msg.sender to be bankroll
modifier onlyBankroll {
require(msg.sender == bankroll);
_;
}
// Requires msg.sender to be owner or bankroll
modifier onlyOwnerOrBankroll {
require(msg.sender == owner || msg.sender == bankroll);
_;
}
// ---------------------- Variables
// Configurables
uint constant public maxProfitDivisor = 1000000;
uint constant public houseEdgeDivisor = 1000;
mapping (uint => uint) public maxProfit;
uint public maxProfitAsPercentOfHouse;
uint public minBet = 1e18;
address public zlotsJackpot;
address private owner;
address private bankroll;
bool gamePaused;
// Trackers
uint public totalSpins;
uint public totalZTHWagered;
mapping (uint => uint) public contractBalance;
// Is betting allowed? (Administrative function, in the event of unforeseen bugs)
bool public gameActive;
// Bankroll & token addresses
address private ZTHTKNADDR;
address private ZTHBANKROLL;
// ---------------------- Functions
// Constructor; must supply bankroll address
constructor(address BankrollAddress)
public
{
// Set up the bankroll interface
setupBankrollInterface(BankrollAddress);
// Owner is deployer
owner = msg.sender;
// Default max profit to 5% of contract balance
ownerSetMaxProfitAsPercentOfHouse(50000);
// Set starting variables
bankroll = ZTHBANKROLL;
gameActive = true;
// Init min bet (1 ZTH)
ownerSetMinBet(1e18);
}
// Zethr dividends gained are accumulated and sent to bankroll manually
function() public payable { }
// If the contract receives tokens, bundle them up in a struct and fire them over to _spinTokens for validation.
struct TKN { address sender; uint value; }
function execute(address _from, uint _value, uint divRate, bytes _data)
public
fromBankroll
returns (bool)
{
TKN memory _tkn;
_tkn.sender = _from;
_tkn.value = _value;
_spinTokens(_tkn, divRate, uint8(_data[0]));
return true;
}
struct playerSpin {
uint192 tokenValue; // Token value in uint
uint48 blockn; // Block number 48 bits
uint8 tier;
uint8 spins;
uint divRate;
}
// Mapping because a player can do one spin at a time
mapping(address => playerSpin) public playerSpins;
// Execute spin.
function _spinTokens(TKN _tkn, uint divRate, uint8 spins)
private
betIsValid(_tkn.value, divRate, spins)
{
require(gameActive);
require(block.number <= ((2 ** 48) - 1)); // Current block number smaller than storage of 1 uint56
require(_tkn.value <= ((2 ** 192) - 1));
address _customerAddress = _tkn.sender;
uint _wagered = _tkn.value;
playerSpin memory spin = playerSpins[_tkn.sender];
// We update the contract balance *before* the spin is over, not after
// This means that we don't have to worry about unresolved rolls never resolving
// (we also update it when a player wins)
addContractBalance(divRate, _wagered);
// Cannot spin twice in one block
require(block.number != spin.blockn);
// If there exists a spin, finish it
if (spin.blockn != 0) {
_finishSpin(_tkn.sender);
}
// Set struct block number and token value
spin.blockn = uint48(block.number);
spin.tokenValue = uint192(_wagered.div(spins));
spin.tier = uint8(ZethrTierLibrary.getTier(divRate));
spin.divRate = divRate;
spin.spins = spins;
// Store the roll struct - 40k gas.
playerSpins[_tkn.sender] = spin;
// Increment total number of spins
totalSpins += spins;
// Total wagered
totalZTHWagered += _wagered;
emit TokensWagered(_customerAddress, _wagered);
}
// Finish the current spin of a player, if they have one
function finishSpin()
public
gameIsActive
returns (uint[])
{
return _finishSpin(msg.sender);
}
// Stores the data for the roll (spin)
struct rollData {
uint win;
uint loss;
uint jp;
}
// Pay winners, update contract balance, send rewards where applicable.
function _finishSpin(address target)
private
returns (uint[])
{
playerSpin memory spin = playerSpins[target];
require(spin.tokenValue > 0); // No re-entrancy
require(spin.blockn != block.number);
uint[] memory output = new uint[](spin.spins);
rollData memory outcomeTrack = rollData(0,0,0);
uint category = 0;
uint profit;
uint playerDivrate = spin.divRate;
for(uint i=0; i<spin.spins; i++) {
// If the block is more than 255 blocks old, we can't get the result
// Also, if the result has already happened, fail as well
uint result;
if (block.number - spin.blockn > 255) {
result = 1000000; // Can't win: default to largest number
output[i] = 1000000;
} else {
// Generate a result - random based ONLY on a past block (future when submitted).
// Case statement barrier numbers defined by the current payment schema at the top of the contract.
result = random(1000000, spin.blockn, target, i) + 1;
output[i] = result;
}
if (result > 506856) {
// Player has lost. Womp womp.
// Add one percent of player loss to the jackpot
// (do this by requesting a payout to the jackpot)
outcomeTrack.loss += spin.tokenValue/100;
emit Loss(target, spin.blockn);
emit LogResult(target, result, profit, spin.tokenValue, category, false);
} else if (result < 2) {
// Player has won the three-moon mega jackpot!
// Get profit amount via jackpot
profit = ZlotsJackpotHoldingContract(zlotsJackpot).getJackpot();
category = 1;
// Emit events
emit ThreeMoonJackpot(target, spin.blockn);
emit LogResult(target, result, profit, spin.tokenValue, category, true);
outcomeTrack.jp += 1;
} else {
if (result < 299) {
// Player has won a two-moon prize!
profit = SafeMath.mul(spin.tokenValue, 50);
category = 2;
emit TwoMoonPrize(target, spin.blockn);
} else if (result < 3128) {
// Player has won the Z T H prize!
profit = SafeMath.mul(spin.tokenValue, 20);
category = 3;
emit ZTHPrize(target, spin.blockn);
} else if (result < 16961) {
// Player has won a three Z symbol prize!
profit = SafeMath.div(SafeMath.mul(spin.tokenValue, 30), 10);
category = 4;
emit ThreeZSymbols(target, spin.blockn);
} else if (result < 30794) {
// Player has won a three T symbol prize!
profit = SafeMath.div(SafeMath.mul(spin.tokenValue, 30), 10);
category = 5;
emit ThreeTSymbols(target, spin.blockn);
} else if (result < 44627) {
// Player has won a three H symbol prize!
profit = SafeMath.div(SafeMath.mul(spin.tokenValue, 30), 10);
category = 6;
emit ThreeHSymbols(target, spin.blockn);
} else if (result < 46627) {
// Player has won a three Ether icon prize!
profit = SafeMath.mul(spin.tokenValue, 11);
category = 7;
emit ThreeEtherIcons(target, spin.blockn);
} else if (result < 49127) {
// Player has won a three purple pyramid prize!
profit = SafeMath.div(SafeMath.mul(spin.tokenValue, 75), 10);
category = 8;
emit ThreePurplePyramids(target, spin.blockn);
} else if (result < 51627) {
// Player has won a three gold pyramid prize!
profit = SafeMath.mul(spin.tokenValue, 9);
category = 9;
emit ThreeGoldPyramids(target, spin.blockn);
} else if (result < 53127) {
// Player has won a three rocket prize!
profit = SafeMath.mul(spin.tokenValue, 13);
category = 10;
emit ThreeRockets(target, spin.blockn);
} else if (result < 82530) {
// Player has won a one moon prize!
profit = SafeMath.div(SafeMath.mul(spin.tokenValue, 25),10);
category = 11;
emit OneMoonPrize(target, spin.blockn);
} else if (result < 150423) {
// Player has won a each-coloured-pyramid prize!
profit = SafeMath.div(SafeMath.mul(spin.tokenValue, 15),10);
category = 12;
emit OneOfEachPyramidPrize(target, spin.blockn);
} else if (result < 203888) {
// Player has won a two Z symbol prize!
profit = spin.tokenValue;
category = 13;
emit TwoZSymbols(target, spin.blockn);
} else if (result < 257353) {
// Player has won a two T symbol prize!
profit = spin.tokenValue;
category = 14;
emit TwoTSymbols(target, spin.blockn);
} else if (result < 310818) {
// Player has won a two H symbol prize!
profit = spin.tokenValue;
category = 15;
emit TwoHSymbols(target, spin.blockn);
} else if (result < 364283) {
// Player has won a two Ether icon prize!
profit = SafeMath.mul(spin.tokenValue, 2);
category = 16;
emit TwoEtherIcons(target, spin.blockn);
} else if (result < 417748) {
// Player has won a two purple pyramid prize!
profit = SafeMath.div(SafeMath.mul(spin.tokenValue, 125), 100);
category = 17;
emit TwoPurplePyramids(target, spin.blockn);
} else if (result < 471213) {
// Player has won a two gold pyramid prize!
profit = SafeMath.div(SafeMath.mul(spin.tokenValue, 133), 100);
category = 18;
emit TwoGoldPyramids(target, spin.blockn);
} else {
// Player has won a two rocket prize!
profit = SafeMath.div(SafeMath.mul(spin.tokenValue, 25), 10);
category = 19;
emit TwoRockets(target, spin.blockn);
}
uint newMaxProfit = getNewMaxProfit(playerDivrate, outcomeTrack.win);
if (profit > newMaxProfit){
profit = newMaxProfit;
}
emit LogResult(target, result, profit, spin.tokenValue, category, true);
outcomeTrack.win += profit;
}
}
playerSpins[target] = playerSpin(uint192(0), uint48(0), uint8(0), uint8(0), uint(0));
if (outcomeTrack.jp > 0) {
for (i = 0; i < outcomeTrack.jp; i++) {
// In the weird case a player wins two jackpots, we of course pay them twice
ZlotsJackpotHoldingContract(zlotsJackpot).payOutWinner(target);
}
}
if (outcomeTrack.win > 0) {
RequestBankrollPayment(target, outcomeTrack.win, spin.tier);
}
if (outcomeTrack.loss > 0) {
// This loss is the loss to pay to the jackpot account
// The delta in contractBalance is already updated in a pending bet.
RequestBankrollPayment(zlotsJackpot, outcomeTrack.loss, spin.tier);
}
emit SpinConcluded(target, spin.blockn);
return output;
}
// Returns a random number using a specified block number
// Always use a FUTURE block number.
function maxRandom(uint blockn, address entropy, uint index)
private
view
returns (uint256 randomNumber)
{
return uint256(keccak256(
abi.encodePacked(
blockhash(blockn),
entropy,
index
)));
}
// Random helper
function random(uint256 upper, uint256 blockn, address entropy, uint index)
internal
view
returns (uint256 randomNumber)
{
return maxRandom(blockn, entropy, index) % upper;
}
// Sets max profit (internal)
function setMaxProfit(uint divRate)
internal
{
maxProfit[divRate] = (contractBalance[divRate] * maxProfitAsPercentOfHouse) / maxProfitDivisor;
}
// Gets max profit
function getMaxProfit(uint divRate)
public
view
returns (uint)
{
return (contractBalance[divRate] * maxProfitAsPercentOfHouse) / maxProfitDivisor;
}
function getNewMaxProfit(uint divRate, uint currentWin)
public
view
returns (uint)
{
return ((contractBalance[divRate] - currentWin) * maxProfitAsPercentOfHouse) / maxProfitDivisor;
}
// Subtracts from the contract balance tracking var
function subContractBalance(uint divRate, uint sub)
internal
{
contractBalance[divRate] = contractBalance[divRate].sub(sub);
}
// Adds to the contract balance tracking var
function addContractBalance(uint divRate, uint add)
internal
{
contractBalance[divRate] = contractBalance[divRate].add(add);
}
// An EXTERNAL update of tokens should be handled here
// This is due to token allocation
// The game should handle internal updates itself (e.g. tokens are betted)
function bankrollExternalUpdateTokens(uint divRate, uint newBalance)
public
fromBankroll
{
contractBalance[divRate] = newBalance;
setMaxProfit(divRate);
}
// Set the new max profit as percent of house - can be as high as 20%
// (1,000,000 = 100%)
function ownerSetMaxProfitAsPercentOfHouse(uint newMaxProfitAsPercent)
public
onlyOwner
{
// Restricts each bet to a maximum profit of 50% contractBalance
require(newMaxProfitAsPercent <= 500000);
maxProfitAsPercentOfHouse = newMaxProfitAsPercent;
setMaxProfit(2);
setMaxProfit(5);
setMaxProfit(10);
setMaxProfit(15);
setMaxProfit(20);
setMaxProfit(25);
setMaxProfit(33);
}
// Only owner can set minBet
function ownerSetMinBet(uint newMinimumBet)
public
onlyOwner
{
minBet = newMinimumBet;
}
// Only owner can set zlotsJackpot address
function ownerSetZlotsAddress(address zlotsAddress)
public
onlyOwner
{
zlotsJackpot = zlotsAddress;
}
// If, for any reason, betting needs to be paused (very unlikely), this will freeze all bets.
function pauseGame()
public
onlyOwnerOrBankroll
{
gameActive = false;
}
// The converse of the above, resuming betting if a freeze had been put in place.
function resumeGame()
public
onlyOwnerOrBankroll
{
gameActive = true;
}
// Administrative function to change the owner of the contract.
function changeOwner(address _newOwner)
public
onlyOwnerOrBankroll
{
owner = _newOwner;
}
// Administrative function to change the Zethr bankroll contract, should the need arise.
function changeBankroll(address _newBankroll)
public
onlyOwnerOrBankroll
{
bankroll = _newBankroll;
}
// Is the address that the token has come from actually ZTH?
function _zthToken(address _tokenContract)
private
view
returns (bool)
{
return _tokenContract == ZTHTKNADDR;
}
}
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint a, uint b)
internal
pure
returns (uint)
{
if (a == 0) {
return 0;
}
uint c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint a, uint b)
internal
pure
returns (uint)
{
uint c = a / b;
return c;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint a, uint b)
internal
pure
returns (uint)
{
assert(b <= a);
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint a, uint b)
internal
pure returns (uint)
{
uint c = a + b;
assert(c >= a);
return c;
}
}
{
"compilationTarget": {
"ZlotsMulti.sol": "ZlotsMulti"
},
"evmVersion": "byzantium",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"constant":true,"inputs":[],"name":"totalZTHWagered","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"WithdrawAndTransferToBankroll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"playerSpins","outputs":[{"name":"tokenValue","type":"uint192"},{"name":"blockn","type":"uint48"},{"name":"tier","type":"uint8"},{"name":"spins","type":"uint8"},{"name":"divRate","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxProfitAsPercentOfHouse","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"maxProfit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"resumeGame","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"maxProfitDivisor","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pauseGame","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"zlotsJackpot","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newMaxProfitAsPercent","type":"uint256"}],"name":"ownerSetMaxProfitAsPercentOfHouse","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"divRate","type":"uint256"},{"name":"currentWin","type":"uint256"}],"name":"getNewMaxProfit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newMinimumBet","type":"uint256"}],"name":"ownerSetMinBet","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"WithdrawToBankroll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"zlotsAddress","type":"address"}],"name":"ownerSetZlotsAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_value","type":"uint256"},{"name":"divRate","type":"uint256"},{"name":"_data","type":"bytes"}],"name":"execute","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSpins","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"finishSpin","outputs":[{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"minBet","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"changeOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newBankroll","type":"address"}],"name":"changeBankroll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"divRate","type":"uint256"}],"name":"getMaxProfit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"houseEdgeDivisor","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"divRate","type":"uint256"}],"name":"getZethrTokenBankroll","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"divRate","type":"uint256"},{"name":"newBalance","type":"uint256"}],"name":"bankrollExternalUpdateTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"gameActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"contractBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"BankrollAddress","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"timeTaken","type":"uint256"},{"indexed":false,"name":"tokensWithdrawn","type":"uint256"}],"name":"HouseRetrievedTake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_wagered","type":"uint256"}],"name":"TokensWagered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_result","type":"uint256"},{"indexed":false,"name":"_profit","type":"uint256"},{"indexed":false,"name":"_wagered","type":"uint256"},{"indexed":false,"name":"_category","type":"uint256"},{"indexed":false,"name":"_win","type":"bool"}],"name":"LogResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"Loss","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"ThreeMoonJackpot","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"TwoMoonPrize","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"ZTHPrize","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"ThreeZSymbols","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"ThreeTSymbols","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"ThreeHSymbols","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"ThreeEtherIcons","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"ThreePurplePyramids","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"ThreeGoldPyramids","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"ThreeRockets","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"OneMoonPrize","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"OneOfEachPyramidPrize","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"TwoZSymbols","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"TwoTSymbols","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"TwoHSymbols","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"TwoEtherIcons","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"TwoPurplePyramids","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"TwoGoldPyramids","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"TwoRockets","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_wagerer","type":"address"},{"indexed":false,"name":"_block","type":"uint256"}],"name":"SpinConcluded","type":"event"}]