1. 启动ganache-cli
//cmd
ganache-cli
  1. 创建Voting目录,安装truffle模板

  2. 编写智能合约

// Voting/contracts/Voting.sol
pragma solidity >=0.4.22 <0.8.0;

contract Voting{
    bytes32[] public candidateList;
    mapping(bytes32 => uint8) public votesReceived;

    constructor(bytes32[] memory candidateListName) public {
        candidateList = candidateListName;
    }

    function voteForCandidate(bytes32 candidateName) public {
        require(validateCandidate(candidateName));
        votesReceived[candidateName] += 1;
    }

    function totalVotesFor(bytes32 candidateName) view public returns (uint8) {
        require(validateCandidate(candidateName));
        return votesReceived[candidateName];
    }

    function validateCandidate(bytes32 candidateName) internal view returns (bool) {
        for (uint8 i=0; i < candidateList.length; i++) {
            if (candidateName == candidateList[i]) {
                return true;
            }
        }
        return false;
    }
}
  1. 编译并部署智能合约
// Voting 目录下用cmd命令
truffle compile
truffle migrate
  1. 修改配置文件
// Voting/migrations/2_deploy_contracts.js


const Voting = artifacts.require('Voting')

module.exports = function(deployer) {
  deployer.deploy(Voting, [
  // 以下为ganache默认10个地址
      '0xdDc0eB90f015BCCa3FE5E66A3fA93bE2A85C295D',
      '0x60879543aeBfe29003bB4Ed1ba2A0eb52Ad2C4Db',
      '0x7a454ce98fA1579Dca442976C70A08b193Acf25a',
      '0xfC17042417b07cb401a084dabA2c3A1522E6a103',
      '0xe785cA40212beBb80c12c083fA558AAa325cF038',
      '0xE086301df6b83CdDc4Cb8414674FA95c9cF21fF4',
      '0x06739F807D0d466C33dD077C75B406293ECcc67d',
      '0x88CfaD631CD6776fB224c242e02074021B2DEc88',
      '0xB9e130a95965d34a9700630238E2C6edDde3bCe3',
      '0x9E824340973B7f0D00A839390411340D6E740a5D'
    ]
  )
};

  1. 修改html
// Voting/app/src/index.html
<!DOCTYPE html>
<html>
  <head>
    <title>My Voting Dapp</title>
  </head>
  <style>
  </style>
  <body>
    <h1>Voting Dapp</h1>
    <p>Alice: <strong id="alice">loading...</strong> tickets</p>
    <p>Bob: <strong id="bob">loading...</strong> tickets</p>

    <label>VoteFor:</label>
    <input type="text" id="candidate" />
    <button onclick="App.voteForCandidate()">vote</button>

    <script src="index.js"></script>
  </body>
</html>

  1. 修改js
// Voting/app/src/index.js

import Web3 from "web3";
import votingArtifact from "../../build/contracts/Voting.json";

const ainBytes32 = "0x60879543aeBfe29003bB4Ed1ba2A0eb52Ad2C4Db"
const binBytes32 = "0x7a454ce98fA1579Dca442976C70A08b193Acf25a"

const App = {
  web3: null,
  account: null,
  voting: null,

  start: async function() {
    const { web3 } = this;

    try {
      // get contract instance
      const networkId = await web3.eth.net.getId();
      const deployedNetwork = votingArtifact.networks[networkId];
      this.voting = new web3.eth.Contract(
        votingArtifact.abi,
        deployedNetwork.address,
      );

      // get accounts
      const accounts = await web3.eth.getAccounts();
      this.account = accounts[0];

      // this.refreshBalance()
      this.ready()
    } catch (error) {
      console.error("Could not connect to contract or chain.");
    }
  },

  refresh: async function(id, nameInBytes32) {
    const {totalVotesFor} = this.voting.methods;
    const tickets = await totalVotesFor(nameInBytes32).call()
    const element = document.getElementById(id)
    element.innerHTML = tickets.toString()
  },

  ready: async function() {
    try {
      this.refresh("alice", ainBytes32)
      this.refresh("bob", binBytes32)
    } catch (err) {
      console.log(err)
    }
  },

  voteForCandidate: async function() {
    try {
      const {voteForCandidate} = this.voting.methods
      const candidateName = document.getElementById('candidate').value

      if (candidateName === "Alice") {
        await voteForCandidate(ainBytes32).send({from: this.account})
        this.refresh('alice', ainBytes32)
      } else if (candidateName === "Bob") {
        await voteForCandidate(binBytes32).send({from: this.account})
        this.refresh('bob', binBytes32)
      }
    } catch (err) {
      console.log(err)
    }
  }

};

window.App = App;

window.addEventListener("load", function() {
  if (window.ethereum) {
    // use MetaMask's provider
    App.web3 = new Web3(window.ethereum);
    window.ethereum.enable(); // get permission to access accounts
  } else {
    console.warn(
      "No web3 detected. Falling back to http://127.0.0.1:8545. You should remove this fallback when you deploy live",
    );
    // fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)
    App.web3 = new Web3(
      new Web3.providers.HttpProvider("http://127.0.0.1:8545"),
    );
  }

  App.start();
});

  1. 测试
npm run dev

效果如下
sdklgnmdfkhis20220626095643

Q.E.D.


一个二次元web开发咸鱼