原理;

https://medium.com/dapppub/fairdicedesign-315a4e253ad6

早期版本地址:

https://etherscan.io/address/0xD1CEeeef70c61da45800bd81BE3352160ad72F2a#code

https://etherscan.io/address/0xD1CEeeefA68a6aF0A5f6046132D986066c7f9426#code

pragma solidity ^0.4.23;

contract Dice2Win {

/// Constants

// Chance to win jackpot - currently 0.1%
uint256 constant JACKPOT_MODULO = 1000; // Each bet is deducted 2% amount - 1% is house edge, 1% goes to jackpot fund.
uint256 constant HOUSE_EDGE_PERCENT = 2;
uint256 constant JACKPOT_FEE_PERCENT = 50; // Minimum supported bet is 0.02 ETH, made possible by optimizing gas costs
// compared to our competitors.
uint256 constant MIN_BET = 0.02 ether; // Only bets higher that 0.1 ETH have a chance to win jackpot.
uint256 constant MIN_JACKPOT_BET = 0.1 ether; // Random number generation is provided by the hashes of future blocks.
// Two blocks is a good compromise between responsive gameplay and safety from miner attacks.
uint256 constant BLOCK_DELAY = 2; // Bets made more than 100 blocks ago are considered failed - this has to do
// with EVM limitations on block hashes that are queryable. Settlement failure
// is most probably due to croupier bot failure, if you ever end in this situation
// ask dice2.win support for a refund!
uint256 constant BET_EXPIRATION_BLOCKS = 100; /// Contract storage. // Changing ownership of the contract safely
address public owner;
address public nextOwner; // Max bet limits for coin toss/single dice and double dice respectively.
// Setting these values to zero effectively disables the respective games.
uint256 public maxBetCoinDice;
uint256 public maxBetDoubleDice; // Current jackpot size.
uint128 public jackpotSize; // Amount locked in ongoing bets - this is to be sure that we do not commit to bets
// that we cannot fulfill in case of win.
uint128 public lockedInBets; /// Enum representing games enum GameId {
CoinFlip,
SingleDice,
DoubleDice, MaxGameId
} uint256 constant MAX_BLOCK_NUMBER = 2 ** 56;
uint256 constant MAX_BET_MASK = 2 ** 64;
uint256 constant MAX_AMOUNT = 2 ** 128; // Struct is tightly packed into a single 256-bit by Solidity compiler.
// This is made to reduce gas costs of placing & settlement transactions.
struct ActiveBet {
// A game that was played.
GameId gameId;
// Block number in which bet transaction was mined.
uint56 placeBlockNumber;
// A binary mask with 1 for each option.
// For example, if you play dice, the mask ranges from 000001 in binary (betting on one)
// to 111111 in binary (betting on all dice outcomes at once).
uint64 mask;
// Bet amount in wei.
uint128 amount;
} mapping (address => ActiveBet) activeBets; // Events that are issued to make statistic recovery easier.
event FailedPayment(address indexed _beneficiary, uint256 amount);
event Payment(address indexed _beneficiary, uint256 amount);
event JackpotPayment(address indexed _beneficiary, uint256 amount); /// Contract governance. constructor () public {
owner = msg.sender;
// all fields are automatically initialized to zero, which is just what's needed.
} modifier onlyOwner {
require (msg.sender == owner);
_;
} // This is pretty standard ownership change routine. function approveNextOwner(address _nextOwner) public onlyOwner {
require (_nextOwner != owner);
nextOwner = _nextOwner;
} function acceptNextOwner() public {
require (msg.sender == nextOwner);
owner = nextOwner;
} // Contract may be destroyed only when there are no ongoing bets,
// either settled or refunded. All funds are transferred to contract owner. function kill() public onlyOwner {
require (lockedInBets == 0);
selfdestruct(owner);
} // Fallback function deliberately left empty. It's primary use case
// is to top up the bank roll.
function () public payable {
} // Helper routines to alter the respective max bet limits.
function changeMaxBetCoinDice(uint256 newMaxBetCoinDice) public onlyOwner {
maxBetCoinDice = newMaxBetCoinDice;
} function changeMaxBetDoubleDice(uint256 newMaxBetDoubleDice) public onlyOwner {
maxBetDoubleDice = newMaxBetDoubleDice;
} // Ability to top up jackpot faster than it's natural growth by house fees.
function increaseJackpot(uint256 increaseAmount) public onlyOwner {
require (increaseAmount <= address(this).balance);
require (jackpotSize + lockedInBets + increaseAmount <= address(this).balance);
jackpotSize += uint128(increaseAmount);
} // Funds withdrawal to cover costs of dice2.win operation.
function withdrawFunds(address beneficiary, uint256 withdrawAmount) public onlyOwner {
require (withdrawAmount <= address(this).balance);
require (jackpotSize + lockedInBets + withdrawAmount <= address(this).balance);
sendFunds(beneficiary, withdrawAmount, withdrawAmount);
} /// Betting logic // Bet transaction - issued by player. Contains the desired game id and betting options
// mask. Wager is the value in ether attached to the transaction.
function placeBet(GameId gameId, uint256 betMask) public payable {
// Check that there is no ongoing bet already - we support one game at a time
// from single address.
ActiveBet storage bet = activeBets[msg.sender];
require (bet.amount == 0); // Check that the values passed fit into respective limits.
require (gameId < GameId.MaxGameId);
require (msg.value >= MIN_BET && msg.value <= getMaxBet(gameId));
require (betMask < MAX_BET_MASK); // Determine roll parameters.
uint256 rollModulo = getRollModulo(gameId);
uint256 rollUnder = getRollUnder(rollModulo, betMask); // Check whether contract has enough funds to process this bet.
uint256 reservedAmount = getDiceWinAmount(msg.value, rollModulo, rollUnder);
uint256 jackpotFee = getJackpotFee(msg.value);
require (jackpotSize + lockedInBets + reservedAmount + jackpotFee <= address(this).balance); // Update reserved amounts.
lockedInBets += uint128(reservedAmount);
jackpotSize += uint128(jackpotFee); // Store the bet parameters on blockchain.
bet.gameId = gameId;
bet.placeBlockNumber = uint56(block.number);
bet.mask = uint64(betMask);
bet.amount = uint128(msg.value);
} // Settlement transaction - can be issued by anyone, but is designed to be handled by the
// dice2.win croupier bot. However nothing prevents you from issuing it yourself, or anyone
// issuing the settlement transaction on your behalf - that does not affect the bet outcome and
// is in fact encouraged in the case the croupier bot malfunctions.
function settleBet(address gambler) public {
// Check that there is already a bet for this gambler.
ActiveBet storage bet = activeBets[gambler];
require (bet.amount != 0); // Check that the bet is neither too early nor too late.
require (block.number > bet.placeBlockNumber + BLOCK_DELAY);
require (block.number <= bet.placeBlockNumber + BET_EXPIRATION_BLOCKS); // The RNG - use hash of the block that is unknown at the time of placing the bet,
// SHA3 it with gambler address. The latter step is required to make the outcomes of
// different settlement transactions mined into the same block different.
bytes32 entropy = keccak256(gambler, blockhash(bet.placeBlockNumber + BLOCK_DELAY)); uint256 diceWin = 0;
uint256 jackpotWin = 0; // Determine roll parameters, do a roll by taking a modulo of entropy.
uint256 rollModulo = getRollModulo(bet.gameId);
uint256 dice = uint256(entropy) % rollModulo; uint256 rollUnder = getRollUnder(rollModulo, bet.mask);
uint256 diceWinAmount = getDiceWinAmount(bet.amount, rollModulo, rollUnder); // Check the roll result against the bet bit mask.
if ((2 ** dice) & bet.mask != 0) {
diceWin = diceWinAmount;
} // Unlock the bet amount, regardless of the outcome.
lockedInBets -= uint128(diceWinAmount); // Roll for a jackpot (if eligible).
if (bet.amount >= MIN_JACKPOT_BET) {
// The second modulo, statistically independent from the "main" dice roll.
// Effectively you are playing two games at once!
uint256 jackpotRng = (uint256(entropy) / rollModulo) % JACKPOT_MODULO; // Bingo!
if (jackpotRng == 0) {
jackpotWin = jackpotSize;
jackpotSize = 0;
}
} // Remove the processed bet from blockchain storage.
delete activeBets[gambler]; // Tally up the win.
uint256 totalWin = diceWin + jackpotWin; if (totalWin == 0) {
totalWin = 1 wei;
} if (jackpotWin > 0) {
emit JackpotPayment(gambler, jackpotWin);
} // Send the funds to gambler.
sendFunds(gambler, totalWin, diceWin);
} // Refund transaction - return the bet amount of a roll that was not processed
// in due timeframe (100 Ethereum blocks). Processing such bets is not possible,
// because EVM does not have access to the hashes further than 256 blocks ago.
//
// Like settlement, this transaction may be issued by anyone, but if you ever
// find yourself in situation like this, just contact the dice2.win support!
function refundBet(address gambler) public {
// Check that there is already a bet for this gambler.
ActiveBet storage bet = activeBets[gambler];
require (bet.amount != 0); // The bet should be indeed late.
require (block.number > bet.placeBlockNumber + BET_EXPIRATION_BLOCKS); // Determine roll parameters to calculate correct amount of funds locked.
uint256 rollModulo = getRollModulo(bet.gameId);
uint256 rollUnder = getRollUnder(rollModulo, bet.mask); lockedInBets -= uint128(getDiceWinAmount(bet.amount, rollModulo, rollUnder)); // Delete the bet from the blockchain.
uint256 refundAmount = bet.amount;
delete activeBets[gambler]; // Refund the bet.
sendFunds(gambler, refundAmount, refundAmount);
} /// Helper routines. // Number of bet options for specific game.
function getRollModulo(GameId gameId) pure private returns (uint256) {
if (gameId == GameId.CoinFlip) {
// Heads/tails
return 2; } else if (gameId == GameId.SingleDice) {
// One through six.
return 6; } else if (gameId == GameId.DoubleDice) {
// 6*6=36 possible outcomes.
return 36; }
} // Max bet amount for a specific game.
function getMaxBet(GameId gameId) view private returns (uint256) {
if (gameId == GameId.CoinFlip) {
return maxBetCoinDice; } else if (gameId == GameId.SingleDice) {
return maxBetCoinDice; } else if (gameId == GameId.DoubleDice) {
return maxBetDoubleDice; }
} // Count 1 bits in the bet bit mask to find the total number of bet options
function getRollUnder(uint256 rollModulo, uint256 betMask) pure private returns (uint256) {
uint256 rollUnder = 0;
uint256 singleBitMask = 1;
for (uint256 shift = 0; shift < rollModulo; shift++) {
if (betMask & singleBitMask != 0) {
rollUnder++;
} singleBitMask *= 2;
} return rollUnder;
} // Get the expected win amount after house edge is subtracted.
function getDiceWinAmount(uint256 amount, uint256 rollModulo, uint256 rollUnder) pure private
returns (uint256) {
require (0 < rollUnder && rollUnder <= rollModulo);
return amount * rollModulo / rollUnder * (100 - HOUSE_EDGE_PERCENT) / 100;
} // Get the portion of bet amount that is to be accumulated in the jackpot.
function getJackpotFee(uint256 amount) pure private returns (uint256) {
return amount * HOUSE_EDGE_PERCENT / 100 * JACKPOT_FEE_PERCENT / 100;
} // Helper routine to process the payment.
function sendFunds(address beneficiary, uint256 amount, uint256 successLogAmount) private {
if (beneficiary.send(amount)) {
emit Payment(beneficiary, successLogAmount);
} else {
emit FailedPayment(beneficiary, amount);
}
}

}

dice2win早期版本的更多相关文章

  1. 将“早期版本的Windows”改名

    将“早期版本的Windows”改名,并修改系统等待时间 问题描述:       先装Windows XP,再装Windows 7,启动菜单会出现“早期版本的Windows”与“Windows 7”两个 ...

  2. 安装了SQL2005再安装SQL 2008R2,提示此计算机上安装了 Microsoft Visual Studio 2008 的早期版本和检查是否安装了 SQL Server 2005 Express 工具的解决方案

    工作电脑上安装了SQL 2005, 但是客户电脑上安装的是SQL 2008R2,有时候连接他们的库调试没法连接,很不方便.然后又安装了个SQL2008 R2,期间遇到这两个问题,网上搜索了一下收到了解 ...

  3. SQL SERVER安装提示“安装了 Microsoft Visual Studio 2008 的早期版本

    工作共遇到的问题记录: 安装Sql Server 2008 R2时提示错误:“此计算机上安装了 Microsoft Visual Studio 2008 的早期版本.请在安装 SQL Server 2 ...

  4. 【转】预编译头文件来自编译器的早期版本,或者预编译头为 C++ 而在 C 中使用它(或相反)

    用VC++ 2008 编写C语言程序,编译出现错误: 预编译头文件来自编译器的早期版本,或者预编译头为 C++ 而在 C 中使用它(或相反) 解决方法: 建工程时 建立空项目 或者在项目设置里关闭预编 ...

  5. VS2005 MFC 预编译头文件来自编译器的早期版本,或者预编译头为 C++ 而在 C 中使用它(或相反)

    当 Visual C++ 项目启用了预编译头 (Precompiled header) 功能时,如果项目中同时混合有 .c 和 .cpp 源文件,则可能收到 C1853 编译器错误:fatal err ...

  6. Java 垃圾回收机制(早期版本)

    Java 垃圾回收机制在我们普通理解来看,应该视为一种低优先级的后台进程来实现的,其实早期版本的Java虚拟机并非以这种方式实现的. 先从一种很简单的垃圾回收方式开始. 引用计数 引用计数是一种简单但 ...

  7. [转帖]Windows 10 部分早期版本已完全停止技术支持服务

    Windows 10 部分早期版本已完全停止技术支持服务 2019-4-12 01:27| 发布者: cjy__05| 查看: 10186| 评论: 47|来自: pcbeta 收藏分享 转帖来源:h ...

  8. 从 Confluence 5.3 及其早期版本中恢复空间

    如果你需要从 Confluence 5.3 及其早期版本中的导出文件恢复到晚于 Confluence 5.3 的 Confluence 中的话.你可以使用临时的 Confluence 空间安装,然后将 ...

  9. 预编译头文件来自编译器的早期版本,或者预编译头为 C++ 而在 C 中使用它(或相反)(转)

    用VC++ 2008 编写C语言程序,编译出现错误: 预编译头文件来自编译器的早期版本,或者预编译头为 C++ 而在 C 中使用它(或相反) 解决方法: 建工程时 建立空项目 或者在项目设置里关闭预编 ...

随机推荐

  1. NoSQL数据库浅析

    NoSQL(NoSQL = Not Only SQL ):非关系型的数据库.NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称. 今天我们可以通过第 ...

  2. 本人擅长Ai、Fw、Fl、Br、Ae、Pr、Id、Ps等

    本人擅长Ai.Fw.Fl.Br.Ae.Pr.Id.Ps等软件的安装与卸载,精通CSS.JavaScript.PHP.ASP.C.C++.C#.Java.Ruby.Perl.Lisp.python.Ob ...

  3. python的基本知识

    1. python的简介    python的创始⼈人为吉多·范罗苏姆(Guido van Rossum).1989年年的圣诞节期间,吉多· 范罗苏姆为了了在阿姆斯特丹丹打发时间,决⼼心开发⼀个新的脚 ...

  4. 浅谈ETL架构中ODS的作用以及如何在HaoheDI中自动创建ODS表

    什么是ODS表? 在ETL架构中,源数据很少会直接抽取加载到数据仓库EDW,二者之间往往会设置一个源数据的临时存储区域,存储数据在清洗转换前的原始形态,通常被大家称做操作型数据存储,简称ODS,在Ki ...

  5. 最新版的stm32f1xx.h文件中取消了u8, u16, u32的类型定义

    使用芯片stm32f103zet6和stm32l151c8t6,在移植程序时发现,编译器提示u8未定义: 在Keil MDK 开发环境里,st定义无符号32位整形数据有很多种表示方法: 1 unsig ...

  6. [OpenCV][关于OpenCV3.2.0+VS2015+Win10环境搭建]

    在VS2015上搭建OpenCV3.2.0+Win10 1.OpenCV3.2.0在VS2015上的配置 1).下载.解压OPENCV 登陆OpenCV官方网站下载相应版本的OpenCV-SDK 这里 ...

  7. Python学习手册之正则表达式和元字符

    在上一篇文章中,我们介绍了 Python 的数据封装.类方法.静态方法和属性函数,现在我们介绍 Python 的正则表达式和元字符.查看上一篇文章请点击:https://www.cnblogs.com ...

  8. sigmoid function和softmax function

    sigmoid函数(也叫逻辑斯谛函数):  引用wiki百科的定义: A logistic function or logistic curve is a common “S” shape (sigm ...

  9. Solr与Lucene的区别

    Lucene是一个优秀的开源搜索库,Solr是在Lucene上封装的完善的搜索引擎.通俗地说,如果Solr是汽车,那么Lucene就是发动机,没有发动机,汽车就没法运转,但对于用户来说只可开车,不能开 ...

  10. 使用 Linux 下的的logrotate进行日志的切割

    实际生产中,使用一个log文件来记录所有信息的话,一方面,时间过久,就会占用很大的空间:另一方面,就是一个文件记录对于后期日志的查看非常不利.为了解决查看了一下资料,发现linux里面有一个logro ...