Published on

Web3 示例

Authors
  • avatar
    Name
    MissTree
    Twitter

投票系统

投票合约

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Voting {
    // 投票人结构体
    struct Voter {
        uint256 id; // 投票的候选人id
        uint256 amount; // 投票数量
        bool voted; // 是否已经投票
        address voterAddress; // 投票人地址
    }
    // 投票看板结构体
    struct Board {
        uint256 id;
        string name; // 候选人姓名
        uint256 totalAmount; // 票数
    }
    // 主持人信息
    address public host;

    mapping(address => Voter) public voters;
    Board public board;

    constructor(string[] memory nameLists) {
        host = msg.sender;
        // 给主持人初始化一票
        voters[host].amount = 1;

        for (uint256 i = 0; i < nameLists.length; i++) {
            board memory BoardItem = Board(nameLists[i], 0);
            board.push(BoardItem);
        }
    }
    // 返回看板集合
    function getBoardInfo( ) public view returns (Board[] memory) {
        rturn board;
    }
    // 给某些地址赋予选票
    function mandate(address[] calldata addressesList) public  {
        // 只有主持人可以调用此方法
        require(msg.sender == host, "只有自己有投票权");
        for (uint256 i = 0; i < addressesList.length; i++) {
          if(!voters[addressesList[i]].voted){
            voters[addressesList[i]].amount = 1;
          }
        }
    }
    // 委托投票给他人
    function delegate(address to) public {
      // 委托人的地址
      Voter storage sender = voters[msg.sender];
      require(sender.amount != 0, "没有投票权");
      require(!sender.voted, "已经投过票了");
      require(to != msg.sender, "不能委托给自己");
      require(to != address(0), "不能委托给空地址");
      // 检查是否是循环委托
      while (voters[to].delegator != address(0)) {
        to = voters[to].delegator;
        require(to == msg.sender, "不能循环授权");
      }
      // 开始授权
      sender.voted = true;
      sender.delegator = to;
      //
      Voter storage delegate_ = voters[to];
      if (delegate_.voted) {
        // 如果委托的人已经投票了,那么票数就加到委托人的id上
        board[delegate_.id].totalAmount += sender.amount;
      } else {
        // 如果委托的人还没有投票,那么票数就加到委托人的amount上
        delegate_.amount += sender.amount;
      }
    }
    // 投票
    function vote(unit256 id) public {
      Voter storage sender = voters[msg.sender];
      require(sender.amount != 0, "没有投票权");
      require(!sender.voted, "已经投过票了");
      require(id < board.length, "投票id不存在");
      sender.voted = true;
      sender.id = id;
      board[id].totalAmount += sender.amount;
      emit(VoteEvent(unicode'投票成功');
    }
    // 投票成功事件
    event VoteEvent(string);
}

投票前端

将上面的合约在remix上编译,然后使用编译的Json文件,复制到 /contracts/Voting.json 中,然后使用web3.js来调用合约。

// hooks/useWeb3.js
const useWeb3 = () => {
  import Web3 from "web3";
  import VoteJson from "../contracts/Voting.json"; // 合约Json文件,看自己情况而定
  const web3 = new Web3(Web3.givenProvider || "http://localhost:8545");
  // ContractAddress 看自己合约地址
  const ContractAddress = "0x5FbDB2315678afecb367f032d93F642f64180aa3";
  const contract = new web3.eth.Contract(VoteJson.abi, ContractAddress);
  const getAccount = async () => {
    const accounts = await web3.eth.requestAccounts();
    return accounts[0];
  }

  return {
    web3,
    contract,
    getAccount,
    ContractAddress,
  }
}

export default useWeb3;


import useWeb3 from "./useWeb3";


const { web3,contract, ContractAddress,getAccount } = useWeb3();

// 调用合约的方法
const getHostInfo = async () => {
  const boardInfo = await contract.methods.host().call();
}

// 后续通过调用合约的方法进行投票、委托等操作

合约

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract FundToken {
    // 1. 通证的名字
    // 2. 通证的简称
    // 3. 通证的发行数量
    // 4. owner地址
    // 5. balance address => uint256
    string public tokenName;
    string public tokenSymbol;
    uint256 public totalSupply;
    address public owner;
    mapping(address => uint256) public balances;

    constructor(string memory _tokenName, string memory _tokenSymbol) {
        tokenName = _tokenName;
        tokenSymbol = _tokenSymbol;
        owner = msg.sender;
    }

    // mint: 获取通证
    function mint(uint256 amountToMint) public {
        balances[msg.sender] += amountToMint;
        totalSupply += amountToMint;
    }

    // transfer: transfer 通证
    function transfer(address payee, uint256 amount) public {
        require(balances[msg.sender] >= amount, "You do not have enough balance to transfer");
        balances[msg.sender] -= amount;
        balances[payee] += amount;
    } 

    // balanceOf: 查看某一个地址的通证数量
    function balanceOf(address addr) public view returns(uint256) {
        return balances[addr];
    }

}