Untitled

 avatar
user_7432713
plain_text
a month ago
4.1 kB
11
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();
        }

        // Check if the voter has tokens
        if (balanceOf(msg.sender) > 0) {
            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;
                }
            }
        } else {
            revert NoTokensHeld(); // Revert if the voter has no tokens
        }
    }
}
Leave a Comment