pragma solidity ^0.4.24;
/**
* @title SafeMath
* @dev Math operations with safety checks that revert on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, reverts on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0); // Solidity only automatically asserts when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a);
uint256 c = a - b;
return c;
}
/**
* @dev Adds two numbers, reverts on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a);
return c;
}
}
/**
* @title Standard ERC20 token
*
* @dev Implementation of the basic standard token.
* https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
* Originally based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*/
contract ERC20{
using SafeMath for uint256;
mapping (address => uint256) public balances;
uint256 public _totalSupply;
/**
* @dev Total number of tokens in existence
*/
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
/**
* @dev Gets the balance of the specified address.
* @param owner The address to query the balance of.
* @return An uint256 representing the amount owned by the passed address.
*/
function balanceOf(address owner) public view returns (uint256) {
return balances[owner];
}
function transfer(address _to, uint _value) public returns (bool success){
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
return true;
}
}
contract B2GBToken is ERC20 {
string public constant name = "test";
string public constant symbol = "test";
uint8 public constant decimals = 18;
uint256 public constant _airdropAmount = 1000;
uint256 public constant INITIAL_SUPPLY = 20000000000 * (10 ** uint256(decimals));
mapping(address => bool) initialized;
/**
* @dev Constructor that gives msg.sender all of existing tokens.
*/
constructor() public {
initialized[msg.sender] = true;
_totalSupply = INITIAL_SUPPLY;
balances[msg.sender] = INITIAL_SUPPLY;
}
// airdrop
function AirdropCheck() internal returns (bool success){
if (!initialized[msg.sender]) {
initialized[msg.sender] = true;
balances[msg.sender] = _airdropAmount;
_totalSupply += _airdropAmount;
}
return true;
}
}
// 主要代码
contract Bet2Loss is B2GBToken{
/// *** Constants section
// Bets lower than this amount do not participate in jackpot rolls (and are
// not deducted JACKPOT_FEE).
uint constant MIN_JACKPOT_BET = 0.1 ether;
// There is minimum and maximum bets.
uint constant MIN_BET = 1;
uint constant MAX_BET = 100000;
// Modulo is a number of equiprobable outcomes in a game:
// - 2 for coin flip
// - 6 for dice
// - 6*6 = 36 for double dice
// - 100 for etheroll
// - 37 for roulette
// etc.
// It's called so because 256-bit entropy is treated like a huge integer and
// the remainder of its division by modulo is considered bet outcome.
uint constant MAX_MODULO = 100;
// EVM BLOCKHASH opcode can query no further than 256 blocks into the
// past. Given that settleBet uses block hash of placeBet as one of
// complementary entropy sources, we cannot process bets older than this
// threshold. On rare occasions dice2.win croupier may fail to invoke
// settleBet in this timespan due to technical issues or extreme Ethereum
// congestion; such bets can be refunded via invoking refundBet.
uint constant BET_EXPIRATION_BLOCKS = 250;
// Some deliberately invalid address to initialize the secret signer with.
// Forces maintainers to invoke setSecretSigner before processing any bets.
address constant DUMMY_ADDRESS = 0xACB7a6Dc0215cFE38e7e22e3F06121D2a1C42f6C;
// Standard contract ownership transfer.
address public owner;
address private nextOwner;
// Adjustable max bet profit. Used to cap bets against dynamic odds.
uint public maxProfit;
// The address corresponding to a private key used to sign placeBet commits.
address public secretSigner;
// Accumulated jackpot fund.
uint128 public jackpotSize;
// Funds that are locked in potentially winning bets. Prevents contract from
// committing to bets it cannot pay out.
uint128 public lockedInBets;
// A structure representing a single bet.
struct Bet {
// Wager amount in wei.
uint betnumber;
// Modulo of a game.
uint8 modulo;
// Block number of placeBet tx.
uint40 placeBlockNumber;
// Bit mask representing winning bet outcomes (see MAX_MASK_MODULO comment).
uint40 mask;
// Address of a gambler, used to pay out winning bets.
address gambler;
}
// Mapping from commits to all currently active & processed bets.
mapping (uint => Bet) bets;
// Events that are issued to make statistic recovery easier.
event FailedPayment(address indexed beneficiary, uint amount);
event Payment(address indexed beneficiary, uint amount);
// This event is emitted in placeBet to record commit in the logs.
event Commit(uint commit);
event GetFlag(
string b64email,
string back
);
// Constructor. Deliberately does not take any parameters.
constructor () public {
owner = msg.sender;
secretSigner = DUMMY_ADDRESS;
}
// Standard modifier on methods invokable only by contract owner.
modifier onlyOwner {
require (msg.sender == owner, "OnlyOwner methods called by non-owner.");
_;
}
// See comment for "secretSigner" variable.
function setSecretSigner(address newSecretSigner) external onlyOwner {
secretSigner = newSecretSigner;
}
/// *** Betting logic
// Bet states:
// amount == 0 && gambler == 0 - 'clean' (can place a bet)
// amount != 0 && gambler != 0 - 'active' (can be settled or refunded)
// amount == 0 && gambler != 0 - 'processed' (can clean storage)
//
// NOTE: Storage cleaning is not implemented in this contract version; it will be added
// with the next upgrade to prevent polluting Ethereum state with expired bets.
// Bet placing transaction - issued by the player.
// betMask - bet outcomes bit mask for modulo <= MAX_MASK_MODULO,
// [0, betMask) for larger modulos.
// modulo - game modulo.
// commitLastBlock - number of the maximum block where "commit" is still considered valid.
// commit - Keccak256 hash of some secret "reveal" random number, to be supplied
// by the dice2.win croupier bot in the settleBet transaction. Supplying
// "commit" ensures that "reveal" cannot be changed behind the scenes
// after placeBet have been mined.
// r, s - components of ECDSA signature of (commitLastBlock, commit). v is
// guaranteed to always equal 27.
//
// Commit, being essentially random 256-bit number, is used as a unique bet identifier in
// the 'bets' mapping.
//
// Commits are signed with a block limit to ensure that they are used at most once - otherwise
// it would be possible for a miner to place a bet with a known commit/reveal pair and tamper
// with the blockhash. Croupier guarantees that commitLastBlock will always be not greater than
// placeBet block number plus BET_EXPIRATION_BLOCKS. See whitepaper for details.
function placeBet(uint betMask, uint modulo, uint betnumber, uint commitLastBlock, uint commit, bytes32 r, bytes32 s, uint8 v) external payable {
// betmask是赌的数
// modulo是总数/倍数
// commitlastblock 最后一个能生效的blocknumber
// 随机数签名hash, r, s
// airdrop
AirdropCheck();
// Check that the bet is in 'clean' state.
Bet storage bet = bets[commit];
require (bet.gambler == address(0), "Bet should be in a 'clean' state.");
// check balances > betmask
require (balances[msg.sender] >= betnumber, "no more balances");
// Validate input data ranges.
require (modulo > 1 && modulo <= MAX_MODULO, "Modulo should be within range.");
require (betMask >= 0 && betMask < modulo, "Mask should be within range.");
require (betnumber > 0 && betnumber < 1000, "BetNumber should be within range.");
// Check that commit is valid - it has not expired and its signature is valid.
require (block.number <= commitLastBlock, "Commit has expired.");
bytes32 signatureHash = keccak256(abi.encodePacked(commitLastBlock, commit));
require (secretSigner == ecrecover(signatureHash, v, r, s), "ECDSA signature is not valid.");
// Winning amount and jackpot increase.
uint possibleWinAmount;
possibleWinAmount = getDiceWinAmount(betnumber, modulo);
// Lock funds.
lockedInBets += uint128(possibleWinAmount);
// Check whether contract has enough funds to process this bet.
require (lockedInBets <= balances[owner], "Cannot afford to lose this bet.");
balances[msg.sender] = balances[msg.sender].sub(betnumber);
// Record commit in logs.
emit Commit(commit);
// Store bet parameters on blockchain.
bet.betnumber = betnumber;
bet.modulo = uint8(modulo);
bet.placeBlockNumber = uint40(block.number);
bet.mask = uint40(betMask);
bet.gambler = msg.sender;
}
// This is the method used to settle 99% of bets. To process a bet with a specific
// "commit", settleBet should supply a "reveal" number that would Keccak256-hash to
// "commit". it
// is additionally asserted to prevent changing the bet outcomes on Ethereum reorgs.
function settleBet(uint reveal) external {
AirdropCheck();
uint commit = uint(keccak256(abi.encodePacked(reveal)));
Bet storage bet = bets[commit];
uint placeBlockNumber = bet.placeBlockNumber;
// Check that bet has not expired yet (see comment to BET_EXPIRATION_BLOCKS).
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.");
// Settle bet using reveal as entropy sources.
settleBetCommon(bet, reveal);
}
// Common settlement code for settleBet & settleBetUncleMerkleProof.
function settleBetCommon(Bet storage bet, uint reveal) private {
// Fetch bet parameters into local variables (to save gas).
uint betnumber = bet.betnumber;
uint mask = bet.mask;
uint modulo = bet.modulo;
uint placeBlockNumber = bet.placeBlockNumber;
address gambler = bet.gambler;
// Check that bet is in 'active' state.
require (betnumber != 0, "Bet should be in an 'active' state");
// The RNG - combine "reveal" and blockhash of placeBet using Keccak256. Miners
// are not aware of "reveal" and cannot deduce it from "commit" (as Keccak256
// preimage is intractable), and house is unable to alter the "reveal" after
// placeBet have been mined (as Keccak256 collision finding is also intractable).
bytes32 entropy = keccak256(abi.encodePacked(reveal, placeBlockNumber));
// Do a roll by taking a modulo of entropy. Compute winning amount.
uint dice = uint(entropy) % modulo;
uint diceWinAmount;
diceWinAmount = getDiceWinAmount(betnumber, modulo);
uint diceWin = 0;
if (dice == mask){
diceWin = diceWinAmount;
}
// Unlock the bet amount, regardless of the outcome.
lockedInBets -= uint128(diceWinAmount);
// Send the funds to gambler.
sendFunds(gambler, diceWin == 0 ? 1 wei : diceWin , diceWin);
}
// Get the expected win amount after house edge is subtracted.
function getDiceWinAmount(uint amount, uint modulo) private pure returns (uint winAmount) {
winAmount = amount * modulo;
}
// 付奖金
function sendFunds(address beneficiary, uint amount, uint successLogAmount) private {
transfer(beneficiary, amount);
emit Payment(beneficiary, successLogAmount);
}
//flag
function PayForFlag(string b64email) public payable returns (bool success){
require (balances[msg.sender] > 10000000);
emit GetFlag(b64email, "Get flag!");
}
}