pragma solidity >=0.5.6;
interface xEtherTokensContractInterface {
function ecosystemDividends() external payable;
}
contract XetherSicboLottery {
uint256 public HOUSE_EDGE_MINIMUM_AMOUNT = 0.0009 ether;
uint256 public TICKET_PRICE = 0.01 ether;
uint256 public MAX_AMOUNT = 100 ether;
uint256 constant BET_EXPIRATION_BLOCKS = 250;
uint16 constant JACKPOT_MODULO = 10000;
uint256 public JACKPOT_FEE = 0.001 ether;
uint256 lastTicketTime = now;
uint8 averageLotteryLock = 1;
uint256 public MIN_BET = 0.01 ether;
uint256 public MIN_JACKPOT_BET = 0.1 ether;
address constant DUMMY_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
uint256 public maxProfitLottery = 5 ether;
uint256 public maxProfitSicbo = 1 ether;
uint8 public TICKET_MAX_COUNT = 100;
uint256 public sicboTableLimit = 2 ether;
uint8[] public sumPayput = [
61,
31,
18,
13,
9,
7,
7,
7,
7,
9,
13,
18,
31,
61
];
uint8[2][15] public pairBet = [
[1, 2],
[1, 3],
[1, 4],
[1, 5],
[1, 6],
[2, 3],
[2, 4],
[2, 5],
[2, 6],
[3, 4],
[3, 5],
[3, 6],
[4, 5],
[4, 6],
[5, 6]
];
uint8 public DIVIDENDS_PERCENT = 10; // 1% example: 15 will be 1.5%
uint8 public ADVERTISE_PERCENT = 0; // 1%
uint8 public HOUSE_EDGE_PERCENT = 10; // 1%
uint16 constant PERCENTAGES_BASE = 1000;
uint256 constant DIVIDENDS_LIMIT = 1 ether;
uint16 public luckyNumberLottery = 7777;
uint16 public luckyNumberSicbo = 777;
uint256 public jackpotSizeLottery;
uint256 public jackpotSizeSicbo;
uint256 public jackpotSize = 0;
uint8 public gamesStopped = 0;
struct Ticket {
uint256 amount;
uint256 count;
uint40 placeBlockNumber;
address payable gambler;
uint128 locked;
uint256 clientSeed;
}
mapping(uint256 => Ticket) tickets;
struct Bet {
uint256 totalBetAmount;
uint128 locked;
mapping(uint8 => uint256) amount;
mapping(uint8 => uint8) bettype;
uint40 placeBlockNumber;
uint256 clientSeed;
mapping(uint8 => uint256) nums;
address payable gambler;
uint8 betsCount;
}
mapping(uint256 => Bet) bets;
mapping(address => uint256) public bonusProgrammAccumulated;
xEtherTokensContractInterface public xEtherTokensContract;
address public owner;
address private nextOwner;
address public moderator;
uint256 public totalDividends = 0;
uint256 public totalAdvertise = 0;
address public secretSigner;
address public croupier;
uint128 public lockedInBetsLottery;
uint128 public lockedInBetsSicbo;
event PaymentLottery(
address beneficiary,
uint256 commit,
uint256 amount,
string paymentType,
uint256[] numbers
);
event PaymentSicbo(
address beneficiary,
uint256 commit,
uint256 amount,
string paymentType
);
event JackpotSicboPayment(
address indexed beneficiary,
uint256 commit,
uint256 amount
);
event JackpotLotteryPayment(
address indexed beneficiary,
uint256 commit,
uint256 amount
);
event PayDividendsSuccess(uint256 time, uint256 amount);
event PayDividendsFailed(uint256 time, uint256 amount);
event CommitLottery(uint256 commit, uint256 clientSeed, uint256 amount);
event CommitSicbo(uint256 commit, uint256 clientSeed, uint256 amount);
modifier onlyModeration {
require(
msg.sender == owner || msg.sender == moderator,
"Moderation methods called by non-moderator."
);
_;
}
constructor() public {
owner = msg.sender;
}
modifier onlyOwner {
require(msg.sender == owner, "OnlyOwner methods called by non-owner.");
_;
}
modifier onlyCroupier {
require(
msg.sender == croupier,
"OnlyCroupier methods called by non-croupier."
);
_;
}
function approveNextOwner(address _nextOwner) external onlyOwner {
require(_nextOwner != owner, "Cannot approve current owner.");
nextOwner = _nextOwner;
}
function acceptNextOwner() external {
require(
msg.sender == nextOwner,
"Can only accept preapproved new owner."
);
owner = nextOwner;
}
function setMaxProfit(uint256 _maxProfit, uint8 game) public onlyOwner {
require(
_maxProfit < MAX_AMOUNT,
"maxProfit cant be great then top limit."
);
if (game == 0) {
maxProfitSicbo = _maxProfit;
} else {
maxProfitLottery = _maxProfit;
}
}
function changeMaxTickets(uint8 _newMaxTickets) external onlyOwner {
require(
0 <= _newMaxTickets && _newMaxTickets < 1000,
"Wrong tickets number"
);
TICKET_MAX_COUNT = _newMaxTickets;
}
function getBonusProgrammLevel(address gambler)
public
view
returns (uint8 discount)
{
uint256 accumulated = bonusProgrammAccumulated[gambler];
discount = 0;
if (accumulated >= 20 ether && accumulated < 100 ether) {
discount = 1;
} else if (accumulated >= 100 ether && accumulated < 500 ether) {
discount = 2;
} else if (accumulated >= 500 ether && accumulated < 1000 ether) {
discount = 3;
} else if (accumulated >= 1000 ether && accumulated < 5000 ether) {
discount = 4;
} else if (accumulated >= 5000 ether) {
discount = 5;
}
}
function() external payable {}
function setNewPercents(
uint8 newHouseEdgePercent,
uint8 newDividendsPercent,
uint8 newAdvertPercent
) external onlyModeration {
// We guarantee that dividends will be minimum 0.5%
require(newDividendsPercent >= 5, "dividentds limit");
// Total percentages not greater then 3%
require(
newHouseEdgePercent + newDividendsPercent + newAdvertPercent <= 30,
"Total percentages not greater then 3%"
);
HOUSE_EDGE_PERCENT = newHouseEdgePercent;
ADVERTISE_PERCENT = newAdvertPercent;
DIVIDENDS_PERCENT = newDividendsPercent;
}
function setAdditionalVariables(
uint256 he,
uint256 mjb,
uint256 jf,
uint256 mb,
uint256 ma,
uint8 al
) external onlyModeration {
if (he != 0 && he > 0) {
HOUSE_EDGE_MINIMUM_AMOUNT = he;
}
if (mjb != 0 && mjb > 0) {
MIN_JACKPOT_BET = mjb;
}
if (jf != 0 && jf > 0) {
JACKPOT_FEE = jf;
}
if (mb != 0 && mb > 0) {
MIN_BET = mb;
}
if (ma != 0 && ma > 0) {
MAX_AMOUNT = ma;
}
if (al != 0 && al > 0) {
averageLotteryLock = al;
}
}
function stopGames(uint8 _stopGames) external onlyModeration {
gamesStopped = _stopGames;
}
function setTableLimit(uint256 _newTableLimit) public onlyModeration {
require(
_newTableLimit < MAX_AMOUNT,
"tableLimit cant be great then top limit."
);
sicboTableLimit = _newTableLimit;
}
function setXEtherContract(address xEtherContract) external onlyModeration {
xEtherTokensContract = xEtherTokensContractInterface(xEtherContract);
}
function setAddresses(
address newCroupier,
address newSecretSigner,
address newModerator
) external onlyOwner {
secretSigner = newSecretSigner;
croupier = newCroupier;
moderator = newModerator;
}
function increaseJackpot(uint256 increaseAmount, uint8 game)
external
onlyModeration
{
require(
increaseAmount <= address(this).balance,
"Increase amount larger than balance."
);
if (game == 0) {
require(
jackpotSizeSicbo + lockedInBetsSicbo + increaseAmount <=
address(this).balance,
"Not enough funds."
);
jackpotSizeSicbo += uint128(increaseAmount);
} else {
require(
jackpotSizeLottery + lockedInBetsLottery + increaseAmount <=
address(this).balance,
"Not enough funds."
);
jackpotSizeLottery += uint128(increaseAmount);
}
}
function releaseLockedInBetSicboAmount() external onlyModeration {
lockedInBetsSicbo = 0;
}
function releaseLockedInBetLotteryAmount() external onlyModeration {
lockedInBetsLottery = 0;
}
function withdrawFunds(address payable beneficiary, uint256 withdrawAmount)
external
onlyOwner
{
require(
withdrawAmount <= address(this).balance,
"Increase amount larger than balance."
);
require(
jackpotSizeSicbo +
jackpotSizeLottery +
lockedInBetsSicbo +
lockedInBetsLottery +
withdrawAmount <=
address(this).balance,
"Not enough funds."
);
sendFundsSicbo(beneficiary, withdrawAmount, 0, "withdraw");
}
function withdrawAdvertiseFunds(
address payable beneficiary,
uint256 withdrawAmount
) external onlyOwner {
require(
withdrawAmount <= totalAdvertise,
"Increase amount larger than balance."
);
totalAdvertise = 0;
sendFundsSicbo(beneficiary, withdrawAmount, 0, "withdraw");
}
function withdrawLotteryJackpot(
address payable beneficiary,
uint256 withdrawAmount
) external onlyOwner {
require(
withdrawAmount <= jackpotSizeLottery,
"Increase amount larger than balance."
);
require(
now >= lastTicketTime + 1 days,
"Withdraw jacpot on 1 day inactivity"
);
jackpotSizeLottery -= withdrawAmount;
uint256[] memory tmp;
sendFundsLottery(beneficiary, withdrawAmount, 0, "withdraw", tmp);
}
function end() external onlyOwner {
require(
lockedInBetsSicbo == 0 && lockedInBetsLottery == 0,
"All bets should be processed (settled or refunded) before self-destruct."
);
selfdestruct(address(uint160(owner)));
}
function sendDividends() public payable {
if (address(xEtherTokensContract) != address(0)) {
uint256 tmpDividends = totalDividends;
xEtherTokensContract.ecosystemDividends.value(tmpDividends)();
totalDividends = 0;
emit PayDividendsSuccess(now, tmpDividends);
}
}
// ----------- SicBo ------------
function placeBet(
uint8[] calldata betType,
uint256[] calldata betNums,
uint256[] calldata betAmount,
uint256 commitLastBlock,
uint256 commit,
uint256 clientSeed,
bytes32 r,
bytes32 s
) external payable {
require(gamesStopped == 0, "Games is running");
Bet storage bet = bets[commit];
Ticket storage ticket = tickets[commit];
require(bet.gambler == address(0) && ticket.gambler == address(0), "Bet should be in a 'clean' state.");
require(
msg.value <= sicboTableLimit,
"Bets sum must be LTE table limit"
);
require(
uint8(betNums.length) == uint8(betType.length) &&
uint8(betNums.length) == uint8(betAmount.length),
"Arguments length not match"
);
bet.betsCount = uint8(betNums.length);
require(block.number <= commitLastBlock, "Commit has expired.");
require(
secretSigner ==
ecrecover(
keccak256(
abi.encodePacked(uint40(commitLastBlock), commit)
),
27,
r,
s
) ||
secretSigner ==
ecrecover(
keccak256(
abi.encodePacked(uint40(commitLastBlock), commit)
),
28,
r,
s
),
"ECDSA signature is not valid."
);
if (totalDividends >= DIVIDENDS_LIMIT) {
sendDividends();
}
bet.gambler = msg.sender;
placeBetProcess(commit, betType, betNums, betAmount);
lockedInBetsSicbo += bet.locked;
require(
lockedInBetsSicbo <= address(this).balance,
"Cannot afford to lose this bet."
);
bonusProgrammAccumulated[msg.sender] += msg.value;
bet.totalBetAmount = msg.value;
bet.placeBlockNumber = uint40(block.number);
bet.clientSeed = clientSeed;
emit CommitSicbo(commit, clientSeed, msg.value);
}
function placeBetProcess(
uint256 commit,
uint8[] memory betType,
uint256[] memory betNums,
uint256[] memory betAmount
) internal {
Bet storage bet = bets[commit];
uint256 totalBetAmount = 0;
uint128 possibleWinAmount;
uint256 jackpotFee = msg.value >= MIN_JACKPOT_BET ? JACKPOT_FEE : 0;
uint256 feeToJP = msg.value >= MIN_JACKPOT_BET
? JACKPOT_FEE / bet.betsCount
: 0;
for (uint8 count = 0; count < bet.betsCount; count += 1) {
require(
betAmount[count] >= MIN_BET && betAmount[count] <= MAX_AMOUNT,
"Amount should be within range."
);
totalBetAmount += betAmount[count];
require(
totalBetAmount <= msg.value,
"Total bets amount should be LTE amount"
);
uint8[3] memory tmp1;
possibleWinAmount = getDiceWinAmount(
betAmount[count] - feeToJP,
betType[count],
bet.gambler,
betNums[count],
tmp1,
true
);
require(
possibleWinAmount <= betAmount[count] + maxProfitSicbo,
"maxProfitPlinko limit violation."
);
if (possibleWinAmount > bet.locked) {
bet.locked = possibleWinAmount;
}
bet.nums[count] = betNums[count];
bet.bettype[count] = betType[count];
bet.amount[count] = betAmount[count];
}
jackpotSizeSicbo += uint128(jackpotFee);
}
function settleBet(uint256 reveal) external onlyCroupier {
uint256 commit = uint256(keccak256(abi.encodePacked(reveal)));
Bet storage bet = bets[commit];
uint256 placeBlockNumber = bet.placeBlockNumber;
require(bet.totalBetAmount > 0, "Bet already processed");
require(
block.number > placeBlockNumber,
"settleBet in the same block as placeBet, or before."
);
require(
block.number <= placeBlockNumber + BET_EXPIRATION_BLOCKS,
"Can't be queried by EVM."
);
settleBet(bet, reveal);
}
function settleBet(Bet storage bet, uint256 reveal) private {
require(bet.totalBetAmount != 0, "Bet should be in an 'active' state");
address payable gambler = bet.gambler;
bytes32 entropy = keccak256(abi.encodePacked(reveal, bet.clientSeed));
uint8[3] memory dice = [
uint8((uint256(entropy) % 6) + 1),
uint8(((uint256(entropy) / 6) % 6) + 1),
uint8(((uint256(entropy) / 6 / 6) % 6) + 1)
];
uint256 diceWin = 0;
uint256 possibleWinAmount = 0;
uint256 feeToJP = bet.totalBetAmount >= MIN_JACKPOT_BET
? JACKPOT_FEE / bet.betsCount
: 0;
for (uint8 index = 0; index < bet.betsCount; index += 1) {
possibleWinAmount = getDiceWinAmount(
bet.amount[index] - feeToJP,
bet.bettype[index],
bet.gambler,
bet.nums[index],
dice,
false
);
diceWin += possibleWinAmount;
}
lockedInBetsSicbo -= bet.locked;
uint256 jackpotWin = checkJackPotWin(entropy, 6, 0);
if (jackpotWin > 0) {
emit JackpotSicboPayment(
gambler,
uint256(keccak256(abi.encodePacked(reveal))),
jackpotWin
);
}
sendFundsSicbo(
gambler,
diceWin + jackpotWin == 0 ? 1 wei : diceWin + jackpotWin,
uint256(keccak256(abi.encodePacked(reveal))),
"payment"
);
bet.totalBetAmount = 0;
}
function getDiceWinAmount(
uint256 amount,
uint8 betType,
address gambler,
uint256 nums,
uint8[3] memory dice,
bool init
) private returns (uint128 winAmount) {
uint256 tmp = 0;
uint256 totalPercentages = HOUSE_EDGE_PERCENT +
ADVERTISE_PERCENT +
DIVIDENDS_PERCENT;
uint256 houseEdge = (amount *
(totalPercentages - getBonusProgrammLevel(gambler))) /
PERCENTAGES_BASE;
if (houseEdge < HOUSE_EDGE_MINIMUM_AMOUNT) {
houseEdge = HOUSE_EDGE_MINIMUM_AMOUNT;
}
if (init) {
totalDividends += (amount * DIVIDENDS_PERCENT) / PERCENTAGES_BASE;
totalAdvertise += (amount * ADVERTISE_PERCENT) / PERCENTAGES_BASE;
if (betType == 0 || betType == 1) {
require(nums == 0, "Wrong number");
tmp = amount * 2;
}
if (betType == 2) {
require(nums > 0 && nums <= 6, "Wrong number");
tmp = amount * 4;
}
if (betType == 3) {
require(nums >= 0 && nums <= 14, "Wrong number");
tmp = amount * 6;
}
if (betType == 4) {
require(nums >= 4 && nums <= 17, "Wrong number");
tmp = amount * sumPayput[nums - 4];
}
if (betType == 5) {
require(nums >= 1 && nums <= 6, "Wrong number");
tmp = amount * 11;
}
if (betType == 6) {
require(nums >= 1 && nums <= 6, "Wrong number");
tmp = amount * 181;
}
if (betType == 7) {
require(nums == 0, "Wrong number");
tmp = amount * 31;
}
winAmount = uint128(tmp);
} else {
uint8 rate = checkBet(betType, nums, dice);
winAmount = uint128((amount - houseEdge) * rate);
}
}
function checkBet(
uint8 betType,
uint256 nums,
uint8[3] memory dices
) private view returns (uint8 rate) {
uint8 sum = dices[0] + dices[1] + dices[2];
uint8 ismatch = 0;
rate = 0;
if (betType == 0) {
// Small bet
if (dices[0] == dices[1] && dices[0] == dices[2]) {
rate = 0;
} else if (sum >= 4 && sum <= 10) {
rate = 2;
}
}
if (betType == 1) {
// Big bet
if (dices[0] == dices[1] && dices[0] == dices[2]) {
rate = 0;
} else if (sum >= 11 && sum <= 17) {
rate = 2;
}
}
if (betType == 2) {
// Number bets
if (nums == dices[0]) {
rate += 1;
}
if (nums == dices[1]) {
rate += 1;
}
if (nums == dices[2]) {
rate += 1;
}
rate += (rate > 0) ? 1 : 0;
}
if (betType == 3) {
// Pair bets
ismatch = 0;
uint8[2] memory tmpNums = pairBet[nums];
if (tmpNums[0] != tmpNums[1]) {
if (
tmpNums[0] == dices[0] ||
tmpNums[0] == dices[1] ||
tmpNums[0] == dices[2]
) {
ismatch += 1;
}
if (
tmpNums[1] == dices[0] ||
tmpNums[1] == dices[1] ||
tmpNums[1] == dices[2]
) {
ismatch += 1;
}
rate = (ismatch == 2) ? 6 : 0;
}
}
if (betType == 4 && nums == sum && (sum >= 4 && sum <= 17)) {
// Total bets
rate = sumPayput[sum - 4];
}
if (betType == 5) {
// 5 Double bets
if (
dices[0] == dices[1] ||
dices[1] == dices[2] ||
dices[0] == dices[2]
) {
if (dices[0] == dices[1] && dices[0] == nums) {
rate = 11;
}
if (dices[1] == dices[2] && dices[1] == nums) {
rate = 11;
}
if (dices[0] == dices[2] && dices[0] == nums) {
rate = 11;
}
}
}
if (betType == 6) {
// 6 Triple bets
if (dices[0] == dices[1] && dices[0] == dices[2]) {
if (dices[0] == nums) {
rate = 181;
}
}
}
if (betType == 7) {
// 7 Three of a kind
if (dices[0] == dices[1] && dices[0] == dices[2]) {
rate = 31;
}
}
}
function checkForTicketWin(uint256 number) private pure returns (uint256) {
if (number == 2000) {
return 1000;
} else if (2000 > number && number >= 1998) {
return 800;
} else if (1998 > number && number >= 1994) {
return 500;
} else if (1994 > number && number >= 1984) {
return 200;
} else if (1984 > number && number >= 1964) {
return 100;
} else if (1964 > number && number >= 1924) {
return 50;
} else if (1924 > number && number >= 1824) {
return 20;
} else if (1824 > number && number >= 1500) {
return 10;
} else if (1500 > number && number >= 1250) {
return 5;
} else if (1250 > number && number >= 1000) {
return 3;
} else if (1000 > number && number >= 500) {
return 1;
}
return 0;
}
// --------------- Lottery ----------------
function buyTicket(
uint256 commitLastBlock,
uint256 commit,
uint256 clientSeed,
bytes32 r,
bytes32 s
) external payable {
require(gamesStopped == 0, "Games is running");
Bet storage bet = bets[commit];
Ticket storage ticket = tickets[commit];
require(bet.gambler == address(0) && ticket.gambler == address(0), "Bet should be in a 'clean' state.");
uint256 amount = msg.value;
uint256 ticketsCount = amount / TICKET_PRICE;
require(
0 < ticketsCount && ticketsCount <= TICKET_MAX_COUNT,
"Tickets is not in range"
);
require(amount >= TICKET_PRICE, "Amount should be within range.");
require(block.number <= commitLastBlock, "Commit has expired.");
require(
secretSigner ==
ecrecover(
keccak256(
abi.encodePacked(uint40(commitLastBlock), commit)
),
27,
r,
s
) ||
secretSigner ==
ecrecover(
keccak256(
abi.encodePacked(uint40(commitLastBlock), commit)
),
28,
r,
s
),
"ECDSA signature is not valid."
);
if (totalDividends >= DIVIDENDS_LIMIT) {
sendDividends();
}
uint256 totalPercentages = HOUSE_EDGE_PERCENT +
ADVERTISE_PERCENT +
DIVIDENDS_PERCENT;
uint256 houseEdge = (amount * totalPercentages) / PERCENTAGES_BASE;
if (houseEdge < HOUSE_EDGE_MINIMUM_AMOUNT) {
houseEdge = HOUSE_EDGE_MINIMUM_AMOUNT;
}
totalDividends += (amount * DIVIDENDS_PERCENT) / PERCENTAGES_BASE;
totalAdvertise += (amount * ADVERTISE_PERCENT) / PERCENTAGES_BASE;
uint256 possibleWinAmount = ticketsCount *
TICKET_PRICE *
averageLotteryLock; // lock average possible win
// check if we can pay max profit for 1 ticket
require(
TICKET_PRICE * 100 <= address(this).balance,
"Can't pay max profit"
);
require(
possibleWinAmount <= amount + maxProfitLottery,
"maxProfit limit violation."
);
lockedInBetsLottery += uint128(possibleWinAmount);
require(
jackpotSizeLottery + lockedInBetsLottery <= address(this).balance,
"Cannot afford to lose this bet."
);
ticket.count = ticketsCount;
ticket.amount = ticketsCount * TICKET_PRICE - houseEdge;
ticket.placeBlockNumber = uint40(block.number);
ticket.gambler = msg.sender;
ticket.locked = uint128(possibleWinAmount);
ticket.clientSeed = clientSeed;
lastTicketTime = now;
emit CommitLottery(commit, clientSeed, amount);
}
function processTickets(uint256 reveal) external onlyCroupier {
uint256 commit = uint256(keccak256(abi.encodePacked(reveal)));
Ticket storage ticket = tickets[commit];
uint256 placeBlockNumber = ticket.placeBlockNumber;
require(
block.number > placeBlockNumber,
"settleBet in the same block as placeBet, or before."
);
require(
block.number <= placeBlockNumber + BET_EXPIRATION_BLOCKS,
"Blockhash can't be queried by EVM."
);
_processTickets(ticket, reveal);
}
function _processTickets(Ticket storage ticket, uint256 reveal) private {
bytes32 entropy;
uint256[] memory ticketsWins = new uint256[](ticket.count);
uint256 ticketNumber;
uint256 winRate;
uint256 totalRate = 0;
uint256 jackpotWin = 0;
uint256 zeroTickets = 0;
uint256 commit = uint256(keccak256(abi.encodePacked(reveal)));
for (uint8 index = 0; index < ticket.count; index += 1) {
entropy = keccak256(
abi.encodePacked(reveal, ticket.clientSeed, index)
);
ticketNumber = uint256(entropy) % 2000;
winRate = checkForTicketWin(ticketNumber);
ticketsWins[index] = ticketNumber;
totalRate += winRate;
if (winRate == 0) {
zeroTickets += 1;
}
jackpotWin += checkJackPotWin(entropy, ticketNumber, 1);
if (jackpotWin > 0) {
emit JackpotLotteryPayment(ticket.gambler, commit, jackpotWin);
}
}
if (zeroTickets != 0) {
jackpotSizeLottery += (zeroTickets * TICKET_PRICE) / 2;
}
lockedInBetsLottery -= uint128(ticket.locked);
uint256 winAmount = ((ticket.amount / ticket.count) * totalRate) /
10 +
jackpotWin;
sendFundsLottery(
ticket.gambler,
winAmount == 0 ? 1 wei : winAmount,
commit,
"payment",
ticketsWins
);
}
function checkJackPotWin(
bytes32 entropy,
uint256 randMod,
uint8 game
) internal returns (uint256 jackpotWin) {
jackpotWin = 0;
uint256 jackpotRng = (uint256(entropy) / randMod) % JACKPOT_MODULO;
if (game == 0) {
if (jackpotRng == luckyNumberSicbo) {
jackpotWin = jackpotSizeSicbo;
jackpotSizeSicbo = 0;
}
} else {
if (jackpotRng == luckyNumberLottery) {
jackpotWin = jackpotSizeLottery;
jackpotSizeLottery = 0;
}
}
}
function sendFundsLottery(
address payable beneficiary,
uint256 amount,
uint256 commit,
string memory paymentType,
uint256[] memory numbers
) private {
if (beneficiary.send(amount)) {
emit PaymentLottery(
beneficiary,
commit,
amount,
paymentType,
numbers
);
} else {
emit PaymentLottery(
beneficiary,
commit,
amount,
paymentType,
numbers
);
}
}
function sendFundsSicbo(
address payable beneficiary,
uint256 amount,
uint256 commit,
string memory paymentType
) private {
if (beneficiary.send(amount)) {
emit PaymentSicbo(beneficiary, commit, amount, paymentType);
} else {
emit PaymentSicbo(beneficiary, commit, amount, paymentType);
}
}
function refundLotteryBet(uint256 commit) external {
Ticket storage ticket = tickets[commit];
uint256 amount = ticket.amount;
require(amount != 0, "Bet should be in an 'active' state");
require(
block.number > ticket.placeBlockNumber + BET_EXPIRATION_BLOCKS,
"Blockhash can't be queried by EVM."
);
ticket.amount = 0;
lockedInBetsLottery -= ticket.locked;
uint256[] memory tmp;
sendFundsLottery(ticket.gambler, amount, commit, "refund", tmp);
}
function refundBetSicbo(uint256 commit) external {
Bet storage bet = bets[commit];
uint256 amount = bet.totalBetAmount;
require(amount != 0, "Bet should be in an 'active' state");
require(
block.number > bet.placeBlockNumber + BET_EXPIRATION_BLOCKS,
"Blockhash can't be queried by EVM."
);
bet.totalBetAmount = 0;
for (uint8 index = 0; index < bet.betsCount; index += 1) {
bet.amount[index] = 0;
}
lockedInBetsSicbo -= bet.locked;
if (amount >= MIN_JACKPOT_BET && jackpotSizeSicbo > JACKPOT_FEE) {
jackpotSizeSicbo -= uint128(JACKPOT_FEE);
}
sendFundsSicbo(bet.gambler, amount, commit, "refund");
}
}
{
"compilationTarget": {
"XetherSicboLottery.sol": "XetherSicboLottery"
},
"evmVersion": "petersburg",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"sumPayput","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ADVERTISE_PERCENT","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"luckyNumberLottery","outputs":[{"name":"","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MIN_JACKPOT_BET","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"he","type":"uint256"},{"name":"mjb","type":"uint256"},{"name":"jf","type":"uint256"},{"name":"mb","type":"uint256"},{"name":"ma","type":"uint256"},{"name":"al","type":"uint8"}],"name":"setAdditionalVariables","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"betType","type":"uint8[]"},{"name":"betNums","type":"uint256[]"},{"name":"betAmount","type":"uint256[]"},{"name":"commitLastBlock","type":"uint256"},{"name":"commit","type":"uint256"},{"name":"clientSeed","type":"uint256"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"}],"name":"placeBet","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"reveal","type":"uint256"}],"name":"settleBet","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_maxProfit","type":"uint256"},{"name":"game","type":"uint8"}],"name":"setMaxProfit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"TICKET_PRICE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"bonusProgrammAccumulated","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"xEtherTokensContract","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"TICKET_MAX_COUNT","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newCroupier","type":"address"},{"name":"newSecretSigner","type":"address"},{"name":"newModerator","type":"address"}],"name":"setAddresses","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"moderator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"gambler","type":"address"}],"name":"getBonusProgrammLevel","outputs":[{"name":"discount","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"xEtherContract","type":"address"}],"name":"setXEtherContract","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"increaseAmount","type":"uint256"},{"name":"game","type":"uint8"}],"name":"increaseJackpot","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"commit","type":"uint256"}],"name":"refundBetSicbo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"secretSigner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"jackpotSize","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"jackpotSizeLottery","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MIN_BET","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"croupier","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newMaxTickets","type":"uint8"}],"name":"changeMaxTickets","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"sicboTableLimit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"beneficiary","type":"address"},{"name":"withdrawAmount","type":"uint256"}],"name":"withdrawAdvertiseFunds","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"jackpotSizeSicbo","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_stopGames","type":"uint8"}],"name":"stopGames","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"name":"pairBet","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"releaseLockedInBetLotteryAmount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalDividends","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"releaseLockedInBetSicboAmount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"maxProfitLottery","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"commitLastBlock","type":"uint256"},{"name":"commit","type":"uint256"},{"name":"clientSeed","type":"uint256"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"}],"name":"buyTicket","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"lockedInBetsSicbo","outputs":[{"name":"","type":"uint128"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalAdvertise","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newHouseEdgePercent","type":"uint8"},{"name":"newDividendsPercent","type":"uint8"},{"name":"newAdvertPercent","type":"uint8"}],"name":"setNewPercents","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"sendDividends","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"commit","type":"uint256"}],"name":"refundLotteryBet","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"HOUSE_EDGE_MINIMUM_AMOUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"HOUSE_EDGE_PERCENT","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"JACKPOT_FEE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"gamesStopped","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"beneficiary","type":"address"},{"name":"withdrawAmount","type":"uint256"}],"name":"withdrawFunds","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newTableLimit","type":"uint256"}],"name":"setTableLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"reveal","type":"uint256"}],"name":"processTickets","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"acceptNextOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MAX_AMOUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nextOwner","type":"address"}],"name":"approveNextOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"beneficiary","type":"address"},{"name":"withdrawAmount","type":"uint256"}],"name":"withdrawLotteryJackpot","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"lockedInBetsLottery","outputs":[{"name":"","type":"uint128"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxProfitSicbo","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"end","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"DIVIDENDS_PERCENT","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"luckyNumberSicbo","outputs":[{"name":"","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"beneficiary","type":"address"},{"indexed":false,"name":"commit","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"paymentType","type":"string"},{"indexed":false,"name":"numbers","type":"uint256[]"}],"name":"PaymentLottery","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"beneficiary","type":"address"},{"indexed":false,"name":"commit","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"paymentType","type":"string"}],"name":"PaymentSicbo","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"beneficiary","type":"address"},{"indexed":false,"name":"commit","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"JackpotSicboPayment","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"beneficiary","type":"address"},{"indexed":false,"name":"commit","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"JackpotLotteryPayment","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"time","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"PayDividendsSuccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"time","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"PayDividendsFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"commit","type":"uint256"},{"indexed":false,"name":"clientSeed","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"CommitLottery","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"commit","type":"uint256"},{"indexed":false,"name":"clientSeed","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"CommitSicbo","type":"event"}]