Last active
December 22, 2017 20:16
-
-
Save AlwaysBCoding/fa141a313f404b585016ff2a1e62adaf to your computer and use it in GitHub Desktop.
Ethereum Ðapp Development - Video 10 | Smart Contracts - Coin Flipper (Part 2)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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({}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} | |
} |
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
In the expression for coinFlip, all variables are type uint256, so no type conversion is required:
uint256 coinFlip = blockValue/FACTOR;