Untitled

 avatar
user_7432713
plain_text
a month ago
3.5 kB
2
Indexable
Never
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

contract WeightedVoting is ERC20 {
    uint public constant maxSupply = 1000000;

    error TokensClaimed();
    error AllTokensClaimed();
    error NoTokensHeld();
    error QuorumTooHigh(uint quorum);
    error AlreadyVoted();
    error VotingClosed();

    using EnumerableSet for EnumerableSet.AddressSet;

    struct Issue {
        EnumerableSet.AddressSet voters;
        string issueDesc;
        uint votesFor;
        uint votesAgainst;
        uint votesAbstain;
        uint totalVotes;
        uint quorum;
        bool passed;
        bool closed;
    }

    struct IssueView {
        string issueDesc;
        uint votesFor;
        uint votesAgainst;
        uint votesAbstain;
        uint totalVotes;
        uint quorum;
        bool passed;
        bool closed;
    }

    Issue[] private issues;
    mapping(uint => mapping(address => bool)) private hasVoted;
    mapping(uint => mapping(address => uint)) private voterTokens;
    mapping(address => bool) private hasClaimed;

    enum Votes { AGAINST, FOR, ABSTAIN }

    constructor() ERC20("WeightedVotingToken", "WVT") {
        _mint(address(this), maxSupply);
        _burn(address(this), maxSupply);
    }

    function claim() public {
        require(!hasClaimed[msg.sender], "TokensClaimed");
        require(totalSupply() < maxSupply, "AllTokensClaimed");
        _mint(msg.sender, 100);
        hasClaimed[msg.sender] = true;
    }

    function createIssue(string memory _issueDesc, uint _quorum) external returns(uint) {
        require(balanceOf(msg.sender) > 0, "NoTokensHeld");
        require(_quorum <= totalSupply(), "QuorumTooHigh");

        Issue storage newIssue = issues[issues.length];
        newIssue.issueDesc = _issueDesc;
        newIssue.quorum = _quorum;

        return issues.length - 1;
    }

    function getIssue(uint _id) external view returns (IssueView memory) {
        Issue storage issue = issues[_id];

        return IssueView({
            issueDesc: issue.issueDesc,
            votesFor: issue.votesFor,
            votesAgainst: issue.votesAgainst,
            votesAbstain: issue.votesAbstain,
            totalVotes: issue.totalVotes,
            quorum: issue.quorum,
            passed: issue.passed,
            closed: issue.closed
        });
    }

    function vote(uint _issueId, Votes _vote) public {
        require(balanceOf(msg.sender) > 0, "NoTokensHeld");
        Issue storage issue = issues[_issueId];
        require(!issue.closed, "VotingClosed");
        require(!hasVoted[_issueId][msg.sender], "AlreadyVoted");

        hasVoted[_issueId][msg.sender] = true;
        voterTokens[_issueId][msg.sender] = balanceOf(msg.sender);
        issue.totalVotes += balanceOf(msg.sender);

        if (_vote == Votes.FOR) {
            issue.votesFor += balanceOf(msg.sender);
        } else if (_vote == Votes.AGAINST) {
            issue.votesAgainst += balanceOf(msg.sender);
        } else if (_vote == Votes.ABSTAIN) {
            issue.votesAbstain += balanceOf(msg.sender);
        } else {
            revert("Invalid vote option");
        }

        if (issue.totalVotes >= issue.quorum) {
            issue.closed = true;
            issue.passed = issue.votesFor > issue.votesAgainst;
        }
    }
}
Leave a Comment