原理;

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. Oracle的分析函数

    Oracle的分析函数row_number(),rank(),dense_rank()的用法与区别 比如查询工资排名第7的员工信息,可以用分析函数来做. --查询工资排名第7的员工信息select * ...

  2. Jquery 操作 select 的操作指南

    这里我们以一个简单的select作为原型来进行说明: <select> <option value="a1">香蕉1</option> < ...

  3. jQuery动态绑定事件(左右移动)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. font(字体)所使用的属性

    1.font-weight:normal blod bolder lighter  100-900之间 400=normal p:first-child{ padding-top: 50px; pos ...

  5. Android小例子:使用反射机制来读取图片制作一个图片浏览器

    效果图: 工程文件夹: 该例子可供于新手参考练习,如果有哪里不对的地方,望指正>-< <黑幕下的人> java代码(MainActivity.java): package co ...

  6. VMWARE虚拟机中CentOs7网络连接

    1.选择网络连接模式 这里选择NAT模式 2.查看虚拟机逻辑地址段 编辑---->虚拟网络编辑器 这里显示的是192.168.40.0 我们本机占用了192.168.40.1,网关是192.16 ...

  7. appium+python解决每次运行代码都提示安装Unlock以及AppiumSetting的问题

    appium+python解决每次运行代码都提示安装Unlock以及AppiumSetting的问题(部分安卓机型) 1.修改appium-android-driver\lib下的android-he ...

  8. 常用的go语言IDE对比

    Go语言目前已经在开发者中越发的流行,自然很多人都在寻找合适的IDE来实现代码语法高亮.自动补全以及其他编辑特性. 下面就几种常用的IDE进行对比介绍: 1. Sublime text 这个文本编辑器 ...

  9. C# 面试题 (二)

    1. 什么是C#? C#是微软公司发布的一种面向对象的.运行于.NET Framework之上的高级程序设计语言.C#是一种安全的.稳定的.简单的.优雅的,由C和C++衍生出来的面向对象的编程语言. ...

  10. Caliburn.Micro 杰的入门教程2 ,了解Data Binding 和 Events(翻译)

    Caliburn.Micro 杰的入门教程1(翻译)Caliburn.Micro 杰的入门教程2 ,了解Data Binding 和 Events(翻译)Caliburn.Micro 杰的入门教程3, ...