ERC20 exercise

 avatar
user_7432713
plain_text
15 days ago
3.9 kB
3
Indexable
Never
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import "./ERC20.sol";
import "./EnumerableSet.sol";

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

contract WeightedVoting is ERC20 {
    using EnumerableSet for EnumerableSet.AddressSet;
    uint256 public maxSupply;
    uint256 public totalClaimed;

    struct Issue {
        EnumerableSet.AddressSet voters;
        string issueDesc;
        uint256 votesFor;
        uint256 votesAgainst;
        uint256 votesAbstain;
        uint256 totalVotes;
        uint256 quorum;
        bool isPassed;
        bool isClosed;
    }

    struct ReturnableIssue {
        address[] voters; 
        string issueDesc;
        uint256 votesFor;
        uint256 votesAgainst;
        uint256 votesAbstain;
        uint256 totalVotes;
        uint256 quorum;
        bool isPassed;
        bool isClosed;
    }

    Issue[] issues;

    enum Votes { AGAINST, FOR, ABSTAIN }

    constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) {
        maxSupply = 1000000;
        issues.push();
    }

    function claim() external {
        if (totalClaimed == maxSupply) {
            revert AllTokensClaimed();
        }
       
        if (balanceOf(msg.sender) >= 100) {
            revert TokensClaimed();
        }

        _mint(msg.sender, 100);
        totalClaimed = totalClaimed + 100;
    }

    function createIssue(string memory _issueDesc, uint256 _quorum) external returns (uint256) {
        if (_quorum > totalClaimed) {
            revert QuorumTooHigh();
        }
         if (balanceOf(msg.sender) == 0) {
            revert NoTokensHeld();
        }

        uint256 newIssueIndex = issues.length;
        issues.push();
        Issue storage newIssue = issues[newIssueIndex];
        newIssue.issueDesc = _issueDesc;
        newIssue.quorum = _quorum;

        return newIssueIndex;
    }

    function getIssue(uint256 _issueId) external view returns (ReturnableIssue memory) {
        Issue storage issue = issues[_issueId];

        address[] memory issueVoters = new address[](issue.voters.length());
         for (uint256 i = 0; i < issue.voters.length(); i++){
            issueVoters[i] = issue.voters.at(i);
        }

        ReturnableIssue memory result;
        result.voters = issueVoters;
        result.issueDesc = issue.issueDesc;
        result.votesFor = issue.votesFor;
        result.votesAgainst = issue.votesAgainst;
        result.votesAbstain = issue.votesAbstain;
        result.totalVotes = issue.totalVotes;
        result.quorum = issue.quorum;
        result.isPassed = issue.isPassed;
        result.isClosed = issue.isClosed;

        return result;
    }

    function vote(uint256 _issueId, Votes _vote) external {
        Issue storage issue = issues[_issueId];

        if(issue.isClosed) {
            revert VotingClosed();
        }
        if(issue.voters.contains(msg.sender)) {
            revert AlreadyVoted();
        }

        uint256 voterBalance = balanceOf(msg.sender);

        if (_vote == Votes.FOR) {
            issue.votesFor += voterBalance;
        } else if (_vote == Votes.AGAINST) {
            issue.votesAgainst += voterBalance;
        } else if (_vote == Votes.ABSTAIN) {
            issue.votesAbstain += voterBalance;
        }

        issue.totalVotes += voterBalance;

        issue.voters.add(msg.sender);

        if (issue.totalVotes >= issue.quorum) {
            issue.isClosed = true;

            if (issue.votesFor > issue.votesAgainst) {
                issue.isPassed = true;
            }
            if (issue.quorum > totalSupply()) revert QuorumTooHigh();
            if (balanceOf(msg.sender) == 0) revert NoTokensHeld();
        }
    }
}
Leave a Comment