85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/chapter2/app/src/index.js:
--------------------------------------------------------------------------------
1 | import Web3 from "web3";
2 | import votingArtifact from "../../build/contracts/Voting.json";
3 |
4 | let candidates = {"Rama": "candidate-1", "Nick": "candidate-2", "Jose": "candidate-3"}
5 |
6 | const App = {
7 | web3: null,
8 | account: null,
9 | voting: null,
10 |
11 | start: async function() {
12 | const { web3 } = this;
13 |
14 | try {
15 | /* Get the network we are connected to and then read the build/contracts/Voting.json and instantiate a contract object to use
16 | */
17 |
18 | //
19 | const networkId = await web3.eth.net.getId();
20 | const deployedNetwork = votingArtifact.networks[networkId];
21 | this.voting = new web3.eth.Contract(
22 | votingArtifact.abi,
23 | deployedNetwork.address,
24 | );
25 |
26 | // get accounts
27 | const accounts = await web3.eth.getAccounts();
28 | this.account = accounts[0];
29 |
30 | this.loadCandidatesAndVotes();
31 | } catch (error) {
32 | console.error("Could not connect to contract or chain.");
33 | }
34 | },
35 |
36 | loadCandidatesAndVotes: async function() {
37 | const { totalVotesFor } = this.voting.methods;
38 | //const { sendCoin } = this.meta.methods;
39 | //await sendCoin(receiver, amount).send({ from: this.account });
40 | let candidateNames = Object.keys(candidates);
41 | for (var i = 0; i < candidateNames.length; i++) {
42 | let name = candidateNames[i];
43 | var count = await totalVotesFor(this.web3.utils.asciiToHex(name)).call();
44 | $("#" + candidates[name]).html(count);
45 | }
46 | },
47 |
48 | voteForCandidate: async function() {
49 | let candidateName = $("#candidate").val();
50 | $("#msg").html("Vote has been submitted. The vote count will increment as soon as the vote is recorded on the blockchain. Please wait.")
51 | $("#candidate").val("");
52 |
53 | const { totalVotesFor, voteForCandidate } = this.voting.methods;
54 |
55 |
56 | /* Voting.deployed() returns an instance of the contract. Every call
57 | * in Truffle returns a promise which is why we have used then()
58 | * everywhere we have a transaction call
59 | */
60 | await voteForCandidate(this.web3.utils.asciiToHex(candidateName)).send({gas: 140000, from: this.account});
61 | let div_id = candidates[candidateName];
62 | var count = await totalVotesFor(this.web3.utils.asciiToHex(candidateName)).call();
63 | $("#" + div_id).html(count);
64 | $("#msg").html("");
65 | }
66 |
67 | };
68 |
69 | window.App = App;
70 |
71 | window.addEventListener("load", function() {
72 | if (window.ethereum) {
73 | // use MetaMask's provider
74 | App.web3 = new Web3(window.ethereum);
75 | window.ethereum.enable(); // get permission to access accounts
76 | } else {
77 | console.warn(
78 | "No web3 detected. Falling back to http://127.0.0.1:8545. You should remove this fallback when you deploy live",
79 | );
80 | // fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)
81 | App.web3 = new Web3(
82 | new Web3.providers.HttpProvider("http://127.0.0.1:8545"),
83 | );
84 | }
85 |
86 | App.start();
87 | });
88 |
89 |
90 |
--------------------------------------------------------------------------------
/chapter4/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Hello World DApp
5 |
6 |
7 |
8 |
9 |
10 |
11 |
Decentralized Voting Application
12 |
Without voters having to pay gas
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
Candidate
22 |
Votes
23 |
24 |
25 |
26 |
27 |
Alice
28 |
29 |
30 |
31 |
Bob
32 |
33 |
34 |
35 |
Carol
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
Vote for your favorite candidate
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
Submit vote to blockchain
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/chapter4/app/javascripts/app.js:
--------------------------------------------------------------------------------
1 | // Import the page's CSS. Webpack will know what to do with it.
2 | import "../stylesheets/app.css";
3 |
4 | // Import libraries we need.
5 | import { default as Web3} from 'web3';
6 | import { default as contract } from 'truffle-contract';
7 | import { default as ethUtil} from 'ethereumjs-util';
8 | import { default as sigUtil} from 'eth-sig-util';
9 |
10 |
11 | /*
12 | * When you compile and deploy your Voting contract,
13 | * truffle stores the abi and deployed address in a json
14 | * file in the build directory. We will use this information
15 | * to setup a Voting abstraction. We will use this abstraction
16 | * later to create an instance of the Voting contract.
17 | * Compare this against the index.js from our previous tutorial to see the difference
18 | * https://gist.github.com/maheshmurthy/f6e96d6b3fff4cd4fa7f892de8a1a1b4#file-index-js
19 | */
20 |
21 | import voting_artifacts from '../../build/contracts/Voting.json'
22 |
23 | var Voting = contract(voting_artifacts);
24 |
25 | let candidates = {"Alice": "candidate-1", "Bob": "candidate-2", "Carol": "candidate-3"}
26 |
27 | window.submitVote = function(candidate) {
28 | let candidateName = $("#candidate-name").val();
29 | let signature = $("#voter-signature").val();
30 | let voterAddress = $("#voter-address").val();
31 |
32 | console.log(candidateName);
33 | console.log(signature);
34 | console.log(voterAddress);
35 |
36 | $("#msg").html("Vote has been submitted. The vote count will increment as soon as the vote is recorded on the blockchain. Please wait.")
37 |
38 | Voting.deployed().then(function(contractInstance) {
39 | contractInstance.voteForCandidate(candidateName, voterAddress, signature, {gas: 140000, from: web3.eth.accounts[0]}).then(function() {
40 | let div_id = candidates[candidateName];
41 | console.log(div_id);
42 | return contractInstance.totalVotesFor.call(candidateName).then(function(v) {
43 | console.log(v.toString());
44 | $("#" + div_id).html(v.toString());
45 | $("#msg").html("");
46 | });
47 | });
48 | });
49 | }
50 |
51 | window.voteForCandidate = function(candidate) {
52 | let candidateName = $("#candidate").val();
53 |
54 | let msgParams = [
55 | {
56 | type: 'string', // Any valid solidity type
57 | name: 'Message', // Any string label you want
58 | value: 'Vote for ' + candidateName // The value to sign
59 | }
60 | ]
61 |
62 | var from = web3.eth.accounts[0]
63 |
64 | var params = [msgParams, from]
65 | var method = 'eth_signTypedData'
66 |
67 | console.log("Hash is ");
68 | console.log(sigUtil.typedSignatureHash(msgParams));
69 |
70 | web3.currentProvider.sendAsync({
71 | method,
72 | params,
73 | from,
74 | }, function (err, result) {
75 | if (err) return console.dir(err)
76 | if (result.error) {
77 | alert(result.error.message)
78 | }
79 | if (result.error) return console.error(result)
80 | $("#msg").html("User wants to vote for " + candidateName + ". Any one can now submit the vote to the blockchain on behalf of this user. Use the below values to submit the vote to the blockchain");
81 | $("#vote-for").html("Candidate: " + candidateName);
82 | $("#addr").html("Address: " + from);
83 | $("#signature").html("Signature: " + result.result);
84 | console.log('PERSONAL SIGNED:' + JSON.stringify(result.result))
85 | })
86 | }
87 |
88 | $( document ).ready(function() {
89 | if (typeof web3 !== 'undefined') {
90 | console.warn("Using web3 detected from external source like Metamask")
91 | // Use Mist/MetaMask's provider
92 | window.web3 = new Web3(web3.currentProvider);
93 | } else {
94 | console.warn("No web3 detected. Falling back to http://localhost:8545. You should remove this fallback when you deploy live, as it's inherently insecure. Consider switching to Metamask for development. More info here: http://truffleframework.com/tutorials/truffle-and-metamask");
95 | // fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)
96 | window.web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
97 | }
98 |
99 | Voting.setProvider(web3.currentProvider);
100 | let candidateNames = Object.keys(candidates);
101 | for (var i = 0; i < candidateNames.length; i++) {
102 | let name = candidateNames[i];
103 | Voting.deployed().then(function(contractInstance) {
104 | contractInstance.totalVotesFor.call(name).then(function(v) {
105 | $("#" + candidates[name]).html(v.toString());
106 | });
107 | })
108 | }
109 | });
110 |
--------------------------------------------------------------------------------
/chapter2/truffle-config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Use this file to configure your truffle project. It's seeded with some
3 | * common settings for different networks and features like migrations,
4 | * compilation and testing. Uncomment the ones you need or modify
5 | * them to suit your project as necessary.
6 | *
7 | * More information about configuration can be found at:
8 | *
9 | * truffleframework.com/docs/advanced/configuration
10 | *
11 | * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider)
12 | * to sign your transactions before they're sent to a remote public node. Infura accounts
13 | * are available for free at: infura.io/register.
14 | *
15 | * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
16 | * public/private key pairs. If you're publishing your code to GitHub make sure you load this
17 | * phrase from a file you've .gitignored so it doesn't accidentally become public.
18 | *
19 | */
20 |
21 | // const HDWallet = require('truffle-hdwallet-provider');
22 | // const infuraKey = "fj4jll3k.....";
23 | //
24 | // const fs = require('fs');
25 | // const mnemonic = fs.readFileSync(".secret").toString().trim();
26 |
27 | module.exports = {
28 | /**
29 | * Networks define how you connect to your ethereum client and let you set the
30 | * defaults web3 uses to send transactions. If you don't specify one truffle
31 | * will spin up a development blockchain for you on port 9545 when you
32 | * run `develop` or `test`. You can ask a truffle command to use a specific
33 | * network from the command line, e.g
34 | *
35 | * $ truffle test --network
36 | */
37 |
38 | networks: {
39 | // Useful for testing. The `development` name is special - truffle uses it by default
40 | // if it's defined here and no other network is specified at the command line.
41 | // You should run a client (like ganache-cli, geth or parity) in a separate terminal
42 | // tab if you use this network and you must also set the `host`, `port` and `network_id`
43 | // options below to some value.
44 | //
45 | // development: {
46 | // host: "127.0.0.1", // Localhost (default: none)
47 | // port: 8545, // Standard Ethereum port (default: none)
48 | // network_id: "*", // Any network (default: none)
49 | // },
50 |
51 | develop: {
52 | host: 'localhost',
53 | port: 8545,
54 | gas: 6700000,
55 | network_id: '*'
56 | },
57 |
58 | // Another network with more advanced options...
59 | // advanced: {
60 | // port: 8777, // Custom port
61 | // network_id: 1342, // Custom network
62 | // gas: 8500000, // Gas sent with each transaction (default: ~6700000)
63 | // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
64 | // from: , // Account to send txs from (default: accounts[0])
65 | // websockets: true // Enable EventEmitter interface for web3 (default: false)
66 | // },
67 |
68 | // Useful for deploying to a public network.
69 | // NB: It's important to wrap the provider as a function.
70 | // ropsten: {
71 | // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
72 | // network_id: 3, // Ropsten's id
73 | // gas: 5500000, // Ropsten has a lower block limit than mainnet
74 | // confirmations: 2, // # of confs to wait between deployments. (default: 0)
75 | // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
76 | // skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
77 | // },
78 |
79 | // Useful for private networks
80 | // private: {
81 | // provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
82 | // network_id: 2111, // This network is yours, in the cloud.
83 | // production: true // Treats this network as if it was a public net. (default: false)
84 | // }
85 | },
86 |
87 | // Set default mocha options here, use special reporters etc.
88 | mocha: {
89 | // timeout: 100000
90 | },
91 |
92 | // Configure your compilers
93 | compilers: {
94 | solc: {
95 | version: "0.6.4", // Fetch exact version from solc-bin (default: truffle's version)
96 | // docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
97 | // settings: { // See the solidity docs for advice about optimization and evmVersion
98 | // optimizer: {
99 | // enabled: false,
100 | // runs: 200
101 | // },
102 | // evmVersion: "byzantium"
103 | // }
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/chapter3/contracts/Voting.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.4.18; //We have to specify what version of the compiler this code will use
2 |
3 | contract Voting {
4 |
5 | // We use the struct datatype to store the voter information.
6 | struct voter {
7 | address voterAddress; // The address of the voter
8 | uint tokensBought; // The total no. of tokens this voter owns
9 | uint[] tokensUsedPerCandidate; // Array to keep track of votes per candidate.
10 | /* We have an array of candidates initialized below.
11 | Every time this voter votes with her tokens, the value at that
12 | index is incremented. Example, if candidateList array declared
13 | below has ["Rama", "Nick", "Jose"] and this
14 | voter votes 10 tokens to Nick, the tokensUsedPerCandidate[1]
15 | will be incremented by 10.
16 | */
17 | }
18 |
19 | /* mapping is equivalent to an associate array or hash
20 | The key of the mapping is candidate name stored as type bytes32 and value is
21 | an unsigned integer which used to store the vote count
22 | */
23 |
24 | mapping (address => voter) public voterInfo;
25 |
26 | /* Solidity doesn't let you return an array of strings yet. We will use an array of bytes32
27 | instead to store the list of candidates
28 | */
29 |
30 | mapping (bytes32 => uint) public votesReceived;
31 |
32 | bytes32[] public candidateList;
33 |
34 | uint public totalTokens; // Total no. of tokens available for this election
35 | uint public balanceTokens; // Total no. of tokens still available for purchase
36 | uint public tokenPrice; // Price per token
37 |
38 | /* When the contract is deployed on the blockchain, we will initialize
39 | the total number of tokens for sale, cost per token and all the candidates
40 | */
41 | function Voting(uint tokens, uint pricePerToken, bytes32[] candidateNames) public {
42 | candidateList = candidateNames;
43 | totalTokens = tokens;
44 | balanceTokens = tokens;
45 | tokenPrice = pricePerToken;
46 | }
47 |
48 | function totalVotesFor(bytes32 candidate) view public returns (uint) {
49 | return votesReceived[candidate];
50 | }
51 |
52 | /* Instead of just taking the candidate name as an argument, we now also
53 | require the no. of tokens this voter wants to vote for the candidate
54 | */
55 | function voteForCandidate(bytes32 candidate, uint votesInTokens) public {
56 | uint index = indexOfCandidate(candidate);
57 | require(index != uint(-1));
58 |
59 | // msg.sender gives us the address of the account/voter who is trying
60 | // to call this function
61 | if (voterInfo[msg.sender].tokensUsedPerCandidate.length == 0) {
62 | for(uint i = 0; i < candidateList.length; i++) {
63 | voterInfo[msg.sender].tokensUsedPerCandidate.push(0);
64 | }
65 | }
66 |
67 | // Make sure this voter has enough tokens to cast the vote
68 | uint availableTokens = voterInfo[msg.sender].tokensBought - totalTokensUsed(voterInfo[msg.sender].tokensUsedPerCandidate);
69 | require(availableTokens >= votesInTokens);
70 |
71 | votesReceived[candidate] += votesInTokens;
72 |
73 | // Store how many tokens were used for this candidate
74 | voterInfo[msg.sender].tokensUsedPerCandidate[index] += votesInTokens;
75 | }
76 |
77 | // Return the sum of all the tokens used by this voter.
78 | function totalTokensUsed(uint[] _tokensUsedPerCandidate) private pure returns (uint) {
79 | uint totalUsedTokens = 0;
80 | for(uint i = 0; i < _tokensUsedPerCandidate.length; i++) {
81 | totalUsedTokens += _tokensUsedPerCandidate[i];
82 | }
83 | return totalUsedTokens;
84 | }
85 |
86 | function indexOfCandidate(bytes32 candidate) view public returns (uint) {
87 | for(uint i = 0; i < candidateList.length; i++) {
88 | if (candidateList[i] == candidate) {
89 | return i;
90 | }
91 | }
92 | return uint(-1);
93 | }
94 |
95 | /* This function is used to purchase the tokens. Note the keyword 'payable'
96 | below. By just adding that one keyword to a function, your contract can
97 | now accept Ether from anyone who calls this function. Accepting money can
98 | not get any easier than this!
99 | */
100 |
101 | function buy() payable public returns (uint) {
102 | uint tokensToBuy = msg.value / tokenPrice;
103 | require(tokensToBuy <= balanceTokens);
104 | voterInfo[msg.sender].voterAddress = msg.sender;
105 | voterInfo[msg.sender].tokensBought += tokensToBuy;
106 | balanceTokens -= tokensToBuy;
107 | return tokensToBuy;
108 | }
109 |
110 | function tokensSold() view public returns (uint) {
111 | return totalTokens - balanceTokens;
112 | }
113 |
114 | function voterDetails(address user) view public returns (uint, uint[]) {
115 | return (voterInfo[user].tokensBought, voterInfo[user].tokensUsedPerCandidate);
116 | }
117 |
118 | /* All the ether sent by voters who purchased the tokens is in this
119 | contract's account. This method will be used to transfer out all those ethers
120 | in to another account. *** The way this function is written currently, anyone can call
121 | this method and transfer the balance in to their account. In reality, you should add
122 | check to make sure only the owner of this contract can cash out.
123 | */
124 |
125 | function transferTo(address account) public {
126 | account.transfer(this.balance);
127 | }
128 |
129 | function allCandidates() view public returns (bytes32[]) {
130 | return candidateList;
131 | }
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/chapter3/app/javascripts/app.js:
--------------------------------------------------------------------------------
1 | // Import the page's CSS. Webpack will know what to do with it.
2 | import "../stylesheets/app.css";
3 |
4 | // Import libraries we need.
5 | import { default as Web3} from 'web3';
6 | import { default as contract } from 'truffle-contract'
7 |
8 | /*
9 | * When you compile and deploy your Voting contract,
10 | * truffle stores the abi and deployed address in a json
11 | * file in the build directory. We will use this information
12 | * to setup a Voting abstraction. We will use this abstraction
13 | * later to create an instance of the Voting contract.
14 | * Compare this against the index.js from our previous tutorial to see the difference
15 | * https://gist.github.com/maheshmurthy/f6e96d6b3fff4cd4fa7f892de8a1a1b4#file-index-js
16 | */
17 |
18 | import voting_artifacts from '../../build/contracts/Voting.json'
19 |
20 | var Voting = contract(voting_artifacts);
21 |
22 | let candidates = {}
23 |
24 | let tokenPrice = null;
25 |
26 | window.voteForCandidate = function(candidate) {
27 | let candidateName = $("#candidate").val();
28 | let voteTokens = $("#vote-tokens").val();
29 | $("#msg").html("Vote has been submitted. The vote count will increment as soon as the vote is recorded on the blockchain. Please wait.")
30 | $("#candidate").val("");
31 | $("#vote-tokens").val("");
32 |
33 | /* Voting.deployed() returns an instance of the contract. Every call
34 | * in Truffle returns a promise which is why we have used then()
35 | * everywhere we have a transaction call
36 | */
37 | Voting.deployed().then(function(contractInstance) {
38 | contractInstance.voteForCandidate(candidateName, voteTokens, {gas: 140000, from: web3.eth.accounts[0]}).then(function() {
39 | let div_id = candidates[candidateName];
40 | return contractInstance.totalVotesFor.call(candidateName).then(function(v) {
41 | $("#" + div_id).html(v.toString());
42 | $("#msg").html("");
43 | });
44 | });
45 | });
46 | }
47 |
48 | /* The user enters the total no. of tokens to buy. We calculate the total cost and send it in
49 | * the request. We have to send the value in Wei. So, we use the toWei helper method to convert
50 | * from Ether to Wei.
51 | */
52 |
53 | window.buyTokens = function() {
54 | let tokensToBuy = $("#buy").val();
55 | let price = tokensToBuy * tokenPrice;
56 | $("#buy-msg").html("Purchase order has been submitted. Please wait.");
57 | Voting.deployed().then(function(contractInstance) {
58 | contractInstance.buy({value: web3.toWei(price, 'ether'), from: web3.eth.accounts[0]}).then(function(v) {
59 | $("#buy-msg").html("");
60 | web3.eth.getBalance(contractInstance.address, function(error, result) {
61 | $("#contract-balance").html(web3.fromWei(result.toString()) + " Ether");
62 | });
63 | })
64 | });
65 | populateTokenData();
66 | }
67 |
68 | window.lookupVoterInfo = function() {
69 | let address = $("#voter-info").val();
70 | Voting.deployed().then(function(contractInstance) {
71 | contractInstance.voterDetails.call(address).then(function(v) {
72 | $("#tokens-bought").html("Total Tokens bought: " + v[0].toString());
73 | let votesPerCandidate = v[1];
74 | $("#votes-cast").empty();
75 | $("#votes-cast").append("Votes cast per candidate: ");
76 | let allCandidates = Object.keys(candidates);
77 | for(let i=0; i < allCandidates.length; i++) {
78 | $("#votes-cast").append(allCandidates[i] + ": " + votesPerCandidate[i] + " ");
79 | }
80 | });
81 | });
82 | }
83 |
84 | /* Instead of hardcoding the candidates hash, we now fetch the candidate list from
85 | * the blockchain and populate the array. Once we fetch the candidates, we setup the
86 | * table in the UI with all the candidates and the votes they have received.
87 | */
88 | function populateCandidates() {
89 | Voting.deployed().then(function(contractInstance) {
90 | contractInstance.allCandidates.call().then(function(candidateArray) {
91 | for(let i=0; i < candidateArray.length; i++) {
92 | /* We store the candidate names as bytes32 on the blockchain. We use the
93 | * handy toUtf8 method to convert from bytes32 to string
94 | */
95 | candidates[web3.toUtf8(candidateArray[i])] = "candidate-" + i;
96 | }
97 | setupCandidateRows();
98 | populateCandidateVotes();
99 | populateTokenData();
100 | });
101 | });
102 | }
103 |
104 | function populateCandidateVotes() {
105 | let candidateNames = Object.keys(candidates);
106 | for (var i = 0; i < candidateNames.length; i++) {
107 | let name = candidateNames[i];
108 | Voting.deployed().then(function(contractInstance) {
109 | contractInstance.totalVotesFor.call(name).then(function(v) {
110 | $("#" + candidates[name]).html(v.toString());
111 | });
112 | });
113 | }
114 | }
115 |
116 | function setupCandidateRows() {
117 | Object.keys(candidates).forEach(function (candidate) {
118 | $("#candidate-rows").append("
" + candidate + "
");
119 | });
120 | }
121 |
122 | /* Fetch the total tokens, tokens available for sale and the price of
123 | * each token and display in the UI
124 | */
125 | function populateTokenData() {
126 | Voting.deployed().then(function(contractInstance) {
127 | contractInstance.totalTokens().then(function(v) {
128 | $("#tokens-total").html(v.toString());
129 | });
130 | contractInstance.tokensSold.call().then(function(v) {
131 | $("#tokens-sold").html(v.toString());
132 | });
133 | contractInstance.tokenPrice().then(function(v) {
134 | tokenPrice = parseFloat(web3.fromWei(v.toString()));
135 | $("#token-cost").html(tokenPrice + " Ether");
136 | });
137 | web3.eth.getBalance(contractInstance.address, function(error, result) {
138 | $("#contract-balance").html(web3.fromWei(result.toString()) + " Ether");
139 | });
140 | });
141 | }
142 |
143 | $( document ).ready(function() {
144 | if (typeof web3 !== 'undefined') {
145 | console.warn("Using web3 detected from external source like Metamask")
146 | // Use Mist/MetaMask's provider
147 | window.web3 = new Web3(web3.currentProvider);
148 | } else {
149 | console.warn("No web3 detected. Falling back to http://localhost:8545. You should remove this fallback when you deploy live, as it's inherently insecure. Consider switching to Metamask for development. More info here: http://truffleframework.com/tutorials/truffle-and-metamask");
150 | // fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)
151 | window.web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
152 | }
153 |
154 | Voting.setProvider(web3.currentProvider);
155 | populateCandidates();
156 |
157 | });
158 |
--------------------------------------------------------------------------------