Skip to content

Instantly share code, notes, and snippets.

@AlwaysBCoding
Last active December 22, 2017 20:16
Show Gist options
  • Save AlwaysBCoding/fa141a313f404b585016ff2a1e62adaf to your computer and use it in GitHub Desktop.
Save AlwaysBCoding/fa141a313f404b585016ff2a1e62adaf to your computer and use it in GitHub Desktop.
Ethereum Ðapp Development - Video 10 | Smart Contracts - Coin Flipper (Part 2)
// Config
global.config = {
rpc: {
host: "localhost",
port: "8545"
}
}
// Load Libraries
global.solc = require("solc")
global.fs = require("fs")
global.Web3 = require("web3")
// Connect Web3 Instance
global.web3 = new Web3(new Web3.providers.HttpProvider(`http://${global.config.rpc.host}:${global.config.rpc.port}`))
// Global Account Accessors
global.acct1 = web3.eth.accounts[0]
global.acct2 = web3.eth.accounts[1]
global.acct3 = web3.eth.accounts[2]
global.acct4 = web3.eth.accounts[3]
global.acct5 = web3.eth.accounts[4]
// Helper Functions
class Helpers {
contractName(source) {
var re1 = /contract.*{/g
var re2 = /\s\w+\s/
return source.match(re1).pop().match(re2)[0].trim()
}
createContract(source, options={}) {
var compiled = solc.compile(source)
var contractName = this.contractName(source)
var bytecode = compiled["contracts"][contractName]["bytecode"]
var abi = JSON.parse(compiled["contracts"][contractName]["interface"])
var contract = global.web3.eth.contract(abi)
var gasEstimate = global.web3.eth.estimateGas({ data: bytecode })
var deployed = contract.new(Object.assign({
from: global.web3.eth.accounts[0],
data: bytecode,
gas: gasEstimate,
gasPrice: 5
}, options), (error, result) => { })
return deployed
}
loadContract(name) {
var path = `./${name.toLowerCase()}.sol`
return fs.readFileSync(path, 'utf8')
}
deployContract(name, options={}) {
var source = this.loadContract(name)
return this.createContract(source, options)
}
etherBalance(contract) {
switch(typeof(contract)) {
case "object":
if(contract.address) {
return global.web3.fromWei(global.web3.eth.getBalance(contract.address), 'ether').toNumber()
} else {
return new Error("cannot call getEtherBalance on an object that does not have a property 'address'")
}
break
case "string":
return global.web3.fromWei(global.web3.eth.getBalance(contract), 'ether').toNumber()
break
}
}
}
// Load Helpers into Decypher namespace
global.decypher = new Helpers()
// Start repl
require('repl').start({})
contract Flipper {
enum GameState {noWager, wagerMade, wagerAccepted}
GameState public currentState;
uint public wager;
address public player1;
address public player2;
uint public seedBlockNumber;
modifier onlyState(GameState expectedState) { if(expectedState == currentState) { _; } else { throw; } }
function Flipper() {
currentState = GameState.noWager;
}
function makeWager() onlyState(GameState.noWager) payable returns (bool) {
wager = msg.value;
player1 = msg.sender;
currentState = GameState.wagerMade;
return true;
}
function acceptWager() onlyState(GameState.wagerMade) payable returns (bool) {
if(msg.value == wager) {
player2 = msg.sender;
seedBlockNumber = block.number;
currentState = GameState.wagerAccepted;
return true;
} else {
throw;
}
}
function resolveBet() onlyState(GameState.wagerAccepted) returns (bool) {
uint256 blockValue = uint256(block.blockhash(seedBlockNumber));
uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
uint256 coinFlip = uint256(uint256(blockValue) / FACTOR);
if(coinFlip == 0) {
player1.send(this.balance);
currentState = GameState.noWager;
return true;
} else {
player2.send(this.balance);
currentState = GameState.noWager;
return true;
}
}
}
@jmlon
Copy link

jmlon commented Dec 22, 2017

In the expression for coinFlip, all variables are type uint256, so no type conversion is required:
uint256 coinFlip = blockValue/FACTOR;

@jmlon
Copy link

jmlon commented Dec 22, 2017

Using send(..) in recent versions of solidity produces a compiler warning of the form:
':77:13: Warning: Failure condition of \'send\' ignored. Consider using \'transfer\' instead.\n player1.send(this.balance);\n ^------------------------^\n',
apparently the solution is to use transfer(...) which reverts all the operations (except used gas) in the case of an error:

        if (coinFlip==0) {
            player1.transfer(this.balance);
        }
        else {
            player2.transfer(this.balance);
       }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment