Skip to content

huiyuyyds/ZJU_Block_study

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ZJU_Block_study

区块链投票网址制作

功能与实现分析

功能简介

  1. 学生登陆网站,注册后领取通证积分(浙大币)
  2. 使用100浙大币可以发起提案
  3. 提案在发起规定时间(默认5min)内,所有网站注册人员可使用100浙大币对提案进行投票(反对/赞成),且每人仅有一次投票机会。此外,任何人都可以选择将自己对某一提案的投票权委托给他人。
  4. 时间截止后,赞成数大于反对数,则提案通过,提案者可以自动获取500浙大币作为奖励。
  5. 当发布的提案累计通过3个时,有机会领取社团网站颁发的纪念品,每一个纪念品对应相应的ID,每一个ID对应了一张图片作为奖励。

合约代码分析

  1. 数据结构
uint256 constant public PUBLISH_AMOUNT = 100; // 发布提案的浙大币
uint256 constant public VOTE_AMOUNT = 100; // 投票的浙大币
int256 constant public Limit_TIME = 5 minutes; // 默认时间
address[] public players; // 注册人员列表
MyERC20 public myERC20; // 彩票相关的代币合约
MyERC721 public myERC721; // 奖励NFT代币合约
Proposal[] public proposals; // 所有发布提案储存区域
mapping(address => Voter) public voters; // 投票人地址映射为Voter型
mapping(address => uint256) public proposer; // 投票人地址对应的通过提案数
提案结构
struct Proposal {
    string name;   // 提案的名字
    string content; // 提案的内容
    uint approve; // 赞成的票数
    uint reject; // 反对的票数
    bool closed; // 投票是否关闭
    uint start; // 提案发布时间
    int256 remaintime; // 提案剩余时间
    bool publish; // 是否发布
    address proposer_in; // 发布者的名字
    bool get_credit; // 成功发布后是否已获得奖励
}
投票人结构
struct Voter {
    uint weight; // The weight of the vote count
    address delegate; // delegate
    uint agree_reject;
    bool[] proposal_voted;
}
  1. 注册与领取浙大币
// 加入投票提案圈
function join() external {
    players.push(msg.sender);
    proposer[msg.sender] = 0;
    for (uint i = 0; i < proposals.length; i++) {
        voters[msg.sender].proposal_voted.push(false);
    }
}
// 领取浙大币,每人一定时间内只能领取两次
function airdrop() external {
    require(claimedAirdropPlayerList[msg.sender] == false, "This user has claimed all airdrops already");
    _mint(msg.sender, 1000);
    count[msg.sender] = count[msg.sender] + 1;
    if (count[msg.sender] >= 2){
        claimedAirdropPlayerList[msg.sender] = true;
    }
}
  1. 发起提案
// 发布提案
function publishProposal(string memory _name, string memory _content) public {
    // 委托转账操作
    myERC20.transferFrom(msg.sender, address(this), PUBLISH_AMOUNT);
    // 把参与者加入到彩票池中
    ProposalInitial(_name, _content);
    // 给所有人员提供投票权
    for (uint256 i = 0; i < players.length; i++){
        givePermissionToVote(players[i]);
    }
    // 把提案加入到提案数组中
    proposals.push(proposal);
    refresh(); // 刷新相关参数
}
  1. 投票与委托
// 给提案投票,k=0表示反对,k=1表示赞成
function vote(uint k, uint index) public {
    Voter storage sender = voters[msg.sender];
    require(sender.weight>0, "You don't have right to vote.");
    require(!sender.proposal_voted[index], "Already voted this proposal.");
    sender.proposal_voted[index] = true;
    sender.agree_reject = k;
    if (k == 1){
        proposals[index].approve += sender.weight;
    }
    else{
        proposals[index].reject += sender.weight;
    }
}

// 参与投票, index表示提案的编号
function voteToProposal(uint index, uint k) public {
    // 投票操作
    myERC20.transferFrom(msg.sender, address(this), VOTE_AMOUNT); // 委托转账操作
    require(index < proposals.length, "Your proposal is not available"); // 验证
    vote(k, index); // 调用相关投票函数
    refresh();
}
// 把你的投票委托到投票者 to。
function delegate(address to, uint index) public {
    Voter storage sender = voters[msg.sender];
    require(!sender.proposal_voted[index], "You already voted."); // 判断是否已经投票

    require(to != msg.sender, "Self-delegation is disallowed."); // 判断委托人是否为自己

    while (voters[to].delegate != address(0)) {
        to = voters[to].delegate;

        // 不允许闭环委托
        require(to != msg.sender, "Found loop in delegation.");
    }

    sender.proposal_voted[index] = true; // 将自己变成已投票了
    sender.delegate = to;
    Voter storage delegate_ = voters[to];
    if (delegate_.proposal_voted[index]) {
        // 若被委托者已经投过票了,直接增加得票数
        if (delegate_.agree_reject == 1){
            proposal.approve += sender.weight;
        }
        else{
            proposal.reject += sender.weight;
        }
    } else {
        // 若被委托者还没投票,增加委托者的权重, 即授权这个委托者有投票权
        delegate_.weight += sender.weight;
    }
}
  1. 提案终止与浙大币返还
// 判断该提案是否通过
function judgePublish(uint index) internal {
    if (proposals[index].approve > proposals[index].reject && proposals[index].remaintime <= 0 && !proposals[index].publish) {
        proposals[index].closed = true;
        proposals[index].publish = true;
        proposer[proposals[index].proposer_in] += 1;
    }
    else {
        if (proposals[index].remaintime <= 0) {
            proposals[index].closed = true;
        }
    }
}
// 奖励500浙大币
function get_credit(address a) external {
    _mint(a, 500);
}
  1. 通过提案计数,与领取奖励
// 领取纪念品奖励
function getBonus() public returns(uint256) {
    uint256 Id = 0;
    require(proposer[msg.sender]>=3, "You don't have published more than three proposals.");
    Id = myERC721.awardItem(msg.sender, "https://pixabay.com/zh/photos/germany-bavaria-swiss-francs-7534750/");
    proposer[msg.sender] -= 3; // proposer是映射类型,对应通过的提案数
    return Id;
}
// 利用ERC721
function awardItem(address player, string memory tokenURI) public returns(uint256){
    _tokenIds.increment();

    uint256 newItemId = _tokenIds.current();
    _mint(player, newItemId);
    _setTokenURI(newItemId, tokenURI);

    return newItemId;
}

如何运行项目

  1. 在电脑上安装Node,ganache,hardhat。在浏览器中安装MetaMask插件。
  2. 将整个程序包下载到本地之后,按照下面操作进行
mkdir demo
cd demo
mkdir contracts
cd contracts
npx hardhat // 选择create typescript
将程序包中contracts的内容全部复制到该文件夹下(全部替换)【保留node_modules】
然后打开ganache软件,将获得的用户地址与url填入hardhat.config.ts
npm install @openzeppelin/contracts
npx hardhat compile 
npx hardhat run ./scripts/deploy.ts --network ganache
记录此时获得的三个合约的部署地址
cd ..
npx create-react-app front --template typescript
cd front
npm run start
在浏览器中看到网站出现后,说明操作无误,接下来将程序包中front文件夹下的所有内容拷贝到这个文件夹中(全部替换)【保留node_modules】,打开contract-addresses.json文件,将前面的合约地址对应填入。
npm install antd
npm install @ant-design/pro-components
npm install -D web3
npm run start
之后在浏览器中就可以进入网页,开始操作

关键界面和流程截图

开始界面 开始界面 开始界面 开始界面 开始界面 开始界面 开始界面 开始界面 开始界面 开始界面 开始界面 开始界面 开始界面 开始界面 开始界面 开始界面

About

区块链投票网址制作

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 80.7%
  • Solidity 15.1%
  • HTML 2.6%
  • CSS 1.6%