etherapps.info presents

HonestDice

Contract address: 0xd79b4c6791784184e2755b2fc1659eaab0f80456 | Source code

HonestDice is is a completely fair dice game that cannot be cheated by neither the casino nor the player.
Thanks to the awesomeness of Ethereum, you can bet with peice of mind knowing that even if our entire server goes offline, you will still have full access to your funds.
The game is played by the player putting up his bet and supplying a hashed secret that the server cannot know.
The server then detects the bet and supplies a seed. After this the user can use his secret and the server seed to generate the outcome of the bet.
As the server does not know the users secret beforehand, the server has no idea if the user is going to win or lose before supplying the seed.
The worst the server could do is go offline and not supply a seed at all, in which the user can call the refund (claimTimeout()) command to get his money back.
Minimum Bet: 1 ether.
Maximum Win: Up to 5% of the bank roll. Currently around 100 ether per roll (Please check with the commands at the bottom of the page).
House edge: 1%.
UPDATE: Version 2 is now released and adds in the rule where the contract creator (us) cannot withdraw without locking the funds for 1 day. This is to stop the attack where we could withdraw all funds while big bets and in progress. Thanks goes out to ddworken for his suggestions and help.
UPDATE 2: Our minimum bet is now only 1 ether! To allow this we deduct 0.1 from any winnings to pay for the gas fees of supplying seeds

----- THE EASY WAY TO PLAY: -----

1) Paste the following into your geth console to load the contract ABI

dice = new web3.eth.contract([{"constant":true,"inputs":[],"name":"getBetsLocked","outputs":[{"name":"_r","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"user","type":"address"},{"name":"seed","type":"bytes32"}],"name":"serverSeed","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"value","type":"uint256"},{"name":"chance","type":"uint256"}],"name":"calcWinnings","outputs":[{"name":"_r","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"getBankroll","outputs":[{"name":"_r","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[],"name":"claimTimeout","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"secret","type":"bytes32"}],"name":"didWin","outputs":[{"name":"_r","type":"bool"}],"type":"function"},{"constant":true,"inputs":[],"name":"getMaxPayout","outputs":[{"name":"_r","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"_user","type":"address"}],"name":"isReadyFor","outputs":[{"name":"_r","type":"bool"}],"type":"function"},{"constant":false,"inputs":[],"name":"lockBetsForWithdraw","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"newFeed","type":"address"}],"name":"setFeed","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"getMinimumBet","outputs":[{"name":"_r","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"chance","type":"uint256"},{"name":"secretHash","type":"bytes32"}],"name":"roll","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"isReady","outputs":[{"name":"_r","type":"bool"}],"type":"function"},{"constant":false,"inputs":[],"name":"unlockBets","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"secret","type":"bytes32"}],"name":"getResult","outputs":[{"name":"_r","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"secret","type":"bytes32"}],"name":"claim","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"canClaimTimeout","outputs":[{"name":"_r","type":"bool"}],"type":"function"},{"constant":true,"inputs":[{"name":"hash","type":"bytes32"}],"name":"hashTo256","outputs":[{"name":"_r","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"input","type":"bytes32"}],"name":"hash","outputs":[{"name":"_r","type":"uint256"}],"type":"function"},{"inputs":[],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"blocknum","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"chance","type":"uint256"}],"name":"Bet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"chance","type":"uint256"}],"name":"Won","type":"event"}]).at('0xd79b4c6791784184e2755b2fc1659eaab0f80456')

2) Paste the following to set up an easy function you can call when you want to bet

You can edit the "use_account" variable to use a different ethereum account. Please also update your web3.eth.defaultAccount though.
use_account = eth.accounts[0]; active = false; secret = ""; blocknum = 0; last_chance = 0; function bet(amount, chance) { var adj_chance = Math.floor(chance / 100 * 256); secret = "s"+Math.random(); last_chance = adj_chance; blocknum = eth.blockNumber; var wei = web3.toWei(amount, "ether"); if (active) { return "-- It looks like have a bet in progress already. To override this type: active = false --"; } if (adj_chance < 1 || adj_chance > 255) { return "-- Invalid chance setting --"; } if (eth.getBalance(use_account).lessThan(amount)) { return "-- You do not have enough ether --"; } if (new BigNumber(wei).lessThan(dice.getMinimumBet())) { return "-- Bet is too low --"; } if (dice.calcWinnings(wei, adj_chance).greaterThan(dice.getMaxPayout())) { return "-- Bet is above max payout, please lower the value or increase your chance --"; } active = true; dice.roll(adj_chance, dice.hash(secret, {from:use_account}), {from:use_account, value:wei, gas:300000}); return "-- Rolling "+amount+" ether with "+adj_chance+"/256 chance. Type check() for updates --"; } function check() { result = dice.getResult(secret, {from:use_account}); if (!active) { return "-- No bet has been placed yet. Try bet(AMOUNT,CHANCE) --" } if (blocknum >= eth.blockNumber || !dice.isReady({from:use_account}) || (!dice.didWin(secret, {from:use_account}) && result == 0)) { return "-- Bet is not ready yet, please wait a couple of blocks -- "; } if (!dice.didWin(secret, {from:use_account}) && result != 0) { blocknum = eth.blockNumber; active = false; return "-- You lost. Rolled "+dice.getResult(secret, {from:use_account})+", needed below "+last_chance+" --"; } dice.claim(secret, {from:use_account, gas:300000}); blocknum = eth.blockNumber; active = false; return "-- You won! Rolled "+result+", which is lower than "+last_chance+". Your winnings have been sent! --"; }

3) Then, place a bet

PLEASE NOTE: There is a minimum bet of 1 ether atm, this is to make it profitable for us as we have to use alot of gas providing random seeds

Select a chance between 1 and 99%; This will be converted to a number between 0 and 256
bet(AMOUNT_IN_ETH, CHANCE_OUT_OF_100)

Example (1 ether @ 50% chance):

bet(1,50)

4) Check the status of your bet and auto claim it if it won.

check()

----- OR, THE MANUAL WAY: -----

1) Paste the following into your geth console to load the contract ABI

dice = new web3.eth.contract([{"constant":false,"inputs":[{"name":"user","type":"address"},{"name":"seed","type":"bytes32"}],"name":"serverSeed","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"value","type":"uint256"},{"name":"chance","type":"uint256"}],"name":"calcWinnings","outputs":[{"name":"_r","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"getBankroll","outputs":[{"name":"_r","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[],"name":"claimTimeout","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"secret","type":"bytes32"}],"name":"didWin","outputs":[{"name":"_r","type":"bool"}],"type":"function"},{"constant":true,"inputs":[],"name":"getMaxPayout","outputs":[{"name":"_r","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"_user","type":"address"}],"name":"isReadyFor","outputs":[{"name":"_r","type":"bool"}],"type":"function"},{"constant":false,"inputs":[{"name":"newFeed","type":"address"}],"name":"setFeed","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"getMinimumBet","outputs":[{"name":"_r","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"chance","type":"uint256"},{"name":"secretHash","type":"bytes32"}],"name":"roll","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"isReady","outputs":[{"name":"_r","type":"bool"}],"type":"function"},{"constant":true,"inputs":[{"name":"secret","type":"bytes32"}],"name":"getResult","outputs":[{"name":"_r","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"secret","type":"bytes32"}],"name":"claim","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"hash","type":"bytes32"}],"name":"hashTo256","outputs":[{"name":"_r","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"input","type":"bytes32"}],"name":"hash","outputs":[{"name":"_r","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"canClaimTimeout","outputs":[{"name":"_r","type":"bool"}],"type":"function"},{"inputs":[],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"blocknum","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"chance","type":"uint256"}],"name":"Bet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"chance","type":"uint256"}],"name":"Won","type":"event"}]).at('0xd79b4c6791784184e2755b2fc1659eaab0f80456')

2) Generate a random secret so we cannot cheat you

secret = 's'+Math.random()

3) Call the bet function

dice.roll(CHANCE_OUT_OF_256, dice.hash(secret), {from:eth.accounts[0], value:toWei(AMOUNT_IN_ETH, "ether"), gas:300000})

Example: 10 ether @ 50% chance (128/256)

dice.roll(128, dice.hash(secret), {from:eth.accounts[0], value:toWei(10, "ether"), gas:300000})

4) Wait a block or two and see if your bet is ready to claim

dice.isReady()

5) Check if your bet won

dice.didWin(secret)

6) If you won, claim your winnings!

dice.claim(secret, {from:eth.accounts[0], gas:300000}))

----- Other functions: -----

dice.getMinimumBet()
dice.getMaxPayout()
dice.calcWinnings(web3.toWei(AMOUNT_IN_ETH, "ether"))

Get a list of all bets or all wins

dice.Bet({},{fromBlock:0}).get();
dice.Won({},{fromBlock:0}).get();

If for any reason our server doesn't respond to your bet or is unfair in any way, simply refund your bet after 20 blocks

dice.canClaimTimeout()
dice.claimTimeout()

How it works step by step:

1) User creates a bet with a hashed secret using dice.bet(chance, secretHash)
2) Our server see's the bet and provides a random seed with dice.serverSeed(seed), having no idea if the bet will win or lose
3) The user can then claim a win with dice.claim(secret). If the user lost he can just ignore it
4) If our server is inactive never provies a seed, the user can reclaim his bet with dice.claimTimeout()