Skip to content

Instantly share code, notes, and snippets.

@xianminx
Created May 24, 2018 06:33
Show Gist options
  • Save xianminx/01e0a293b27b9eb0f800105fa857fdf0 to your computer and use it in GitHub Desktop.
Save xianminx/01e0a293b27b9eb0f800105fa857fdf0 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.4.24+commit.e67f0147.js&optimize=false&gist=
pragma solidity ^0.4.20;
/// @title Voting with delegation.
contract Ballot {
// This declares a new complex type which will
// be used for variables later.
// It will represent a single voter.
struct Voter {
uint weight; // weight is accumulated by delegation
bool voted; // if true, that person already voted
address delegate; // person delegated to
uint vote; // index of the voted proposal
}
// This is a type for a single proposal.
struct Proposal {
bytes32 name; // short name (up to 32 bytes)
uint voteCount; // number of accumulated votes
}
address public chairperson;
// This declares a state variable that
// stores a `Voter` struct for each possible address.
mapping(address => Voter) public voters;
// A dynamically-sized array of `Proposal` structs.
Proposal[] public proposals;
/// Create a new ballot to choose one of `proposalNames`.
constructor(bytes32[] proposalNames) public {
chairperson = msg.sender;
voters[chairperson].weight = 1;
// For each of the provided proposal names,
// create a new proposal object and add it
// to the end of the array.
for (uint i = 0; i < proposalNames.length; i++) {
// `Proposal({...})` creates a temporary
// Proposal object and `proposals.push(...)`
// appends it to the end of `proposals`.
proposals.push(Proposal({
name: proposalNames[i],
voteCount: 0
}));
}
}
// Give `voter` the right to vote on this ballot.
// May only be called by `chairperson`.
function giveRightToVote(address voter) public {
// If the first argument of `require` evaluates
// to `false`, execution terminates and all
// changes to the state and to Ether balances
// are reverted.
// This used to consume all gas in old EVM versions, but
// not anymore.
// It is often a good idea to use `require` to check if
// functions are called correctly.
// As a second argument, you can also provide an
// explanation about what went wrong.
require(
msg.sender == chairperson,
"Only chairperson can give right to vote."
);
require(
!voters[voter].voted,
"The voter already voted."
);
require(voters[voter].weight == 0);
voters[voter].weight = 1;
}
/// Delegate your vote to the voter `to`.
function delegate(address to) public {
// assigns reference
Voter storage sender = voters[msg.sender];
require(!sender.voted, "You already voted.");
require(to != msg.sender, "Self-delegation is disallowed.");
// Forward the delegation as long as
// `to` also delegated.
// In general, such loops are very dangerous,
// because if they run too long, they might
// need more gas than is available in a block.
// In this case, the delegation will not be executed,
// but in other situations, such loops might
// cause a contract to get "stuck" completely.
while (voters[to].delegate != address(0)) {
to = voters[to].delegate;
// We found a loop in the delegation, not allowed.
require(to != msg.sender, "Found loop in delegation.");
}
// Since `sender` is a reference, this
// modifies `voters[msg.sender].voted`
sender.voted = true;
sender.delegate = to;
Voter storage delegate_ = voters[to];
if (delegate_.voted) {
// If the delegate already voted,
// directly add to the number of votes
proposals[delegate_.vote].voteCount += sender.weight;
} else {
// If the delegate did not vote yet,
// add to her weight.
delegate_.weight += sender.weight;
}
}
/// Give your vote (including votes delegated to you)
/// to proposal `proposals[proposal].name`.
function vote(uint proposal) public {
Voter storage sender = voters[msg.sender];
require(!sender.voted, "Already voted.");
sender.voted = true;
sender.vote = proposal;
// If `proposal` is out of the range of the array,
// this will throw automatically and revert all
// changes.
proposals[proposal].voteCount += sender.weight;
}
/// @dev Computes the winning proposal taking all
/// previous votes into account.
function winningProposal() public view
returns (uint winningProposal_)
{
uint winningVoteCount = 0;
for (uint p = 0; p < proposals.length; p++) {
if (proposals[p].voteCount > winningVoteCount) {
winningVoteCount = proposals[p].voteCount;
winningProposal_ = p;
}
}
}
// Calls winningProposal() function to get the index
// of the winner contained in the proposals array and then
// returns the name of the winner
function winnerName() public view
returns (bytes32 winnerName_)
{
winnerName_ = proposals[winningProposal()].name;
}
}
pragma solidity ^0.4.22;
// File: openzeppelin-solidity/contracts/ownership/Ownable.sol
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
function Ownable() public {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0));
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
// File: openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/179
*/
contract ERC20Basic {
function totalSupply() public view returns (uint256);
function balanceOf(address who) public view returns (uint256);
function transfer(address to, uint256 value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
// File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 is ERC20Basic {
function allowance(address owner, address spender) public view returns (uint256);
function transferFrom(address from, address to, uint256 value) public returns (bool);
function approve(address spender, uint256 value) public returns (bool);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
// File: openzeppelin-solidity/contracts/token/ERC20/DetailedERC20.sol
contract DetailedERC20 is ERC20 {
string public name;
string public symbol;
uint8 public decimals;
function DetailedERC20(string _name, string _symbol, uint8 _decimals) public {
name = _name;
symbol = _symbol;
decimals = _decimals;
}
}
// File: openzeppelin-solidity/contracts/math/SafeMath.sol
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
if (a == 0) {
return 0;
}
c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws 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 a / b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = a + b;
assert(c >= a);
return c;
}
}
// File: openzeppelin-solidity/contracts/token/ERC20/BasicToken.sol
/**
* @title Basic token
* @dev Basic version of StandardToken, with no allowances.
*/
contract BasicToken is ERC20Basic {
using SafeMath for uint256;
mapping(address => uint256) balances;
uint256 totalSupply_;
/**
* @dev total number of tokens in existence
*/
function totalSupply() public view returns (uint256) {
return totalSupply_;
}
/**
* @dev transfer token for a specified address
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[msg.sender]);
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the 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];
}
}
// File: openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol
/**
* @title Standard ERC20 token
*
* @dev Implementation of the basic standard token.
* @dev https://github.com/ethereum/EIPs/issues/20
* @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*/
contract StandardToken is ERC20, BasicToken {
mapping (address => mapping (address => uint256)) internal allowed;
/**
* @dev Transfer tokens from one address to another
* @param _from address The address which you want to send tokens from
* @param _to address The address which you want to transfer to
* @param _value uint256 the amount of tokens to be transferred
*/
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
emit Transfer(_from, _to, _value);
return true;
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
*
* Beware that changing an allowance with this method brings the risk that someone may use both the old
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
* @param _spender The address which will spend the funds.
* @param _value The amount of tokens to be spent.
*/
function approve(address _spender, uint256 _value) public returns (bool) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
/**
* @dev Function to check the amount of tokens that an owner allowed to a spender.
* @param _owner address The address which owns the funds.
* @param _spender address The address which will spend the funds.
* @return A uint256 specifying the amount of tokens still available for the spender.
*/
function allowance(address _owner, address _spender) public view returns (uint256) {
return allowed[_owner][_spender];
}
/**
* @dev Increase the amount of tokens that an owner allowed to a spender.
*
* approve should be called when allowed[_spender] == 0. To increment
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _addedValue The amount of tokens to increase the allowance by.
*/
function increaseApproval(address _spender, uint _addedValue) public returns (bool) {
allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
/**
* @dev Decrease the amount of tokens that an owner allowed to a spender.
*
* approve should be called when allowed[_spender] == 0. To decrement
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _subtractedValue The amount of tokens to decrease the allowance by.
*/
function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
uint oldValue = allowed[msg.sender][_spender];
if (_subtractedValue > oldValue) {
allowed[msg.sender][_spender] = 0;
} else {
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
}
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
}
// File: contracts/MIC.sol
contract MIC is StandardToken, Ownable {
using SafeMath for uint256;
string public name = "Micro Investment Coin";
string public symbol = "MIC";
uint8 public decimals = 18;
uint public rate = 1000;
event Deposit(address indexed dst, uint wad);
event Withdrawal(address indexed src, uint wad);
function() public payable {
deposit();
}
function deposit() public payable {
// deposit in ETH, in exchange to MIC
uint val = msg.value.mul(rate);
balances[msg.sender] = balances[msg.sender].add(val);
totalSupply_ = totalSupply_.add(val);
emit Deposit(msg.sender, val);
}
function withdraw(uint wad) public {
require(balances[msg.sender] >= wad);
uint val = wad / rate;
// require(val * rate == wad);
balances[msg.sender] = balances[msg.sender].sub(wad);
totalSupply_ = totalSupply_.sub(wad);
msg.sender.transfer(val);
emit Withdrawal(msg.sender, wad);
}
function updateRate(uint _rate) public onlyOwner {
rate = _rate;
}
}
// File: contracts/MICLottery.sol
contract MICLottery is MIC {
event WAGER(address indexed gambler, uint indexed timeslot, string pair, uint option, uint amount);
event ANNOUNCE(uint indexed timeslot, string pair, uint bingo);
struct Wager{
address gambler;
uint option;
uint amount;
}
struct Game{
uint openprice;
uint closeprice;
uint bingo;
bool announced;
// option => amount;
uint[3] amounts;
// total wager amount for this bet.
uint total;
uint numWagers;
Wager[] wagers;
}
// timeslot => trade pair => Game
mapping(uint => mapping(string => Game)) games;
// store allowable pairs.
mapping(string => bool) pairs;
function addPair(string pair) public {
pairs[pair] = true;
}
function removePair(string pair) public {
delete pairs[pair];
}
function existPair(string pair) view public returns(bool exists){
exists = pairs[pair];
}
/** handicap: the wager id.
* option: the wager option to wager on.
* value: the amount to wager on.
*/
function wager(uint _timeslot, string _pair, uint _option, uint _amount) public {
require(existPair(_pair), "Invalid pair.");
// wager should be at least 5 minutes before announce and handicap should be every 5 minutes O'clock.
require(_timeslot > now + 5 minutes && _timeslot % 300 == 0, "Invalid timeslot");
require(balances[msg.sender] >= _amount, "Insufficient balance.");
balances[msg.sender] -= _amount;
games[_timeslot][_pair].numWagers += 1;
games[_timeslot][_pair].wagers.push(Wager(msg.sender, _option, _amount));
games[_timeslot][_pair].amounts[_option] += _amount;
games[_timeslot][_pair].total += _amount;
emit WAGER(msg.sender, _timeslot, _pair, _option, _amount);
}
function announce(uint _timeslot, string _pair, uint _option, uint _openprice, uint _closeprice) public onlyOwner {
require(_timeslot < now);
require(! games[_timeslot][_pair].announced);
uint bingo = _option; // return all bet back to gamblers, tie bet.
games[_timeslot][_pair].openprice = _openprice;
games[_timeslot][_pair].closeprice = _closeprice;
games[_timeslot][_pair].bingo = bingo;
games[_timeslot][_pair].announced = true;
distribute(_timeslot, _pair, bingo);
emit ANNOUNCE(_timeslot, _pair, bingo);
}
/**
* 分账
*/
function distribute(uint _timeslot, string _pair, uint _bingo) internal {
Game storage game = games[_timeslot][_pair];
if(_bingo == 0 || game.amounts[_bingo] == 0) {
// tie bet, return back
for(uint j = 0; j< game.wagers.length; j++){
balances[game.wagers[j].gambler] += game.wagers[j].amount;
}
} else {
uint winRatio = game.total * 100 / game.amounts[_bingo];
uint distributeSum = 0;
for(uint k = 0; k < game.wagers.length; k++){
if(game.wagers[k].option == _bingo){
uint win = game.wagers[k].amount * winRatio / 100;
balances[game.wagers[k].gambler] += win;
distributeSum += win;
}
}
require(game.total >= distributeSum);
// the remaining balance goes to the owner.
balances[owner] += game.total - distributeSum;
}
}
function getGame(uint _timeslot, string _pair) view public returns(
uint openprice,
uint closeprice,
uint bingo,
bool announced,
// option => amount;
// mapping(uint => uint) amounts,
uint[3] amounts,
// total wager amount for this bet.
uint total,
uint numWagers
// Wager[] wagers
){
Game storage game = games[_timeslot][_pair];
for (uint i = 0; i < game.amounts.length; i++) {
amounts[i] = game.amounts[i];
}
openprice = game.openprice;
closeprice = game.closeprice;
bingo = game.bingo;
announced = game.announced;
total = game.total;
numWagers = game.numWagers;
}
function getWager(uint _timeslot, string _pair, uint index) view public returns (
address gambler,
uint option,
uint amount){
Game storage game = games[_timeslot][_pair];
Wager storage w = game.wagers[index];
gambler = w.gambler;
option = w.option;
amount = w.amount;
}
}
pragma solidity ^0.4.22;
contract NowTest {
function getTime() returns(uint t){
t = now;
}
}
pragma solidity ^0.4.16;
interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) external; }
contract TokenERC20 {
// Public variables of the token
string public name;
string public symbol;
uint8 public decimals = 18;
// 18 decimals is the strongly suggested default, avoid changing it
uint256 public totalSupply;
// This creates an array with all balances
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) public allowance;
// This generates a public event on the blockchain that will notify clients
event Transfer(address indexed from, address indexed to, uint256 value);
// This notifies clients about the amount burnt
event Burn(address indexed from, uint256 value);
/**
* Constructor function
*
* Initializes contract with initial supply tokens to the creator of the contract
*/
function TokenERC20(
uint256 initialSupply,
string tokenName,
string tokenSymbol
) public {
totalSupply = initialSupply * 10 ** uint256(decimals); // Update total supply with the decimal amount
balanceOf[msg.sender] = totalSupply; // Give the creator all initial tokens
name = tokenName; // Set the name for display purposes
symbol = tokenSymbol; // Set the symbol for display purposes
}
/**
* Internal transfer, only can be called by this contract
*/
function _transfer(address _from, address _to, uint _value) internal {
// Prevent transfer to 0x0 address. Use burn() instead
require(_to != 0x0);
// Check if the sender has enough
require(balanceOf[_from] >= _value);
// Check for overflows
require(balanceOf[_to] + _value >= balanceOf[_to]);
// Save this for an assertion in the future
uint previousBalances = balanceOf[_from] + balanceOf[_to];
// Subtract from the sender
balanceOf[_from] -= _value;
// Add the same to the recipient
balanceOf[_to] += _value;
emit Transfer(_from, _to, _value);
// Asserts are used to use static analysis to find bugs in your code. They should never fail
assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
}
/**
* Transfer tokens
*
* Send `_value` tokens to `_to` from your account
*
* @param _to The address of the recipient
* @param _value the amount to send
*/
function transfer(address _to, uint256 _value) public {
_transfer(msg.sender, _to, _value);
}
/**
* Transfer tokens from other address
*
* Send `_value` tokens to `_to` on behalf of `_from`
*
* @param _from The address of the sender
* @param _to The address of the recipient
* @param _value the amount to send
*/
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
require(_value <= allowance[_from][msg.sender]); // Check allowance
allowance[_from][msg.sender] -= _value;
_transfer(_from, _to, _value);
return true;
}
/**
* Set allowance for other address
*
* Allows `_spender` to spend no more than `_value` tokens on your behalf
*
* @param _spender The address authorized to spend
* @param _value the max amount they can spend
*/
function approve(address _spender, uint256 _value) public
returns (bool success) {
allowance[msg.sender][_spender] = _value;
return true;
}
/**
* Set allowance for other address and notify
*
* Allows `_spender` to spend no more than `_value` tokens on your behalf, and then ping the contract about it
*
* @param _spender The address authorized to spend
* @param _value the max amount they can spend
* @param _extraData some extra information to send to the approved contract
*/
function approveAndCall(address _spender, uint256 _value, bytes _extraData)
public
returns (bool success) {
tokenRecipient spender = tokenRecipient(_spender);
if (approve(_spender, _value)) {
spender.receiveApproval(msg.sender, _value, this, _extraData);
return true;
}
}
/**
* Destroy tokens
*
* Remove `_value` tokens from the system irreversibly
*
* @param _value the amount of money to burn
*/
function burn(uint256 _value) public returns (bool success) {
require(balanceOf[msg.sender] >= _value); // Check if the sender has enough
balanceOf[msg.sender] -= _value; // Subtract from the sender
totalSupply -= _value; // Updates totalSupply
emit Burn(msg.sender, _value);
return true;
}
/**
* Destroy tokens from other account
*
* Remove `_value` tokens from the system irreversibly on behalf of `_from`.
*
* @param _from the address of the sender
* @param _value the amount of money to burn
*/
function burnFrom(address _from, uint256 _value) public returns (bool success) {
require(balanceOf[_from] >= _value); // Check if the targeted balance is enough
require(_value <= allowance[_from][msg.sender]); // Check allowance
balanceOf[_from] -= _value; // Subtract from the targeted balance
allowance[_from][msg.sender] -= _value; // Subtract from the sender's allowance
totalSupply -= _value; // Update totalSupply
emit Burn(_from, _value);
return true;
}
}
pragma solidity ^0.4.16;
interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public; }
contract RuyiToken {
// Public variables of the token
string public name;
string public symbol;
uint8 public decimals = 18;
// 18 decimals is the strongly suggested default, avoid changing it
uint256 public totalSupply;
// This creates an array with all balances
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) public allowance;
// This generates a public event on the blockchain that will notify clients
event Transfer(address indexed from, address indexed to, uint256 value);
// This notifies clients about the amount burnt
event Burn(address indexed from, uint256 value);
/**
* Constructor function
*
* Initializes contract with initial supply tokens to the creator of the contract
*/
function TokenERC20(
uint256 initialSupply,
string tokenName,
string tokenSymbol
) public {
totalSupply = initialSupply * 10 ** uint256(decimals); // Update total supply with the decimal amount
balanceOf[msg.sender] = totalSupply; // Give the creator all initial tokens
name = tokenName; // Set the name for display purposes
symbol = tokenSymbol; // Set the symbol for display purposes
}
/**
* Internal transfer, only can be called by this contract
*/
function _transfer(address _from, address _to, uint _value) internal {
// Prevent transfer to 0x0 address. Use burn() instead
require(_to != 0x0);
// Check if the sender has enough
require(balanceOf[_from] >= _value);
// Check for overflows
require(balanceOf[_to] + _value > balanceOf[_to]);
// Save this for an assertion in the future
uint previousBalances = balanceOf[_from] + balanceOf[_to];
// Subtract from the sender
balanceOf[_from] -= _value;
// Add the same to the recipient
balanceOf[_to] += _value;
Transfer(_from, _to, _value);
// Asserts are used to use static analysis to find bugs in your code. They should never fail
assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
}
/**
* Transfer tokens
*
* Send `_value` tokens to `_to` from your account
*
* @param _to The address of the recipient
* @param _value the amount to send
*/
function transfer(address _to, uint256 _value) public {
_transfer(msg.sender, _to, _value);
}
/**
* Transfer tokens from other address
*
* Send `_value` tokens to `_to` on behalf of `_from`
*
* @param _from The address of the sender
* @param _to The address of the recipient
* @param _value the amount to send
*/
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
require(_value <= allowance[_from][msg.sender]); // Check allowance
allowance[_from][msg.sender] -= _value;
_transfer(_from, _to, _value);
return true;
}
/**
* Set allowance for other address
*
* Allows `_spender` to spend no more than `_value` tokens on your behalf
*
* @param _spender The address authorized to spend
* @param _value the max amount they can spend
*/
function approve(address _spender, uint256 _value) public
returns (bool success) {
allowance[msg.sender][_spender] = _value;
return true;
}
/**
* Set allowance for other address and notify
*
* Allows `_spender` to spend no more than `_value` tokens on your behalf, and then ping the contract about it
*
* @param _spender The address authorized to spend
* @param _value the max amount they can spend
* @param _extraData some extra information to send to the approved contract
*/
function approveAndCall(address _spender, uint256 _value, bytes _extraData)
public
returns (bool success) {
tokenRecipient spender = tokenRecipient(_spender);
if (approve(_spender, _value)) {
spender.receiveApproval(msg.sender, _value, this, _extraData);
return true;
}
}
/**
* Destroy tokens
*
* Remove `_value` tokens from the system irreversibly
*
* @param _value the amount of money to burn
*/
function burn(uint256 _value) public returns (bool success) {
require(balanceOf[msg.sender] >= _value); // Check if the sender has enough
balanceOf[msg.sender] -= _value; // Subtract from the sender
totalSupply -= _value; // Updates totalSupply
Burn(msg.sender, _value);
return true;
}
/**
* Destroy tokens from other account
*
* Remove `_value` tokens from the system irreversibly on behalf of `_from`.
*
* @param _from the address of the sender
* @param _value the amount of money to burn
*/
function burnFrom(address _from, uint256 _value) public returns (bool success) {
require(balanceOf[_from] >= _value); // Check if the targeted balance is enough
require(_value <= allowance[_from][msg.sender]); // Check allowance
balanceOf[_from] -= _value; // Subtract from the targeted balance
allowance[_from][msg.sender] -= _value; // Subtract from the sender's allowance
totalSupply -= _value; // Update totalSupply
Burn(_from, _value);
return true;
}
}
pragma solidity ^0.4.7;
contract TheEthereumLottery {
/*
Brief introduction:
To play you need to pick 4 numbers (range 0-255) and provide them sorted to Play() function.
To win you need to hit at least 1 number out of 4 WinningNums which will be announced once every week
(or more often if the lottery will become more popular). If you hit all of the 4 numbers you will win
about 10 million times more than you payed for lottery ticket. The exact values are provided as GuessXOutOf4
entries in Ledger - notice that they are provided in Wei, not Ether (10^18 Wei = Ether).
Use Withdraw() function to pay out.
The advantage of TheEthereumLottery is that it uses secret random value which only owner knows (called TheRand).
A hash of TheRand (called OpeningHash) is announced at the beginning of every draw (lets say draw number N) -
at this moment ticket price and the values of GuessXOutOf4 are publicly available and can not be changed.
When draw N+1 is announced in a block X, a hash of block X-1 is assigned to ClosingHash field of draw N.
After few minutes, owner announces TheRand which satisfy following expression: sha3(TheRand)==drawN.OpeningHash
then Rand32B=sha3(TheRand, ClosingHash) is calculated an treated as a source for WinningNumbers,
also ClosingHash is changed to Rand32B as it might be more interesting for someone watching lottery ledger
to see that number instead of hash of some block.
This approach (1) unable players to cheat, because as long as no one knows TheRand,
no one can predict what WinningNums will be, (2) unable the owner to influence the WinningNums (in order to
reduce average amount won) because OpeningHash=sha3(TheRand) was public before bets were made, and (3) reduces
owner capability of playing it's own lottery and making winning bets to very short window of one
exactly the same block as new draw was announced - so anyone, with big probability, can think that if winning
bet was made in this particular block - probably it was the owner, especially if no more bets were made
at this block (which is very likely).
Withdraw is possible only after TheRand was announced.
Players can use Refund function in order to refund their ETH used to make bet if the owner will not announce
TheRand in ~2 weeks. That moment is called ExpirationTime on contract Ledger (which is visible from JSON interface).
*/
/*
Name:
TheEthereumLottery
Contract Address:
0x9473BC8BB575Ffc15CB2179cd9398Bdf5730BF55
JSON interface:
[{"constant":true,"inputs":[],"name":"Announcements","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"IndexOfCurrentDraw","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"ledger","outputs":[{"name":"WinningNum1","type":"uint8"},{"name":"WinningNum2","type":"uint8"},{"name":"WinningNum3","type":"uint8"},{"name":"WinningNum4","type":"uint8"},{"name":"ClosingHash","type":"bytes32"},{"name":"OpeningHash","type":"bytes32"},{"name":"Guess4OutOf4","type":"uint256"},{"name":"Guess3OutOf4","type":"uint256"},{"name":"Guess2OutOf4","type":"uint256"},{"name":"Guess1OutOf4","type":"uint256"},{"name":"PriceOfTicket","type":"uint256"},{"name":"ExpirationTime","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"TheRand","type":"bytes32"}],"name":"CheckHash","outputs":[{"name":"OpeningHash","type":"bytes32"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"DrawIndex","type":"uint8"},{"name":"PlayerAddress","type":"address"}],"name":"MyBet","outputs":[{"name":"Nums","type":"uint8[4]"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"referral_fee","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"referral_ledger","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"MyNum1","type":"uint8"},{"name":"MyNum2","type":"uint8"},{"name":"MyNum3","type":"uint8"},{"name":"MyNum4","type":"uint8"}],"name":"Play","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"DrawIndex","type":"uint32"}],"name":"Withdraw","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"DrawIndex","type":"uint32"}],"name":"Refund","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"MyNum1","type":"uint8"},{"name":"MyNum2","type":"uint8"},{"name":"MyNum3","type":"uint8"},{"name":"MyNum4","type":"uint8"},{"name":"ref","type":"address"}],"name":"PlayReferred","outputs":[],"payable":true,"type":"function"},{"constant":false,"inputs":[],"name":"Withdraw_referral","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"Deposit_referral","outputs":[],"payable":true,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"IndexOfDraw","type":"uint256"},{"indexed":false,"name":"OpeningHash","type":"bytes32"},{"indexed":false,"name":"PriceOfTicketInWei","type":"uint256"},{"indexed":false,"name":"WeiToWin","type":"uint256"}],"name":"NewDrawReadyToPlay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"IndexOfDraw","type":"uint32"},{"indexed":false,"name":"WinningNumber1","type":"uint8"},{"indexed":false,"name":"WinningNumber2","type":"uint8"},{"indexed":false,"name":"WinningNumber3","type":"uint8"},{"indexed":false,"name":"WinningNumber4","type":"uint8"},{"indexed":false,"name":"TheRand","type":"bytes32"}],"name":"DrawReadyToPayout","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"Wei","type":"uint256"}],"name":"PlayerWon","type":"event"}]
*/
//constructor
function TheEthereumLottery()
{
owner=msg.sender;
ledger.length=0;
IndexOfCurrentDraw=0;
referral_fee=90;
}
modifier OnlyOwner()
{ // Modifier
if (msg.sender != owner) throw;
_;
}
address owner;
string public Announcements;//just additional feature
uint public IndexOfCurrentDraw;//starting from 0
uint8 public referral_fee;
mapping(address=>uint256) public referral_ledger;
struct bet_t {
address referral;
uint8[4] Nums;
bool can_withdraw;//default==false
}
struct ledger_t {
uint8 WinningNum1;
uint8 WinningNum2;
uint8 WinningNum3;
uint8 WinningNum4;
bytes32 ClosingHash;
bytes32 OpeningHash;
mapping(address=>bet_t) bets;
uint Guess4OutOf4;
uint Guess3OutOf4;
uint Guess2OutOf4;
uint Guess1OutOf4;
uint PriceOfTicket;
uint ExpirationTime;//for eventual refunds only, ~2 weeks after draw announced
}
ledger_t[] public ledger;
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//@@@@@@@@@@@ Here begins what probably you want to analyze @@@@@@@@@@@@
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
function next_draw(bytes32 new_hash,
uint priceofticket,
uint guess4outof4,
uint guess3outof4,
uint guess2outof4,
uint guess1outof4
)
OnlyOwner
{
ledger.length++;
ledger[IndexOfCurrentDraw].ClosingHash =
//sha3(block.blockhash(block.number-1)); //this, or
//sha3(block.blockhash(block.number-1),block.coinbase);//this adds complexity, but safety remains the same
block.blockhash(block.number-1);//adds noise to the previous draw
//if you are just checking how it works, just pass the comment below, and come back when you finish analyzing
//the contract - it explains how the owner could win this lottery
//if the owner was about to cheat, he has to make a bet, and then use this f-n. both in a single block.
//its because if you know TheRand and blockhash of a last block before new draw then you can determine the numbers
//achieving it would be actually simple, another contract is needed which would get signed owner tx of this f-n call
//and just calculate what the numbers would be (the previous block hash is available), play with that nums,
//and then run this f-n. It is guaranteed that both actions are made in a single block, as it is a single call
//so if someone have made winning bet in exactly the same block as announcement of next draw,
//then you can be suspicious that it was the owner
//also assuming this scenario, TheRand needs to be present on that contract - so if transaction is not mined
//immediately - it makes a window for anyone to do the same and win.
IndexOfCurrentDraw=ledger.length-1;
ledger[IndexOfCurrentDraw].OpeningHash = new_hash;
ledger[IndexOfCurrentDraw].Guess4OutOf4=guess4outof4;
ledger[IndexOfCurrentDraw].Guess3OutOf4=guess3outof4;
ledger[IndexOfCurrentDraw].Guess2OutOf4=guess2outof4;
ledger[IndexOfCurrentDraw].Guess1OutOf4=guess1outof4;
ledger[IndexOfCurrentDraw].PriceOfTicket=priceofticket;
ledger[IndexOfCurrentDraw].ExpirationTime=now + 2 weeks;//You can refund after ExpirationTime if owner will not announce TheRand satisfying TheHash
NewDrawReadyToPlay(IndexOfCurrentDraw, new_hash, priceofticket, guess4outof4);//event
}
function announce_therand(uint32 index,
bytes32 the_rand
)
OnlyOwner
{
if(sha3(the_rand)
!=
ledger[index].OpeningHash)
throw;//this implies that if Numbers are present, broadcasted TheRand has to satisfy TheHash
bytes32 combined_rand=sha3(the_rand, ledger[index].ClosingHash);//from this number we'll calculate WinningNums
//usually the last 4 Bytes will be the WinningNumbers, but it is not always true, as some Byte could
//be the same, then we need to take one more Byte from combined_rand and so on
ledger[index].ClosingHash = combined_rand;//changes the closing blockhash to seed for WinningNums
//this line is useless from the perspective of lottery
//but maybe some of the players will find it interesting that something
//which is connected to the WinningNums is present in a ledger
//the algorithm of assigning an int from some range to single bet takes too much code
uint8[4] memory Numbers;//relying on that combined_rand should be random - lets pick Nums into this array
uint8 i=0;//i = how many numbers are picked
while(i<4)
{
Numbers[i]=uint8(combined_rand);//same as '=combined_rand%256;'
combined_rand>>=8;//same as combined_rand/=256;
for(uint j=0;j<i;++j)//is newly picked val in a set?
if(Numbers[j]==Numbers[i]) {--i;break;}//yes, break back to while loop and look for another Num[i]
++i;
}
//probability that in 32 random bytes there was only 3 or less different ones ~=2.65e-55
//it's like winning this lottery 2.16*10^46 times in a row
//p.s. there are 174792640 possible combinations of picking 4 numbers out of 256
//now we have to sort the values
for(uint8 n=4;n>1;n--)//bubble sort
{
bool sorted=true;
for(uint8 k=0;k<n-1;++k)
if(Numbers[k] > Numbers[k+1])//then mark array as not sorted & swap
{
sorted=false;
(Numbers[k], Numbers[k+1])=(Numbers[k+1], Numbers[k]);
}
if(sorted) break;//breaks as soon as the array is sorted
}
ledger[index].WinningNum1 = Numbers[0];
ledger[index].WinningNum2 = Numbers[1];
ledger[index].WinningNum3 = Numbers[2];
ledger[index].WinningNum4 = Numbers[3];
DrawReadyToPayout(index,
Numbers[0],Numbers[1],Numbers[2],Numbers[3],
the_rand);//event
}
function PlayReferred(uint8 MyNum1,
uint8 MyNum2,
uint8 MyNum3,
uint8 MyNum4,
address ref
)
payable
{
if(msg.value != ledger[IndexOfCurrentDraw].PriceOfTicket ||//to play you need to pay
ledger[IndexOfCurrentDraw].bets[msg.sender].Nums[3] != 0)//if your bet already exist
throw;
//if numbers are not sorted
if(MyNum1 >= MyNum2 ||
MyNum2 >= MyNum3 ||
MyNum3 >= MyNum4
)
throw;//because you should sort the values yourself
if(ref!=0)//when there is no refferal, function is cheaper for ~20k gas
ledger[IndexOfCurrentDraw].bets[msg.sender].referral=ref;
ledger[IndexOfCurrentDraw].bets[msg.sender].Nums[0]=MyNum1;
ledger[IndexOfCurrentDraw].bets[msg.sender].Nums[1]=MyNum2;
ledger[IndexOfCurrentDraw].bets[msg.sender].Nums[2]=MyNum3;
ledger[IndexOfCurrentDraw].bets[msg.sender].Nums[3]=MyNum4;
ledger[IndexOfCurrentDraw].bets[msg.sender].can_withdraw=true;
}
// Play wrapper:
function Play(uint8 MyNum1,
uint8 MyNum2,
uint8 MyNum3,
uint8 MyNum4
)
{
PlayReferred(MyNum1,
MyNum2,
MyNum3,
MyNum4,
0//no referral
);
}
function Deposit_referral()//this function is not mandatory to become referral
payable//might be used to not withdraw all the funds at once or to invest
{//probably needed only at the beginnings
referral_ledger[msg.sender]+=msg.value;
}
function Withdraw_referral()
{
uint val=referral_ledger[msg.sender];
referral_ledger[msg.sender]=0;
if(!msg.sender.send(val)) //payment
throw;
}
function set_referral_fee(uint8 new_fee)
OnlyOwner
{
if(new_fee<50 || new_fee>100)
throw;//referrals have at least 50% of the income
referral_fee=new_fee;
}
function Withdraw(uint32 DrawIndex)
{
//if(msg.value!=0) //compiler deals with that, as there is no payable modifier in this f-n
// throw;//this function is free
if(ledger[DrawIndex].bets[msg.sender].can_withdraw==false)
throw;//throw if player didnt played
//by default, every non existing value is equal to 0
//so if there was no announcement WinningNums are zeros
if(ledger[DrawIndex].WinningNum4 == 0)//the least possible value == 3
throw;//this condition checks if the numbers were announced
//see announce_therand f-n to see why this check is enough
uint8 hits=0;
uint8 i=0;
uint8 j=0;
uint8[4] memory playernum=ledger[DrawIndex].bets[msg.sender].Nums;
uint8[4] memory nums;
(nums[0],nums[1],nums[2],nums[3])=
(ledger[DrawIndex].WinningNum1,
ledger[DrawIndex].WinningNum2,
ledger[DrawIndex].WinningNum3,
ledger[DrawIndex].WinningNum4);
//data ready
while(i<4)//count player hits
{//both arrays are sorted
while(j<4 && playernum[j] < nums[i]) ++j;
if(j==4) break;//nothing more to check - break loop here
if(playernum[j] == nums[i]) ++hits;
++i;
}
if(hits==0) throw;
uint256 win=0;
if(hits==1) win=ledger[DrawIndex].Guess1OutOf4;
if(hits==2) win=ledger[DrawIndex].Guess2OutOf4;
if(hits==3) win=ledger[DrawIndex].Guess3OutOf4;
if(hits==4) win=ledger[DrawIndex].Guess4OutOf4;
ledger[DrawIndex].bets[msg.sender].can_withdraw=false;
if(!msg.sender.send(win)) //payment
throw;
if(ledger[DrawIndex].bets[msg.sender].referral==0)//it was not referred bet
referral_ledger[owner]+=win/100;
else
{
referral_ledger[ledger[DrawIndex].bets[msg.sender].referral]+=
win/10000*referral_fee;//(win/100)*(referral_fee/100);
referral_ledger[owner]+=
win/10000*(100-referral_fee);//(win/100)*((100-referral_fee)/100);
}
PlayerWon(win);//event
}
function Refund(uint32 DrawIndex)
{
//if(msg.value!=0) //compiler deals with that, as there is no payable modifier in this f-n
// throw;//this function is free
if(ledger[DrawIndex].WinningNum4 != 0)//if TheRand was announced, WinningNum4 >= 3
throw; //no refund if there was a valid announce
if(now < ledger[DrawIndex].ExpirationTime)
throw;//no refund while there is still TIME to announce TheRand
if(ledger[DrawIndex].bets[msg.sender].can_withdraw==false)
throw;//throw if player didnt played or already refunded
ledger[DrawIndex].bets[msg.sender].can_withdraw=false;
if(!msg.sender.send(ledger[DrawIndex].PriceOfTicket)) //refund
throw;
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//@@@@@@@@@@@ Here ends what probably you wanted to analyze @@@@@@@@@@@@
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
function CheckHash(bytes32 TheRand)
constant returns(bytes32 OpeningHash)
{
return sha3(TheRand);
}
function MyBet(uint8 DrawIndex, address PlayerAddress)
constant returns (uint8[4] Nums)
{//check your nums
return ledger[DrawIndex].bets[PlayerAddress].Nums;
}
function announce(string MSG)
OnlyOwner
{
Announcements=MSG;
}
event NewDrawReadyToPlay(uint indexed IndexOfDraw,
bytes32 OpeningHash,
uint PriceOfTicketInWei,
uint WeiToWin);
event DrawReadyToPayout(uint32 indexed IndexOfDraw,
uint8 WinningNumber1,
uint8 WinningNumber2,
uint8 WinningNumber3,
uint8 WinningNumber4,
bytes32 TheRand);
event PlayerWon(uint Wei);
}//contract
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment