Back to Home

HonestDice (1 ETH)

Unknown
0xd79b4c679178...9eaab0f80456
FrontierContract #195Exact Bytecode MatchEdit this contract
Deployed August 12, 2015 (10 years ago)Block 75,008

Commit-reveal dice game deployed day 13 of Ethereum mainnet with 1,000 ETH bankroll. Still active in 2026 with 84 ETH locked. 1% house edge, 1 ETH minimum bet.

Key Facts

Deployment Block
75,008
Deployment Date
Aug 12, 2015, 04:14 PM
Code Size
1.9 KB
Gas at Deploy
589,063
Transactions by Year
2015274
2016213
201714
201822
20193
20217
202212
202312
20243
202512
202624

Description

HonestDice is a commit-reveal dice gambling contract deployed on August 12, 2015 (block 75,008), 13 days after Ethereum mainnet launch. It was bankrolled with 1,000 ETH just 2 minutes after deployment (block 75,017), making it one of the most heavily capitalized contracts in Ethereum first two weeks.

The contract implements a sophisticated 20-function gambling system with proper anti-front-running protections. Players use roll(uint256, bytes32) to place bets with a client-side seed hash. The operator then responds with serverSeed(address, bytes32) to provide the server random component. Players verify and collect via claim(bytes32). Supporting functions include getBankroll(), getBetsLocked(), getMinimumBet(), getMaxPayout(), isReady(), isReadyFor(address), calcWinnings(uint256, uint256), didWin(bytes32), and getResult(bytes32). The operator can manage the bankroll via lockBetsForWithdraw(), unlockBets(), and withdraw(uint256).

The same deployer (0x87c5b5874a18b4306df8a752a6c8cc3e82dafc19) deployed at least one other HonestDice variant on the same day. This contract saw 30+ transactions from 4 unique addresses. As of 2026, approximately 83.9 ETH remains permanently locked in the contract.

This contract gained secondary attention in March 2016 when a Reddit user noticed that etherchain.org and etherscan.io showed different bytecode for the same address. The community explained this was a display discrepancy: etherchain was showing contract creation bytecode while etherscan showed the correct runtime bytecode.

Source Verified

SolidityExact bytecode match(1,954 bytes)
Compiler: 6ff4cd6

1889-byte runtime matches byte-for-byte. soljson v0.1.1+commit.6ff4cd6, optimizer ON. Same deployer and source as the 10 ETH variant (0xc4c51de1). Key differences: 1 ETH min bet (vs 10), 99% payout (vs 98%), no setMinimumBet(). Broken withdrawal lock due to local variable shadowing.

Heuristic Analysis

The following characteristics were detected through bytecode analysis and may not be accurate.

Detected Type: Unknown

Frontier Era

The initial release of Ethereum. A bare-bones implementation for technical users.

Block span: 01,149,999
July 30, 2015March 14, 2016

Bytecode Overview

Opcodes1,954
Unique Opcodes174
Jump Instructions126
Storage Operations68

Verified Source Available

Source verified through compiler archaeology and exact bytecode matching.

View Verification Proof
Show source code (Solidity)
contract HonestDice {
	
	event Bet(address indexed user, uint blocknum, uint256 amount, uint chance);
	event Won(address indexed user, uint256 amount, uint chance);
	
	struct Roll {
		uint256 value;
		uint chance;
		uint blocknum;
		bytes32 secretHash;
		bytes32 serverSeed;
	}
	
	uint betsLocked;
	address owner;
	address feed;				   
	uint256 minimumBet = 1 * 1000000000000000000; // 1 Ether
	uint256 constant maxPayout = 5; // 5% of bankroll
	uint constant seedCost = 100000000000000000; // This is the cost of supplyin the server seed, deduct it;
	mapping (address => Roll) rolls;
	uint constant timeout = 20; // 5 Minutes
	
	function HonestDice() {
		owner = msg.sender;
		feed = msg.sender;
	}
	
	function roll(uint chance, bytes32 secretHash) {
		if (chance < 1 || chance > 255 || msg.value < minimumBet || calcWinnings(msg.value, chance) > getMaxPayout() || betsLocked != 0) { 
			msg.sender.send(msg.value); // Refund
			return;
		}
		rolls[msg.sender] = Roll(msg.value, chance, block.number, secretHash, 0);
		Bet(msg.sender, block.number, msg.value, chance);
	}
	
	function serverSeed(address user, bytes32 seed) {
		// The server calls this with a random seed
		if (msg.sender != feed) return;
		if (rolls[user].serverSeed != 0) return;
		rolls[user].serverSeed = seed;
	}
	
	function hashTo256(bytes32 hash) constant returns (uint _r) {
		// Returns a number between 0 - 255 from a hash
		return uint(hash) & 0xff;
	}
	
	function hash(bytes32 input) constant returns (uint _r) {
		// Simple sha3 hash. Not to be called via the blockchain
		return uint(sha3(input));
	}
	
	function isReady() constant returns (bool _r) {
		return isReadyFor(msg.sender);
	}
	
	function isReadyFor(address _user) constant returns (bool _r) {
		Roll r = rolls[_user];
		if (r.serverSeed == 0) return false;
		return true;
	}
	
	function getResult(bytes32 secret) constant returns (uint _r) {
		// Get the result number of the roll
		Roll r = rolls[msg.sender];
		if (r.serverSeed == 0) return;
		if (sha3(secret) != r.secretHash) return;
		return hashTo256(sha3(secret, r.serverSeed));
	}
	
	function didWin(bytes32 secret) constant returns (bool _r) {
		// Returns if the player won or not
		Roll r = rolls[msg.sender];
		if (r.serverSeed == 0) return;
		if (sha3(secret) != r.secretHash) return;
		if (hashTo256(sha3(secret, r.serverSeed)) < r.chance) { // Winner
			return true;
		}
		return false;
	}
	
	function calcWinnings(uint256 value, uint chance) constant returns (uint256 _r) {
		// 1% house edge
		return (value * 99 / 100) * 256 / chance;
	}
	
	function getMaxPayout() constant returns (uint256 _r) {
		return this.balance * maxPayout / 100;
	}
	
	function claim(bytes32 secret) {
		Roll r = rolls[msg.sender];
		if (r.serverSeed == 0) return;
		if (sha3(secret) != r.secretHash) return;
		if (hashTo256(sha3(secret, r.serverSeed)) < r.chance) { // Winner
			msg.sender.send(calcWinnings(r.value, r.chance) - seedCost);
			Won(msg.sender, r.value, r.chance);
		}
		
		delete rolls[msg.sender];
	}
	
	function canClaimTimeout() constant returns (bool _r) {
		Roll r = rolls[msg.sender];
		if (r.serverSeed != 0) return false;
		if (r.value <= 0) return false;
		if (block.number < r.blocknum + timeout) return false;
		return true;
	}
	
	function claimTimeout() {
		// Get your monies back if the server isn't responding with a seed
		if (!canClaimTimeout()) return;
		Roll r = rolls[msg.sender];
		msg.sender.send(r.value);
		delete rolls[msg.sender];
	}
	
	function getMinimumBet() constant returns (uint _r) {
		return minimumBet;
	}
	
	function getBankroll() constant returns (uint256 _r) {
		return this.balance;
	}
	
	function getBetsLocked() constant returns (uint _r) {
		return betsLocked;
	}
	
	function setFeed(address newFeed) {
		if (msg.sender != owner) return;
		feed = newFeed;
	}
	
	function lockBetsForWithdraw() {
		if (msg.sender != owner) return;
		uint betsLocked = block.number;
	}
	
	function unlockBets() {
		if (msg.sender != owner) return;
		uint betsLocked = 0;
	}
	
	function withdraw(uint amount) {
		if (msg.sender != owner) return;
		if (betsLocked == 0 || block.number < betsLocked + 5760) return;
		owner.send(amount);
	}
}

External Links