├── js ├── .nvmrc ├── runtestrpc.sh ├── web3-testrpc.js ├── web3-test.js ├── package.json ├── tests │ ├── tools.js │ └── one-value-tests.js ├── genesis.json ├── express-example.js ├── update-contract-test.js ├── deploy-client-receipt.js ├── deploy-contract-test.js ├── deploy-contract-testrpc.js └── watch-client-receipt.js ├── contracts ├── build │ ├── Config.bin │ ├── NameReg.bin │ ├── interitance-example.sol:owned.abi │ ├── interitance-example.sol:mortal.abi │ ├── interitance-example.sol:Config.abi │ ├── interitance-example.sol:named.abi │ ├── interitance-example.sol:NameReg.abi │ ├── owned.bin │ ├── ClientReceipt.sol:ClientReceipt.abi │ ├── OneValue.sol:OneValue.abi │ ├── interitance-example.sol:PriceFeed.abi │ ├── ClientReceipt.bin │ ├── OneValue.bin │ ├── CrowdFunding.sol:CrowdFunding.abi │ ├── WithdrawalContract.sol:WithdrawalContract.abi │ ├── lib-set.sol:Set.abi │ ├── AccessRestriction.sol:AccessRestriction.abi │ ├── mortal.bin │ ├── StateMachine.sol:StateMachine.abi │ ├── remote-purchase.sol:Purchase.abi │ ├── Set.bin │ ├── Ballot.sol:Ballot.abi │ ├── SimpleAuction.sol:SimpleAuction.abi │ ├── CrowdFunding.bin │ ├── WithdrawalContract.bin │ ├── BlindAuction.sol:BlindAuction.abi │ ├── named.bin │ ├── AccessRestriction.bin │ ├── PriceFeed.bin │ ├── StateMachine.bin │ ├── SimpleAuction.bin │ ├── Purchase.bin │ ├── Ballot.bin │ └── BlindAuction.bin ├── .soliumignore ├── build.sh ├── OneValue.sol ├── ClientReceipt.sol ├── .soliumrc.json ├── WithdrawalContract.sol ├── lib-set.sol ├── CrowdFunding.sol ├── StateMachine.sol ├── interitance-example.sol ├── AccessRestriction.sol ├── remote-purchase.sol ├── SimpleAuction.sol ├── Ballot.sol └── BlindAuction.sol ├── dapp_example ├── myDapp │ ├── .gitignore │ ├── .meteor │ │ ├── .gitignore │ │ ├── release │ │ ├── platforms │ │ ├── .id │ │ ├── .finished-upgraders │ │ ├── packages │ │ └── versions │ ├── public │ │ └── a.txt │ ├── deploy.sh │ ├── client │ │ ├── main.less │ │ ├── main.js │ │ └── main.html │ ├── lib │ │ └── init.js │ ├── server │ │ └── main.js │ └── package.json └── myDapp2 │ ├── .gitignore │ ├── .meteor │ ├── .gitignore │ ├── release │ ├── platforms │ ├── .id │ ├── .finished-upgraders │ ├── packages │ └── versions │ ├── deploy.sh │ ├── client │ ├── main.less │ ├── main.html │ └── main.js │ ├── lib │ └── init.js │ ├── server │ └── main.js │ └── package.json ├── slides ├── install.sh ├── images │ ├── mist.gif │ ├── fdi-mist.png │ ├── metamask.png │ ├── fdi-metamask.png │ ├── flightdelay-dapp.jpg │ └── meteor-dashboard.png ├── README.md ├── package.json ├── build.sh ├── 0_Agenda_0906.md ├── 0_Agenda_1114.md ├── 0_Agenda.md ├── 0_Agenda_03232017.md ├── 1_Blockchain_Recap_0323.md ├── 0_Agenda_03172017.md ├── 7_References.md ├── 0_Agenda_03102017.md ├── css │ └── style.css ├── 5_Solidity_Patterns.md ├── yarn.lock ├── 6_Solidity_Testing.md ├── 1_Blockchain_Basics.md ├── 4_Solidity_Security.md ├── 10_Web3_JavaScript.md ├── 9_Dapps_Development.md ├── 2_Ethereum_Development_Environment_and_Tools_03202017.md ├── 8_Insurance_Examples.md └── 2_Ethereum_Development_Environment_and_Tools.md ├── qrcode.png ├── truffle_test ├── migrations │ ├── 1_initial_migration.js │ ├── 3_deploy_one_value_contract.js │ └── 2_deploy_contracts.js ├── contracts │ ├── ConvertLib.sol │ ├── OneValue.sol │ ├── Migrations.sol │ └── MetaCoin.sol ├── truffle.js ├── test │ ├── TestMetacoin.sol │ └── metacoin.js └── app │ ├── stylesheets │ └── app.css │ ├── index.html │ └── javascripts │ └── app.js ├── .gitignore ├── README.MD ├── LECTURES.MD └── FlightDelay └── FlightDelay.sol /js/.nvmrc: -------------------------------------------------------------------------------- 1 | 6.9.1 2 | -------------------------------------------------------------------------------- /contracts/build/Config.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /contracts/build/NameReg.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /contracts/.soliumignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /dapp_example/myDapp/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /dapp_example/myDapp/.meteor/.gitignore: -------------------------------------------------------------------------------- 1 | local 2 | -------------------------------------------------------------------------------- /dapp_example/myDapp/public/a.txt: -------------------------------------------------------------------------------- 1 | public file 2 | -------------------------------------------------------------------------------- /dapp_example/myDapp2/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /dapp_example/myDapp2/.meteor/.gitignore: -------------------------------------------------------------------------------- 1 | local 2 | -------------------------------------------------------------------------------- /dapp_example/myDapp/.meteor/release: -------------------------------------------------------------------------------- 1 | METEOR@1.4.2.7 2 | -------------------------------------------------------------------------------- /dapp_example/myDapp2/.meteor/release: -------------------------------------------------------------------------------- 1 | METEOR@1.4.2.7 2 | -------------------------------------------------------------------------------- /dapp_example/myDapp/.meteor/platforms: -------------------------------------------------------------------------------- 1 | server 2 | browser 3 | -------------------------------------------------------------------------------- /dapp_example/myDapp2/.meteor/platforms: -------------------------------------------------------------------------------- 1 | server 2 | browser 3 | -------------------------------------------------------------------------------- /slides/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | npm install markdown-to-slides -g 3 | -------------------------------------------------------------------------------- /qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getamis/contract-training/HEAD/qrcode.png -------------------------------------------------------------------------------- /dapp_example/myDapp/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | meteor deploy ytdapp01.meteorapp.com 4 | -------------------------------------------------------------------------------- /dapp_example/myDapp2/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | meteor deploy ytdapp02.meteorapp.com 4 | -------------------------------------------------------------------------------- /contracts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Build 4 | solc --bin --abi --gas -o ./build *.sol 5 | -------------------------------------------------------------------------------- /js/runtestrpc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | node_modules/ethereumjs-testrpc/bin/testrpc -p 8600 -a 10 3 | -------------------------------------------------------------------------------- /contracts/build/interitance-example.sol:owned.abi: -------------------------------------------------------------------------------- 1 | [{"inputs":[],"payable":false,"type":"constructor"}] -------------------------------------------------------------------------------- /slides/images/mist.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getamis/contract-training/HEAD/slides/images/mist.gif -------------------------------------------------------------------------------- /slides/images/fdi-mist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getamis/contract-training/HEAD/slides/images/fdi-mist.png -------------------------------------------------------------------------------- /slides/images/metamask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getamis/contract-training/HEAD/slides/images/metamask.png -------------------------------------------------------------------------------- /slides/images/fdi-metamask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getamis/contract-training/HEAD/slides/images/fdi-metamask.png -------------------------------------------------------------------------------- /slides/README.md: -------------------------------------------------------------------------------- 1 | ## Build the slides 2 | 1. Install `markdown-to-slides`: run `install.sh` 3 | 2. Build slides: run `build.sh` 4 | -------------------------------------------------------------------------------- /slides/images/flightdelay-dapp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getamis/contract-training/HEAD/slides/images/flightdelay-dapp.jpg -------------------------------------------------------------------------------- /slides/images/meteor-dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getamis/contract-training/HEAD/slides/images/meteor-dashboard.png -------------------------------------------------------------------------------- /slides/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "global": "^4.3.1", 4 | "markdown-to-slides": "^1.0.5" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /dapp_example/myDapp/client/main.less: -------------------------------------------------------------------------------- 1 | /* CSS declarations go here */ 2 | // libs 3 | @import '{ethereum:dapp-styles}/dapp-styles.less'; 4 | -------------------------------------------------------------------------------- /contracts/build/interitance-example.sol:mortal.abi: -------------------------------------------------------------------------------- 1 | [{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"type":"function"}] -------------------------------------------------------------------------------- /dapp_example/myDapp2/client/main.less: -------------------------------------------------------------------------------- 1 | /* CSS declarations go here */ 2 | // libs 3 | @import '{ethereum:dapp-styles}/dapp-styles.less'; 4 | -------------------------------------------------------------------------------- /dapp_example/myDapp/lib/init.js: -------------------------------------------------------------------------------- 1 | if(typeof web3 === 'undefined') 2 | web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545')); 3 | 4 | -------------------------------------------------------------------------------- /dapp_example/myDapp2/lib/init.js: -------------------------------------------------------------------------------- 1 | if(typeof web3 === 'undefined') 2 | web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545')); 3 | 4 | -------------------------------------------------------------------------------- /dapp_example/myDapp/server/main.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | 3 | Meteor.startup(() => { 4 | // code to run on server at startup 5 | }); 6 | -------------------------------------------------------------------------------- /dapp_example/myDapp2/server/main.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | 3 | Meteor.startup(() => { 4 | // code to run on server at startup 5 | }); 6 | -------------------------------------------------------------------------------- /slides/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | find . -name '*.md' -not -path "./node_modules/*" | xargs -I '{}' markdown-to-slides '{}' -o '{}'.html -s css/style.css -i 3 | -------------------------------------------------------------------------------- /truffle_test/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | var Migrations = artifacts.require("./Migrations.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /truffle_test/migrations/3_deploy_one_value_contract.js: -------------------------------------------------------------------------------- 1 | var OneValue = artifacts.require("./OneValue.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(OneValue); 5 | }; 6 | -------------------------------------------------------------------------------- /contracts/build/interitance-example.sol:Config.abi: -------------------------------------------------------------------------------- 1 | [{"constant":false,"inputs":[{"name":"id","type":"uint256"}],"name":"lookup","outputs":[{"name":"adr","type":"address"}],"payable":false,"type":"function"}] -------------------------------------------------------------------------------- /contracts/build/interitance-example.sol:named.abi: -------------------------------------------------------------------------------- 1 | [{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"type":"function"},{"inputs":[{"name":"name","type":"bytes32"}],"payable":false,"type":"constructor"}] -------------------------------------------------------------------------------- /truffle_test/contracts/ConvertLib.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.4; 2 | 3 | library ConvertLib{ 4 | function convert(uint amount,uint conversionRate) returns (uint convertedAmount) 5 | { 6 | return amount * conversionRate; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /dapp_example/myDapp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "myDapp", 3 | "private": true, 4 | "scripts": { 5 | "start": "meteor run" 6 | }, 7 | "dependencies": { 8 | "meteor-node-stubs": "~0.2.0", 9 | "babel-runtime": "6.18.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /dapp_example/myDapp2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "myDapp", 3 | "private": true, 4 | "scripts": { 5 | "start": "meteor run" 6 | }, 7 | "dependencies": { 8 | "meteor-node-stubs": "~0.2.0", 9 | "babel-runtime": "6.18.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /contracts/build/interitance-example.sol:NameReg.abi: -------------------------------------------------------------------------------- 1 | [{"constant":false,"inputs":[{"name":"name","type":"bytes32"}],"name":"register","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"unregister","outputs":[],"payable":false,"type":"function"}] -------------------------------------------------------------------------------- /js/web3-testrpc.js: -------------------------------------------------------------------------------- 1 | var Web3 = require('web3'); 2 | var TestRPC = require("ethereumjs-testrpc"); 3 | var web3 = new Web3(TestRPC.provider()); 4 | web3.eth.getAccounts(function(e, accts){ 5 | console.log("error:", e); 6 | console.log("accounts:", accts); 7 | process.exit(0); 8 | }); 9 | -------------------------------------------------------------------------------- /js/web3-test.js: -------------------------------------------------------------------------------- 1 | var Web3 = require('web3'); 2 | var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); 3 | 4 | web3.eth.getBlock(48, function(error, result){ 5 | if(!error) 6 | console.log(result) 7 | else 8 | console.error(error); 9 | }); 10 | -------------------------------------------------------------------------------- /contracts/build/owned.bin: -------------------------------------------------------------------------------- 1 | 60606040523415600b57fe5b5b33600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b5b603380605c6000396000f30060606040525bfe00a165627a7a723058205b82c5c0182c317ebd429c65630906900277e50ffbadf01cae0c8c3af36d8cf50029 -------------------------------------------------------------------------------- /truffle_test/migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | var ConvertLib = artifacts.require("./ConvertLib.sol"); 2 | var MetaCoin = artifacts.require("./MetaCoin.sol"); 3 | 4 | module.exports = function(deployer) { 5 | deployer.deploy(ConvertLib); 6 | deployer.link(ConvertLib, MetaCoin); 7 | deployer.deploy(MetaCoin); 8 | }; 9 | -------------------------------------------------------------------------------- /dapp_example/myDapp/.meteor/.id: -------------------------------------------------------------------------------- 1 | # This file contains a token that is unique to your project. 2 | # Check it into your repository along with the rest of this directory. 3 | # It can be used for purposes such as: 4 | # - ensuring you don't accidentally deploy one app on top of another 5 | # - providing package authors with aggregated statistics 6 | 7 | 1c1lvqbf0agoy1ex4vim 8 | -------------------------------------------------------------------------------- /dapp_example/myDapp2/.meteor/.id: -------------------------------------------------------------------------------- 1 | # This file contains a token that is unique to your project. 2 | # Check it into your repository along with the rest of this directory. 3 | # It can be used for purposes such as: 4 | # - ensuring you don't accidentally deploy one app on top of another 5 | # - providing package authors with aggregated statistics 6 | 7 | 1c1lvqbf0agoy1ex4vim 8 | -------------------------------------------------------------------------------- /contracts/build/ClientReceipt.sol:ClientReceipt.abi: -------------------------------------------------------------------------------- 1 | [{"constant":false,"inputs":[{"name":"_id","type":"bytes32"}],"name":"deposit","outputs":[],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_id","type":"bytes32"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Deposit","type":"event"}] -------------------------------------------------------------------------------- /contracts/build/OneValue.sol:OneValue.abi: -------------------------------------------------------------------------------- 1 | [{"constant":true,"inputs":[],"name":"getValue","outputs":[{"name":"result","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"v","type":"uint256"}],"name":"setValue","outputs":[],"payable":false,"type":"function"},{"inputs":[{"name":"initValue","type":"uint256"}],"payable":false,"type":"constructor"}] -------------------------------------------------------------------------------- /contracts/build/interitance-example.sol:PriceFeed.abi: -------------------------------------------------------------------------------- 1 | [{"constant":false,"inputs":[{"name":"newInfo","type":"uint256"}],"name":"updateInfo","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"r","type":"uint256"}],"payable":false,"type":"function"}] -------------------------------------------------------------------------------- /contracts/OneValue.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.4; 2 | 3 | 4 | contract OneValue { 5 | uint256 value; 6 | 7 | function OneValue(uint256 initValue) { 8 | value = initValue; 9 | } 10 | 11 | function setValue(uint256 v) { 12 | value = v; 13 | } 14 | 15 | function getValue() constant returns (uint256 result) { 16 | return value; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /truffle_test/contracts/OneValue.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.8; 2 | 3 | contract OneValue { 4 | uint256 value; 5 | 6 | function OneValue(uint256 initValue) { 7 | value = initValue; 8 | } 9 | 10 | function setValue(uint256 v) { 11 | value = v; 12 | } 13 | 14 | function getValue() constant returns (uint256 result){ 15 | return value; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "contract-training", 3 | "version": "0.1.0", 4 | "dependencies": { 5 | "ethereumjs-testrpc": "^3.0.3", 6 | "express": "4.14.0", 7 | "mocha": "2.4.5", 8 | "truffle": "^2.1.1", 9 | "web3": "0.18.2" 10 | }, 11 | "scripts": { 12 | "test": "find tests -name '*tests.js' -not -path './node_modules/*' | xargs ./node_modules/mocha/bin/_mocha -R spec" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /contracts/ClientReceipt.sol: -------------------------------------------------------------------------------- 1 | contract ClientReceipt { 2 | event Deposit( 3 | address indexed _from, 4 | bytes32 indexed _id, 5 | uint _value 6 | ); 7 | 8 | function deposit(bytes32 _id) { 9 | // Any call to this function (even deeply nested) can 10 | // be detected from the JavaScript API by filtering 11 | // for `Deposit` to be called. 12 | Deposit(msg.sender, _id, msg.value); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /js/tests/tools.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var fs = require('fs'); 4 | 5 | var self = module.exports = { 6 | loadAbi: function(name) { 7 | var abi = JSON.parse(fs.readFileSync( __dirname + '/../../contracts/build/'+name+'.abi').toString()); 8 | return abi; 9 | }, 10 | loadBin: function(name) { 11 | var bin = fs.readFileSync( __dirname + '/../../contracts/build/'+name+'.bin').toString(); 12 | return bin; 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /contracts/build/ClientReceipt.bin: -------------------------------------------------------------------------------- 1 | 6060604052341561000c57fe5b5b60de8061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063b214faa514603a575bfe5b3415604157fe5b6059600480803560001916906020019091905050605b565b005b80600019163373ffffffffffffffffffffffffffffffffffffffff167f19dacbf83c5de6658e14cbf7bcae5c15eca2eedecf1c66fbca928e4d351bea0f346040518082815260200191505060405180910390a35b505600a165627a7a72305820528673a40eadb3be75f92326e0664ef276b182a65164702f0d7c104f291b9c680029 -------------------------------------------------------------------------------- /truffle_test/truffle.js: -------------------------------------------------------------------------------- 1 | var DefaultBuilder = require("truffle-default-builder"); 2 | 3 | module.exports = { 4 | build: new DefaultBuilder({ 5 | "index.html": "index.html", 6 | "app.js": [ 7 | "javascripts/app.js" 8 | ], 9 | "app.css": [ 10 | "stylesheets/app.css" 11 | ], 12 | "images/": "images/" 13 | }), 14 | networks: { 15 | development: { 16 | host: "localhost", 17 | port: 8547, 18 | network_id: "*" // Match any network id 19 | } 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /slides/0_Agenda_0906.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # Ethereum Smart Contract 4 | ## Yu-Te Lin 5 | 6 | --- 7 | 8 | ## 以太坊開發環境及工具介紹 9 | 10 | - Ethereum and Smart contract 11 | 12 | - Wallet GUI: Mist 13 | 14 | - Command line tools: geth, solc 15 | 16 | - Contract editors: atom, sublime text, visual studio. 17 | 18 | - Libraries and Development tools: web3, testrpc, truffle. 19 | 20 | - Contract deployment 21 | 22 | --- 23 | 24 | ## 以太坊智能合約開發 25 | 26 | - 程式設計 27 | 28 | - 資訊安全 29 | 30 | - 設計模式 31 | 32 | - 測試 33 | -------------------------------------------------------------------------------- /contracts/build/OneValue.bin: -------------------------------------------------------------------------------- 1 | 6060604052341561000c57fe5b604051602080610107833981016040528080519060200190919050505b806000819055505b505b60c6806100416000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632096525514604457806355241077146067575bfe5b3415604b57fe5b60516084565b6040518082815260200191505060405180910390f35b3415606e57fe5b60826004808035906020019091905050608f565b005b600060005490505b90565b806000819055505b505600a165627a7a72305820b3bec82e172f8481e07342d3b3a500a8fd2ef3ae60cdbcfec91dbd27feca90490029 -------------------------------------------------------------------------------- /contracts/build/CrowdFunding.sol:CrowdFunding.abi: -------------------------------------------------------------------------------- 1 | [{"constant":false,"inputs":[{"name":"campaignID","type":"uint256"}],"name":"checkGoalReached","outputs":[{"name":"reached","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"campaignID","type":"uint256"}],"name":"contribute","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"beneficiary","type":"address"},{"name":"goal","type":"uint256"}],"name":"newCampaign","outputs":[{"name":"campaignID","type":"uint256"}],"payable":false,"type":"function"}] -------------------------------------------------------------------------------- /dapp_example/myDapp/.meteor/.finished-upgraders: -------------------------------------------------------------------------------- 1 | # This file contains information which helps Meteor properly upgrade your 2 | # app when you run 'meteor update'. You should check it into version control 3 | # with your project. 4 | 5 | notices-for-0.9.0 6 | notices-for-0.9.1 7 | 0.9.4-platform-file 8 | notices-for-facebook-graph-api-2 9 | 1.2.0-standard-minifiers-package 10 | 1.2.0-meteor-platform-split 11 | 1.2.0-cordova-changes 12 | 1.2.0-breaking-changes 13 | 1.3.0-split-minifiers-package 14 | 1.4.0-remove-old-dev-bundle-link 15 | 1.4.1-add-shell-server-package 16 | -------------------------------------------------------------------------------- /dapp_example/myDapp2/.meteor/.finished-upgraders: -------------------------------------------------------------------------------- 1 | # This file contains information which helps Meteor properly upgrade your 2 | # app when you run 'meteor update'. You should check it into version control 3 | # with your project. 4 | 5 | notices-for-0.9.0 6 | notices-for-0.9.1 7 | 0.9.4-platform-file 8 | notices-for-facebook-graph-api-2 9 | 1.2.0-standard-minifiers-package 10 | 1.2.0-meteor-platform-split 11 | 1.2.0-cordova-changes 12 | 1.2.0-breaking-changes 13 | 1.3.0-split-minifiers-package 14 | 1.4.0-remove-old-dev-bundle-link 15 | 1.4.1-add-shell-server-package 16 | -------------------------------------------------------------------------------- /contracts/build/WithdrawalContract.sol:WithdrawalContract.abi: -------------------------------------------------------------------------------- 1 | [{"constant":true,"inputs":[],"name":"richest","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"withdraw","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"mostSent","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"becomeRichest","outputs":[{"name":"","type":"bool"}],"payable":true,"type":"function"},{"inputs":[],"payable":true,"type":"constructor"}] -------------------------------------------------------------------------------- /js/genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "nonce": "0x0000000000000042", 3 | "timestamp": "0x0", 4 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 5 | "extraData": "Any extra data 134ADFAD", 6 | "gasLimit": "0x47e7c4", 7 | "difficulty": "0x9c40", 8 | "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", 9 | "coinbase": "0x3333333333333333333333333333333333333333", 10 | "alloc": { 11 | "0x60cafee22ae353ac9de07852a682558c9bb84e61": { 12 | "balance": "999999999999999999999999999999999" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /contracts/build/lib-set.sol:Set.abi: -------------------------------------------------------------------------------- 1 | [{"constant":false,"inputs":[{"name":"self","type":"Set.Data storage"},{"name":"value","type":"uint256"}],"name":"remove","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"self","type":"Set.Data storage"},{"name":"value","type":"uint256"}],"name":"contains","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"self","type":"Set.Data storage"},{"name":"value","type":"uint256"}],"name":"insert","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"}] -------------------------------------------------------------------------------- /contracts/.soliumrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "custom-rules-filename": null, 3 | "rules": { 4 | "imports-on-top": true, 5 | "variable-declarations": true, 6 | "array-declarations": true, 7 | "operator-whitespace": true, 8 | "lbrace": true, 9 | "mixedcase": true, 10 | "camelcase": true, 11 | "uppercase": true, 12 | "no-with": true, 13 | "no-empty-blocks": true, 14 | "no-unused-vars": true, 15 | "double-quotes": true, 16 | "blank-lines": true, 17 | "indentation": true, 18 | "whitespace": true, 19 | "deprecated-suicide": true, 20 | "pragma-on-top": true 21 | } 22 | } -------------------------------------------------------------------------------- /truffle_test/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.4; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | modifier restricted() { 8 | if (msg.sender == owner) _; 9 | } 10 | 11 | function Migrations() { 12 | owner = msg.sender; 13 | } 14 | 15 | function setCompleted(uint completed) restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /contracts/build/AccessRestriction.sol:AccessRestriction.abi: -------------------------------------------------------------------------------- 1 | [{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"forceOwnerChange","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"disown","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"changeOwner","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"creationTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"}] -------------------------------------------------------------------------------- /dapp_example/myDapp2/client/main.html: -------------------------------------------------------------------------------- 1 | 2 | myDapp 3 | 4 | 5 | 6 |

OneValue Contract

7 | 8 | {{> blockInfo}} 9 | 10 |
11 | 12 | {{> oneValue}} 13 | 14 | 15 | 16 | 19 | 20 | 26 | -------------------------------------------------------------------------------- /contracts/build/mortal.bin: -------------------------------------------------------------------------------- 1 | 60606040525b33600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b5b610108806100576000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806341c0e1b514603a575bfe5b3415604157fe5b60476049565b005b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141560d957600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b5b5600a165627a7a72305820e2d013cfe53a7bda0ac5dc6589fba884f5511bac04be980303103c42dcb83aa30029 -------------------------------------------------------------------------------- /contracts/build/StateMachine.sol:StateMachine.abi: -------------------------------------------------------------------------------- 1 | [{"constant":false,"inputs":[],"name":"bid","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"reveal","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"h","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"stage","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"creationTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"g","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"i","outputs":[],"payable":false,"type":"function"}] -------------------------------------------------------------------------------- /slides/0_Agenda_1114.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # Ethereum Smart Contract 4 | ## Yu-Te Lin 5 | 6 | --- 7 | 8 | ## 以太坊開發環境及工具介紹 9 | 10 | - Ethereum and Smart contract 11 | 12 | - Wallet GUI: Mist 13 | 14 | - Command line tools: geth, solc 15 | 16 | - Contract editors: atom, sublime text, visual studio. 17 | 18 | - Libraries and Development tools: web3, testrpc, truffle. 19 | 20 | - Contract deployment 21 | 22 | --- 23 | 24 | ## 以太坊智能合約開發 25 | 26 | - 程式設計 27 | 28 | - 資訊安全 29 | 30 | - 設計模式 31 | 32 | - 測試 33 | 34 | --- 35 | 36 | ## Github 37 | - Github: https://github.com/amisamity/contract-training 38 | 39 | ![https://github.com/amisamity/contract-training](../qrcode.png "https://github.com/amisamity/contract-training") 40 | -------------------------------------------------------------------------------- /truffle_test/test/TestMetacoin.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.2; 2 | 3 | import "truffle/Assert.sol"; 4 | import "truffle/DeployedAddresses.sol"; 5 | import "../contracts/MetaCoin.sol"; 6 | 7 | contract TestMetacoin { 8 | 9 | function testInitialBalanceUsingDeployedContract() { 10 | MetaCoin meta = MetaCoin(DeployedAddresses.MetaCoin()); 11 | 12 | uint expected = 10000; 13 | 14 | Assert.equal(meta.getBalance(tx.origin), expected, "Owner should have 10000 MetaCoin initially"); 15 | } 16 | 17 | function testInitialBalanceWithNewMetaCoin() { 18 | MetaCoin meta = new MetaCoin(); 19 | 20 | uint expected = 10000; 21 | 22 | Assert.equal(meta.getBalance(tx.origin), expected, "Owner should have 10000 MetaCoin initially"); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /slides/0_Agenda.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # Ethereum Smart Contract 4 | ## Yu-Te Lin 5 | 6 | --- 7 | 8 | ## Blockchain Basics 9 | 10 | - Blockchain 1.0: Bitcoin, Altcoins 11 | 12 | - Blockchain 1.1: Colored coins, decoration protocols 13 | 14 | - Blockchain 2.0: Ethereum, Tendermint 15 | 16 | --- 17 | 18 | ## Ethereum Development Environment and Tools 19 | 20 | - Ethereum and Smart contract 21 | 22 | - Wallet GUI: Mist 23 | 24 | - Command line tools: geth, solc 25 | 26 | - Contract editors: atom, sublime text, visual studio. 27 | 28 | - Libraries and Development tools: web3, testrpc, truffle. 29 | 30 | - Contract deployment 31 | 32 | --- 33 | 34 | ## Smart Contract Coding 35 | 36 | - Basics 37 | 38 | - Security 39 | 40 | - Patterns 41 | 42 | - Testing 43 | -------------------------------------------------------------------------------- /truffle_test/app/stylesheets/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin-left: 25%; 3 | margin-right: 25%; 4 | margin-top: 10%; 5 | font-family: "Open Sans", sans-serif; 6 | } 7 | 8 | label { 9 | display: inline-block; 10 | width: 100px; 11 | } 12 | 13 | input { 14 | width: 500px; 15 | padding: 5px; 16 | font-size: 16px; 17 | } 18 | 19 | button { 20 | font-size: 16px; 21 | padding: 5px; 22 | } 23 | 24 | h1, h2 { 25 | display: inline-block; 26 | vertical-align: middle; 27 | margin-top: 0px; 28 | margin-bottom: 10px; 29 | } 30 | 31 | h2 { 32 | color: #AAA; 33 | font-size: 32px; 34 | } 35 | 36 | h3 { 37 | font-weight: normal; 38 | color: #AAA; 39 | font-size: 24px; 40 | } 41 | 42 | .black { 43 | color: black; 44 | } 45 | 46 | #balance { 47 | color: black; 48 | } 49 | -------------------------------------------------------------------------------- /dapp_example/myDapp/client/main.js: -------------------------------------------------------------------------------- 1 | import { Template } from 'meteor/templating'; 2 | import { ReactiveVar } from 'meteor/reactive-var'; 3 | 4 | import './main.html'; 5 | 6 | Template.hello.onCreated(function helloOnCreated() { 7 | // counter starts at 0 8 | this.counter = new ReactiveVar(0); 9 | }); 10 | 11 | Template.hello.helpers({ 12 | counter() { 13 | return Template.instance().counter.get(); 14 | }, 15 | }); 16 | 17 | Template.hello.events({ 18 | 'click button'(event, instance) { 19 | // increment the counter when button is clicked 20 | instance.counter.set(instance.counter.get() + 1); 21 | }, 22 | }); 23 | 24 | Template.blockInfo.onCreated(function blockInfoOnCreated(){ 25 | EthBlocks.init(); 26 | }); 27 | 28 | Template.blockInfo.helpers({ 29 | currentBlock(){ 30 | return EthBlocks.latest.number; 31 | }, 32 | }); 33 | -------------------------------------------------------------------------------- /js/express-example.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var app = express(); 3 | var Web3 = require('web3'); 4 | var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); 5 | var abi = [{"constant":true,"inputs":[],"name":"getValue","outputs":[{"name":"result","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"v","type":"uint256"}],"name":"setValue","outputs":[],"type":"function"},{"inputs":[{"name":"initValue","type":"uint256"}],"type":"constructor"}]; 6 | var OneValueContract = web3.eth.contract(abi); 7 | var contractAddress = '0x2c8d5011127c5c38cae75f4c63b19e71a644562f'; 8 | var oneValue = OneValueContract.at(contractAddress); 9 | 10 | app.get('/', function (req, res) { 11 | res.send( 12 | 'OneValue Instance: ' + contractAddress + "\n" + 13 | 'Value: '+ oneValue.getValue() + "\n"); 14 | }); 15 | 16 | app.listen(3000) 17 | -------------------------------------------------------------------------------- /dapp_example/myDapp/client/main.html: -------------------------------------------------------------------------------- 1 | 2 | myDapp 3 | 4 | 5 | 6 |

Welcome to Meteor!

7 | 8 | {{> blockInfo}} 9 | 10 | {{> hello}} 11 | {{> info}} 12 | 13 | 14 | 18 | 19 | 28 | 29 | 32 | -------------------------------------------------------------------------------- /js/update-contract-test.js: -------------------------------------------------------------------------------- 1 | var Web3 = require('web3'); 2 | var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); 3 | var abi = [{"constant":true,"inputs":[],"name":"getValue","outputs":[{"name":"result","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"v","type":"uint256"}],"name":"setValue","outputs":[],"type":"function"},{"inputs":[{"name":"initValue","type":"uint256"}],"type":"constructor"}]; 4 | var OneValueContract = web3.eth.contract(abi); 5 | var contractAddress = '0xd34d02bd80b7ad234305e734bd229746e5fe204e'; 6 | var oneValue = OneValueContract.at(contractAddress); 7 | 8 | var addr = web3.eth.accounts[0]; 9 | web3.personal.unlockAccount(addr, 'test1234', function(e, r){ 10 | oneValue.setValue.sendTransaction(1234, {from: addr}, function(error, txid){ 11 | console.log("Error: ", e); 12 | console.log("Txid: ", txid); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /slides/0_Agenda_03232017.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # Ethereum Smart Contract 4 | ## Yu-Te Lin 5 | 6 | --- 7 | ## About me 8 | - VP of Engineering, Amis 9 | - Director of Engineering, MaiCoin 10 | - Manager, HTC 11 | - Co-founder, Everyday.me (Y-Combinator backed) 12 | - Engineer, Oracle/Dell (Wyse) 13 | - MS Stanford, BS NCCU 14 | 15 | --- 16 | 17 | ## 以太坊開發環境及工具介紹 18 | - Ethereum and Smart contract 19 | - Wallet GUI: Mist, MetaMask 20 | - Command line tools: geth, solc 21 | - Contract deployment 22 | --- 23 | 24 | ## 以太坊智能合約開發 25 | - 程式設計 26 | - 資訊安全 27 | - 設計模式 28 | - 測試 29 | --- 30 | 31 | ## Dapps 開發 32 | - Dapp 範例 - FlightDelay 33 | - Web3 JavaScript Ðapp API 34 | - 開發工具 - Meteor 35 | 36 | --- 37 | 38 | ## Github 39 | - Github: https://github.com/amisamity/contract-training 40 | 41 | ![https://github.com/amisamity/contract-training](../qrcode.png "https://github.com/amisamity/contract-training") 42 | -------------------------------------------------------------------------------- /slides/1_Blockchain_Recap_0323.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # Blockchain FAQ 4 | 5 | --- 6 | 7 | ## 什麼是區塊鏈? 8 | - 可看成去中心化資料庫 9 | - 所有區塊鏈網路上節點共同維護一公開帳本(以比特幣為例) 10 | - 資料以一個個區塊方式連結,而串成一個區塊鏈 11 | 12 | --- 13 | 14 | ## 什麼是去中心化? 15 | - 相對於中心化,例如上市證券交易必須透過證交所 16 | - 任何節點都可以成為可靠的資料來源 17 | 18 | --- 19 | 20 | ## 什麼是共識演算法? 21 | - 產生區塊的方式 22 | - 比特幣和以太幣網路都是用工作量證明(Proof of Work/PoW) 23 | 24 | --- 25 | 26 | ## 什麼是挖礦,為什麼要挖礦? 27 | - 工作量證明中,必須算出一個nonce值用以產生合法的區塊,算出這個nonce來得到獎勵的過程就要做挖礦 (mining) 28 | 29 | --- 30 | 31 | ## 什麼是節點? 32 | - 利用 p2p 方式連上區塊鏈網路即成為節點 33 | - 在比特幣網路中可執行 `bitcoind` 程式 34 | - 在以太幣網路中可執行 `geth` 程式 35 | 36 | --- 37 | 38 | ## 什麼是公有鏈,私有鏈,Mainnet,Testnet? 39 | - 公有鏈是大家都可以連上的區塊鏈網路 40 | - Mainnet 等於是公有鏈上的正式環境,Testnet 等於是公有鏈上的測試環境 41 | - 私有鏈可以是跑在私有網路的區塊鏈網路,或是需要特定權限的節點才能加入的區塊鏈網路 42 | 43 | --- 44 | 45 | ## 什麼是 Ethereum Virtual Machine (EVM)? 46 | - EVM 是以太坊實現 Blockchain 2.0 的主要元件,它可以用來執行智能合約編譯後的Byte code,並確保不同電腦架構下的節點在相同的輸入下可以有相同的輸出 47 | -------------------------------------------------------------------------------- /truffle_test/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MetaCoin - Default Truffle App 5 | 6 | 7 | 8 | 9 | 10 |

MetaCoin

11 |

Example Truffle Dapp

12 |

You have META

13 | 14 |
15 |

Send

16 |
17 |
18 |

19 |

20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /slides/0_Agenda_03172017.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # Ethereum API and Ðapp 4 | ## Yu-Te Lin 5 | 6 | --- 7 | ## About me 8 | 9 | - VP of Engineering, Amis 10 | 11 | - Director of Engineering, MaiCoin 12 | 13 | - Manager, HTC 14 | 15 | - Co-founder, Everyday.me (Y-Combinator backed) 16 | 17 | - Engineer, Oracle/Dell (Wyse) 18 | 19 | - MSCS Stanford, BSCS NCCU 20 | 21 | --- 22 | 23 | ## 以太坊開發環境及工具介紹 24 | 25 | - Ethereum and Smart contract 26 | 27 | - Wallet GUI: Mist 28 | 29 | - Command line tools: geth, solc 30 | 31 | - Contract editors: Atom, Sublime text, Visual Studio, Remix IDE 32 | 33 | - Libraries and Development tools: web3, testrpc, truffle 34 | 35 | - Contract deployment 36 | 37 | --- 38 | 39 | ## Ðapps 開發 40 | 41 | - Web3 JavaScript Ðapp API 42 | 43 | - 開發工具 - Meteor 44 | 45 | - 環境連結 46 | 47 | --- 48 | 49 | ## Github 50 | - Github: https://github.com/amisamity/contract-training 51 | 52 | ![https://github.com/amisamity/contract-training](../qrcode.png "https://github.com/amisamity/contract-training") 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Optional npm cache directory 30 | .npm 31 | 32 | # Optional REPL history 33 | .node_repl_history 34 | 35 | # bundler state 36 | .bundle 37 | **/vendor/bundle/ 38 | **/vendor/ruby/ 39 | 40 | # application 41 | services/config/service.json 42 | 43 | # JetBrains 44 | .idea 45 | 46 | # Node runtime stuff 47 | **/.node-xmlhttprequest* 48 | 49 | # NO vendor src 50 | #vendor/src/ 51 | 52 | # Truffle build 53 | truffle_test/build 54 | 55 | # node_modules 56 | node_modules 57 | -------------------------------------------------------------------------------- /contracts/build/remote-purchase.sol:Purchase.abi: -------------------------------------------------------------------------------- 1 | [{"constant":true,"inputs":[],"name":"seller","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"abort","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"value","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"buyer","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"confirmReceived","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"state","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"confirmPurchase","outputs":[],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"},{"payable":false,"type":"fallback"},{"anonymous":false,"inputs":[],"name":"aborted","type":"event"},{"anonymous":false,"inputs":[],"name":"purchaseConfirmed","type":"event"},{"anonymous":false,"inputs":[],"name":"itemReceived","type":"event"}] -------------------------------------------------------------------------------- /truffle_test/contracts/MetaCoin.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.4; 2 | 3 | import "./ConvertLib.sol"; 4 | 5 | // This is just a simple example of a coin-like contract. 6 | // It is not standards compatible and cannot be expected to talk to other 7 | // coin/token contracts. If you want to create a standards-compliant 8 | // token, see: https://github.com/ConsenSys/Tokens. Cheers! 9 | 10 | contract MetaCoin { 11 | mapping (address => uint) balances; 12 | 13 | event Transfer(address indexed _from, address indexed _to, uint256 _value); 14 | 15 | function MetaCoin() { 16 | balances[tx.origin] = 10000; 17 | } 18 | 19 | function sendCoin(address receiver, uint amount) returns(bool sufficient) { 20 | if (balances[msg.sender] < amount) return false; 21 | balances[msg.sender] -= amount; 22 | balances[receiver] += amount; 23 | Transfer(msg.sender, receiver, amount); 24 | return true; 25 | } 26 | 27 | function getBalanceInEth(address addr) returns(uint){ 28 | return ConvertLib.convert(getBalance(addr),2); 29 | } 30 | 31 | function getBalance(address addr) returns(uint) { 32 | return balances[addr]; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /contracts/build/Set.bin: -------------------------------------------------------------------------------- 1 | 6060604052341561000c57fe5b5b61022f8061001c6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063483b8a14146100515780636ce8e0811461008a578063831cb739146100c3575bfe5b61007060048080359060200190919080359060200190919050506100fc565b604051808215151515815260200191505060405180910390f35b6100a96004808035906020019091908035906020019091905050610169565b604051808215151515815260200191505060405180910390f35b6100e26004808035906020019091908035906020019091905050610197565b604051808215151515815260200191505060405180910390f35b600082600001600083815260200190815260200160002060009054906101000a900460ff1615156101305760009050610163565b600083600001600084815260200190815260200160002060006101000a81548160ff021916908315150217905550600190505b92915050565b600082600001600083815260200190815260200160002060009054906101000a900460ff1690505b92915050565b600082600001600083815260200190815260200160002060009054906101000a900460ff16156101ca57600090506101fd565b600183600001600084815260200190815260200160002060006101000a81548160ff021916908315150217905550600190505b929150505600a165627a7a7230582052a1e41ccda643bd44d932d28bfefdd399a92866343498c2cffe078140c09f910029 -------------------------------------------------------------------------------- /contracts/WithdrawalContract.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.0; 2 | 3 | contract WithdrawalContract { 4 | address public richest; 5 | uint public mostSent; 6 | 7 | mapping (address => uint) pendingWithdrawals; 8 | 9 | function WithdrawalContract() payable { 10 | richest = msg.sender; 11 | mostSent = msg.value; 12 | } 13 | 14 | function becomeRichest() payable returns (bool) { 15 | if (msg.value > mostSent) { 16 | pendingWithdrawals[richest] += msg.value; 17 | richest = msg.sender; 18 | mostSent = msg.value; 19 | return true; 20 | } else { 21 | return false; 22 | } 23 | } 24 | 25 | function withdraw() returns (bool) { 26 | uint amount = pendingWithdrawals[msg.sender]; 27 | // Remember to zero the pending refund before 28 | // sending to prevent re-entrancy attacks 29 | pendingWithdrawals[msg.sender] = 0; 30 | if (msg.sender.send(amount)) { 31 | return true; 32 | } else { 33 | pendingWithdrawals[msg.sender] = amount; 34 | return false; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /contracts/lib-set.sol: -------------------------------------------------------------------------------- 1 | library Set { 2 | // We define a new struct datatype that will be used to 3 | // hold its data in the calling contract. 4 | struct Data { mapping(uint => bool) flags; } 5 | 6 | // Note that the first parameter is of type "storage 7 | // reference" and thus only its storage address and not 8 | // its contents is passed as part of the call. This is a 9 | // special feature of library functions. It is idiomatic 10 | // to call the first parameter 'self', if the function can 11 | // be seen as a method of that object. 12 | function insert(Data storage self, uint value) 13 | returns (bool) 14 | { 15 | if (self.flags[value]) 16 | return false; // already there 17 | self.flags[value] = true; 18 | return true; 19 | } 20 | 21 | function remove(Data storage self, uint value) 22 | returns (bool) 23 | { 24 | if (!self.flags[value]) 25 | return false; // not there 26 | self.flags[value] = false; 27 | return true; 28 | } 29 | 30 | function contains(Data storage self, uint value) 31 | returns (bool) 32 | { 33 | return self.flags[value]; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /contracts/build/Ballot.sol:Ballot.abi: -------------------------------------------------------------------------------- 1 | [{"constant":false,"inputs":[{"name":"proposal","type":"uint256"}],"name":"vote","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"proposals","outputs":[{"name":"name","type":"bytes32"},{"name":"voteCount","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"chairperson","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"}],"name":"delegate","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"winningProposal","outputs":[{"name":"winningProposal","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"voter","type":"address"}],"name":"giveRightToVote","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"voters","outputs":[{"name":"weight","type":"uint256"},{"name":"voted","type":"bool"},{"name":"delegate","type":"address"},{"name":"vote","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"proposalNames","type":"bytes32[]"}],"payable":false,"type":"constructor"}] -------------------------------------------------------------------------------- /slides/7_References.md: -------------------------------------------------------------------------------- 1 | ## References: 2 | - Ethereum Frontier Guide https://www.gitbook.com/book/ethereum/frontier-guide/ 3 | - Solidity http://solidity.readthedocs.io/en/latest/ 4 | - Go-ethereum wiki: https://github.com/ethereum/go-ethereum/wiki 5 | - JavaScript console: https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console 6 | - ContractWallet https://github.com/ethereum/meteor-dapp-wallet/blob/develop/Wallet.sol 7 | - Sample contracts https://github.com/fivedogit/solidity-baby-steps/tree/master/contracts/ 8 | - Sample ÐApps https://github.com/ethereum/dapp-bin 9 | - Vitalik Buterin. Ethereum: A Next-Generation Cryptocurrency and Decentralized Application Platform. https://bitcoinmagazine.com/articles/ethereum-next-generation-cryptocurrency-decentralized-application-platform-1390528211 10 | - Taylor Gerring. Blockchain 101 https://blockchainconsulting.expert/slides/blockchains101.pdf 11 | - Bitcoin wiki colored coin https://en.bitcoin.it/wiki/Colored_Coins 12 | - Bitcoin script https://en.bitcoin.it/wiki/Script 13 | - Ethereum white paper: https://github.com/ethereum/wiki/wiki/White-Paper 14 | - Vitalik Buterin. Thoughts on UTXOs https://medium.com/@ConsenSys/thoughts-on-utxo-by-vitalik-buterin-2bb782c67e53#.99hm4kf6x 15 | -------------------------------------------------------------------------------- /slides/0_Agenda_03102017.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # Smart Contract Bootcamp 4 | ## Yu-Te Lin 5 | 6 | --- 7 | ## About me 8 | - VP of Engineering, __Amis__ 9 | 10 | - Director of Engineering, __MaiCoin__ 11 | 12 | - Manager, __HTC__ 13 | 14 | - Co-founder, __Everyday.me__ (Y-Combinator backed) 15 | 16 | - Engineer, __Oracle__/__Dell__ (__Wyse__) 17 | 18 | - MSCS __Stanford__, BSCS __NCCU__ 19 | 20 | --- 21 | 22 | ## 以太坊開發環境及工具介紹 23 | 24 | - Ethereum and Smart contract 25 | 26 | - Wallet GUI: Mist 27 | 28 | - Command line tools: geth, solc 29 | 30 | - Contract editors: atom, sublime text, visual studio. 31 | 32 | - Libraries and Development tools: web3, testrpc, truffle. 33 | 34 | - Contract deployment 35 | 36 | --- 37 | 38 | ## 以太坊智能合約開發 39 | 40 | - 程式設計 41 | 42 | - 資訊安全 43 | 44 | - 設計模式 45 | 46 | - 測試 47 | 48 | --- 49 | 50 | ## 保險智能合約範例 51 | 52 | - FlightDelay 介紹 53 | 54 | - FlightDelay 操作 - MetaMask / Mist 55 | 56 | - FlightDelay 程式碼導讀 57 | 58 | --- 59 | 60 | ## Dapps 開發 61 | 62 | - Web3 JavaScript Ðapp API 63 | 64 | - 開發工具 - Meteor 65 | 66 | - 環境連結 67 | 68 | --- 69 | 70 | ## Github 71 | - Github: https://github.com/amisamity/contract-training 72 | 73 | ![https://github.com/amisamity/contract-training](../qrcode.png "https://github.com/amisamity/contract-training") 74 | -------------------------------------------------------------------------------- /contracts/build/SimpleAuction.sol:SimpleAuction.abi: -------------------------------------------------------------------------------- 1 | [{"constant":false,"inputs":[],"name":"bid","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"auctionEnd","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"beneficiary","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"withdraw","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"auctionStart","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"highestBidder","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"biddingTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"highestBid","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"_biddingTime","type":"uint256"},{"name":"_beneficiary","type":"address"}],"payable":false,"type":"constructor"},{"payable":false,"type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"bidder","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"HighestBidIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"winner","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"AuctionEnded","type":"event"}] -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # Contract Training 2 | Repo for smart contract (solidity) training. 3 | 4 | ## Link 5 | ![https://github.com/amisamity/contract-training](qrcode.png "https://github.com/amisamity/contract-training") 6 | 7 | ## Slides 8 | - [0. Agenda](https://amisamity.github.io/contract-training/slides/0_Agenda.md.html) 9 | - [1. Blockchain Basics](https://amisamity.github.io/contract-training/slides/1_Blockchain_Basics.md.html) 10 | - [2. Ethereum Development Environment and Tools](https://amisamity.github.io/contract-training/slides/2_Ethereum_Development_Environment_and_Tools.md.html) 11 | - [3. Smart Contract and Solidity](https://amisamity.github.io/contract-training/slides/3_Smart_Contract_Solidity_Quick_Start.md.html) 12 | - [4. Solidity Security](https://amisamity.github.io/contract-training/slides/4_Solidity_Security.md.html) 13 | - [5. Solidity Patterns](https://amisamity.github.io/contract-training/slides/5_Solidity_Patterns.md.html) 14 | - [6. Solidity Testing](https://amisamity.github.io/contract-training/slides/6_Solidity_Testing.md.html) 15 | - [7. Ðapps Development](https://amisamity.github.io/contract-training/slides/9_Dapps_Development.md.html) 16 | - [8. Insurance Example](https://amisamity.github.io/contract-training/slides/8_Insurance_Examples.md.html) 17 | - [9. Web3 JavaScript Ðapp API](https://amisamity.github.io/contract-training/slides/10_Web3_JavaScript.md.html) 18 | - [10. References](https://amisamity.github.io/contract-training/slides/7_References.md.html) 19 | 20 | ## 課程投影片 21 | - [課程投影片](LECTURES.MD) 22 | -------------------------------------------------------------------------------- /dapp_example/myDapp/.meteor/packages: -------------------------------------------------------------------------------- 1 | # Meteor packages used by this project, one per line. 2 | # Check this file (and the other files in this directory) into your repository. 3 | # 4 | # 'meteor add' and 'meteor remove' will edit this file for you, 5 | # but you can also edit it by hand. 6 | 7 | meteor-base@1.0.4 # Packages every Meteor app needs to have 8 | mobile-experience@1.0.4 # Packages for a great mobile UX 9 | mongo@1.1.14 # The database Meteor supports right now 10 | blaze-html-templates@1.0.4 # Compile .html files into Meteor Blaze views 11 | reactive-var@1.0.11 # Reactive variable for tracker 12 | jquery@1.11.10 # Helpful client-side library 13 | tracker@1.1.1 # Meteor's client-side reactive programming library 14 | 15 | standard-minifier-css@1.3.2 # CSS minifier run for production mode 16 | standard-minifier-js@1.2.1 # JS minifier run for production mode 17 | es5-shim@4.6.15 # ECMAScript 5 compatibility for older browsers. 18 | ecmascript@0.6.1 # Enable ECMAScript2015+ syntax in app code 19 | shell-server@0.2.1 # Server-side component of the `meteor shell` command 20 | 21 | autopublish@1.0.7 # Publish all data to the clients (for prototyping) 22 | insecure@1.0.7 # Allow all DB writes from clients (for prototyping) 23 | ethereum:web3 24 | ethereum:dapp-styles 25 | ethereum:tools 26 | ethereum:elements 27 | ethereum:accounts 28 | ethereum:blocks 29 | frozeman:template-var 30 | frozeman:persistent-minimongo2 31 | less 32 | -------------------------------------------------------------------------------- /contracts/CrowdFunding.sol: -------------------------------------------------------------------------------- 1 | contract CrowdFunding { 2 | // Defines a new type with two fields. 3 | struct Funder { 4 | address addr; 5 | uint amount; 6 | } 7 | 8 | struct Campaign { 9 | address beneficiary; 10 | uint fundingGoal; 11 | uint numFunders; 12 | uint amount; 13 | mapping (uint => Funder) funders; 14 | } 15 | 16 | uint numCampaigns; 17 | mapping (uint => Campaign) campaigns; 18 | 19 | function newCampaign(address beneficiary, uint goal) returns (uint campaignID) { 20 | campaignID = numCampaigns++; // campaignID is return variable 21 | // Creates new struct and saves in storage. We leave out the mapping type. 22 | campaigns[campaignID] = Campaign(beneficiary, goal, 0, 0); 23 | } 24 | 25 | function contribute(uint campaignID) { 26 | Campaign c = campaigns[campaignID]; 27 | // Creates a new temporary memory struct, initialised with the given values 28 | // and copies it over to storage. 29 | // Note that you can also use Funder(msg.sender, msg.value) to initialise. 30 | c.funders[c.numFunders++] = Funder({addr: msg.sender, amount: msg.value}); 31 | c.amount += msg.value; 32 | } 33 | 34 | function checkGoalReached(uint campaignID) returns (bool reached) { 35 | Campaign c = campaigns[campaignID]; 36 | if (c.amount < c.fundingGoal) 37 | return false; 38 | if (!c.beneficiary.send(c.amount)) 39 | throw; 40 | c.amount = 0; 41 | return true; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /dapp_example/myDapp2/.meteor/packages: -------------------------------------------------------------------------------- 1 | # Meteor packages used by this project, one per line. 2 | # Check this file (and the other files in this directory) into your repository. 3 | # 4 | # 'meteor add' and 'meteor remove' will edit this file for you, 5 | # but you can also edit it by hand. 6 | 7 | meteor-base@1.0.4 # Packages every Meteor app needs to have 8 | mobile-experience@1.0.4 # Packages for a great mobile UX 9 | mongo@1.1.14 # The database Meteor supports right now 10 | blaze-html-templates@1.0.4 # Compile .html files into Meteor Blaze views 11 | reactive-var@1.0.11 # Reactive variable for tracker 12 | jquery@1.11.10 # Helpful client-side library 13 | tracker@1.1.1 # Meteor's client-side reactive programming library 14 | 15 | standard-minifier-css@1.3.2 # CSS minifier run for production mode 16 | standard-minifier-js@1.2.1 # JS minifier run for production mode 17 | es5-shim@4.6.15 # ECMAScript 5 compatibility for older browsers. 18 | ecmascript@0.6.1 # Enable ECMAScript2015+ syntax in app code 19 | shell-server@0.2.1 # Server-side component of the `meteor shell` command 20 | 21 | autopublish@1.0.7 # Publish all data to the clients (for prototyping) 22 | insecure@1.0.7 # Allow all DB writes from clients (for prototyping) 23 | ethereum:web3 24 | ethereum:dapp-styles 25 | ethereum:tools 26 | ethereum:elements 27 | ethereum:accounts 28 | ethereum:blocks 29 | frozeman:template-var 30 | frozeman:persistent-minimongo2 31 | less 32 | erasaur:meteor-lodash 33 | -------------------------------------------------------------------------------- /js/deploy-client-receipt.js: -------------------------------------------------------------------------------- 1 | var Web3 = require('web3'); 2 | var TestRPC = require("ethereumjs-testrpc"); 3 | // var web3 = new Web3(TestRPC.provider()); 4 | var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); 5 | 6 | var abi = [{"constant":false,"inputs":[{"name":"_id","type":"bytes32"}],"name":"deposit","outputs":[],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_id","type":"bytes32"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Deposit","type":"event"}]; 7 | var evmCode = "0x6060604052341561000c57fe5b5b60de8061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063b214faa514603a575bfe5b3415604157fe5b6059600480803560001916906020019091905050605b565b005b80600019163373ffffffffffffffffffffffffffffffffffffffff167f19dacbf83c5de6658e14cbf7bcae5c15eca2eedecf1c66fbca928e4d351bea0f346040518082815260200191505060405180910390a35b505600a165627a7a72305820528673a40eadb3be75f92326e0664ef276b182a65164702f0d7c104f291b9c680029"; 8 | 9 | var ClientReceiptContract = web3.eth.contract(abi); 10 | var callback = function(e, contract){ 11 | if(e == null) { 12 | console.log("Contract transaction: TransactionHash: " + contract.transactionHash); 13 | if(typeof contract.address !== 'undefined'){ 14 | console.log("Contract mined! Address: " + contract.address); 15 | } 16 | } else { 17 | console.log(e); 18 | } 19 | }; 20 | var addr = web3.eth.accounts[0]; 21 | web3.personal.unlockAccount(addr, 'test1234', function(e, r){ 22 | if(e != null){ 23 | console.log("Error:", e); 24 | }else { 25 | var oneValue = ClientReceiptContract.new({from:addr, data: evmCode, gas: 200000}, callback); 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /contracts/build/CrowdFunding.bin: -------------------------------------------------------------------------------- 1 | 6060604052341561000c57fe5b5b6103808061001c6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680635b2329d414610051578063c1cbbca714610089578063f7572cf3146100a9575bfe5b341561005957fe5b61006f60048080359060200190919050506100fc565b604051808215151515815260200191505060405180910390f35b341561009157fe5b6100a760048080359060200190919050506101ae565b005b34156100b157fe5b6100e6600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610283565b6040518082815260200191505060405180910390f35b6000600060016000848152602001908152602001600020905080600101548160030154101561012e57600091506101a8565b8060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc82600301549081150290604051809050600060405180830381858888f19350505050151561019957610000565b60008160030181905550600191505b50919050565b60006001600083815260200190815260200160002090506040604051908101604052803373ffffffffffffffffffffffffffffffffffffffff1681526020013481525081600401600083600201600081548092919060010191905055815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550602082015181600101559050503481600301600082825401925050819055505b5050565b6000600060008154809291906001019190505590506080604051908101604052808473ffffffffffffffffffffffffffffffffffffffff1681526020018381526020016000815260200160008152506001600083815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506020820151816001015560408201518160020155606082015181600301559050505b929150505600a165627a7a723058201e64ca853a8799b9fefd264986797447d85fc0b9c9b57ee7be1b94e19d16783b0029 -------------------------------------------------------------------------------- /js/deploy-contract-test.js: -------------------------------------------------------------------------------- 1 | var Web3 = require('web3'); 2 | var TestRPC = require("ethereumjs-testrpc"); 3 | // var web3 = new Web3(TestRPC.provider()); 4 | var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); 5 | 6 | var abi = [{"constant":true,"inputs":[],"name":"getValue","outputs":[{"name":"result","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"v","type":"uint256"}],"name":"setValue","outputs":[],"type":"function"},{"inputs":[{"name":"initValue","type":"uint256"}],"type":"constructor"}] 7 | var evmCode = "0x606060405260405160208060cf833981016040528080519060200190919050505b806000600050819055505b5060978060386000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063209652551460415780635524107714606257603f565b005b604c60048050506078565b6040518082815260200191505060405180910390f35b607660048080359060200190919050506089565b005b600060006000505490506086565b90565b806000600050819055505b5056"; 8 | 9 | var OneValueContract = web3.eth.contract(abi); 10 | var callback = function(e, contract){ 11 | if(e == null) { 12 | console.log("Contract transaction: TransactionHash: " + contract.transactionHash); 13 | if(typeof contract.address !== 'undefined'){ 14 | console.log("Contract mined! Address: " + contract.address); 15 | var oneValueInst = OneValueContract.at(contract.address); 16 | console.log("Value:", parseInt(oneValueInst.getValue())); 17 | } 18 | } else { 19 | console.log(e); 20 | } 21 | }; 22 | var initValue = 123; 23 | var addr = web3.eth.accounts[0]; 24 | web3.personal.unlockAccount(addr, 'test1234', function(e, r){ 25 | if(e != null){ 26 | console.log("Error:", e); 27 | }else { 28 | var oneValue = OneValueContract.new(initValue, {from:addr, data: evmCode, gas: 200000}, callback); 29 | } 30 | }); 31 | -------------------------------------------------------------------------------- /truffle_test/app/javascripts/app.js: -------------------------------------------------------------------------------- 1 | var accounts; 2 | var account; 3 | var balance; 4 | 5 | function setStatus(message) { 6 | var status = document.getElementById("status"); 7 | status.innerHTML = message; 8 | }; 9 | 10 | function refreshBalance() { 11 | return MetaCoin.deployed().then(function(meta) { 12 | return meta.getBalance.call(account); 13 | }).then(function(outCoinBalance) { 14 | var metaCoinBalance = outCoinBalance.toNumber(); 15 | var balance_element = document.getElementById("balance"); 16 | balance_element.innerHTML = metaCoinBalance.valueOf(); 17 | }); 18 | }; 19 | 20 | function sendCoin() { 21 | var meta; 22 | var amount = parseInt(document.getElementById("amount").value); 23 | var receiver = document.getElementById("receiver").value; 24 | 25 | return MetaCoin.deployed().then(function(instance) { 26 | meta = instance; 27 | setStatus("Initiating transaction... (please wait)"); 28 | return meta.sendCoin(receiver, amount, {from: account}); 29 | }).then(function(tx) { 30 | console.log(tx, tx.tx); 31 | setStatus("Transaction complete!
txid: " + tx.tx); 32 | return refreshBalance(); 33 | }).catch(function(e){ 34 | console.log(e); 35 | setStatus("Error sending coin; see log."); 36 | }); 37 | }; 38 | 39 | window.onload = function() { 40 | web3.eth.getAccounts(function(err, accs) { 41 | if (err != null) { 42 | alert("There was an error fetching your accounts."); 43 | return; 44 | } 45 | 46 | if (accs.length == 0) { 47 | alert("Couldn't get any accounts! Make sure your Ethereum client is configured correctly."); 48 | return; 49 | } 50 | 51 | accounts = accs; 52 | account = accounts[0]; 53 | 54 | refreshBalance(); 55 | }); 56 | } 57 | -------------------------------------------------------------------------------- /js/deploy-contract-testrpc.js: -------------------------------------------------------------------------------- 1 | var Web3 = require('web3'); 2 | var TestRPC = require("ethereumjs-testrpc"); 3 | var web3 = new Web3(TestRPC.provider()); 4 | // var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8547")); 5 | 6 | var abi = [{"constant":true,"inputs":[],"name":"getValue","outputs":[{"name":"result","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"v","type":"uint256"}],"name":"setValue","outputs":[],"type":"function"},{"inputs":[{"name":"initValue","type":"uint256"}],"type":"constructor"}] 7 | var evmCode = "0x606060405260405160208060cf833981016040528080519060200190919050505b806000600050819055505b5060978060386000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063209652551460415780635524107714606257603f565b005b604c60048050506078565b6040518082815260200191505060405180910390f35b607660048080359060200190919050506089565b005b600060006000505490506086565b90565b806000600050819055505b5056"; 8 | 9 | var OneValueContract = web3.eth.contract(abi); 10 | var callback = function(e, contract){ 11 | if(e == null) { 12 | console.log("Contract transaction: TransactionHash: " + contract.transactionHash); 13 | if(typeof contract.address !== 'undefined'){ 14 | console.log("Contract mined! Address: " + contract.address); 15 | var oneValueInst = OneValueContract.at(contract.address); 16 | oneValueInst.getValue(function(e, r){ 17 | console.log("Value:", parseInt(r)); 18 | process.exit(0); 19 | }); 20 | } 21 | } else { 22 | console.log(e); 23 | } 24 | }; 25 | var initValue = 123; 26 | web3.eth.getAccounts(function(e, accts){ 27 | var addr = accts[0]; 28 | //Unlock account 29 | var oneValue = OneValueContract.new(initValue, {from:addr, data: evmCode, gas: 200000}, callback); 30 | }); 31 | -------------------------------------------------------------------------------- /js/watch-client-receipt.js: -------------------------------------------------------------------------------- 1 | var Web3 = require('web3'); 2 | var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); 3 | var abi = [{"constant":false,"inputs":[{"name":"_id","type":"bytes32"}],"name":"deposit","outputs":[],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_id","type":"bytes32"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Deposit","type":"event"}]; 4 | var ClientReceipt = web3.eth.contract(abi); 5 | var clientReceipt = ClientReceipt.at("0x32cb389a408cb79ab1e2d23bf1a454f4420f80b2"); 6 | 7 | var event = clientReceipt.Deposit(); 8 | 9 | var eventPrint = function(result){ 10 | if(result.event == 'Deposit') { 11 | console.log("Deposit " + result.args._value + 12 | " from " + result.args._from + 13 | " id " + result.args._id); 14 | } 15 | } 16 | 17 | // watch for changes 18 | event.watch(function(error, result){ 19 | // result will contain various information 20 | // including the argumets given to the Deposit 21 | // call. 22 | console.log("Received event from all filter"); 23 | if (!error) { 24 | eventPrint(result); 25 | } 26 | }); 27 | 28 | // Or pass a callback to start watching immediately 29 | var event = clientReceipt.Deposit(function(error, result) { 30 | console.log("Received event from 'Deposit' filter"); 31 | if (!error) { 32 | eventPrint(result); 33 | } 34 | process.exit(0); 35 | }); 36 | 37 | //Create transaction 38 | var addr = web3.eth.accounts[0]; 39 | web3.personal.unlockAccount(addr, 'test1234', function(e, r){ 40 | if(e != null){ 41 | console.log("Error:", e); 42 | }else { 43 | var txid = clientReceipt.deposit.sendTransaction(123, {from:addr, gas: 50000}); 44 | console.log("txid:", txid); 45 | } 46 | }); 47 | -------------------------------------------------------------------------------- /contracts/build/WithdrawalContract.bin: -------------------------------------------------------------------------------- 1 | 60606040525b33600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550346001819055505b5b6103748061005e6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806302e26c381461005c5780633ccfd60b146100ae5780636886bf1c146100d857806369934ee7146100fe575bfe5b341561006457fe5b61006c610120565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156100b657fe5b6100be610146565b604051808215151515815260200191505060405180910390f35b34156100e057fe5b6100e8610269565b6040518082815260200191505060405180910390f35b61010661026f565b604051808215151515815260200191505060405180910390f35b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055503373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051809050600060405180830381858888f19350505050156102175760019150610265565b80600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060009150610265565b5b5090565b60015481565b600060015434111561033b573460026000600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555033600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503460018190555060019050610345565b60009050610345565b5b905600a165627a7a72305820deddf4f89657e133f48fe90426f404ad49a1c653421df7c7c407c5cb3f0592f90029 -------------------------------------------------------------------------------- /js/tests/one-value-tests.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | describe('OneValueContract', function(){ 4 | var assert = require('assert'); 5 | var Web3 = require('web3'); 6 | var web3 = new Web3(); 7 | var TestRPC = require("ethereumjs-testrpc"); 8 | var primaryAddress; 9 | var oneValue; 10 | var initValue = 123; 11 | var gas = 200000; 12 | web3.setProvider(TestRPC.provider()); 13 | this.timeout(60000); //1 minute 14 | 15 | // 1. Deploy OneValueContract 16 | before(function(done) { 17 | var tool = require('./tools'); 18 | var abi = tool.loadAbi('OneValue'); 19 | var bin = tool.loadBin('OneValue'); 20 | var OneValueContract = web3.eth.contract(abi); 21 | //2. Get accounts 22 | web3.eth.getAccounts(function(error, result){ 23 | //3. Deploy 24 | primaryAddress = result[0]; //Blockchain Admin 25 | oneValue = OneValueContract.new(initValue, {from:primaryAddress, data: bin, gas: gas}, function(error, contract){ 26 | assert.equal(error, null); 27 | if(error == null && contract.address != null){ 28 | //Mined 29 | done(); 30 | } 31 | }); 32 | }); 33 | }); 34 | 35 | it("initValue should be 123", function(done){ 36 | oneValue.getValue(function(error, result){ 37 | assert.equal(error, null); 38 | assert.equal(initValue, result); 39 | done(); 40 | }); 41 | }); 42 | 43 | it("setValue should store value", function(done){ 44 | var newValue = 456; 45 | oneValue.setValue.sendTransaction(456, {from:primaryAddress, gas: gas}, function(error, txid){ 46 | oneValue.getValue(function(error, result){ 47 | assert.equal(error, null); 48 | assert.equal(newValue, result); 49 | done(); 50 | }); 51 | }); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /contracts/build/BlindAuction.sol:BlindAuction.abi: -------------------------------------------------------------------------------- 1 | [{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"bids","outputs":[{"name":"blindedBid","type":"bytes32"},{"name":"deposit","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"ended","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"auctionEnd","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"beneficiary","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"withdraw","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"biddingEnd","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"auctionStart","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_values","type":"uint256[]"},{"name":"_fake","type":"bool[]"},{"name":"_secret","type":"bytes32[]"}],"name":"reveal","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"highestBidder","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_blindedBid","type":"bytes32"}],"name":"bid","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"revealEnd","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"highestBid","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"_biddingTime","type":"uint256"},{"name":"_revealTime","type":"uint256"},{"name":"_beneficiary","type":"address"}],"payable":false,"type":"constructor"},{"payable":false,"type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"winner","type":"address"},{"indexed":false,"name":"highestBid","type":"uint256"}],"name":"AuctionEnded","type":"event"}] -------------------------------------------------------------------------------- /contracts/build/named.bin: -------------------------------------------------------------------------------- 1 | 6060604052341561000c57fe5b60405160208061042d833981016040528080519060200190919050505b60005b33600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b73d5f9d8d94886e70b06e474c3fb14fd43e2f2397090508073ffffffffffffffffffffffffffffffffffffffff16630a874df660016000604051602001526040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b15156100fa57fe5b60325a03f1151561010757fe5b5050506040518051905073ffffffffffffffffffffffffffffffffffffffff1663e1fa8e84836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808260001916600019168152602001915050600060405180830381600087803b151561018357fe5b60325a03f1151561019057fe5b5050505b50505b610287806101a66000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806341c0e1b51461003b575bfe5b341561004357fe5b61004b61004d565b005b6000600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156101c35773d5f9d8d94886e70b06e474c3fb14fd43e2f2397090508073ffffffffffffffffffffffffffffffffffffffff16630a874df660016000604051602001526040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b151561013157fe5b60325a03f1151561013e57fe5b5050506040518051905073ffffffffffffffffffffffffffffffffffffffff1663e79a198f6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401809050600060405180830381600087803b15156101aa57fe5b60325a03f115156101b757fe5b5050506101c26101c7565b5b5b50565b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561025857600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b5b5600a165627a7a72305820bd022a289f0a2699dfa1127fdfccf8c8d3a5c253b44410bd6c30b3097963abae0029 -------------------------------------------------------------------------------- /dapp_example/myDapp/.meteor/versions: -------------------------------------------------------------------------------- 1 | 3stack:bignumber@2.0.0 2 | alexvandesande:identicon@2.0.2 3 | allow-deny@1.0.5 4 | amplify@1.0.0 5 | autopublish@1.0.7 6 | autoupdate@1.2.11 7 | babel-compiler@6.14.1 8 | babel-runtime@1.0.1 9 | base64@1.0.10 10 | binary-heap@1.0.10 11 | blaze@2.3.0 12 | blaze-html-templates@1.1.0 13 | blaze-tools@1.0.10 14 | boilerplate-generator@1.0.11 15 | caching-compiler@1.1.9 16 | caching-html-compiler@1.1.0 17 | callback-hook@1.0.10 18 | check@1.2.4 19 | ddp@1.2.5 20 | ddp-client@1.2.9 21 | ddp-common@1.2.8 22 | ddp-server@1.2.10 23 | deps@1.0.12 24 | diff-sequence@1.0.7 25 | ecmascript@0.6.3 26 | ecmascript-runtime@0.3.15 27 | ejson@1.0.13 28 | es5-shim@4.6.15 29 | ethereum:accounts@0.4.0 30 | ethereum:blocks@0.3.2 31 | ethereum:dapp-styles@0.5.8 32 | ethereum:elements@0.7.11 33 | ethereum:tools@0.6.0 34 | ethereum:web3@0.18.3 35 | fastclick@1.0.13 36 | frozeman:animation-helper@0.2.6 37 | frozeman:persistent-minimongo@0.1.8 38 | frozeman:persistent-minimongo2@0.3.4 39 | frozeman:storage@0.1.9 40 | frozeman:template-var@1.2.3 41 | geojson-utils@1.0.10 42 | hot-code-push@1.0.4 43 | html-tools@1.0.11 44 | htmljs@1.0.11 45 | http@1.1.8 46 | id-map@1.0.9 47 | insecure@1.0.7 48 | jquery@1.11.10 49 | launch-screen@1.0.12 50 | less@2.5.7 51 | livedata@1.0.18 52 | localstorage@1.0.12 53 | logging@1.1.17 54 | meteor@1.6.1 55 | meteor-base@1.0.4 56 | minifier-css@1.2.16 57 | minifier-js@1.2.17 58 | minimongo@1.0.20 59 | mobile-experience@1.0.4 60 | mobile-status-bar@1.0.14 61 | modules@0.7.9 62 | modules-runtime@0.7.9 63 | mongo@1.1.15 64 | mongo-id@1.0.6 65 | npm-mongo@2.2.16_1 66 | observe-sequence@1.0.15 67 | ordered-dict@1.0.9 68 | promise@0.8.8 69 | random@1.0.10 70 | reactive-var@1.0.11 71 | reload@1.1.11 72 | retry@1.0.9 73 | routepolicy@1.0.12 74 | shell-server@0.2.2 75 | spacebars@1.0.13 76 | spacebars-compiler@1.1.0 77 | standard-minifier-css@1.3.3 78 | standard-minifier-js@1.2.2 79 | standard-minifiers@1.0.6 80 | templating@1.3.0 81 | templating-compiler@1.3.0 82 | templating-runtime@1.3.0 83 | templating-tools@1.1.0 84 | tracker@1.1.2 85 | ui@1.0.12 86 | underscore@1.0.10 87 | url@1.0.11 88 | webapp@1.3.13 89 | webapp-hashing@1.0.9 90 | -------------------------------------------------------------------------------- /contracts/build/AccessRestriction.bin: -------------------------------------------------------------------------------- 1 | 606060405233600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555042600155341561005157fe5b5b6103e2806100616000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630cb0c7f0146100675780631e9bf0da1461009d5780638da5cb5b146100af578063a6f9dae114610101578063d8270dce14610137575bfe5b341561006f57fe5b61009b600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061015d565b005b34156100a557fe5b6100ad610248565b005b34156100b757fe5b6100bf6102e6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561010957fe5b610135600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061030c565b005b341561013f57fe5b6101476103b0565b6040518082815260200191505060405180910390f35b680ad78ebc5ac62000008034101561017457610000565b81600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060016000600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161614156101fe576101ff565b5b80341115610243573373ffffffffffffffffffffffffffffffffffffffff166108fc8234039081150290604051809050600060405180830381858888f19350505050505b5b5050565b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156102a557610000565b62375f0060015401804210156102ba57610000565b600060006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690555b5b505b50565b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561036957610000565b81600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b5b5050565b600154815600a165627a7a7230582000e5323c38ec3a336c215628d2f399824dbe2c96e892d68175558701d1b35d700029 -------------------------------------------------------------------------------- /dapp_example/myDapp2/.meteor/versions: -------------------------------------------------------------------------------- 1 | 3stack:bignumber@2.0.0 2 | alexvandesande:identicon@2.0.2 3 | allow-deny@1.0.5 4 | amplify@1.0.0 5 | autopublish@1.0.7 6 | autoupdate@1.2.11 7 | babel-compiler@6.14.1 8 | babel-runtime@1.0.1 9 | base64@1.0.10 10 | binary-heap@1.0.10 11 | blaze@2.3.0 12 | blaze-html-templates@1.1.0 13 | blaze-tools@1.0.10 14 | boilerplate-generator@1.0.11 15 | caching-compiler@1.1.9 16 | caching-html-compiler@1.1.0 17 | callback-hook@1.0.10 18 | check@1.2.4 19 | ddp@1.2.5 20 | ddp-client@1.2.9 21 | ddp-common@1.2.8 22 | ddp-server@1.2.10 23 | deps@1.0.12 24 | diff-sequence@1.0.7 25 | ecmascript@0.6.3 26 | ecmascript-runtime@0.3.15 27 | ejson@1.0.13 28 | erasaur:meteor-lodash@4.0.0 29 | es5-shim@4.6.15 30 | ethereum:accounts@0.4.0 31 | ethereum:blocks@0.3.2 32 | ethereum:dapp-styles@0.5.8 33 | ethereum:elements@0.7.11 34 | ethereum:tools@0.6.0 35 | ethereum:web3@0.18.3 36 | fastclick@1.0.13 37 | frozeman:animation-helper@0.2.6 38 | frozeman:persistent-minimongo@0.1.8 39 | frozeman:persistent-minimongo2@0.3.4 40 | frozeman:storage@0.1.9 41 | frozeman:template-var@1.2.3 42 | geojson-utils@1.0.10 43 | hot-code-push@1.0.4 44 | html-tools@1.0.11 45 | htmljs@1.0.11 46 | http@1.1.8 47 | id-map@1.0.9 48 | insecure@1.0.7 49 | jquery@1.11.10 50 | launch-screen@1.0.12 51 | less@2.5.7 52 | livedata@1.0.18 53 | localstorage@1.0.12 54 | logging@1.1.17 55 | meteor@1.6.1 56 | meteor-base@1.0.4 57 | minifier-css@1.2.16 58 | minifier-js@1.2.17 59 | minimongo@1.0.20 60 | mobile-experience@1.0.4 61 | mobile-status-bar@1.0.14 62 | modules@0.7.9 63 | modules-runtime@0.7.9 64 | mongo@1.1.15 65 | mongo-id@1.0.6 66 | npm-mongo@2.2.16_1 67 | observe-sequence@1.0.15 68 | ordered-dict@1.0.9 69 | promise@0.8.8 70 | random@1.0.10 71 | reactive-var@1.0.11 72 | reload@1.1.11 73 | retry@1.0.9 74 | routepolicy@1.0.12 75 | shell-server@0.2.2 76 | spacebars@1.0.13 77 | spacebars-compiler@1.1.0 78 | standard-minifier-css@1.3.3 79 | standard-minifier-js@1.2.2 80 | standard-minifiers@1.0.6 81 | templating@1.3.0 82 | templating-compiler@1.3.0 83 | templating-runtime@1.3.0 84 | templating-tools@1.1.0 85 | tracker@1.1.2 86 | ui@1.0.12 87 | underscore@1.0.10 88 | url@1.0.11 89 | webapp@1.3.13 90 | webapp-hashing@1.0.9 91 | -------------------------------------------------------------------------------- /contracts/StateMachine.sol: -------------------------------------------------------------------------------- 1 | contract StateMachine { 2 | enum Stages { 3 | AcceptingBlindedBids, 4 | RevealBids, 5 | AnotherStage, 6 | AreWeDoneYet, 7 | Finished 8 | } 9 | 10 | // This is the current stage. 11 | Stages public stage = Stages.AcceptingBlindedBids; 12 | 13 | uint public creationTime = now; 14 | 15 | modifier atStage(Stages _stage) { 16 | if (stage != _stage) throw; 17 | _; 18 | } 19 | 20 | function nextStage() internal { 21 | stage = Stages(uint(stage) + 1); 22 | } 23 | 24 | // Perform timed transitions. Be sure to mention 25 | // this modifier first, otherwise the guards 26 | // will not take the new stage into account. 27 | modifier timedTransitions() { 28 | if (stage == Stages.AcceptingBlindedBids && 29 | now >= creationTime + 10 days) 30 | nextStage(); 31 | if (stage == Stages.RevealBids && 32 | now >= creationTime + 12 days) 33 | nextStage(); 34 | // The other stages transition by transaction 35 | _; 36 | } 37 | 38 | // Order of the modifiers matters here! 39 | function bid() 40 | timedTransitions 41 | atStage(Stages.AcceptingBlindedBids) { 42 | // We will not implement that here 43 | } 44 | 45 | function reveal() 46 | timedTransitions 47 | atStage(Stages.RevealBids) { 48 | } 49 | 50 | // This modifier goes to the next stage 51 | // after the function is done. 52 | // If you use `return` in the function, 53 | // `nextStage` will not be called 54 | // automatically. 55 | modifier transitionNext() { 56 | _; 57 | nextStage(); 58 | } 59 | 60 | function g() 61 | timedTransitions 62 | atStage(Stages.AnotherStage) 63 | transitionNext { 64 | // If you want to use `return` here, 65 | // you have to call `nextStage()` manually. 66 | } 67 | 68 | function h() 69 | timedTransitions 70 | atStage(Stages.AreWeDoneYet) 71 | transitionNext { 72 | } 73 | 74 | function i() 75 | timedTransitions 76 | atStage(Stages.Finished) { 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /slides/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 3 | } 4 | 5 | h1, h2, h3 { 6 | font-weight: 500; 7 | margin-bottom: 0; 8 | color: #dadada; 9 | } 10 | 11 | .remark-slide-content h1 { 12 | font-size: 3.2em; 13 | } 14 | 15 | .remark-slide-content h2 { 16 | font-size: 2.2em; 17 | } 18 | 19 | .remark-slide-content h3 { 20 | font-size: 1.8em; 21 | } 22 | 23 | .remark-slide-content { 24 | background: #272822; 25 | color: #f3f3f3; 26 | } 27 | 28 | .remark-slide-content li { 29 | font-size: 1.4em; 30 | margin: 14px 0; 31 | } 32 | 33 | .remark-slide-content li li{ 34 | font-size: 1em; 35 | } 36 | 37 | .footnote { 38 | position: absolute; 39 | bottom: 3em; 40 | } 41 | 42 | li p { 43 | line-height: 1.25em; 44 | } 45 | 46 | .red { 47 | color: #fa0000; 48 | } 49 | 50 | .large { 51 | font-size: 2em; 52 | } 53 | 54 | a, a>code { 55 | color: rgb(249, 38, 114); 56 | text-decoration: none; 57 | } 58 | 59 | code { 60 | background: none repeat scroll 0 0 #272822; 61 | border: 1px solid #DEDEDE; 62 | border-radius: 3px; 63 | padding: 0 0.2em; 64 | } 65 | 66 | .remark-code, .remark-inline-code { 67 | font-family: "Bitstream Vera Sans Mono", "Courier", monospace; 68 | } 69 | 70 | .remark-code-line-highlighted { 71 | background-color: #373832; 72 | } 73 | 74 | .pull-left { 75 | float: left; 76 | width: 47%; 77 | } 78 | 79 | .pull-right { 80 | float: right; 81 | width: 47%; 82 | } 83 | 84 | .pull-right~p { 85 | clear: both; 86 | } 87 | 88 | #slideshow .slide .content code { 89 | font-size: 0.8em; 90 | } 91 | 92 | #slideshow .slide .content pre code { 93 | font-size: 0.9em; 94 | padding: 15px; 95 | } 96 | 97 | .main-title, .title { 98 | background: #272822; 99 | color: #777872; 100 | text-shadow: 0 0 20px #333; 101 | } 102 | 103 | .title h1, .title h2, .main-title h1, .main-title h2 { 104 | color: #f3f3f3; 105 | line-height: 0.8em; 106 | } 107 | 108 | .code{ 109 | 110 | } 111 | 112 | /* Custom */ 113 | 114 | .remark-code { 115 | display: block; 116 | padding: 0.5em; 117 | } 118 | -------------------------------------------------------------------------------- /contracts/interitance-example.sol: -------------------------------------------------------------------------------- 1 | contract owned { 2 | function owned() { owner = msg.sender; } 3 | address owner; 4 | } 5 | 6 | 7 | // Use "is" to derive from another contract. Derived 8 | // contracts can access all non-private members including 9 | // internal functions and state variables. These cannot be 10 | // accessed externally via `this`, though. 11 | contract mortal is owned { 12 | function kill() { 13 | if (msg.sender == owner) selfdestruct(owner); 14 | } 15 | } 16 | 17 | 18 | // These abstract contracts are only provided to make the 19 | // interface known to the compiler. Note the function 20 | // without body. If a contract does not implement all 21 | // functions it can only be used as an interface. 22 | contract Config { 23 | function lookup(uint id) returns (address adr); 24 | } 25 | 26 | 27 | contract NameReg { 28 | function register(bytes32 name); 29 | function unregister(); 30 | } 31 | 32 | 33 | // Multiple inheritance is possible. Note that "owned" is 34 | // also a base class of "mortal", yet there is only a single 35 | // instance of "owned" (as for virtual inheritance in C++). 36 | contract named is owned, mortal { 37 | function named(bytes32 name) { 38 | Config config = Config(0xd5f9d8d94886e70b06e474c3fb14fd43e2f23970); 39 | NameReg(config.lookup(1)).register(name); 40 | } 41 | 42 | // Functions can be overridden, both local and 43 | // message-based function calls take these overrides 44 | // into account. 45 | function kill() { 46 | if (msg.sender == owner) { 47 | Config config = Config(0xd5f9d8d94886e70b06e474c3fb14fd43e2f23970); 48 | NameReg(config.lookup(1)).unregister(); 49 | // It is still possible to call a specific 50 | // overridden function. 51 | mortal.kill(); 52 | } 53 | } 54 | } 55 | 56 | 57 | // If a constructor takes an argument, it needs to be 58 | // provided in the header (or modifier-invocation-style at 59 | // the constructor of the derived contract (see below)). 60 | contract PriceFeed is owned, mortal, named("GoldFeed") { 61 | function updateInfo(uint newInfo) { 62 | if (msg.sender == owner) info = newInfo; 63 | } 64 | 65 | function get() constant returns(uint r) { return info; } 66 | 67 | uint info; 68 | } 69 | -------------------------------------------------------------------------------- /slides/5_Solidity_Patterns.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | # Solidity - Patterns 3 | 4 | --- 5 | ## Withdrawal from contracts 6 | withdraw-contract.sol 7 | 8 | Let users withdraw themselves (rather than sending fund directly) 9 | 10 | ```Javascript 11 | contract WithdrawalContract { 12 | ... 13 | 14 | function withdraw() returns (bool) { 15 | uint amount = pendingWithdrawals[msg.sender]; 16 | // Remember to zero the pending refund before 17 | // sending to prevent re-entrancy attacks 18 | pendingWithdrawals[msg.sender] = 0; 19 | if (msg.sender.send(amount)) { 20 | return true; 21 | } 22 | else { 23 | pendingWithdrawals[msg.sender] = amount; 24 | return false; 25 | } 26 | } 27 | } 28 | ``` 29 | 30 | --- 31 | ## Restricting access 32 | You can make it a bit harder by using encryption, but if your contract is supposed to read the data, so will everyone else. 33 | 34 | access-restriction.sol 35 | 36 | --- 37 | ## State machine 38 | state-machine.sol 39 | 40 | ```Javascript 41 | contract StateMachine { 42 | enum Stages { 43 | AcceptingBlindedBids, 44 | RevealBids, 45 | AnotherStage, 46 | AreWeDoneYet, 47 | Finished 48 | } 49 | 50 | Stages public stage = Stages.AcceptingBlindedBids; 51 | 52 | modifier atStage(Stages _stage) { 53 | if (stage != _stage) throw; 54 | _; 55 | } 56 | 57 | function bid() atStage(Stages.AcceptingBlindedBids) { 58 | //To implement 59 | } 60 | 61 | function reveal() atStage(Stages.RevealBids) { 62 | //To implement 63 | } 64 | } 65 | ``` 66 | 67 | --- 68 | ## Checks-Effects-Interactions pattern 69 | 70 | ```Javascript 71 | function auctionEnd() { 72 | // 1. checking conditions 73 | // 2. performing actions (potentially changing conditions) 74 | // 3. interacting with other contracts 75 | 76 | // 1. Conditions 77 | if (now <= auctionStart + biddingTime) 78 | throw; // auction did not yet end 79 | if (ended) 80 | throw; // this function has already been called 81 | 82 | // 2. Effects 83 | ended = true; 84 | AuctionEnded(highestBidder, highestBid); 85 | 86 | // 3. Interaction 87 | if (!beneficiary.send(highestBid)) 88 | throw; 89 | } 90 | ``` 91 | -------------------------------------------------------------------------------- /dapp_example/myDapp2/client/main.js: -------------------------------------------------------------------------------- 1 | import { Template } from 'meteor/templating'; 2 | import { ReactiveVar } from 'meteor/reactive-var'; 3 | _ = lodash; 4 | 5 | import './main.html'; 6 | 7 | // Template - blockInfo 8 | Template.blockInfo.onCreated(function blockInfoOnCreated(){ 9 | EthBlocks.init(); 10 | }); 11 | 12 | Template.blockInfo.helpers({ 13 | currentBlock(){ 14 | return EthBlocks.latest.number; 15 | }, 16 | }); 17 | 18 | // Template - OneValue 19 | Template.oneValue.onCreated(function oneValueOnCreated(){ 20 | var abi = [{"constant":true,"inputs":[],"name":"getValue","outputs":[{"name":"result","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"v","type":"uint256"}],"name":"setValue","outputs":[],"type":"function"},{"inputs":[{"name":"initValue","type":"uint256"}],"type":"constructor"}];; 21 | var OneValueContract = web3.eth.contract(abi); 22 | this.contractAddress = '0xe07438274839E9793baEAaa757F695CfED4A9e26'; 23 | var oneValue = this.oneValue = OneValueContract.at(this.contractAddress); 24 | var currentValue = this.currentValue = new ReactiveVar(0); 25 | var message = this.message = new ReactiveVar(""); 26 | setInterval(function(){ 27 | oneValue.getValue(function(err, res){ 28 | if(!_.isEqual(res.toNumber(), currentValue.get())){ 29 | currentValue.set(res.toNumber()); 30 | message.set("Update value to: " + res.toNumber()); 31 | } 32 | }); 33 | }, 1000); 34 | 35 | }); 36 | 37 | Template.oneValue.helpers({ 38 | oneValueAddress(){ 39 | return Template.instance().contractAddress; 40 | }, 41 | currentValue(){ 42 | return Template.instance().currentValue.get(); 43 | }, 44 | getMessage(){ 45 | return Template.instance().message.get(); 46 | } 47 | }); 48 | 49 | Template.oneValue.events({ 50 | 'click button'(event, instance) { 51 | // increment the counter when button is clicked 52 | //instance.counter.set(instance.counter.get() + 1); 53 | var newValue = $('#new-value').val(); 54 | var oneValue = Template.instance().oneValue; 55 | var message = Template.instance().message; 56 | oneValue.setValue.sendTransaction(_.toNumber(newValue), function(err, res){ 57 | message.set("Transaction hash: " + res); 58 | }); 59 | }, 60 | }); 61 | -------------------------------------------------------------------------------- /contracts/AccessRestriction.sol: -------------------------------------------------------------------------------- 1 | contract AccessRestriction { 2 | // These will be assigned at the construction 3 | // phase, where `msg.sender` is the account 4 | // creating this contract. 5 | address public owner = msg.sender; 6 | uint public creationTime = now; 7 | 8 | // Modifiers can be used to change 9 | // the body of a function. 10 | // If this modifier is used, it will 11 | // prepend a check that only passes 12 | // if the function is called from 13 | // a certain address. 14 | modifier onlyBy(address _account) 15 | { 16 | if (msg.sender != _account) 17 | throw; 18 | // Do not forget the "_"! It will 19 | // be replaced by the actual function 20 | // body when the modifier is invoked. 21 | _; 22 | } 23 | 24 | /// Make `_newOwner` the new owner of this 25 | /// contract. 26 | function changeOwner(address _newOwner) 27 | onlyBy(owner) 28 | { 29 | owner = _newOwner; 30 | } 31 | 32 | modifier onlyAfter(uint _time) { 33 | if (now < _time) throw; 34 | _; 35 | } 36 | 37 | /// Erase ownership information. 38 | /// May only be called 6 weeks after 39 | /// the contract has been created. 40 | function disown() 41 | onlyBy(owner) 42 | onlyAfter(creationTime + 6 weeks) 43 | { 44 | delete owner; 45 | } 46 | 47 | // This modifier requires a certain 48 | // fee being associated with a function call. 49 | // If the caller sent too much, he or she is 50 | // refunded, but only after the function body. 51 | // This is dangerous, because if the function 52 | // uses `return` explicitly, this will not be 53 | // done! This behavior will be fixed in Version 0.4.0. 54 | modifier costs(uint _amount) { 55 | if (msg.value < _amount) 56 | throw; 57 | _; 58 | if (msg.value > _amount) 59 | msg.sender.send(msg.value - _amount); 60 | } 61 | 62 | function forceOwnerChange(address _newOwner) 63 | costs(200 ether) 64 | { 65 | owner = _newOwner; 66 | // just some example condition 67 | if (uint(owner) & 0 == 1) 68 | // in this case, overpaid fees will not 69 | // be refunded 70 | return; 71 | // otherwise, refund overpaid fees 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /contracts/remote-purchase.sol: -------------------------------------------------------------------------------- 1 | contract Purchase { 2 | uint public value; 3 | address public seller; 4 | address public buyer; 5 | enum State { Created, Locked, Inactive } 6 | State public state; 7 | 8 | function Purchase() { 9 | seller = msg.sender; 10 | value = msg.value / 2; 11 | if (2 * value != msg.value) throw; 12 | } 13 | 14 | modifier require(bool _condition) { 15 | if (!_condition) throw; 16 | _; 17 | } 18 | 19 | modifier onlyBuyer() { 20 | if (msg.sender != buyer) throw; 21 | _; 22 | } 23 | 24 | modifier onlySeller() { 25 | if (msg.sender != seller) throw; 26 | _; 27 | } 28 | 29 | modifier inState(State _state) { 30 | if (state != _state) throw; 31 | _; 32 | } 33 | 34 | event aborted(); 35 | event purchaseConfirmed(); 36 | event itemReceived(); 37 | 38 | /// Abort the purchase and reclaim the ether. 39 | /// Can only be called by the seller before 40 | /// the contract is locked. 41 | function abort() 42 | onlySeller 43 | inState(State.Created) 44 | { 45 | aborted(); 46 | state = State.Inactive; 47 | if (!seller.send(this.balance)) 48 | throw; 49 | } 50 | 51 | /// Confirm the purchase as buyer. 52 | /// Transaction has to include `2 * value` ether. 53 | /// The ether will be locked until confirmReceived 54 | /// is called. 55 | function confirmPurchase() 56 | inState(State.Created) 57 | require(msg.value == 2 * value) 58 | { 59 | purchaseConfirmed(); 60 | buyer = msg.sender; 61 | state = State.Locked; 62 | } 63 | 64 | /// Confirm that you (the buyer) received the item. 65 | /// This will release the locked ether. 66 | function confirmReceived() 67 | onlyBuyer 68 | inState(State.Locked) 69 | { 70 | itemReceived(); 71 | // It is important to change the state first because 72 | // otherwise, the contracts called using `send` below 73 | // can call in again here. 74 | state = State.Inactive; 75 | // This actually allows both the buyer and the seller to 76 | // block the refund. 77 | if (!buyer.send(value) || !seller.send(this.balance)) 78 | throw; 79 | } 80 | 81 | function() { 82 | throw; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /contracts/build/PriceFeed.bin: -------------------------------------------------------------------------------- 1 | 60606040527f476f6c64466565640000000000000000000000000000000000000000000000005b60005b33600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b73d5f9d8d94886e70b06e474c3fb14fd43e2f2397090508073ffffffffffffffffffffffffffffffffffffffff16630a874df660016000604051602001526040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b15156100f757fe5b60325a03f1151561010457fe5b5050506040518051905073ffffffffffffffffffffffffffffffffffffffff1663e1fa8e84836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808260001916600019168152602001915050600060405180830381600087803b151561018057fe5b60325a03f1151561018d57fe5b5050505b50505b610350806101a36000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063316db7f21461005157806341c0e1b5146100715780636d4ce63c14610083575bfe5b341561005957fe5b61006f60048080359060200190919050506100a9565b005b341561007957fe5b61008161010b565b005b341561008b57fe5b610093610285565b6040518082815260200191505060405180910390f35b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561010757806001819055505b5b50565b6000600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156102815773d5f9d8d94886e70b06e474c3fb14fd43e2f2397090508073ffffffffffffffffffffffffffffffffffffffff16630a874df660016000604051602001526040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b15156101ef57fe5b60325a03f115156101fc57fe5b5050506040518051905073ffffffffffffffffffffffffffffffffffffffff1663e79a198f6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401809050600060405180830381600087803b151561026857fe5b60325a03f1151561027557fe5b505050610280610290565b5b5b50565b600060015490505b90565b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561032157600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b5b5600a165627a7a7230582011b740302371ef0e89ab0bb4a03558ac0954ff017c635c348ca26bcc721615370029 -------------------------------------------------------------------------------- /slides/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | dom-walk@^0.1.0: 6 | version "0.1.1" 7 | resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" 8 | 9 | global@^4.3.1: 10 | version "4.3.1" 11 | resolved "https://registry.yarnpkg.com/global/-/global-4.3.1.tgz#5f757908c7cbabce54f386ae440e11e26b7916df" 12 | dependencies: 13 | min-document "^2.19.0" 14 | process "~0.5.1" 15 | 16 | markdown-to-slides@^1.0.5: 17 | version "1.0.5" 18 | resolved "https://registry.yarnpkg.com/markdown-to-slides/-/markdown-to-slides-1.0.5.tgz#6699bd31a1cf5189ab8e04c2f4dcd83c1ef185f0" 19 | dependencies: 20 | marked "^0.3.2" 21 | marked-to-md "1.0.x" 22 | mustache "2.1.x" 23 | optimist "~0.3.4" 24 | remark "git://github.com/gnab/remark.git#v0.13.0" 25 | 26 | marked-to-md@1.0.x: 27 | version "1.0.1" 28 | resolved "https://registry.yarnpkg.com/marked-to-md/-/marked-to-md-1.0.1.tgz#864cacb02f3f0a92510c53a8d5fa1e14acd09a5f" 29 | 30 | marked@0.3.1: 31 | version "0.3.1" 32 | resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.1.tgz#156a3b803cc54c59290e60354b83baaa7d66c074" 33 | 34 | marked@^0.3.2: 35 | version "0.3.6" 36 | resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.6.tgz#b2c6c618fccece4ef86c4fc6cb8a7cbf5aeda8d7" 37 | 38 | min-document@^2.19.0: 39 | version "2.19.0" 40 | resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" 41 | dependencies: 42 | dom-walk "^0.1.0" 43 | 44 | mustache@2.1.x: 45 | version "2.1.3" 46 | resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.1.3.tgz#25b90b4204a454c898e8bb2e38d26de223abbd56" 47 | 48 | optimist@~0.3.4: 49 | version "0.3.7" 50 | resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.3.7.tgz#c90941ad59e4273328923074d2cf2e7cbc6ec0d9" 51 | dependencies: 52 | wordwrap "~0.0.2" 53 | 54 | process@~0.5.1: 55 | version "0.5.2" 56 | resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" 57 | 58 | "remark@git://github.com/gnab/remark.git#v0.13.0": 59 | version "0.13.0" 60 | resolved "git://github.com/gnab/remark.git#a6fdde973b965c1e1a5e6d93645096f71f96a05b" 61 | dependencies: 62 | marked "0.3.1" 63 | 64 | wordwrap@~0.0.2: 65 | version "0.0.3" 66 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" 67 | -------------------------------------------------------------------------------- /slides/6_Solidity_Testing.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # Solidity testing 4 | 5 | --- 6 | 7 | ## Tools: 8 | 9 | - Testrpc: https://github.com/ethereumjs/testrpc 10 | ```bash 11 | testrpc -p 8600 -a 10 12 | ``` 13 | 14 | - Mocha: https://mochajs.org/ 15 | 16 | --- 17 | ## Mocha 18 | Mocha is a feature-rich JavaScript test framework running on Node.js and in the browser, making asynchronous testing simple and fun. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases. Hosted on GitHub. 19 | 20 | --- 21 | ## Test case example 22 | one-value-tests.js 23 | 24 | ```JavaScript 25 | describe('OneValueContract', function(){ 26 | // 1. Deploy OneValueContract 27 | before(function(done) { 28 | web3.eth.getAccounts(function(error, result){ 29 | //3. Deploy 30 | primaryAddress = result[0]; //Blockchain Admin 31 | oneValue = OneValueContract.new(initValue, {from:primaryAddress, data: bin}, function(error, contract){ 32 | if(error == null && contract.address != null){ 33 | //Mined 34 | done(); 35 | } 36 | }); 37 | }); 38 | }); 39 | 40 | it("initValue should be 123", function(done){ 41 | oneValue.getValue(function(error, result){ 42 | assert.equal(initValue, result); 43 | done(); 44 | }); 45 | }); 46 | }); 47 | 48 | ``` 49 | 50 | --- 51 | ## Run tests 52 | Add test script in package.json 53 | ```Javascript 54 | { 55 | "dependencies": { 56 | "mocha": "2.4.5" 57 | }, 58 | "scripts": { 59 | "test": "find tests -name '*tests.js' -not -path './node_modules/*' | xargs ./node_modules/mocha/bin/_mocha -R spec" 60 | } 61 | } 62 | ``` 63 | 64 | Run: `npm test` 65 | 66 | --- 67 | ## Test with truffle 68 | https://truffle.readthedocs.io/en/latest/getting_started/testing/ 69 | 70 | ```Javascript 71 | contract('MetaCoin', function(accounts) { 72 | it("should put 10000 MetaCoin in the first account", function() { 73 | // Get a reference to the deployed MetaCoin contract, as a JS object. 74 | var meta = MetaCoin.deployed(); 75 | 76 | // Get the MetaCoin balance of the first account and assert that it's 10000. 77 | return meta.getBalance.call(accounts[0]).then(function(balance) { 78 | assert.equal(balance.valueOf(), 10000, "10000 wasn't in the first account"); 79 | }); 80 | }); 81 | }); 82 | ``` 83 | 84 | Run: `truffle test` 85 | -------------------------------------------------------------------------------- /truffle_test/test/metacoin.js: -------------------------------------------------------------------------------- 1 | var MetaCoin = artifacts.require("./MetaCoin.sol"); 2 | 3 | contract('MetaCoin', function(accounts) { 4 | it("should put 10000 MetaCoin in the first account", function() { 5 | return MetaCoin.deployed().then(function(instance) { 6 | return instance.getBalance.call(accounts[0]); 7 | }).then(function(balance) { 8 | assert.equal(balance.valueOf(), 10000, "10000 wasn't in the first account"); 9 | }); 10 | }); 11 | it("should call a function that depends on a linked library", function() { 12 | var meta; 13 | var metaCoinBalance; 14 | var metaCoinEthBalance; 15 | 16 | return MetaCoin.deployed().then(function(instance) { 17 | meta = instance; 18 | return meta.getBalance.call(accounts[0]); 19 | }).then(function(outCoinBalance) { 20 | metaCoinBalance = outCoinBalance.toNumber(); 21 | return meta.getBalanceInEth.call(accounts[0]); 22 | }).then(function(outCoinBalanceEth) { 23 | metaCoinEthBalance = outCoinBalanceEth.toNumber(); 24 | }).then(function() { 25 | assert.equal(metaCoinEthBalance, 2 * metaCoinBalance, "Library function returned unexpected function, linkage may be broken"); 26 | }); 27 | }); 28 | it("should send coin correctly", function() { 29 | var meta; 30 | 31 | // Get initial balances of first and second account. 32 | var account_one = accounts[0]; 33 | var account_two = accounts[1]; 34 | 35 | var account_one_starting_balance; 36 | var account_two_starting_balance; 37 | var account_one_ending_balance; 38 | var account_two_ending_balance; 39 | 40 | var amount = 10; 41 | 42 | return MetaCoin.deployed().then(function(instance) { 43 | meta = instance; 44 | return meta.getBalance.call(account_one); 45 | }).then(function(balance) { 46 | account_one_starting_balance = balance.toNumber(); 47 | return meta.getBalance.call(account_two); 48 | }).then(function(balance) { 49 | account_two_starting_balance = balance.toNumber(); 50 | return meta.sendCoin(account_two, amount, {from: account_one}); 51 | }).then(function() { 52 | return meta.getBalance.call(account_one); 53 | }).then(function(balance) { 54 | account_one_ending_balance = balance.toNumber(); 55 | return meta.getBalance.call(account_two); 56 | }).then(function(balance) { 57 | account_two_ending_balance = balance.toNumber(); 58 | 59 | assert.equal(account_one_ending_balance, account_one_starting_balance - amount, "Amount wasn't correctly taken from the sender"); 60 | assert.equal(account_two_ending_balance, account_two_starting_balance + amount, "Amount wasn't correctly sent to the receiver"); 61 | }); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /slides/1_Blockchain_Basics.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # Blockchain Basics 4 | 5 | --- 6 | 7 | ## Blockchain 1.0 - Bitcoin and Alt coins (Dogecoin, Litecoin, etc) 8 | - P2P payment system 9 | 10 | - Blockchain 11 | 12 | - Immutable: create and read. no update and delete. 13 | 14 | - Non-repudiable: digital signatures, sign & verify 15 | 16 | - Fault-tolerant: censorship resistant, partially-connected mesh resilience 17 | 18 | --- 19 | 20 | ## Blockchain 1.1 - Colored Coins, Decoration protocols 21 | - Colored coins – leverage additional 40 bytes scripting size in Bitcoin 22 | 23 | - Mastercoin, Bitshares and Counterparty 24 | 25 | - financial derivatives 26 | 27 | - savings wallets 28 | 29 | - decentralized exchange 30 | 31 | --- 32 | ## Blockchain 2.0 - Ethereum, Tendermint 33 | - General purpose blockchain 34 | 35 | - Ethereum: TCP/IP = Bitcoin: SMTP 36 | 37 | --- 38 | ## Ethereum 39 | - Turing-complete 40 | 41 | - Universal scripting language 42 | 43 | - Mining algorithm - specialized hardware resistant. (Dagger) 44 | 45 | - Fee system 46 | 47 | - GHOST (fast block confirmation time, 3 ~ 30 sec) 48 | 49 | --- 50 | ## Ethereum Virtual Machine vs. Bitcoin Scripting 51 | | Ethereum | Bitcoin | 52 | | -- | -- | 53 | | Turing-completeness | Turing-incomplete - no loop | 54 | | State-awareness | Lack of state - single stage | 55 | | Value-awareness | Value-blindness - all or nothing | 56 | | Blockchain-awareness | Blockchain-blindness - no blockchain reference | 57 | 58 | --- 59 | ## Accounts vs UTXO 60 | - Accounts 61 | 62 | - Large space savings 63 | 64 | - Greater fungibility 65 | 66 | - Simplicity 67 | 68 | - Constant light client reference 69 | 70 | - UTXO 71 | 72 | - Higher degree of privacy 73 | 74 | - Potential scalability paradigms 75 | 76 | --- 77 | ## Why not UTXO - State 78 | - UTXOs are unnecessarily complicated 79 | 80 | - UTXOs are stateless, and so are not well-suited to dapps 81 | 82 | --- 83 | ## Bitcoin Script: pay-to-pubkey-hash 84 | | Stack | Script | Description | 85 | | -- | -- | -- | 86 | | Empty. | ` OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG` |scriptSig and scriptPubKey are combined. | 87 | | ` ` | `OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG` | Constants are added to the stack. | 88 | | ` ` | `OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG`|Top stack item is duplicated. | 89 | | ` ` | ` OP_EQUALVERIFY OP_CHECKSIG` | Top stack item is hashed. | 90 | | ` ` | `OP_EQUALVERIFY OP_CHECKSIG` | Constant added. | 91 | | ` ` | `OP_CHECKSIG` |Equality is checked between the top two stack items. | 92 | | `true` | Empty. | Signature is checked for top two stack items.| 93 | 94 | --- 95 | ## Ethereum Virtual Machine v.s. Bitcoin Scripting (2) 96 | - Bitcoin script is primarily about expressing ownership conditions. 97 | 98 | - Ethereum script is more suited to describing business logic (though it can express ownership conditions too) 99 | -------------------------------------------------------------------------------- /contracts/build/StateMachine.bin: -------------------------------------------------------------------------------- 1 | 60606040526000600060006101000a81548160ff0219169083600481111561002357fe5b021790555042600155341561003457fe5b5b6105e7806100446000396000f30060606040523615610081576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631998aeef14610083578063a475b5dd14610095578063b8c9d365146100a7578063c040e6b8146100b9578063d8270dce146100ed578063e2179b8e14610113578063e5aa3d5814610125575bfe5b341561008b57fe5b610093610137565b005b341561009d57fe5b6100a5610206565b005b34156100af57fe5b6100b76102d5565b005b34156100c157fe5b6100c96103ad565b604051808260048111156100d957fe5b60ff16815260200191505060405180910390f35b34156100f557fe5b6100fd6103c0565b6040518082815260200191505060405180910390f35b341561011b57fe5b6101236103c6565b005b341561012d57fe5b61013561049e565b005b6000600481111561014457fe5b600060009054906101000a900460ff16600481111561015f57fe5b1480156101735750620d2f00600154014210155b156101815761018061056d565b5b6001600481111561018e57fe5b600060009054906101000a900460ff1660048111156101a957fe5b1480156101bd5750620fd200600154014210155b156101cb576101ca61056d565b5b60008060048111156101d957fe5b600060009054906101000a900460ff1660048111156101f457fe5b14151561020057610000565b5b5b505b565b6000600481111561021357fe5b600060009054906101000a900460ff16600481111561022e57fe5b1480156102425750620d2f00600154014210155b156102505761024f61056d565b5b6001600481111561025d57fe5b600060009054906101000a900460ff16600481111561027857fe5b14801561028c5750620fd200600154014210155b1561029a5761029961056d565b5b60018060048111156102a857fe5b600060009054906101000a900460ff1660048111156102c357fe5b1415156102cf57610000565b5b5b505b565b600060048111156102e257fe5b600060009054906101000a900460ff1660048111156102fd57fe5b1480156103115750620d2f00600154014210155b1561031f5761031e61056d565b5b6001600481111561032c57fe5b600060009054906101000a900460ff16600481111561034757fe5b14801561035b5750620fd200600154014210155b156103695761036861056d565b5b600380600481111561037757fe5b600060009054906101000a900460ff16600481111561039257fe5b14151561039e57610000565b5b6103a761056d565b5b5b505b565b600060009054906101000a900460ff1681565b60015481565b600060048111156103d357fe5b600060009054906101000a900460ff1660048111156103ee57fe5b1480156104025750620d2f00600154014210155b156104105761040f61056d565b5b6001600481111561041d57fe5b600060009054906101000a900460ff16600481111561043857fe5b14801561044c5750620fd200600154014210155b1561045a5761045961056d565b5b600280600481111561046857fe5b600060009054906101000a900460ff16600481111561048357fe5b14151561048f57610000565b5b61049861056d565b5b5b505b565b600060048111156104ab57fe5b600060009054906101000a900460ff1660048111156104c657fe5b1480156104da5750620d2f00600154014210155b156104e8576104e761056d565b5b600160048111156104f557fe5b600060009054906101000a900460ff16600481111561051057fe5b1480156105245750620fd200600154014210155b156105325761053161056d565b5b600480600481111561054057fe5b600060009054906101000a900460ff16600481111561055b57fe5b14151561056757610000565b5b5b505b565b6001600060009054906101000a900460ff16600481111561058a57fe5b01600481111561059657fe5b600060006101000a81548160ff021916908360048111156105b357fe5b02179055505b5600a165627a7a723058200f1afd541c5e6b4fea80f12bd340858c4cedfa92dc803d126ead9f3c9ec6ff590029 -------------------------------------------------------------------------------- /contracts/build/SimpleAuction.bin: -------------------------------------------------------------------------------- 1 | 6060604052341561000c57fe5b6040516040806106aa833981016040528080519060200190919080519060200190919050505b80600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555042600181905550816002819055505b50505b610616806100946000396000f3006060604052361561008c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631998aeef146100a15780632a24f46c146100b357806338af3eed146100c55780633ccfd60b146101175780634f245ef71461012957806391f901571461014f578063d074a38d146101a1578063d57bde79146101c7575b341561009457fe5b61009f5b610000565b565b005b34156100a957fe5b6100b16101ed565b005b34156100bb57fe5b6100c361037a565b005b34156100cd57fe5b6100d56104bc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561011f57fe5b6101276104e2565b005b341561013157fe5b6101396105b2565b6040518082815260200191505060405180910390f35b341561015757fe5b61015f6105b8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101a957fe5b6101b16105de565b6040518082815260200191505060405180910390f35b34156101cf57fe5b6101d76105e4565b6040518082815260200191505060405180910390f35b6002546001540142111561020057610000565b6004543411151561021057610000565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415156102c45760045460056000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505b33600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550346004819055507ff4757a49b326036464bec6fe419a4ae38c8a02ce3e68bf0809674f6aab8ad3003334604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a15b565b600254600154014211151561038e57610000565b600660009054906101000a900460ff16156103a857610000565b6001600660006101000a81548160ff0219169083151502179055507fdaec4582d5d9595688c8c98545fdd1c696d41c6aeaeb636737e84ed2f5c00eda600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600454604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a1600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc6004549081150290604051809050600060405180830381858888f1935050505015156104b957610000565b5b565b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055503373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051809050600060405180830381858888f1935050505015156105ae57610000565b5b50565b60015481565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60025481565b600454815600a165627a7a72305820e1260d03188896b26a39fa796a88cc438744c944427a6c185390e2243b424e750029 -------------------------------------------------------------------------------- /contracts/build/Purchase.bin: -------------------------------------------------------------------------------- 1 | 6060604052341561000c57fe5b5b33600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060023481151561005a57fe5b046000819055503460005460020214151561007457610000565b5b5b61066f806100856000396000f30060606040523615610081576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806308551a531461009657806335a063b4146100e85780633fa4f245146100fa5780637150d8ae1461012057806373fac6f014610172578063c19d93fb14610184578063d6960697146101b8575b341561008957fe5b6100945b610000565b565b005b341561009e57fe5b6100a66101ca565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156100f057fe5b6100f86101f0565b005b341561010257fe5b61010a610356565b6040518082815260200191505060405180910390f35b341561012857fe5b61013061035c565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561017a57fe5b610182610382565b005b341561018c57fe5b61019461054c565b604051808260028111156101a457fe5b60ff16815260200191505060405180910390f35b34156101c057fe5b6101c861055f565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561024c57610000565b600080600281111561025a57fe5b600260149054906101000a900460ff16600281111561027557fe5b14151561028157610000565b7f80b62b7017bb13cf105e22749ee2a06a417ffba8c7f57b665057e0f3c2e925d960405180905060405180910390a16002600260146101000a81548160ff021916908360028111156102cf57fe5b0217905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051809050600060405180830381858888f19350505050151561035057610000565b5b5b505b565b60005481565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156103de57610000565b60018060028111156103ec57fe5b600260149054906101000a900460ff16600281111561040757fe5b14151561041357610000565b7f64ea507aa320f07ae13c28b5e9bf6b4833ab544315f5f2aa67308e21c252d47d60405180905060405180910390a16002600260146101000a81548160ff0219169083600281111561046157fe5b0217905550600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc6000549081150290604051809050600060405180830381858888f19350505050158061053c5750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051809050600060405180830381858888f19350505050155b1561054657610000565b5b5b505b565b600260149054906101000a900460ff1681565b600080600281111561056d57fe5b600260149054906101000a900460ff16600281111561058857fe5b14151561059457610000565b60005460020234148015156105a857610000565b7f764326667cab2f2f13cad5f7b7665c704653bd1acc250dcb7b422bce726896b460405180905060405180910390a133600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600260146101000a81548160ff0219169083600281111561063757fe5b02179055505b5b505b505600a165627a7a72305820bbd82f72fd90ed3d00e57f28362b391ff6241d37eb8322801d75c4fad70ea3de0029 -------------------------------------------------------------------------------- /LECTURES.MD: -------------------------------------------------------------------------------- 1 | 2 | ## 政大 (03/23/2017) 3 | - [0. Agenda](https://amisamity.github.io/contract-training/slides/0_Agenda_03232017.md.html) 4 | - [1. Ethereum Development Environment and Tools](https://amisamity.github.io/contract-training/slides/2_Ethereum_Development_Environment_and_Tools_03202017.md.html) 5 | - [2. Smart Contract and Solidity](https://amisamity.github.io/contract-training/slides/3_Smart_Contract_Solidity_Quick_Start_03232017.md.html) 6 | - [3. Ðapp Example - FlightDelay](https://amisamity.github.io/contract-training/slides/8_Insurance_Examples.md.html) 7 | - [4. Web3 JavaScript Ðapp API](https://amisamity.github.io/contract-training/slides/10_Web3_JavaScript.md.html) 8 | - [5. Ðapps Development](https://amisamity.github.io/contract-training/slides/9_Dapps_Development.md.html) 9 | - [6. References](https://amisamity.github.io/contract-training/slides/7_References.md.html) 10 | 11 | ## 台科大 (03/17/2017) 12 | - [0. Agenda](https://amisamity.github.io/contract-training/slides/0_Agenda_03172017.md.html) 13 | - [1. Ethereum Development Environment and Tools](https://amisamity.github.io/contract-training/slides/2_Ethereum_Development_Environment_and_Tools.md.html) 14 | - [2. Ðapp Example - FlightDelay](https://amisamity.github.io/contract-training/slides/8_Insurance_Examples.md.html) 15 | - [3. Web3 JavaScript Ðapp API](https://amisamity.github.io/contract-training/slides/10_Web3_JavaScript.md.html) 16 | - [4. Ðapps Development](https://amisamity.github.io/contract-training/slides/9_Dapps_Development.md.html) 17 | - [5. References](https://amisamity.github.io/contract-training/slides/7_References.md.html) 18 | 19 | ## 保發中心 (03/10/2017) 20 | - [0. Agenda](https://amisamity.github.io/contract-training/slides/0_Agenda_03102017.md.html) 21 | - [1. Ethereum Development Environment and Tools](https://amisamity.github.io/contract-training/slides/2_Ethereum_Development_Environment_and_Tools.md.html) 22 | - [2. Smart Contract and Solidity](https://amisamity.github.io/contract-training/slides/3_Smart_Contract_Solidity_Quick_Start.md.html) 23 | - [3. Insurance Example](https://amisamity.github.io/contract-training/slides/8_Insurance_Examples.md.html) 24 | - [4. Web3 JavaScript Ðapp API](https://amisamity.github.io/contract-training/slides/10_Web3_JavaScript.md.html) 25 | - [5. Ðapps Development](https://amisamity.github.io/contract-training/slides/9_Dapps_Development.md.html) 26 | - [6. Solidity Security](https://amisamity.github.io/contract-training/slides/4_Solidity_Security.md.html) 27 | - [7. Solidity Patterns](https://amisamity.github.io/contract-training/slides/5_Solidity_Patterns.md.html) 28 | - [8. Solidity Testing](https://amisamity.github.io/contract-training/slides/6_Solidity_Testing.md.html) 29 | - [9. References](https://amisamity.github.io/contract-training/slides/7_References.md.html) 30 | 31 | ## 政大 (11/14/2016) 32 | - [0. Agenda](https://amisamity.github.io/contract-training/slides/0_Agenda_1114.md.html) 33 | - [1. Ethereum Development Environment and Tools](https://amisamity.github.io/contract-training/slides/2_Ethereum_Development_Environment_and_Tools.md.html) 34 | - [2. Smart Contract and Solidity](https://amisamity.github.io/contract-training/slides/3_Smart_Contract_Solidity.md.html) 35 | - [3. Solidity Security](https://amisamity.github.io/contract-training/slides/4_Solidity_Security.md.html) 36 | - [4. Solidity Patterns](https://amisamity.github.io/contract-training/slides/5_Solidity_Patterns.md.html) 37 | - [5. Solidity Testing](https://amisamity.github.io/contract-training/slides/6_Solidity_Testing.md.html) 38 | - [6. References](https://amisamity.github.io/contract-training/slides/7_References.md.html) 39 | - [7. Devcon2](https://goo.gl/PEj4Ka) 40 | 41 | ## 台科大 (09/06/2016) 42 | - [0. Agenda](https://amisamity.github.io/contract-training/slides/0_Agenda_0906.md.html) 43 | - [1. Ethereum Development Environment and Tools](https://amisamity.github.io/contract-training/slides/2_Ethereum_Development_Environment_and_Tools.md.html) 44 | - [2. Smart Contract and Solidity](https://amisamity.github.io/contract-training/slides/3_Smart_Contract_Solidity.md.html) 45 | -------------------------------------------------------------------------------- /slides/4_Solidity_Security.md: -------------------------------------------------------------------------------- 1 | class: middle, center 2 | 3 | # Solidity Security 4 | 5 | --- 6 | ## Private information and randomness 7 | 8 | - Everything you use in a smart contract is publicly visible, even local variables and state variables marked `private`. 9 | 10 | - Using random numbers in smart contracts is quite tricky if you do not want miners to be able to cheat. 11 | Reference: https://github.com/randao/randao 12 | 13 | --- 14 | ## Re-entrancy 15 | 16 | Any interaction from a contract (A) with another contract (B) and any transfer of Ether hands over control to that contract (B). This makes it possible for B to call back into A before this interaction is completed. 17 | 18 | ```Javascript 19 | // THIS CONTRACT CONTAINS A BUG - DO NOT USE 20 | contract Fund { 21 | /// Mapping of ether shares of the contract. 22 | mapping(address => uint) shares; 23 | /// Withdraw your share. 24 | function withdraw() { 25 | if (msg.sender.send(shares[msg.sender])) 26 | shares[msg.sender] = 0; 27 | } 28 | } 29 | ``` 30 | 31 | --- 32 | ## Checks-Effects-Interactions pattern 33 | 34 | ```Javascript 35 | function auctionEnd() { 36 | // 1. checking conditions 37 | // 2. performing actions (potentially changing conditions) 38 | // 3. interacting with other contracts 39 | 40 | // 1. Conditions 41 | if (now <= auctionStart + biddingTime) 42 | throw; // auction did not yet end 43 | if (ended) 44 | throw; // this function has already been called 45 | 46 | // 2. Effects 47 | ended = true; 48 | AuctionEnded(highestBidder, highestBid); 49 | 50 | // 3. Interaction 51 | if (!beneficiary.send(highestBid)) 52 | throw; 53 | } 54 | ``` 55 | 56 | --- 57 | ## Gas limit and loops 58 | - Be careful for loops that do not have a fixed number of iterations. 59 | 60 | - Most fallback function (called by `send`) rely on the "gas stipend" (2300 gas) 61 | 62 | - There is a way to forward more gas to the receiving contract using addr.call.value(x)(). Be careful for malicious actors. 63 | 64 | - If you are using address.send. 65 | 66 | - If the recipient is a contact, you will call its fallback function 67 | 68 | - Sending Ether can fail due to the call depth going above 1024. 69 | 70 | --- 71 | ## tx.origin 72 | Never use tx.origin for authorization. Let’s say you have a wallet contract like this: 73 | ``` Javascript 74 | contract TxUserWallet { 75 | address owner; 76 | 77 | function TxUserWallet() { 78 | owner = msg.sender; 79 | } 80 | 81 | function transfer(address dest, uint amount) { 82 | if (tx.origin != owner) { throw; } 83 | if (!dest.call.value(amount)()) throw; 84 | } 85 | } 86 | ``` 87 | --- 88 | ## tx.origin 89 | Now someone tricks you into sending ether to the address of this attack wallet: 90 | ```Javascript 91 | contract TxAttackWallet { 92 | address owner; 93 | 94 | function TxAttackWallet() { 95 | owner = msg.sender; 96 | } 97 | 98 | function() { 99 | TxUserWallet(msg.sender).transfer(owner, msg.sender.balance); 100 | } 101 | } 102 | ``` 103 | 104 | --- 105 | ## Recommendations 106 | 107 | - Restrict the Amount of Ether 108 | 109 | - Keep it Small and Modular 110 | 111 | - Use the Checks-Effects-Interactions Pattern 112 | 113 | - Include a Fail-Safe Mode 114 | 115 | --- 116 | ## DAO attack 117 | 118 | Fix: https://github.com/slockit/DAO/pull/242 119 | 120 | ManagedAccount.sol 121 | ```Javascript 122 | function payOut(address _recipient, uint _amount) returns (bool) { 123 | if (msg.sender != owner || msg.value > 0 || (payOwnerOnly && _recipient != owner)) 124 | throw; 125 | if (_recipient.call.value(_amount)()) { 126 | PayOut(_recipient, _amount); 127 | return true; 128 | } else { 129 | return false; 130 | } 131 | } 132 | ``` 133 | 134 | --- 135 | ## DAO attack 136 | DAO.sol 137 | 138 | ```Javascript 139 | function withdrawRewardFor(address _account) noEther internal returns (bool _success) { 140 | if ((balanceOf(_account) * rewardAccount.accumulatedInput()) / totalSupply < paidOut[_account]) 141 | throw; 142 | 143 | uint reward = 144 | (balanceOf(_account) * rewardAccount.accumulatedInput()) / totalSupply - paidOut[_account]; 145 | 146 | reward = rewardAccount.balance < reward ? rewardAccount.balance : reward; 147 | 148 | + paidOut[_account] += reward; 149 | 150 | if (!rewardAccount.payOut(_account, reward)) 151 | throw; 152 | 153 | - paidOut[_account] += reward; 154 | 155 | return true; 156 | } 157 | ``` 158 | -------------------------------------------------------------------------------- /contracts/SimpleAuction.sol: -------------------------------------------------------------------------------- 1 | contract SimpleAuction { 2 | // Parameters of the auction. Times are either 3 | // absolute unix timestamps (seconds since 1970-01-01) 4 | // or time periods in seconds. 5 | address public beneficiary; 6 | uint public auctionStart; 7 | uint public biddingTime; 8 | 9 | // Current state of the auction. 10 | address public highestBidder; 11 | uint public highestBid; 12 | 13 | // Allowed withdrawals of previous bids 14 | mapping(address => uint) pendingReturns; 15 | 16 | // Set to true at the end, disallows any change 17 | bool ended; 18 | 19 | // Events that will be fired on changes. 20 | event HighestBidIncreased(address bidder, uint amount); 21 | event AuctionEnded(address winner, uint amount); 22 | 23 | // The following is a so-called natspec comment, 24 | // recognizable by the three slashes. 25 | // It will be shown when the user is asked to 26 | // confirm a transaction. 27 | 28 | /// Create a simple auction with `_biddingTime` 29 | /// seconds bidding time on behalf of the 30 | /// beneficiary address `_beneficiary`. 31 | function SimpleAuction( 32 | uint _biddingTime, 33 | address _beneficiary 34 | ) { 35 | beneficiary = _beneficiary; 36 | auctionStart = now; 37 | biddingTime = _biddingTime; 38 | } 39 | 40 | /// Bid on the auction with the value sent 41 | /// together with this transaction. 42 | /// The value will only be refunded if the 43 | /// auction is not won. 44 | function bid() { 45 | // No arguments are necessary, all 46 | // information is already part of 47 | // the transaction. 48 | if (now > auctionStart + biddingTime) { 49 | // Revert the call if the bidding 50 | // period is over. 51 | throw; 52 | } 53 | if (msg.value <= highestBid) { 54 | // If the bid is not higher, send the 55 | // money back. 56 | throw; 57 | } 58 | if (highestBidder != 0) { 59 | // Sending back the money by simply using 60 | // highestBidder.send(highestBid) is a security risk 61 | // because it can be prevented by the caller by e.g. 62 | // raising the call stack to 1023. It is always safer 63 | // to let the recipient withdraw their money themselves. 64 | pendingReturns[highestBidder] += highestBid; 65 | } 66 | highestBidder = msg.sender; 67 | highestBid = msg.value; 68 | HighestBidIncreased(msg.sender, msg.value); 69 | } 70 | 71 | /// Withdraw a bid that was overbid. 72 | function withdraw() { 73 | var amount = pendingReturns[msg.sender]; 74 | // It is important to set this to zero because the recipient 75 | // can call this function again as part of the receiving call 76 | // before `send` returns. 77 | pendingReturns[msg.sender] = 0; 78 | if (!msg.sender.send(amount)) 79 | throw; // If anything fails, this will revert the changes above 80 | } 81 | 82 | /// End the auction and send the highest bid 83 | /// to the beneficiary. 84 | function auctionEnd() { 85 | // It is a good guideline to structure functions that interact 86 | // with other contracts (i.e. they call functions or send Ether) 87 | // into three phases: 88 | // 1. checking conditions 89 | // 2. performing actions (potentially changing conditions) 90 | // 3. interacting with other contracts 91 | // If these phases are mixed up, the other contract could call 92 | // back into the current contract and modify the state or cause 93 | // effects (ether payout) to be perfromed multiple times. 94 | // If functions called internally include interaction with external 95 | // contracts, they also have to be considered interaction with 96 | // external contracts. 97 | 98 | // 1. Conditions 99 | if (now <= auctionStart + biddingTime) 100 | throw; // auction did not yet end 101 | if (ended) 102 | throw; // this function has already been called 103 | 104 | // 2. Effects 105 | ended = true; 106 | AuctionEnded(highestBidder, highestBid); 107 | 108 | // 3. Interaction 109 | if (!beneficiary.send(highestBid)) 110 | throw; 111 | } 112 | 113 | function () { 114 | // This function gets executed if a 115 | // transaction with invalid data is sent to 116 | // the contract or just ether without data. 117 | // We revert the send so that no-one 118 | // accidentally loses money when using the 119 | // contract. 120 | throw; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /contracts/Ballot.sol: -------------------------------------------------------------------------------- 1 | /// @title Voting with delegation. 2 | contract Ballot { 3 | // This declares a new complex type which will 4 | // be used for variables later. 5 | // It will represent a single voter. 6 | struct Voter { 7 | uint weight; // weight is accumulated by delegation 8 | bool voted; // if true, that person already voted 9 | address delegate; // person delegated to 10 | uint vote; // index of the voted proposal 11 | } 12 | 13 | // This is a type for a single proposal. 14 | struct Proposal 15 | { 16 | bytes32 name; // short name (up to 32 bytes) 17 | uint voteCount; // number of accumulated votes 18 | } 19 | 20 | address public chairperson; 21 | 22 | // This declares a state variable that 23 | // stores a `Voter` struct for each possible address. 24 | mapping(address => Voter) public voters; 25 | 26 | // A dynamically-sized array of `Proposal` structs. 27 | Proposal[] public proposals; 28 | 29 | /// Create a new ballot to choose one of `proposalNames`. 30 | function Ballot(bytes32[] proposalNames) { 31 | chairperson = msg.sender; 32 | voters[chairperson].weight = 1; 33 | 34 | // For each of the provided proposal names, 35 | // create a new proposal object and add it 36 | // to the end of the array. 37 | for (uint i = 0; i < proposalNames.length; i++) { 38 | // `Proposal({...})` creates a temporary 39 | // Proposal object and `proposals.push(...)` 40 | // appends it to the end of `proposals`. 41 | proposals.push(Proposal({ 42 | name: proposalNames[i], 43 | voteCount: 0 44 | })); 45 | } 46 | } 47 | 48 | // Give `voter` the right to vote on this ballot. 49 | // May only be called by `chairperson`. 50 | function giveRightToVote(address voter) { 51 | if (msg.sender != chairperson || voters[voter].voted) { 52 | // `throw` terminates and reverts all changes to 53 | // the state and to Ether balances. It is often 54 | // a good idea to use this if functions are 55 | // called incorrectly. But watch out, this 56 | // will also consume all provided gas. 57 | throw; 58 | } 59 | voters[voter].weight = 1; 60 | } 61 | 62 | /// Delegate your vote to the voter `to`. 63 | function delegate(address to) { 64 | // assigns reference 65 | Voter sender = voters[msg.sender]; 66 | if (sender.voted) 67 | throw; 68 | 69 | // Forward the delegation as long as 70 | // `to` also delegated. 71 | // In general, such loops are very dangerous, 72 | // because if they run too long, they might 73 | // need more gas than is available in a block. 74 | // In this case, the delegation will not be executed, 75 | // but in other situations, such loops might 76 | // cause a contract to get "stuck" completely. 77 | while ( 78 | voters[to].delegate != address(0) && 79 | voters[to].delegate != msg.sender 80 | ) { 81 | to = voters[to].delegate; 82 | } 83 | 84 | // We found a loop in the delegation, not allowed. 85 | if (to == msg.sender) { 86 | throw; 87 | } 88 | 89 | // Since `sender` is a reference, this 90 | // modifies `voters[msg.sender].voted` 91 | sender.voted = true; 92 | sender.delegate = to; 93 | Voter delegate = voters[to]; 94 | if (delegate.voted) { 95 | // If the delegate already voted, 96 | // directly add to the number of votes 97 | proposals[delegate.vote].voteCount += sender.weight; 98 | } 99 | else { 100 | // If the delegate did not vote yet, 101 | // add to her weight. 102 | delegate.weight += sender.weight; 103 | } 104 | } 105 | 106 | /// Give your vote (including votes delegated to you) 107 | /// to proposal `proposals[proposal].name`. 108 | function vote(uint proposal) { 109 | Voter sender = voters[msg.sender]; 110 | if (sender.voted) 111 | throw; 112 | sender.voted = true; 113 | sender.vote = proposal; 114 | 115 | // If `proposal` is out of the range of the array, 116 | // this will throw automatically and revert all 117 | // changes. 118 | proposals[proposal].voteCount += sender.weight; 119 | } 120 | 121 | /// @dev Computes the winning proposal taking all 122 | /// previous votes into account. 123 | function winningProposal() constant 124 | returns (uint winningProposal) 125 | { 126 | uint winningVoteCount = 0; 127 | for (uint p = 0; p < proposals.length; p++) { 128 | if (proposals[p].voteCount > winningVoteCount) { 129 | winningVoteCount = proposals[p].voteCount; 130 | winningProposal = p; 131 | } 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /contracts/build/Ballot.bin: -------------------------------------------------------------------------------- 1 | 6060604052341561000c57fe5b604051610ab1380380610ab1833981016040528080518201919050505b600033600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600160016000600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000181905550600090505b815181101561016b57600280548060010182816100f89190610173565b916000526020600020906002020160005b604060405190810160405280868681518110151561012357fe5b906020019060200201516000191681526020016000815250909190915060008201518160000190600019169055602082015181600101555050505b80806001019150506100db565b5b50506101d5565b8154818355818115116101a05760020281600202836000526020600020918201910161019f91906101a5565b5b505050565b6101d291905b808211156101ce57600060008201600090556001820160009055506002016101ab565b5090565b90565b6108cd806101e46000396000f30060606040523615610081576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630121b93f14610083578063013cf08b146100a35780632e4176cf146100e65780635c19a95c14610138578063609ff1bd1461016e5780639e7b8d6114610194578063a3ec138d146101ca575bfe5b341561008b57fe5b6100a16004808035906020019091905050610259565b005b34156100ab57fe5b6100c16004808035906020019091905050610319565b6040518083600019166000191681526020018281526020019250505060405180910390f35b34156100ee57fe5b6100f661034d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561014057fe5b61016c600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610373565b005b341561017657fe5b61017e6106be565b6040518082815260200191505060405180910390f35b341561019c57fe5b6101c8600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610745565b005b34156101d257fe5b6101fe600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610844565b60405180858152602001841515151581526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200194505050505060405180910390f35b6000600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060010160009054906101000a900460ff16156102b857610000565b60018160010160006101000a81548160ff02191690831515021790555081816002018190555080600001546002838154811015156102f257fe5b906000526020600020906002020160005b50600101600082825401925050819055505b5050565b60028181548110151561032857fe5b906000526020600020906002020160005b915090508060000154908060010154905082565b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006000600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002091508160010160009054906101000a900460ff16156103d457610000565b5b600073ffffffffffffffffffffffffffffffffffffffff16600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415801561050257503373ffffffffffffffffffffffffffffffffffffffff16600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b1561057157600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1692506103d5565b3373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156105aa57610000565b60018260010160006101000a81548160ff021916908315150217905550828260010160016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060010160009054906101000a900460ff16156106a15781600001546002826002015481548110151561067a57fe5b906000526020600020906002020160005b50600101600082825401925050819055506106b8565b816000015481600001600082825401925050819055505b5b505050565b60006000600060009150600090505b60028054905081101561073f57816002828154811015156106ea57fe5b906000526020600020906002020160005b506001015411156107315760028181548110151561071557fe5b906000526020600020906002020160005b506001015491508092505b5b80806001019150506106cd565b5b505090565b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415806107ee5750600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160009054906101000a900460ff165b156107f857610000565b6001600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001819055505b50565b60016020528060005260406000206000915090508060000154908060010160009054906101000a900460ff16908060010160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff169080600201549050845600a165627a7a72305820e8c4b61e79292c26738d22f5e6776af18bb3a4fada27400684670263b82f9d650029 -------------------------------------------------------------------------------- /contracts/BlindAuction.sol: -------------------------------------------------------------------------------- 1 | contract BlindAuction { 2 | struct Bid { 3 | bytes32 blindedBid; 4 | uint deposit; 5 | } 6 | 7 | address public beneficiary; 8 | uint public auctionStart; 9 | uint public biddingEnd; 10 | uint public revealEnd; 11 | bool public ended; 12 | 13 | mapping(address => Bid[]) public bids; 14 | 15 | address public highestBidder; 16 | uint public highestBid; 17 | 18 | // Allowed withdrawals of previous bids 19 | mapping(address => uint) pendingReturns; 20 | 21 | event AuctionEnded(address winner, uint highestBid); 22 | 23 | /// Modifiers are a convenient way to validate inputs to 24 | /// functions. `onlyBefore` is applied to `bid` below: 25 | /// The new function body is the modifier's body where 26 | /// `_` is replaced by the old function body. 27 | modifier onlyBefore(uint _time) { if (now >= _time) throw; _; } 28 | modifier onlyAfter(uint _time) { if (now <= _time) throw; _; } 29 | 30 | function BlindAuction( 31 | uint _biddingTime, 32 | uint _revealTime, 33 | address _beneficiary 34 | ) { 35 | beneficiary = _beneficiary; 36 | auctionStart = now; 37 | biddingEnd = now + _biddingTime; 38 | revealEnd = biddingEnd + _revealTime; 39 | } 40 | 41 | /// Place a blinded bid with `_blindedBid` = sha3(value, 42 | /// fake, secret). 43 | /// The sent ether is only refunded if the bid is correctly 44 | /// revealed in the revealing phase. The bid is valid if the 45 | /// ether sent together with the bid is at least "value" and 46 | /// "fake" is not true. Setting "fake" to true and sending 47 | /// not the exact amount are ways to hide the real bid but 48 | /// still make the required deposit. The same address can 49 | /// place multiple bids. 50 | function bid(bytes32 _blindedBid) 51 | onlyBefore(biddingEnd) 52 | { 53 | bids[msg.sender].push(Bid({ 54 | blindedBid: _blindedBid, 55 | deposit: msg.value 56 | })); 57 | } 58 | 59 | /// Reveal your blinded bids. You will get a refund for all 60 | /// correctly blinded invalid bids and for all bids except for 61 | /// the totally highest. 62 | function reveal( 63 | uint[] _values, 64 | bool[] _fake, 65 | bytes32[] _secret 66 | ) 67 | onlyAfter(biddingEnd) 68 | onlyBefore(revealEnd) 69 | { 70 | uint length = bids[msg.sender].length; 71 | if ( 72 | _values.length != length || 73 | _fake.length != length || 74 | _secret.length != length 75 | ) { 76 | throw; 77 | } 78 | 79 | uint refund; 80 | for (uint i = 0; i < length; i++) { 81 | var bid = bids[msg.sender][i]; 82 | var (value, fake, secret) = 83 | (_values[i], _fake[i], _secret[i]); 84 | if (bid.blindedBid != sha3(value, fake, secret)) { 85 | // Bid was not actually revealed. 86 | // Do not refund deposit. 87 | continue; 88 | } 89 | refund += bid.deposit; 90 | if (!fake && bid.deposit >= value) { 91 | if (placeBid(msg.sender, value)) 92 | refund -= value; 93 | } 94 | // Make it impossible for the sender to re-claim 95 | // the same deposit. 96 | bid.blindedBid = 0; 97 | } 98 | if (!msg.sender.send(refund)) 99 | throw; 100 | } 101 | 102 | // This is an "internal" function which means that it 103 | // can only be called from the contract itself (or from 104 | // derived contracts). 105 | function placeBid(address bidder, uint value) internal 106 | returns (bool success) 107 | { 108 | if (value <= highestBid) { 109 | return false; 110 | } 111 | if (highestBidder != 0) { 112 | // Refund the previously highest bidder. 113 | pendingReturns[highestBidder] += highestBid; 114 | } 115 | highestBid = value; 116 | highestBidder = bidder; 117 | return true; 118 | } 119 | 120 | /// Withdraw a bid that was overbid. 121 | function withdraw() { 122 | var amount = pendingReturns[msg.sender]; 123 | // It is important to set this to zero because the recipient 124 | // can call this function again as part of the receiving call 125 | // before `send` returns (see the remark above about 126 | // conditions -> effects -> interaction). 127 | pendingReturns[msg.sender] = 0; 128 | if (!msg.sender.send(amount)) 129 | throw; // If anything fails, this will revert the changes above 130 | } 131 | 132 | /// End the auction and send the highest bid 133 | /// to the beneficiary. 134 | function auctionEnd() 135 | onlyAfter(revealEnd) 136 | { 137 | if (ended) 138 | throw; 139 | AuctionEnded(highestBidder, highestBid); 140 | ended = true; 141 | // We send all the money we have, because some 142 | // of the refunds might have failed. 143 | if (!beneficiary.send(this.balance)) 144 | throw; 145 | } 146 | 147 | function () { 148 | throw; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /slides/10_Web3_JavaScript.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # Web3 JavaScript Ðapp API 4 | 5 | --- 6 | 7 | ## Reference 8 | 9 | https://github.com/ethereum/wiki/wiki/JavaScript-API 10 | 11 | --- 12 | 13 | ## Web3 14 | 15 | - Github: https://github.com/ethereum/web3.js 16 | 17 | - JavaScript library 18 | 19 | - 透過 RPC 與 Ethereum 溝通 20 | 21 | - web3: 一般工具函式 22 | 23 | - web3.eth: Ethereum blockchain 函式 24 | 25 | - web3.net: 網路狀態 26 | 27 | - web3.ssh: Whisper 函式 (略過) 28 | 29 | --- 30 | 31 | ## 安裝 Web3 32 | 33 | - npm: `npm install web3` 34 | 35 | - meteor: `meteor add ethereum:web3` 36 | - Ðapp 開發介紹將使用meteor 37 | 38 | --- 39 | 40 | ## 啟用 RPC 41 | 42 | 選擇其中一種方式: 43 | 44 | - Geth 指令:啟用時帶入下列參數: 45 | 46 | `--rpc --rpccorsdomain "*" --rpcapi "eth,net,web3"` 47 | 48 | - Geth console: 49 | 50 | `admin.startRPC("0.0.0.0", 8545, "*","eth,net,web3")` 51 | 52 | - 直接使用 Mist browser 53 | 54 | Develop -> Toggle Develop Tools -> Mist UI -> `web3.currentProvider` 55 | 56 | - 直接使用 MetaMask 57 | 58 | View -> Developer -> JavaScript Console -> `web3.currentPovider` 59 | 60 | - Web3 library supported RPC APIs: `eth, db, net, personal` 61 | 62 | https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console 63 | 64 | --- 65 | 66 | 67 | ## Web3 連線 68 | 69 | 70 | ```Javascript 71 | if (typeof web3 !== 'undefined') { 72 | web3 = new Web3(web3.currentProvider); 73 | } else { 74 | // set the provider you want from Web3.providers 75 | web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); 76 | } 77 | ``` 78 | 79 | --- 80 | 81 | ## 同步呼叫 82 | 83 | ```Javascript 84 | var block = web3.eth.getBlock(48); 85 | console.log(block); 86 | ``` 87 | 88 | --- 89 | 90 | ## 非同步呼叫 - 使用 callbacks 91 | 92 | ```Javascript 93 | web3.eth.getBlock(48, function(error, result){ 94 | if(!error) 95 | console.log(result) 96 | else 97 | console.error(error); 98 | }); 99 | 100 | ``` 101 | 102 | --- 103 | 104 | ## BigNumber (1/2) 105 | 106 | JavaScript 無法處理 big number 107 | ```JavaScript 108 | Number.MAX_SAFE_INTEGER 109 | 9007199254740991 110 | ``` 111 | 112 | Ethereum 中最大的數字 uint256: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 113 | 114 | Web3 回傳的數值都使用 bignumber.js 115 | https://github.com/MikeMcl/bignumber.js/ 116 | 117 | --- 118 | 119 | ## BigNumber (2/2) 120 | 121 | ```Javascript 122 | var balance = new BigNumber('131242344353464564564574574567456'); 123 | balance.plus(21).toString(10); // toString(10) converts it to a number string 124 | // "131242344353464564564574574567477" 125 | ``` 126 | 127 | __Note__: 浮點數只支援到20位,所以盡量都使用Wei(Ethereum貨幣中最小的單位) 128 | ```Javascript 129 | var balance = new BigNumber('13124.234435346456466666457455567456'); 130 | balance.plus(21).toString(10); // toString(10) converts it to a number string, but can only show max 20 floating points 131 | // "13145.23443534645646666646" // you number would be cut after the 20 floating point 132 | ``` 133 | 134 | --- 135 | 136 | ## Web3 所有函式列表 137 | 138 | https://github.com/ethereum/wiki/wiki/JavaScript-API#web3js-api-reference 139 | 140 | --- 141 | 142 | ## Web3 常用工具函式 143 | 144 | - 單位轉換:(http://ether.fund/tool/converter) 145 | 146 | ```Javascript 147 | var weiValue = web3.toWei('12', 'ether'); 148 | var value = web3.fromWei(weiValue, 'ether'); 149 | ``` 150 | 151 | - 編碼: 152 | 153 | ```Javascript: 154 | var str = web3.toHex({test: 'test'}); 155 | console.log(str); // '0x7b22746573742 156 | web3.toAscii(str); 157 | web3.sha3(str); 158 | ``` 159 | 160 | --- 161 | 162 | ## Web3 常用 eth 函式 - 區塊鏈資訊 163 | 164 | ```Javascript 165 | var callback = function(error, result){ 166 | if(!error) 167 | console.log(result); 168 | else 169 | console.error(error); 170 | }; 171 | web3.eth.getBlockNumber(callback); 172 | web3.eth.getBlock(10, callback); 173 | web3.eth.getBlock("0xda882aeff30f59eda9da2b3ace3023366ab9d4219b5a83cdd589347baae8678e", callback); 174 | ``` 175 | 176 | --- 177 | 178 | ## Web3 常用 eth 函式 - 交易函式 179 | 180 | ```Javascript 181 | web3.eth.sendTransaction({value: 123, to: "0x764248D16C713Cb168ddfB5a5456fBC9F9e7357b", gas: 40000}, callback); 182 | web3.eth.getTransaction('0xcc82f65ac8c62c1bc0337aeee5b5b7db33b1eacfe9706af178d9113c5827cd42', callback); 183 | web3.eth.getTransactionReceipt('0xcc82f65ac8c62c1bc0337aeee5b5b7db33b1eacfe9706af178d9113c5827cd42', callback); 184 | 185 | ``` 186 | 187 | --- 188 | 189 | ## Web3 常用 eth 函式 - 合約函式 190 | 191 | 參考: ClientReceipt.sol, watch-client-receipt.js 192 | 193 | ``` Javascript 194 | web3.eth.contract(abiArray) 195 | web3.eth.contract.myMethod() 196 | web3.eth.contract.myEvent() 197 | ``` 198 | 199 | ```Javascript 200 | var abi = [{"constant":false,"inputs":[{"name":"_id","type":"bytes32"}],"name":"deposit","outputs":[],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_id","type":"bytes32"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Deposit","type":"event"}]; 201 | var ClientReceipt = web3.eth.contract(abi); 202 | var clientReceipt = ClientReceipt.at("0x32cb389a408cb79ab1e2d23bf1a454f4420f80b2"); 203 | var event = clientReceipt.Deposit(); 204 | event.watch(function(error, result){ 205 | console.log(error, result); 206 | console.log("Deposit id: " + result.args._id); 207 | event.stopWatching(); 208 | }); 209 | clientReceipt.deposit.sendTransaction(123, {gas: 50000},callback); 210 | 211 | ``` 212 | -------------------------------------------------------------------------------- /contracts/build/BlindAuction.bin: -------------------------------------------------------------------------------- 1 | 6060604052341561000c57fe5b604051606080610c0a833981016040528080519060200190919080519060200190919080519060200190919050505b80600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055504260018190555082420160028190555081600254016003819055505b5050505b610b5f806100ab6000396000f300606060405236156100b8576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806301495c1c146100cd57806312fa6feb1461012f5780632a24f46c1461015957806338af3eed1461016b5780633ccfd60b146101bd578063423b217f146101cf5780634f245ef7146101f5578063900f080a1461021b57806391f90157146102f2578063957bb1e014610344578063a6e6647714610368578063d57bde791461038e575b34156100c057fe5b6100cb5b610000565b565b005b34156100d557fe5b61010a600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506103b4565b6040518083600019166000191681526020018281526020019250505060405180910390f35b341561013757fe5b61013f6103f5565b604051808215151515815260200191505060405180910390f35b341561016157fe5b610169610408565b005b341561017357fe5b61017b61055e565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101c557fe5b6101cd610584565b005b34156101d757fe5b6101df610654565b6040518082815260200191505060405180910390f35b34156101fd57fe5b61020561065a565b6040518082815260200191505060405180910390f35b341561022357fe5b6102f06004808035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050610660565b005b34156102fa57fe5b6103026108cd565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561034c57fe5b6103666004808035600019169060200190919050506108f3565b005b341561037057fe5b6103786109a8565b6040518082815260200191505060405180910390f35b341561039657fe5b61039e6109ae565b6040518082815260200191505060405180910390f35b6005602052816000526040600020818154811015156103cf57fe5b906000526020600020906002020160005b91509150508060000154908060010154905082565b600460009054906101000a900460ff1681565b600354804211151561041957610000565b600460009054906101000a900460ff161561043357610000565b7fdaec4582d5d9595688c8c98545fdd1c696d41c6aeaeb636737e84ed2f5c00eda600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600754604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a16001600460006101000a81548160ff021916908315150217905550600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051809050600060405180830381858888f19350505050151561055957610000565b5b5b50565b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000600860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055503373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051809050600060405180830381858888f19350505050151561065057610000565b5b50565b60025481565b60015481565b6000600060006000600060006000600254804211151561067f57610000565b600354804210151561069057610000565b600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509850888c511415806106e65750888b5114155b806106f25750888a5114155b156106fc57610000565b600096505b8887101561087957600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208781548110151561075557fe5b906000526020600020906002020160005b5095508b8781518110151561077757fe5b906020019060200201518b8881518110151561078f57fe5b906020019060200201518b898151811015156107a757fe5b906020019060200201519450945094508484846040518084815260200183151515157f0100000000000000000000000000000000000000000000000000000000000000028152600101826000191660001916815260200193505050506040518091039020600019168660000154600019161415156108245761086c565b8560010154880197508315801561083f575084866001015410155b1561085a5761084e33866109b4565b156108595784880397505b5b60006001028660000181600019169055505b8680600101975050610701565b3373ffffffffffffffffffffffffffffffffffffffff166108fc899081150290604051809050600060405180830381858888f1935050505015156108bc57610000565b5b5b505b5050505050505050505050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600254804210151561090457610000565b600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080548060010182816109559190610ad1565b916000526020600020906002020160005b6040604051908101604052808660001916815260200134815250909190915060008201518160000190600019169055602082015181600101555050505b5b5050565b60035481565b60075481565b6000600754821115156109ca5760009050610acb565b6000600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141515610a7e5760075460086000600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505b8160078190555082600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600190505b92915050565b815481835581811511610afe57600202816002028360005260206000209182019101610afd9190610b03565b5b505050565b610b3091905b80821115610b2c5760006000820160009055600182016000905550600201610b09565b5090565b905600a165627a7a72305820cbf27fe851ff6a486ad595a12c02c25a48c70715a9720512a532c65ae76cdbca0029 -------------------------------------------------------------------------------- /slides/9_Dapps_Development.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # Dapps Development 4 | 5 | --- 6 | 7 | ## What are Dapps 8 | 9 | - Dapps - decentralized applications 10 | 11 | - Ethereum Dapps - applications interact with Ethereum blockchain 12 | 13 | --- 14 | 15 | ## Development environment 16 | 17 | - Ethereum RPC: (Geth, Mist, MetaMask) 18 | 19 | - Library: Web3 20 | 21 | - Framework: Meteor, Truffle 22 | 23 | - We will focus on __Meteor__ in this lecture 24 | 25 | - For __Truffle__ please see [Ethereum Development Environment and Tools](https://amisamity.github.io/contract-training/slides/2_Ethereum_Development_Environment_and_Tools.md.html) 26 | 27 | --- 28 | 29 | ## Web3 API Connection 30 | 31 | - Geth: ` admin.startRPC("0.0.0.0", 8545, "*","db,eth,net,web3,personal")` 32 | ```Javascript 33 | web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545')); 34 | ``` 35 | - Mist: `http://localhost:3000/` 36 | Will be replaced with IpcProvider 37 | ```Javascript 38 | > web3.currentProvider 39 | > IpcProvider 40 | ``` 41 | - MetaMask: `http://localhost:3000/` in Chrome 42 | Will be replaced with MetamaskInpageProvider 43 | ```Javascript 44 | > web3.currentProvider 45 | > MetamaskInpageProvider 46 | ``` 47 | 48 | --- 49 | 50 | ## Dapp example (Meteor): Ethereum Wallet 51 | 52 | ``` 53 | git clone git@github.com:ethereum/meteor-dapp-wallet.git 54 | npm install 55 | cd meteor-dapp-wallet/app 56 | meteor 57 | ``` 58 | 59 | - Client options: 60 | 61 | - Mist browser 62 | 63 | - Chrome with MetaMask 64 | 65 | - Browser with Geth RPC 66 | 67 | --- 68 | 69 | ## Meteor 70 | 71 | - Framework for building javascript apps. 72 | https://www.meteor.com/ 73 | 74 | --- 75 | 76 | ## Meteor - get started 77 | 78 | - Install: 79 | 80 | `curl https://install.meteor.com/ | sh` 81 | 82 | - Create app 83 | 84 | `meteor create myDapp` 85 | 86 | - Install app packages 87 | 88 | `cd myDapp && npm install` 89 | 90 | - Run 91 | 92 | `meteor` 93 | 94 | --- 95 | 96 | ## Meteor - add Libraries 97 | 98 | - Required: 99 | 100 | ``` 101 | meteor add ethereum:web3 102 | meteor add less 103 | meteor add ethereum:dapp-styles 104 | ``` 105 | 106 | - Optionals 107 | 108 | ``` 109 | meteor add ethereum:tools 110 | meteor add ethereum:elements 111 | meteor add ethereum:accounts 112 | meteor add ethereum:blocks 113 | meteor add frozeman:template-var 114 | meteor add frozeman:persistent-minimongo2 115 | ``` 116 | 117 | --- 118 | 119 | ## Meteor - ethereum libraries 120 | 121 | - `ethereum:tools`: https://github.com/ethereum/meteor-package-tools 122 | 123 | - `ethereum:blocks`: https://github.com/ethereum/meteor-package-blocks 124 | 125 | - `ethereum:elements`: https://github.com/ethereum/meteor-package-elements 126 | 127 | - `ethereum:accounts:`: https://github.com/ethereum/meteor-package-accounts 128 | 129 | --- 130 | 131 | ## Meteor - file structure 132 | 133 | - __client__ : loaded by the client. Most of our files go. 134 | 135 | - __lib__: loaded before other files in the same folder. 136 | 137 | - __public__: assets available on the root of the Dapp. 138 | 139 | --- 140 | 141 | ## Meteor - add web3 Library 142 | 143 | ``` 144 | mkdir lib 145 | cd lib && touch init.js 146 | ``` 147 | 148 | Add following: 149 | 150 | ```Javascript 151 | if(typeof web3 === 'undefined') 152 | web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545')); 153 | ``` 154 | 155 | --- 156 | 157 | ## Meteor - check web3 connection 158 | 159 | - Run meteor: 160 | 161 | ```bash 162 | meteor 163 | ``` 164 | 165 | - Open chrome: 166 | View -> Developer -> Javascript Console 167 | 168 | ```bash 169 | web3.eth.accounts 170 | ``` 171 | 172 | --- 173 | 174 | ## Meteor - styling 175 | 176 | - rename main.css to main.less 177 | 178 | - add following 179 | 180 | ```Javascript 181 | // libs 182 | @import '{ethereum:dapp-styles}/dapp-styles.less'; 183 | 184 | ``` 185 | 186 | --- 187 | 188 | ## Meteor - using ethereum packages (1/2) 189 | 190 | - In main.html: 191 | - Add `{{> blockInfo}}` in `body` section. 192 | - Add following in the end 193 | 194 | ```html 195 | 198 | ``` 199 | 200 | --- 201 | 202 | ## Meteor - using ethereum packages (2/2) 203 | 204 | - In main.js: 205 | 206 | ```Javascript 207 | Template.blockInfo.onCreated(function blockInfoOnCreated(){ 208 | EthBlocks.init(); 209 | }); 210 | 211 | Template.blockInfo.helpers({ 212 | currentBlock(){ 213 | return EthBlocks.latest.number; 214 | }, 215 | }); 216 | ``` 217 | 218 | --- 219 | 220 | ## OneValue with Meteor - OneValue Contract 221 | 222 | Deployed at: `0xe07438274839E9793baEAaa757F695CfED4A9e26` 223 | 224 | ```Javascript 225 | pragma solidity ^0.4.4; 226 | 227 | contract OneValue { 228 | uint256 value; 229 | 230 | function OneValue(uint256 initValue) { 231 | value = initValue; 232 | } 233 | 234 | function setValue(uint256 v) { 235 | value = v; 236 | } 237 | 238 | function getValue() constant returns (uint256 result) { 239 | return value; 240 | } 241 | } 242 | ``` 243 | 244 | --- 245 | 246 | ## OneValue with Meteor - interaction (1/2) 247 | 248 | OneValue instance: 249 | 250 | ```Javascript 251 | var abi = [{"constant":true,"inputs":[],"name":"getValue","outputs":[{"name":"result","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"v","type":"uint256"}],"name":"setValue","outputs":[],"type":"function"},{"inputs":[{"name":"initValue","type":"uint256"}],"type":"constructor"}];; 252 | var OneValueContract = web3.eth.contract(abi); 253 | this.contractAddress = '0xe07438274839E9793baEAaa757F695CfED4A9e26'; 254 | var oneValue = this.oneValue = OneValueContract.at(this.contractAddress); 255 | ``` 256 | 257 | --- 258 | 259 | ## OneValue with Meteor - interaction (1/2) 260 | 261 | - Get value: 262 | ```Javascript 263 | oneValue.getValue(function(err, res){ 264 | currentValue.set(res.toNumber()); 265 | }); 266 | ``` 267 | 268 | - Set value: 269 | ```Javascript 270 | oneValue.setValue.sendTransaction(_.toNumber(newValue), function(err, res){ 271 | message.set("Transaction hash: " + res); 272 | }); 273 | ``` 274 | 275 | --- 276 | 277 | ## Deployment - Meteor Galaxy 278 | 279 | - Create account: https://galaxy.meteor.com/ 280 | 281 | - Pricing: starts from $0.04/ hour 282 | 283 | - Deploy doc: http://galaxy-guide.meteor.com/ 284 | 285 | - Quick command: `meteor deploy .meteorapp.com` 286 | 287 | --- 288 | 289 | ## Meteor galaxy dashboard 290 | 291 | ![alt text](images/meteor-dashboard.png "Meteor dashboard") 292 | -------------------------------------------------------------------------------- /slides/2_Ethereum_Development_Environment_and_Tools_03202017.md: -------------------------------------------------------------------------------- 1 | ## 以太坊開發工具 2 | - __結點 / 錢包__ 3 | - 智能合約開發工具,函式庫 4 | 5 | --- 6 | 7 | ## 圖形化錢包 / 節點:Mist/Ethereum wallet 8 | - 錢包 9 | - Ðapps 瀏覽器 10 | - 本地節點 11 | - Github: https://github.com/ethereum/mist 12 | - Installable binaries: https://github.com/ethereum/mist/releases 13 | 14 | --- 15 | 16 | ## Ethereum wallet demo 17 | - Network: mainnet and testnet 18 | - Mining: testnet only (can still enable it via console) 19 | - Wallets 20 | - Send 21 | - Contracts 22 | 23 | --- 24 | 25 | ## 雲端錢包: MetaMask 26 | - 雲端節點: 不須等待資料同步 27 | - MetaMask: https://metamask.io/ 28 | ![alt text](images/metamask.png "MetaMask") 29 | 30 | --- 31 | 32 | ## Geth 節點 33 | - 以太坊 Golang 實作節點 34 | - Mist 預設使用節點 35 | - Ethstats 上大部分是 `Geth` 和 `Parity` 36 | - https://ethstats.net/ 37 | 38 | --- 39 | 40 | ## 利用 geth 連上 mainnet 41 | ```bash 42 | geth --fast \ 43 | --datadir "~/.eth/mainnet" \ 44 | --rpc --rpccorsdomain "*" \ 45 | --ipcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" \ 46 | --rpcapi "db,eth,net,web3,personal" \ 47 | --rpcport "8547" \ 48 | --port "30305" \ 49 | console 50 | ``` 51 | 52 | --- 53 | 54 | ## 利用 geth 連上 testnet 55 | ```bash 56 | geth --fast \ 57 | --datadir "~/.eth/testnet" \ 58 | --ipcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" \ 59 | --rpc --rpccorsdomain "*" \ 60 | --rpcapi "db,eth,net,web3,personal" \ 61 | --rpcport "8546" \ 62 | --port "30304" \ 63 | --testnet \ 64 | console 65 | ``` 66 | 67 | --- 68 | 69 | ## 利用 geth 跑私有鏈 70 | - 使用 `networkid` 71 | 72 | ```bash 73 | geth --fast \ 74 | --datadir "~/.eth/privnet" \ 75 | --ipcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" \ 76 | --rpc --rpccorsdomain "*" \ 77 | --rpcapi "db,eth,net,web3,personal" \ 78 | --rpcport "8545" \ 79 | --port "30303" \ 80 | --networkid "12345" \ 81 | --nodiscover \ 82 | console 83 | ``` 84 | 85 | --- 86 | 87 | ## 利用 geth 跑私有鏈 88 | - 使用 `networkid`及`genesis.json` 89 | 90 | ```JavaScript 91 | { 92 | "nonce": "0x0000000000000042", 93 | "timestamp": "0x0", 94 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 95 | "extraData": "Any extra data 134ADFAD", 96 | "gasLimit": "0x47e7c4", 97 | "difficulty": "0x9c40", 98 | "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", 99 | "coinbase": "0x3333333333333333333333333333333333333333", 100 | "alloc": { 101 | "0x60cafee22ae353ac9de07852a682558c9bb84e61": { 102 | "balance": "999999999999999999999999999999999" 103 | } 104 | } 105 | } 106 | ``` 107 | 108 | --- 109 | 110 | ## 利用 geth 跑私有鏈 111 | - 使用 `networkid`及`genesis.json` 112 | 113 | Init blockchain: 114 | ```bash 115 | geth --datadir "~/.eth/privnet2" \ 116 | init "/PATH/TO/genesis.json" 117 | ``` 118 | 119 | Run: 120 | ```bash 121 | geth --fast \ 122 | --datadir "~/.eth/privnet2" \ 123 | --ipcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" \ 124 | --rpc --rpccorsdomain "*" \ 125 | --rpcapi "db,eth,net,web3,personal" \ 126 | --rpcport "8545" \ 127 | --port "30303" \ 128 | --networkid "12345" \ 129 | --nodiscover \ 130 | console 131 | ``` 132 | 133 | --- 134 | 135 | ## 以太坊節點 136 | - 同步區塊鏈網路資料:建立本地端資料備份 137 | - 錢包:發送交易 138 | - 提供 API 接口:RPC, IPC, WebSocket 139 | 140 | --- 141 | 142 | ## 以太坊開發工具 143 | - 結點 / 錢包 144 | - __智能合約開發工具,函式庫__ 145 | 146 | --- 147 | 148 | ## Simple contract: OneValueContract 149 | ```Javascript 150 | contract OneValue { 151 | uint256 value; 152 | 153 | function OneValue(uint256 initValue) { 154 | value = initValue; 155 | } 156 | 157 | function setValue(uint256 v) { 158 | value = v; 159 | } 160 | 161 | function getValue() constant returns (uint256 result){ 162 | return value; 163 | } 164 | } 165 | ``` 166 | 167 | --- 168 | 169 | ## Solidity compiler: solc 170 | - solcjs 171 | ```bash 172 | npm install solc -g 173 | ``` 174 | 175 | - solc: https://github.com/ethereum/solidity 176 | ```bash 177 | git clone --recursive https://github.com/ethereum/solidity.git 178 | cd solidity 179 | mkdir build 180 | cd build 181 | cmake .. && make && make install 182 | ``` 183 | 184 | --- 185 | 186 | ## Compile contract 187 | - Browser-Solidity (Remix IDE): 188 | https://ethereum.github.io/browser-solidity/ 189 | - solc 190 | ```bash 191 | solc --abi --bin --gas -o ./build OneValue.sol 192 | ``` 193 | 194 | --- 195 | 196 | ## Web3 197 | - Web3: ethereum compatible [JavaScript API](https://github.com/ethereum/wiki/wiki/JavaScript-API) which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) spec 198 | 199 | - 安裝: `npm install web3` 200 | 201 | --- 202 | 203 | ## Web3 使用方式 204 | - Enable rpc in console: 205 | ```Javascript 206 | admin.startRPC("0.0.0.0", 8545, "*","db,eth,net,web3,personal") 207 | ``` 208 | - Example code: `node web3-test.js` 209 | ```Javascript 210 | var Web3 = require('web3'); 211 | var web3 = new Web3( 212 | new Web3.providers.HttpProvider("http://localhost:8545")); 213 | 214 | web3.eth.getBlock(48, function(error, result){ 215 | if(!error) 216 | console.log(result) 217 | else 218 | console.error(error); 219 | }); 220 | ``` 221 | 222 | --- 223 | ## Contract deployment 224 | - Mist 225 | - Web3 226 | 227 | --- 228 | ## Deploy contract with Mist 229 | - Contracts → Deploy new contract → Paste code and deploy 230 | - Remix IDE → Create 231 | 232 | --- 233 | 234 | ## Deploy contract with Web3 235 | - Deploy to testnet: 236 | ```Javascript 237 | node deploy-contract-test.js 238 | ``` 239 | 240 | --- 241 | 242 | ## Deploy contract with Web3 程式碼節錄 243 | - Example code (partial): 244 | ```Javascript 245 | var abi = ... 246 | var evmCode = ... 247 | var OneValueContract = web3.eth.contract(abi); 248 | var oneValue = OneValueContract.new(initValue, 249 | {from:addr, data: evmCode, gas: 4700000}, 250 | function(error, contract){ 251 | ... 252 | } 253 | ); 254 | ``` 255 | --- 256 | 257 | ## Testrpc 258 | 259 | - Fast Ethereum RPC client for testing and development. (RPC mock) 260 | - 安裝: 261 | ```bash 262 | npm install -g ethereumjs-testrpc 263 | ``` 264 | - 使用: 265 | ```bash 266 | testrpc -p 8547 267 | ``` 268 | 269 | --- 270 | 271 | ## Web3 連線到 Testrpc 272 | - Connect with Web3: 273 | ```bash 274 | node web3-testrpc.js 275 | ``` 276 | 277 | ```Javascript 278 | var Web3 = require('web3'); 279 | var TestRPC = require("ethereumjs-testrpc"); 280 | var web3 = new Web3(TestRPC.provider()); 281 | web3.eth.getAccounts(function(e, accts){ 282 | console.log("error:", e); 283 | console.log("accounts:", accts); 284 | process.exit(0); 285 | }); 286 | ``` 287 | 288 | --- 289 | 290 | ## Deploy contract with Web3 291 | - Deploy to testrpc: 292 | ```Javascript 293 | node deploy-contract-testrpc.js 294 | ``` 295 | 296 | --- 297 | 298 | ## 與智能合約互動 (Express + Web3) 299 | 300 | - Example (partial): 301 | 302 | ```Javascript 303 | var abi = ... var OneValueContract = web3.eth.contract(abi); 304 | var contractAddress = '0x36274a6286c9cf3c8e09c85c5bfa572a8827fddc'; //Testnet 305 | var oneValue = OneValueContract.at(contractAddress); 306 | 307 | app.get('/', function (req, res) { 308 | res.send( 309 | 'OneValue Instance: ' + contractAddress + "\n" + 310 | 'Value: '+ oneValue.getValue() + "\n"); 311 | }); 312 | 313 | app.listen(3000) 314 | ``` 315 | 316 | - Run: `node express-example.js` 317 | - Test: `curl http://localhost:3000` 318 | -------------------------------------------------------------------------------- /slides/8_Insurance_Examples.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # Insurance Examples - Flight Delay 4 | 5 | --- 6 | 7 | ## Cryptocoins: Blockchain to Disrupt Air Travel and Insurance with FlightDelay 8 | 9 | - FlightDelay: https://fdd.etherisc.com/ 10 | - Github: https://github.com/etherisc/flightDelay 11 | - Cryptocoins news article: https://www.cryptocoinsnews.com/blockchain-disrupt-air-travel-insurance-flightdelay/ 12 | 13 | --- 14 | ## FlightDelay example from Cryptocoins News 15 | - Picked a random flight and pay 0.5 ETH premium 16 | - No delay: receive nothing 17 | - Delay for 15 to 29 minutes (20.34%): receive 0.95 ETH 18 | ![alt text](images/flightdelay-dapp.jpg "Policy") 19 | 20 | --- 21 | ## FlightDelay DApp Demo - MetaMask 22 | - MetaMask: https://metamask.io/ 23 | ![alt text](images/fdi-metamask.png "Policy") 24 | 25 | --- 26 | ## FlightDelay DApp Demo - Mist 27 | - Mist: https://github.com/ethereum/mist/releases 28 | ![alt text](images/fdi-mist.png "Policy") 29 | 30 | --- 31 | 32 | ## FlightDelay code tracing 33 | - Github: https://github.com/etherisc/flightDelay/blob/master/FlightDelay.sol 34 | - Oraclize: https://github.com/oraclize/ethereum-api 35 | - Underwriting: flight delay probability 36 | - Payout: how much delay 37 | - Flight Stats API: https://developer.flightstats.com/api-docs/ 38 | 39 | --- 40 | 41 | ## FlightDelay.sol 42 | 43 | - 使用 Oraclize 取得外部資料:事實上還是由 Oraclize 將外部資料填入智能合約當中。 44 | - 主要兩種 API: 45 | - Ratings: 班機延誤評等 API。用來核保,及計算理賠金額。 46 | - Status: 班機起降狀態 API。用來核賠。 47 | 48 | ```JavaScript 49 | contract FlightDelay is usingOraclize { 50 | ... 51 | string constant oraclize_RatingsBaseUrl = 52 | "[URL] json(https://api.flightstats.com/flex/ratings/rest/v1/json/flight/"; 53 | ... 54 | string constant oraclize_StatusBaseUrl = 55 | "[URL] json(https://api.flightstats.com/flex/flightstatus/rest/v2/json/flight/status/"; 56 | 57 | ... 58 | } 59 | ``` 60 | 61 | --- 62 | 63 | ## FlightDelay.sol - 合約狀態 (1/2) 64 | - Applied: 客戶已經支付保費,但是 oracle 還沒檢查投保班機延誤評等。 65 | - Accepted: oracle 已檢查投保班機評等並承保該保單。 66 | - Revoked: 客戶取消保單,費用扣除手續費後退回給客戶。 67 | - PaidOut: 確認班機延誤並已理賠。 68 | - Expired: 確認班機延誤時間少於 15 分鐘,不理賠。 69 | - Declined: 核保未通過,費用扣除手續費後退回給客戶。 70 | - SendFailed: 退費或是理賠失敗,將金額置入 RiskFund 中。 71 | 72 | 73 | --- 74 | 75 | ## FlightDelay.sol - 合約狀態 (2/2) 76 | 77 | ```Javascript 78 | // 00 01 02 03 79 | enum policyState {Applied, Accepted, Revoked, PaidOut, 80 | // 04 05 06 81 | Expired, Declined, SendFailed} 82 | ``` 83 | 84 | --- 85 | 86 | ## FlightDelay.solc - 保單資料結構 87 | 88 | ```Javascript 89 | struct policy { 90 | // 0 - the customer 91 | address customer; 92 | // 1 - premium 93 | uint premium; 94 | 95 | // risk specific parameters: 96 | // 2 - pointer to the risk in the risks mapping 97 | bytes32 riskId; 98 | // 3 - probability weight. this is the central parameter 99 | uint weight; 100 | // 4 - calculated Payout 101 | uint calculatedPayout; 102 | // 5 - actual Payout 103 | uint actualPayout; 104 | 105 | // status fields: 106 | // 6 - the state of the policy 107 | policyState state; 108 | // 7 - time of last state change 109 | uint stateTime; 110 | // 8 - state change message/reason 111 | bytes32 stateMessage; 112 | // 9 - TLSNotary Proof 113 | bytes proof; 114 | } 115 | ``` 116 | 117 | --- 118 | 119 | ## FlightDelay.sol - 航班險資料結構 120 | 121 | ```Javascript 122 | struct risk { 123 | // 0 - Airline Code + FlightNumber 124 | string carrierFlightNumber; 125 | // 1 - scheduled departure and arrival time in the format /dep/YYYY/MM/DD 126 | string departureYearMonthDay; 127 | // 2 - the initial arrival time 128 | uint arrivalTime; 129 | // 3 - the final delay in minutes 130 | uint delayInMinutes; 131 | // 4 - the determined delay category (0-5) 132 | uint8 delay; 133 | // 5 - counter; limit the number of identical risks. 134 | uint8 counter; 135 | } 136 | ``` 137 | 138 | --- 139 | 140 | ## FlightDelay.sol - 產生保單 141 | 142 | ```JavaScript 143 | function newPolicy( 144 | string _carrierFlightNumber, string _departureYearMonthDay, 145 | uint _departureTime, uint _arrivalTime){ 146 | ... 147 | bytes32 riskId = sha3(_carrierFlightNumber, _departureYearMonthDay, _arrivalTime); 148 | risk r = risks[riskId]; 149 | ... 150 | uint policyId = policies.length++; 151 | policy p = policies[policyId]; 152 | p.customer = msg.sender; 153 | p.premium = bookAndCalcRemainingPremium(); 154 | p.riskId = riskId; 155 | ... 156 | r.carrierFlightNumber = _carrierFlightNumber; 157 | r.departureYearMonthDay = _departureYearMonthDay; 158 | r.arrivalTime = _arrivalTime; 159 | ... 160 | 161 | // now we have successfully applied 162 | p.state = policyState.Applied; 163 | p.stateMessage = 'Policy applied by customer'; 164 | p.stateTime = now; 165 | 166 | // call oraclize to get Flight Stats; this will also call underwrite() 167 | getFlightStats(policyId, _carrierFlightNumber); 168 | } 169 | ``` 170 | 171 | --- 172 | 173 | ## FlightDelay.sol - 取得航班評等資料 174 | 175 | ```Javascript 176 | function getFlightStats( uint _policyId, string _carrierFlightNumber) { 177 | 178 | // call oraclize and retrieve the number of observations from flightstats API 179 | // format https://api.flightstats.com/flex/ratings/rest/v1/json/flight/OS/75?appId=**&appKey=** 180 | 181 | string memory oraclize_url = strConcat( 182 | oraclize_RatingsBaseUrl, 183 | _carrierFlightNumber, 184 | oraclizeRatingsQuery 185 | ); 186 | 187 | bytes32 queryId = oraclize_query("nested", oraclize_url, oraclizeGas); 188 | // calculate the spent gas 189 | bookkeeping(acc_OraclizeCosts, acc_Balance, uint((-ledger[acc_Balance]) - int(this.balance))); 190 | oraclizeCallbacks[queryId] = oraclizeCallback(_policyId, oraclizeState.ForUnderwriting, 0); 191 | } 192 | ``` 193 | 194 | --- 195 | 196 | ## FlightDelay.sol - 等待 Oraclize 回應以後決定承保或是拒保 197 | 198 | ``` Javascript 199 | function callback_ForUnderwriting(uint _policyId, string _result, bytes _proof) 200 | onlyInState(_policyId, policyState.Applied) 201 | internal { 202 | 203 | var sl_result = _result.toSlice(); 204 | ... 205 | if (observations <= minObservations) { 206 | decline(_policyId, 'Declined (too few observations)', _proof); 207 | } else { 208 | uint[6] memory statistics; 209 | // calculate statistics (scaled by 100) 210 | statistics[0] = observations; 211 | ... 212 | // underwrite policy 213 | underwrite(_policyId, statistics, _proof); 214 | } 215 | } 216 | ``` 217 | 218 | --- 219 | 220 | ## FlightDelay.sol - 承保,並排程 Oraclize 取得該航班狀態 221 | 222 | ``` Javascript 223 | function underwrite(uint _policyId, uint[6] _statistics, bytes _proof) internal { 224 | policy p = policies[_policyId]; // throws if _policyId invalid 225 | for (uint8 i = 1; i <= 5; i++ ) { 226 | p.weight += weightPattern[i] * _statistics[i]; 227 | // 1% = 100 / 100% = 10,000 228 | } 229 | // to avoid div0 in the payout section, we have to make a minimal assumption on p.weight. 230 | if (p.weight == 0) { p.weight = 100000 / _statistics[0]; } 231 | p.proof = _proof; 232 | risk r = risks[p.riskId]; 233 | 234 | // schedule payout Oracle 235 | schedulePayoutOraclizeCall( 236 | _policyId, 237 | r.carrierFlightNumber, 238 | r.departureYearMonthDay, 239 | r.arrivalTime + 15 minutes 240 | ); 241 | 242 | p.state = policyState.Accepted; 243 | p.stateMessage = 'Policy underwritten by oracle'; 244 | p.stateTime = now; 245 | } 246 | ``` 247 | 248 | --- 249 | 250 | ## FlightDelay.sol - 排程 Oraclize 取得該航班狀態 251 | 252 | ```JavaScript 253 | function schedulePayoutOraclizeCall( 254 | uint _policyId, 255 | string _carrierFlightNumber, 256 | string _departureYearMonthDay, 257 | uint _oraclizeTime) 258 | internal { 259 | 260 | string memory oraclize_url = strConcat( 261 | oraclize_StatusBaseUrl, 262 | _carrierFlightNumber, 263 | _departureYearMonthDay, 264 | oraclizeStatusQuery 265 | ); 266 | 267 | bytes32 queryId = oraclize_query(_oraclizeTime, 'nested', oraclize_url, oraclizeGas); 268 | bookkeeping(acc_OraclizeCosts, acc_Balance, uint((-ledger[acc_Balance]) - int(this.balance))); 269 | oraclizeCallbacks[queryId] = oraclizeCallback(_policyId, oraclizeState.ForPayout, _oraclizeTime); 270 | } 271 | ``` 272 | 273 | --- 274 | 275 | ## FlightDelay.sol - 取得 Oraclize 回應並決定是否理賠 (1/2) 276 | 277 | ```Javascript 278 | function callback_ForPayout(bytes32 _queryId, string _result, bytes _proof) internal { 279 | oraclizeCallback memory o = oraclizeCallbacks[_queryId]; 280 | uint policyId = o.policyId; 281 | var sl_result = _result.toSlice(); 282 | ... 283 | bytes1 status = bytes(sl_result.toString())[0]; // s = L 284 | 285 | // 取消或是改航線 286 | if (status == 'C') { 287 | // flight cancelled --> payout 288 | payOut(policyId, 4, 0); 289 | return; 290 | } else if (status == 'D') { 291 | // flight diverted --> payout 292 | payOut(policyId, 5, 0); 293 | return; 294 | } else if (status != 'L' && status != 'A' && status != 'C' && status != 'D') { 295 | LOG_PolicyManualPayout(policyId, 'Unprocessable status'); 296 | return; 297 | } 298 | ... 299 | } 300 | ``` 301 | 302 | --- 303 | 304 | ## FlightDelay.sol - 取得 Oraclize 回應並決定是否理賠 (2/2) 305 | 306 | ```Javascript 307 | function callback_ForPayout(bytes32 _queryId, string _result, bytes _proof) internal { 308 | ... 309 | sl_result = _result.toSlice(); 310 | bool arrived = sl_result.contains('actualGateArrival'.toSlice()); 311 | if (status == 'A' || (status == 'L' && !arrived)) { 312 | // flight still active or not at gate --> reschedule 313 | ... 314 | schedulePayoutOraclizeCall(policyId, r.carrierFlightNumber, r.departureYearMonthDay, o.oraclizeTime + 45 minutes); 315 | } else if (status == 'L' && arrived) { 316 | uint delayInMinutes = ... 317 | if (delayInMinutes < 15) { 318 | payOut(policyId, 0, 0); 319 | } else if (delayInMinutes < 30) { 320 | payOut(policyId, 1, delayInMinutes); 321 | } else if (delayInMinutes < 45) { 322 | payOut(policyId, 2, delayInMinutes); 323 | } else { 324 | payOut(policyId, 3, delayInMinutes); 325 | } 326 | } else { // no delay info 327 | payOut(policyId, 0, 0); 328 | } 329 | } 330 | ``` 331 | -------------------------------------------------------------------------------- /slides/2_Ethereum_Development_Environment_and_Tools.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # Ethereum Development Environment and Tools 4 | 5 | --- 6 | ## Ethereum and Smart Contract 7 | 8 | - General purpose blockchain 9 | 10 | - Ethereum: TCP/IP = Bitcoin: SMTP 11 | 12 | - Smart contract: logic + data at a specific address 13 | 14 | --- 15 | ## Ethereum accounts 16 | 17 | - External accounts: controlled by public-private key pairs (i.e. humans) 18 | - ether 19 | 20 | - Contract accounts: controlled by the code stored together with the account. 21 | - ether 22 | - code (logic) 23 | - data (storage) 24 | 25 | - EVM treats the two types equally 26 | 27 | --- 28 | ## Simple contract: OneValueContract 29 | ```Javascript 30 | contract OneValue { 31 | uint256 value; 32 | 33 | function OneValue(uint256 initValue) { 34 | value = initValue; 35 | } 36 | 37 | function setValue(uint256 v) { 38 | value = v; 39 | } 40 | 41 | function getValue() constant returns (uint256 result){ 42 | return value; 43 | } 44 | } 45 | ``` 46 | 47 | --- 48 | ## All in one wallet: Mist/Ethereum Wallet 49 | - The Mist browser is the tool of choice to browse and use Ðapps (decentralized applications). 50 | 51 | - Github: https://github.com/ethereum/mist 52 | 53 | - Installable binaries: https://github.com/ethereum/mist/releases 54 | 55 | --- 56 | 57 | ## Ethereum wallet demo 58 | 59 | - Network: mainnet and testnet 60 | 61 | - Mining: testnet only (can still enable it via console) 62 | 63 | - Wallets 64 | 65 | - Send 66 | 67 | - Contracts 68 | 69 | --- 70 | 71 | ## Mist / Ethereum data location 72 | 73 | - Mist: 74 | - Windows: `%APPDATA%\Mist` 75 | 76 | - Mac: `~/Library/Application Support/Mist` 77 | 78 | - Linux: `~/.config/Mist` 79 | 80 | - Ethereum: 81 | 82 | - Mac: `~/Library/Ethereum` 83 | 84 | --- 85 | 86 | ## In browser wallet - MetaMask 87 | 88 | - MetaMask: https://metamask.io/ 89 | 90 | - Chrome plugin: https://goo.gl/8uPYIA 91 | 92 | ![alt text](images/metamask.png "MetaMask") 93 | 94 | 95 | --- 96 | ## Geth 97 | 98 | - Ethereum go implementation (Mist is actually using geth) 99 | - `ps -aef | grep geth` 100 | 101 | - Install: 102 | - https://www.ethereum.org/cli 103 | 104 | - Management API: 105 | - https://github.com/ethereum/go-ethereum/wiki/Management-APIs 106 | 107 | - Javascript Console: 108 | - https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console 109 | 110 | --- 111 | 112 | ## Run geth (mainnet) 113 | 114 | ```bash 115 | geth --fast \ 116 | --datadir "~/.eth/mainnet" \ 117 | --rpc --rpccorsdomain "*" \ 118 | --ipcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" \ 119 | --rpcapi "db,eth,net,web3,personal" \ 120 | --rpcport "8547" \ 121 | --port "30305" \ 122 | console 123 | ``` 124 | 125 | --- 126 | 127 | ## Run geth (testnet) 128 | 129 | ```bash 130 | geth --fast \ 131 | --datadir "~/.eth/testnet" \ 132 | --ipcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" \ 133 | --rpc --rpccorsdomain "*" \ 134 | --rpcapi "db,eth,net,web3,personal" \ 135 | --rpcport "8546" \ 136 | --port "30304" \ 137 | --testnet \ 138 | console 139 | ``` 140 | 141 | --- 142 | 143 | ## Run geth (private chain) 144 | option 1: use `networkid` 145 | 146 | ```bash 147 | geth --fast \ 148 | --datadir "~/.eth/privnet" \ 149 | --ipcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" \ 150 | --rpc --rpccorsdomain "*" \ 151 | --rpcapi "db,eth,net,web3,personal" \ 152 | --rpcport "8545" \ 153 | --port "30303" \ 154 | --networkid "12345" \ 155 | --nodiscover \ 156 | console 157 | ``` 158 | 159 | --- 160 | 161 | ## Run geth (private chain) 162 | option 2: use both `networkid` and custom `genesis.json` 163 | 164 | Example genesis.json: 165 | 166 | ```JSON 167 | { 168 | "nonce": "0x0000000000000042", 169 | "timestamp": "0x0", 170 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 171 | "extraData": "Any extra data 134ADFAD", 172 | "gasLimit": "0x47e7c4", 173 | "difficulty": "0x9c40", 174 | "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", 175 | "coinbase": "0x3333333333333333333333333333333333333333", 176 | "alloc": { 177 | "0x60cafee22ae353ac9de07852a682558c9bb84e61": { 178 | "balance": "999999999999999999999999999999999" 179 | } 180 | } 181 | } 182 | ``` 183 | 184 | --- 185 | 186 | ## Run geth (private chain) 187 | option 2: use both `networkid` and custom `genesis.json`, so we can avoid network id collision. 188 | 189 | Init blockchain: 190 | ```bash 191 | geth --datadir "~/.eth/privnet2" \ 192 | init "/PATH/TO/genesis.json" 193 | ``` 194 | 195 | Run: 196 | ```bash 197 | geth --fast \ 198 | --datadir "~/.eth/privnet2" \ 199 | --ipcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" \ 200 | --rpc --rpccorsdomain "*" \ 201 | --rpcapi "db,eth,net,web3,personal" \ 202 | --rpcport "8545" \ 203 | --port "30303" \ 204 | --networkid "12345" \ 205 | --nodiscover \ 206 | console 207 | ``` 208 | 209 | --- 210 | ## Geth API 211 | 212 | - IPC: Unix socket 213 | 214 | - Attach to Mist geth console: 215 | ``` 216 | geth attach ipc:~/Library/Ethereum/geth.ipc 217 | ``` 218 | 219 | - RPC: HTTP API 220 | 221 | - WebSocket 222 | 223 | --- 224 | ## Solidity compiler: solc 225 | 226 | - solcjs 227 | 228 | ```bash 229 | npm install solc -g 230 | ``` 231 | 232 | - solc: https://github.com/ethereum/solidity 233 | 234 | ```bash 235 | git clone --recursive https://github.com/ethereum/solidity.git 236 | cd solidity 237 | mkdir build 238 | cd build 239 | cmake .. && make && make install 240 | ``` 241 | 242 | --- 243 | ## Compile contract 244 | 245 | - Browser-Solidity: https://ethereum.github.io/browser-solidity/ 246 | 247 | - solc 248 | 249 | ``` 250 | solc --abi --bin --gas -o ./build OneValue.sol 251 | ``` 252 | 253 | --- 254 | 255 | ## Solidity editor 256 | 257 | - Atom: language-ethereum 258 | 259 | - SublimeText: ethereum 260 | 261 | - Visual Studio: Solidity 262 | 263 | - Remix (formerly Mix) IDE https://github.com/ethereum/remix 264 | 265 | --- 266 | 267 | ## Mist demo - Remix IDE 268 | 269 | ![alt text](images/mist.gif "mist") 270 | 271 | --- 272 | 273 | ## Libraries and development tools 274 | 275 | - Web3: https://github.com/ethereum/web3.js 276 | 277 | This is the Ethereum compatible [JavaScript API](https://github.com/ethereum/wiki/wiki/JavaScript-API) which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) spec. 278 | 279 | - Testrpc: https://github.com/ethereumjs/testrpc 280 | 281 | Fast Ethereum RPC client for testing and development. (RPC mock) 282 | 283 | 284 | - Truffle: https://github.com/ConsenSys/truffle 285 | 286 | Truffle is a development environment, testing framework and asset pipeline for Ethereum, aiming to make life as an Ethereum developer easier. 287 | 288 | --- 289 | ## Web3 290 | 291 | - Install: 292 | 293 | `npm install web3` 294 | 295 | - Enable rpc in console: 296 | 297 | `admin.startRPC("0.0.0.0", 8545, "*","db,eth,net,web3,personal")` 298 | 299 | - Example code: `node web3-test.js` 300 | 301 | ```Javascript 302 | var Web3 = require('web3'); 303 | var web3 = new Web3( 304 | new Web3.providers.HttpProvider("http://localhost:8545")); 305 | 306 | web3.eth.getBlock(48, function(error, result){ 307 | if(!error) 308 | console.log(result) 309 | else 310 | console.error(error); 311 | }); 312 | ``` 313 | 314 | --- 315 | ## Testrpc 316 | 317 | - Install: 318 | 319 | `npm install -g ethereumjs-testrpc` 320 | 321 | 322 | - Run testrpc: 323 | 324 | `testrpc -p 8547` 325 | 326 | - Connect with Web3: `node web3-testrpc.js` 327 | 328 | ```Javascript 329 | var Web3 = require('web3'); 330 | var TestRPC = require("ethereumjs-testrpc"); 331 | var web3 = new Web3(TestRPC.provider()); 332 | web3.eth.getAccounts(function(e, accts){ 333 | console.log("error:", e); 334 | console.log("accounts:", accts); 335 | process.exit(0); 336 | }); 337 | ``` 338 | 339 | - NOTE: As of version 3.0.2, testrpc requires at least Node 6.9.1 to run - this is because the ethereumjs-vm@2.0.1 dependency is now shipping using ES2015 language features. 340 | 341 | - Suggestion: using NVM [https://github.com/creationix/nvm](https://github.com/creationix/nvm) 342 | 343 | --- 344 | ## NVM 345 | Node Version Manager - Simple bash script to manage multiple active node.js versions 346 | 347 | - Install: 348 | 349 | https://github.com/creationix/nvm#installation 350 | 351 | - Use nvm: 352 | ``` 353 | > cd js 354 | > nvm use 355 | ``` 356 | 357 | --- 358 | ## NVM (install 6.9.1) 359 | 360 | - Install: 361 | ``` 362 | nvm install 6.9.1 363 | ``` 364 | 365 | - List installations: 366 | ``` 367 | nvm list 368 | ``` 369 | 370 | - Use: 371 | ``` 372 | nvm use 6.9.1 373 | ``` 374 | 375 | --- 376 | ## Truffle 377 | - Document: http://truffleframework.com/docs/ 378 | 379 | - Install: 380 | `npm install -g truffle` 381 | 382 | - Init: 383 | `truffle init` 384 | 385 | - Compile: 386 | `truffle compile` 387 | 388 | - Deploy: 389 | `truffle migrate` 390 | 391 | - Test: 392 | `truffle test` 393 | 394 | --- 395 | ## Truffle Dapp 396 | 397 | - Default builder is no longer shipped with truffle from 3.* 398 | 399 | - Install default builder: 400 | `npm install truffle-default-builder --save` 401 | 402 | - Config `truffle.js` 403 | 404 | - Build frontend: 405 | `truffle build` 406 | 407 | - Run frontend: 408 | `truffle serve` 409 | 410 | - Edit `truffle.js` to config rpc. 411 | 412 | - Open dapp: 413 | `open http://localhost:8080` 414 | 415 | --- 416 | ## Contract deployment 417 | - Mist 418 | 419 | - Truffle 420 | 421 | - Web3 422 | 423 | --- 424 | ## Deploy contract with Mist 425 | 426 | - Contracts -> Deploy new contract -> Paste code and deploy 427 | 428 | - Remix IDE -> Create 429 | 430 | --- 431 | ## Deploy contract with Truffle 432 | 433 | - Update rpc setting in `truffle.js` 434 | 435 | - Create contract: `truffle create:contract OneValue` 436 | 437 | - Edit `OneValue.sol` 438 | 439 | - Compile: `truffle compile` 440 | 441 | - Add migration file: `3_deploy_one_value_contract.js` 442 | 443 | - Deploy: `truffle migrate` 444 | 445 | - Note: need to unlock account before deployment if you are using live network. 446 | 447 | --- 448 | ## Deploy contract with Web3 449 | 450 | - Deploy to testrpc: `node deploy-contract-testrpc.js` 451 | 452 | - Deploy to testnet: `node deploy-contract-test.js` 453 | 454 | - Example code (partial): 455 | 456 | ```Javascript 457 | var abi = ... 458 | var evmCode = ... 459 | var OneValueContract = web3.eth.contract(abi); 460 | var oneValue = OneValueContract.new(initValue, 461 | {from:addr, data: evmCode, gas: 4700000}, 462 | function(error, contract){ 463 | ... 464 | } 465 | ); 466 | ``` 467 | 468 | --- 469 | ## Mining 470 | 471 | - In console: 472 | 473 | ``` 474 | miner.start(1) 475 | ``` 476 | 477 | - In geth command: 478 | 479 | ``` 480 | geth --mine --minerthread "4" 481 | ``` 482 | 483 | - In mist: (testnet only) 484 | 485 | - Develop -> Start Mining 486 | 487 | 488 | --- 489 | ## Interact with contract (Express + Web3) 490 | 491 | - Example (partial): 492 | 493 | ```Javascript 494 | var abi = ... var OneValueContract = web3.eth.contract(abi); 495 | var contractAddress = '0x36274a6286c9cf3c8e09c85c5bfa572a8827fddc'; //Testnet 496 | var oneValue = OneValueContract.at(contractAddress); 497 | 498 | app.get('/', function (req, res) { 499 | res.send( 500 | 'OneValue Instance: ' + contractAddress + "\n" + 501 | 'Value: '+ oneValue.getValue() + "\n"); 502 | }); 503 | 504 | app.listen(3000) 505 | ``` 506 | 507 | - Run: `node express-example.js` 508 | 509 | - Test: `curl http://localhost:3000` 510 | -------------------------------------------------------------------------------- /FlightDelay/FlightDelay.sol: -------------------------------------------------------------------------------- 1 | /* 2 | Source: https://github.com/etherisc/flightDelay/blob/master/FlightDelay.sol 3 | */ 4 | /* 5 | FlightDelay with Oraclized Underwriting and Payout 6 | All times are UTC. 7 | Copyright (C) Christoph Mussenbrock, Stephan Karpischek 8 | 9 | */ 10 | import "github.com/oraclize/ethereum-api/oraclizeAPI.sol"; 11 | import "github.com/Arachnid/solidity-stringutils/strings.sol"; 12 | 13 | contract FlightDelay is usingOraclize { 14 | 15 | using strings for *; 16 | 17 | modifier noEther { if (msg.value > 0) throw; _; } 18 | modifier onlyOwner { if (msg.sender != owner) throw; _; } 19 | modifier onlyOraclize { if (msg.sender != oraclize_cbAddress()) throw; _; } 20 | 21 | modifier onlyInState (uint _policyId, policyState _state) { 22 | 23 | policy p = policies[_policyId]; 24 | if (p.state != _state) throw; 25 | _; 26 | 27 | } 28 | 29 | modifier onlyCustomer(uint _policyId) { 30 | 31 | policy p = policies[_policyId]; 32 | if (p.customer != msg.sender) throw; 33 | _; 34 | 35 | } 36 | 37 | modifier notInMaintenance { 38 | healthCheck(); 39 | if (maintenance_mode >= maintenance_Emergency) throw; 40 | _; 41 | } 42 | 43 | // the following modifier is always checked at last, so previous modifiers 44 | // may throw without affecting reentrantGuard 45 | modifier noReentrant { 46 | if (reentrantGuard) throw; 47 | reentrantGuard = true; 48 | _; 49 | reentrantGuard = false; 50 | } 51 | 52 | // policy Status Codes and meaning: 53 | // 54 | // 00 = Applied: the customer has payed a premium, but the oracle has 55 | // not yet checked and confirmed. 56 | // The customer can still revoke the policy. 57 | // 01 = Accepted: the oracle has checked and confirmed. 58 | // The customer can still revoke the policy. 59 | // 02 = Revoked: The customer has revoked the policy. 60 | // The premium minus cancellation fee is payed back to the 61 | // customer by the oracle. 62 | // 03 = PaidOut: The flight has ended with delay. 63 | // The oracle has checked and payed out. 64 | // 04 = Expired: The flight has endet with <15min. delay. 65 | // No payout. 66 | // 05 = Declined: The application was invalid. 67 | // The premium minus cancellation fee is payed back to the 68 | // customer by the oracle. 69 | // 06 = SendFailed: During Revoke, Decline or Payout, sending ether failed 70 | // for unknown reasons. 71 | // The funds remain in the contracts RiskFund. 72 | 73 | 74 | // 00 01 02 03 75 | enum policyState {Applied, Accepted, Revoked, PaidOut, 76 | // 04 05 06 77 | Expired, Declined, SendFailed} 78 | 79 | // oraclize callback types: 80 | enum oraclizeState { ForUnderwriting, ForPayout } 81 | 82 | event LOG_PolicyApplied( 83 | uint policyId, 84 | address customer, 85 | string carrierFlightNumber, 86 | uint premium 87 | ); 88 | event LOG_PolicyAccepted( 89 | uint policyId, 90 | uint statistics0, 91 | uint statistics1, 92 | uint statistics2, 93 | uint statistics3, 94 | uint statistics4, 95 | uint statistics5 96 | ); 97 | event LOG_PolicyRevoked( 98 | uint policyId 99 | ); 100 | event LOG_PolicyPaidOut( 101 | uint policyId, 102 | uint amount 103 | ); 104 | event LOG_PolicyExpired( 105 | uint policyId 106 | ); 107 | event LOG_PolicyDeclined( 108 | uint policyId, 109 | bytes32 reason 110 | ); 111 | event LOG_PolicyManualPayout( 112 | uint policyId, 113 | bytes32 reason 114 | ); 115 | event LOG_SendFail( 116 | uint policyId, 117 | bytes32 reason 118 | ); 119 | event LOG_OraclizeCall( 120 | uint policyId, 121 | bytes32 queryId, 122 | string oraclize_url 123 | ); 124 | event LOG_OraclizeCallback( 125 | uint policyId, 126 | bytes32 queryId, 127 | string result, 128 | bytes proof 129 | ); 130 | event LOG_HealthCheck( 131 | bytes32 message, 132 | int diff, 133 | uint balance, 134 | int ledgerBalance 135 | ); 136 | 137 | // some general constants for the system: 138 | // minimum observations for valid prediction 139 | uint constant minObservations = 10; 140 | // minimum premium to cover costs 141 | uint constant minPremium = 500 finney; 142 | // maximum premium 143 | uint constant maxPremium = 5 ether; 144 | // maximum payout 145 | uint constant maxPayout = 200 ether; 146 | // maximum number of identical risks 147 | uint8 constant maxIdenticalRisks = 10; 148 | // 1 percent for DAO, 1 percent for maintainer 149 | uint8 constant rewardPercent = 2; 150 | // reserve for tail risks 151 | uint8 constant reservePercent = 1; 152 | // the weight pattern; in future versions this may become part of the policy struct. 153 | // currently can't be constant because of compiler restrictions 154 | // weightPattern[0] is not used, just to be consistent 155 | uint8[6] weightPattern = [0, 10,20,30,50,50]; 156 | // Deadline for acceptance of policies: Mon, 26 Sep 2016 12:00:00 GMT 157 | uint contractDeadline = 1474891200; 158 | 159 | // account numbers for the internal ledger: 160 | // sum of all Premiums of all currently active policies 161 | uint8 constant acc_Premium = 0; 162 | // Risk fund; serves as reserve for tail risks 163 | uint8 constant acc_RiskFund = 1; 164 | // sum of all payed out policies 165 | uint8 constant acc_Payout = 2; 166 | // the balance of the contract (negative!!) 167 | uint8 constant acc_Balance = 3; 168 | // the reward account for DAO and maintainer 169 | uint8 constant acc_Reward = 4; 170 | // oraclize costs 171 | uint8 constant acc_OraclizeCosts = 5; 172 | // when adding more accounts, remember to increase ledger array length 173 | 174 | // Maintenance modes 175 | uint8 constant maintenance_None = 0; 176 | uint8 constant maintenance_BalTooHigh = 1; 177 | uint8 constant maintenance_Emergency = 255; 178 | 179 | 180 | // gas Constants for oraclize 181 | uint constant oraclizeGas = 500000; 182 | 183 | // URLs and query strings for oraclize 184 | 185 | string constant oraclize_RatingsBaseUrl = 186 | "[URL] json(https://api.flightstats.com/flex/ratings/rest/v1/json/flight/"; 187 | string constant oraclizeRatingsQuery = 188 | "?${[decrypt] BDhAVBaQP2CS2VqQ/coqIStcYpSdSdLc1RJoC0gSoh++xsk6cBtLmJBHmB82X6mTMyzJXJPIvfa7ISzfwwhY+k8C3N+oP7htYGZ3N4INH03Uorw7Sif70hOw+xMR6PTX9ri2vkqiNwu9ensNkvTLyGd2l6NHJuij+RmgVw/mXGGZb9wHYC2T}).ratings[0]['observations','late15','late30','late45','cancelled','diverted']"; 189 | 190 | // [URL] json(https://api.flightstats.com/flex/flightstatus/rest/v2/json/flight/status/LH/410/dep/2016/09/01?appId={appId}&appKey={appKey}) 191 | string constant oraclize_StatusBaseUrl = 192 | "[URL] json(https://api.flightstats.com/flex/flightstatus/rest/v2/json/flight/status/"; 193 | string constant oraclizeStatusQuery = 194 | "?${[decrypt] BDhAVBaQP2CS2VqQ/coqIStcYpSdSdLc1RJoC0gSoh++xsk6cBtLmJBHmB82X6mTMyzJXJPIvfa7ISzfwwhY+k8C3N+oP7htYGZ3N4INH03Uorw7Sif70hOw+xMR6PTX9ri2vkqiNwu9ensNkvTLyGd2l6NHJuij+RmgVw/mXGGZb9wHYC2T}).flightStatuses[0]['status','delays','operationalTimes']"; 195 | 196 | 197 | // the policy structure: this structure keeps track of the individual parameters of a policy. 198 | // typically customer address, premium and some status information. 199 | 200 | struct policy { 201 | 202 | // 0 - the customer 203 | address customer; 204 | // 1 - premium 205 | uint premium; 206 | 207 | // risk specific parameters: 208 | // 2 - pointer to the risk in the risks mapping 209 | bytes32 riskId; 210 | // custom payout pattern 211 | // in future versions, customer will be able to tamper with this array. 212 | // to keep things simple, we have decided to hard-code the array for all policies. 213 | // uint8[5] pattern; 214 | // 3 - probability weight. this is the central parameter 215 | uint weight; 216 | // 4 - calculated Payout 217 | uint calculatedPayout; 218 | // 5 - actual Payout 219 | uint actualPayout; 220 | 221 | // status fields: 222 | // 6 - the state of the policy 223 | policyState state; 224 | // 7 - time of last state change 225 | uint stateTime; 226 | // 8 - state change message/reason 227 | bytes32 stateMessage; 228 | // 9 - TLSNotary Proof 229 | bytes proof; 230 | } 231 | 232 | // the risk structure; this structure keeps track of the risk-specific parameters. 233 | // several policies can share the same risk structure (typically some people flying 234 | // with the same plane) 235 | 236 | struct risk { 237 | 238 | // 0 - Airline Code + FlightNumber 239 | string carrierFlightNumber; 240 | // 1 - scheduled departure and arrival time in the format /dep/YYYY/MM/DD 241 | string departureYearMonthDay; 242 | // 2 - the inital arrival time 243 | uint arrivalTime; 244 | // 3 - the final delay in minutes 245 | uint delayInMinutes; 246 | // 4 - the determined delay category (0-5) 247 | uint8 delay; 248 | // 5 - counter; limit the number of identical risks. 249 | uint8 counter; 250 | } 251 | 252 | // the oraclize callback structure: we use several oraclize calls. 253 | // all oraclize calls will result in a common callback to __callback(...). 254 | // to keep track of the different querys we have to introduce this struct. 255 | 256 | struct oraclizeCallback { 257 | 258 | // for which policy have we called? 259 | uint policyId; 260 | // for which purpose did we call? {ForUnderwrite | ForPayout} 261 | oraclizeState oState; 262 | uint oraclizeTime; 263 | 264 | } 265 | 266 | address public owner; 267 | 268 | // Table of policies 269 | policy[] public policies; 270 | // Lookup policyIds from customer addresses 271 | mapping (address => uint[]) public customerPolicies; 272 | // Lookup policy Ids from queryIds 273 | mapping (bytes32 => oraclizeCallback) public oraclizeCallbacks; 274 | mapping (bytes32 => risk) public risks; 275 | // Internal ledger 276 | int[6] public ledger; 277 | 278 | // invariant: acc_Premium + acc_RiskFund + acc_Payout 279 | // + acc_Balance + acc_Reward == 0 280 | 281 | // Mutex 282 | bool public reentrantGuard; 283 | uint8 public maintenance_mode; 284 | 285 | function healthCheck() internal { 286 | int diff = int(this.balance-msg.value) + ledger[acc_Balance]; 287 | if (diff == 0) { 288 | return; // everything ok. 289 | } 290 | if (diff > 0) { 291 | LOG_HealthCheck('Balance too high', diff, this.balance, ledger[acc_Balance]); 292 | maintenance_mode = maintenance_BalTooHigh; 293 | } else { 294 | LOG_HealthCheck('Balance too low', diff, this.balance, ledger[acc_Balance]); 295 | maintenance_mode = maintenance_Emergency; 296 | } 297 | } 298 | 299 | // manually perform healthcheck. 300 | // @param _maintenance_mode: 301 | // 0 = reset maintenance_mode, even in emergency 302 | // 1 = perform health check 303 | // 255 = set maintenance_mode to maintenance_emergency (no newPolicy anymore) 304 | function performHealthCheck(uint8 _maintenance_mode) onlyOwner { 305 | maintenance_mode = _maintenance_mode; 306 | if (maintenance_mode > 0 && maintenance_mode < maintenance_Emergency) { 307 | healthCheck(); 308 | } 309 | } 310 | 311 | function payReward() onlyOwner { 312 | 313 | if (!owner.send(this.balance)) throw; 314 | maintenance_mode = maintenance_Emergency; // don't accept any policies 315 | 316 | } 317 | 318 | function bookkeeping(uint8 _from, uint8 _to, uint _amount) internal { 319 | 320 | ledger[_from] -= int(_amount); 321 | ledger[_to] += int(_amount); 322 | 323 | } 324 | 325 | // if ledger gets corrupt for unknown reasons, have a way to correct it: 326 | function audit(uint8 _from, uint8 _to, uint _amount) onlyOwner { 327 | 328 | bookkeeping (_from, _to, _amount); 329 | 330 | } 331 | 332 | function getPolicyCount(address _customer) 333 | constant returns (uint _count) { 334 | return policies.length; 335 | } 336 | 337 | function getCustomerPolicyCount(address _customer) 338 | constant returns (uint _count) { 339 | return customerPolicies[_customer].length; 340 | } 341 | 342 | function bookAndCalcRemainingPremium() internal returns (uint) { 343 | 344 | uint v = msg.value; 345 | uint reserve = v * reservePercent / 100; 346 | uint remain = v - reserve; 347 | uint reward = remain * rewardPercent / 100; 348 | 349 | bookkeeping(acc_Balance, acc_Premium, v); 350 | bookkeeping(acc_Premium, acc_RiskFund, reserve); 351 | bookkeeping(acc_Premium, acc_Reward, reward); 352 | 353 | return (uint(remain - reward)); 354 | 355 | } 356 | 357 | // constructor 358 | function FlightDelay () { 359 | 360 | owner = msg.sender; 361 | reentrantGuard = false; 362 | maintenance_mode = maintenance_None; 363 | 364 | // initially put all funds in risk fund. 365 | bookkeeping(acc_Balance, acc_RiskFund, msg.value); 366 | oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS); 367 | 368 | } 369 | 370 | // create new policy 371 | function newPolicy( 372 | string _carrierFlightNumber, 373 | string _departureYearMonthDay, 374 | uint _departureTime, 375 | uint _arrivalTime 376 | ) 377 | notInMaintenance { 378 | 379 | // sanity checks: 380 | 381 | // don't accept to low or to high policies 382 | 383 | if (msg.value < minPremium || msg.value > maxPremium) { 384 | LOG_PolicyDeclined(0, 'Invalid premium value'); 385 | if (!msg.sender.send(msg.value)) { 386 | LOG_SendFail(0, 'newPolicy sendback failed (1)'); 387 | } 388 | return; 389 | } 390 | 391 | // don't accept flights with departure time earlier than in 24 hours, 392 | // or arrivalTime before departureTime, or departureTime after Mon, 26 Sep 2016 12:00:00 GMT 393 | if ( 394 | _arrivalTime < _departureTime || 395 | _arrivalTime > _departureTime + 2 days || 396 | _departureTime < now + 24 hours || 397 | _departureTime > contractDeadline) { 398 | LOG_PolicyDeclined(0, 'Invalid arrival/departure time'); 399 | if (!msg.sender.send(msg.value)) { 400 | LOG_SendFail(0, 'newPolicy sendback failed (2)'); 401 | } 402 | return; 403 | } 404 | 405 | // accept only a number of maxIdenticalRisks identical risks: 406 | 407 | bytes32 riskId = sha3(_carrierFlightNumber, _departureYearMonthDay, _arrivalTime); 408 | risk r = risks[riskId]; 409 | 410 | if (r.counter >= maxIdenticalRisks) { 411 | LOG_PolicyDeclined(0, 'To many identical risks'); 412 | if (!msg.sender.send(msg.value)) { 413 | LOG_SendFail(0, 'newPolicy sendback failed (3)'); 414 | } 415 | return; 416 | } 417 | 418 | // store or update policy 419 | uint policyId = policies.length++; 420 | customerPolicies[msg.sender].push(policyId); 421 | policy p = policies[policyId]; 422 | 423 | p.customer = msg.sender; 424 | p.premium = bookAndCalcRemainingPremium(); 425 | p.riskId = riskId; 426 | // the remaining premium after deducting reserve and reward 427 | 428 | // store risk parameters 429 | // Airline Code 430 | if (r.counter == 0) { 431 | // we have a new struct 432 | r.carrierFlightNumber = _carrierFlightNumber; 433 | r.departureYearMonthDay = _departureYearMonthDay; 434 | r.arrivalTime = _arrivalTime; 435 | } 436 | // increase counter; 437 | r.counter += 1; 438 | 439 | // now we have successfully applied 440 | p.state = policyState.Applied; 441 | p.stateMessage = 'Policy applied by customer'; 442 | p.stateTime = now; 443 | LOG_PolicyApplied(policyId, msg.sender, _carrierFlightNumber, p.premium); 444 | 445 | // call oraclize to get Flight Stats; this will also call underwrite() 446 | getFlightStats(policyId, _carrierFlightNumber); 447 | } 448 | 449 | function underwrite(uint _policyId, uint[6] _statistics, bytes _proof) internal { 450 | 451 | policy p = policies[_policyId]; // throws if _policyId invalid 452 | for (uint8 i = 1; i <= 5; i++ ) { 453 | p.weight += weightPattern[i] * _statistics[i]; 454 | // 1% = 100 / 100% = 10,000 455 | } 456 | // to avoid div0 in the payout section, we have to make a minimal assumption on p.weight. 457 | if (p.weight == 0) { p.weight = 100000 / _statistics[0]; } 458 | p.proof = _proof; 459 | risk r = risks[p.riskId]; 460 | 461 | // schedule payout Oracle 462 | schedulePayoutOraclizeCall( 463 | _policyId, 464 | r.carrierFlightNumber, 465 | r.departureYearMonthDay, 466 | r.arrivalTime + 15 minutes 467 | ); 468 | 469 | p.state = policyState.Accepted; 470 | p.stateMessage = 'Policy underwritten by oracle'; 471 | p.stateTime = now; 472 | 473 | LOG_PolicyAccepted( 474 | _policyId, 475 | _statistics[0], 476 | _statistics[1], 477 | _statistics[2], 478 | _statistics[3], 479 | _statistics[4], 480 | _statistics[5] 481 | ); 482 | 483 | } 484 | 485 | function decline(uint _policyId, bytes32 _reason, bytes _proof) internal { 486 | 487 | policy p = policies[_policyId]; 488 | 489 | p.state = policyState.Declined; 490 | p.stateMessage = _reason; 491 | p.stateTime = now; // won't be reverted in case of errors 492 | p.proof = _proof; 493 | bookkeeping(acc_Premium, acc_Balance, p.premium); 494 | 495 | if (!p.customer.send(p.premium)) { 496 | bookkeeping(acc_Balance, acc_RiskFund, p.premium); 497 | p.state = policyState.SendFailed; 498 | p.stateMessage = 'decline: Send failed.'; 499 | LOG_SendFail(_policyId, 'decline sendfail'); 500 | } 501 | else { 502 | LOG_PolicyDeclined(_policyId, _reason); 503 | } 504 | 505 | 506 | } 507 | 508 | function schedulePayoutOraclizeCall( 509 | uint _policyId, 510 | string _carrierFlightNumber, 511 | string _departureYearMonthDay, 512 | uint _oraclizeTime) 513 | internal { 514 | 515 | string memory oraclize_url = strConcat( 516 | oraclize_StatusBaseUrl, 517 | _carrierFlightNumber, 518 | _departureYearMonthDay, 519 | oraclizeStatusQuery 520 | ); 521 | 522 | bytes32 queryId = oraclize_query(_oraclizeTime, 'nested', oraclize_url, oraclizeGas); 523 | bookkeeping(acc_OraclizeCosts, acc_Balance, uint((-ledger[acc_Balance]) - int(this.balance))); 524 | oraclizeCallbacks[queryId] = oraclizeCallback(_policyId, oraclizeState.ForPayout, _oraclizeTime); 525 | 526 | LOG_OraclizeCall(_policyId, queryId, oraclize_url); 527 | } 528 | 529 | function payOut(uint _policyId, uint8 _delay, uint _delayInMinutes) 530 | notInMaintenance 531 | onlyOraclize 532 | onlyInState(_policyId, policyState.Accepted) 533 | internal { 534 | 535 | policy p = policies[_policyId]; 536 | risk r = risks[p.riskId]; 537 | r.delay = _delay; 538 | r.delayInMinutes = _delayInMinutes; 539 | 540 | if (_delay == 0) { 541 | p.state = policyState.Expired; 542 | p.stateMessage = 'Expired - no delay!'; 543 | p.stateTime = now; 544 | LOG_PolicyExpired(_policyId); 545 | } else { 546 | 547 | uint payout = p.premium * weightPattern[_delay] * 10000 / p.weight; 548 | p.calculatedPayout = payout; 549 | 550 | if (payout > maxPayout) { 551 | payout = maxPayout; 552 | } 553 | 554 | if (payout > uint(-ledger[acc_Balance])) { // don't go for chapter 11 555 | payout = uint(-ledger[acc_Balance]); 556 | } 557 | 558 | p.actualPayout = payout; 559 | bookkeeping(acc_Payout, acc_Balance, payout); // cash out payout 560 | 561 | 562 | if (!p.customer.send(payout)) { 563 | bookkeeping(acc_Balance, acc_Payout, payout); 564 | p.state = policyState.SendFailed; 565 | p.stateMessage = 'Payout, send failed!'; 566 | p.actualPayout = 0; 567 | LOG_SendFail(_policyId, 'payout sendfail'); 568 | } 569 | else { 570 | p.state = policyState.PaidOut; 571 | p.stateMessage = 'Payout successful!'; 572 | p.stateTime = now; // won't be reverted in case of errors 573 | LOG_PolicyPaidOut(_policyId, payout); 574 | } 575 | } 576 | 577 | } 578 | 579 | // fallback function: don't accept ether, except from owner 580 | function () onlyOwner { 581 | 582 | // put additional funds in risk fund. 583 | bookkeeping(acc_Balance, acc_RiskFund, msg.value); 584 | 585 | } 586 | 587 | // internal, so no reentrant guard neccessary 588 | function getFlightStats( 589 | uint _policyId, 590 | string _carrierFlightNumber) 591 | internal { 592 | 593 | // call oraclize and retrieve the number of observations from flightstats API 594 | // format https://api.flightstats.com/flex/ratings/rest/v1/json/flight/OS/75?appId=**&appKey=** 595 | 596 | // using nested data sources (query type nested) and partial 597 | // encrypted queries in the next release of oraclize 598 | // note that the first call maps the encrypted string to the 599 | // sending contract address, this string can't be used from any other sender 600 | string memory oraclize_url = strConcat( 601 | oraclize_RatingsBaseUrl, 602 | _carrierFlightNumber, 603 | oraclizeRatingsQuery 604 | ); 605 | 606 | bytes32 queryId = oraclize_query("nested", oraclize_url, oraclizeGas); 607 | // calculate the spent gas 608 | bookkeeping(acc_OraclizeCosts, acc_Balance, uint((-ledger[acc_Balance]) - int(this.balance))); 609 | oraclizeCallbacks[queryId] = oraclizeCallback(_policyId, oraclizeState.ForUnderwriting, 0); 610 | 611 | LOG_OraclizeCall(_policyId, queryId, oraclize_url); 612 | 613 | } 614 | 615 | // this is a dispatcher, but must be called __callback 616 | function __callback(bytes32 _queryId, string _result, bytes _proof) 617 | onlyOraclize 618 | noReentrant { 619 | 620 | oraclizeCallback memory o = oraclizeCallbacks[_queryId]; 621 | LOG_OraclizeCallback(o.policyId, _queryId, _result, _proof); 622 | 623 | if (o.oState == oraclizeState.ForUnderwriting) { 624 | callback_ForUnderwriting(o.policyId, _result, _proof); 625 | } 626 | else { 627 | callback_ForPayout(_queryId, _result, _proof); 628 | } 629 | } 630 | 631 | function callback_ForUnderwriting(uint _policyId, string _result, bytes _proof) 632 | onlyInState(_policyId, policyState.Applied) 633 | internal { 634 | 635 | var sl_result = _result.toSlice(); 636 | risk memory r = risks[policies[_policyId].riskId]; 637 | 638 | // we expect result to contain 6 values, something like 639 | // "[61, 10, 4, 3, 0, 0]" -> 640 | // ['observations','late15','late30','late45','cancelled','diverted'] 641 | 642 | if (bytes(_result).length == 0) { 643 | decline(_policyId, 'Declined (empty result)', _proof); 644 | } else { 645 | 646 | // now slice the string using 647 | // https://github.com/Arachnid/solidity-stringutils 648 | 649 | if (sl_result.count(', '.toSlice()) != 5) { // check if result contains 6 values 650 | decline(_policyId, 'Declined (invalid result)', _proof); 651 | } else { 652 | sl_result.beyond("[".toSlice()).until("]".toSlice()); 653 | 654 | uint observations = parseInt(sl_result.split(', '.toSlice()).toString()); 655 | 656 | // decline on < minObservations observations, 657 | // can't calculate reasonable probabibilities 658 | if (observations <= minObservations) { 659 | decline(_policyId, 'Declined (too few observations)', _proof); 660 | } else { 661 | uint[6] memory statistics; 662 | // calculate statistics (scaled by 100) 663 | statistics[0] = observations; 664 | for(uint i = 1; i <= 5; i++) { 665 | statistics[i] = 666 | parseInt(sl_result.split(', '.toSlice()).toString()) * 10000/observations; 667 | } 668 | 669 | // underwrite policy 670 | underwrite(_policyId, statistics, _proof); 671 | } 672 | } 673 | } 674 | } 675 | 676 | function callback_ForPayout(bytes32 _queryId, string _result, bytes _proof) internal { 677 | 678 | oraclizeCallback memory o = oraclizeCallbacks[_queryId]; 679 | uint policyId = o.policyId; 680 | var sl_result = _result.toSlice(); 681 | 682 | if (bytes(_result).length == 0) { 683 | // hmm ... bad! try again some minutes later ... 684 | schedulePayoutOraclizeCall(policyId, r.carrierFlightNumber, r.departureYearMonthDay, o.oraclizeTime + 45 minutes); 685 | } else { 686 | 687 | // first check status 688 | 689 | // extract the status field: 690 | sl_result.find('"'.toSlice()).beyond('"'.toSlice()); 691 | sl_result.until(sl_result.copy().find('"'.toSlice())); 692 | bytes1 status = bytes(sl_result.toString())[0]; // s = L 693 | 694 | if (status == 'C') { 695 | // flight cancelled --> payout 696 | payOut(policyId, 4, 0); 697 | return; 698 | } else if (status == 'D') { 699 | // flight diverted --> payout 700 | payOut(policyId, 5, 0); 701 | return; 702 | } else if (status != 'L' && status != 'A' && status != 'C' && status != 'D') { 703 | LOG_PolicyManualPayout(policyId, 'Unprocessable status'); 704 | return; 705 | } 706 | 707 | // process the rest of the response: 708 | sl_result = _result.toSlice(); 709 | bool arrived = sl_result.contains('actualGateArrival'.toSlice()); 710 | 711 | if (status == 'A' || (status == 'L' && !arrived)) { 712 | // flight still active or not at gate --> reschedule 713 | risk memory r = risks[policies[policyId].riskId]; 714 | if (o.oraclizeTime > r.arrivalTime + 120 minutes) { 715 | LOG_PolicyManualPayout(policyId, 'No arrival at +120 min'); 716 | } else { 717 | schedulePayoutOraclizeCall(policyId, r.carrierFlightNumber, r.departureYearMonthDay, o.oraclizeTime + 45 minutes); 718 | } 719 | } else if (status == 'L' && arrived) { 720 | var aG = '"arrivalGateDelayMinutes": '.toSlice(); 721 | if (sl_result.contains(aG)) { 722 | sl_result.find(aG).beyond(aG); 723 | sl_result.until(sl_result.copy().find('"'.toSlice()).beyond('"'.toSlice())); 724 | sl_result.until(sl_result.copy().find('}'.toSlice())); 725 | sl_result.until(sl_result.copy().find(','.toSlice())); 726 | uint delayInMinutes = parseInt(sl_result.toString()); 727 | } else { 728 | delayInMinutes = 0; 729 | } 730 | 731 | if (delayInMinutes < 15) { 732 | payOut(policyId, 0, 0); 733 | } else if (delayInMinutes < 30) { 734 | payOut(policyId, 1, delayInMinutes); 735 | } else if (delayInMinutes < 45) { 736 | payOut(policyId, 2, delayInMinutes); 737 | } else { 738 | payOut(policyId, 3, delayInMinutes); 739 | } 740 | } else { // no delay info 741 | payOut(policyId, 0, 0); 742 | } 743 | } 744 | } 745 | } 746 | --------------------------------------------------------------------------------