0

Task: Create an event ProposalCreated which takes a single argument: a uint proposal ID. Emit this event whenever a new Proposal struct is created. Create an event VoteCast which takes two arguments: a uint proposal ID and an address for the voter's address. Emit this event any time a new vote is cast. enter image description here

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

contract Voting {
    struct Proposal {
        address target;
        bytes data;
        uint yesCount;
        uint noCount;
        mapping(address => bool) hasVoted; // Track if an address has voted on this proposal
        mapping(address => bool) voteChoice; // Track the vote (true = yes, false = no) of each voter
    }

    // Events
    event ProposalCreated(uint256 indexed proposalId); // Event to be emitted when a proposal is created
    event VoteCast(uint256 indexed proposalId, address indexed voteCaster); // Event to be emitted when a vote is cast

    Proposal[] public proposals;

    // Function to create a new proposal
    function newProposal(address target, bytes memory data) external {
        require(target != address(0), "Target address cannot be zero"); // Ensure target is valid

        Proposal storage proposal = proposals.push(); // Add a new proposal to the array
        proposal.target = target;
        proposal.data = data;

        uint proposalId = proposals.length - 1; // Get the ID of the new proposal

        emit ProposalCreated(proposalId); // Emit the ProposalCreated event with the proposal ID
    }

    // Function to cast or change a vote on a proposal
    function castVote(uint proposalId, bool support) external {
        require(proposalId < proposals.length, "Invalid proposal ID");

        Proposal storage proposal = proposals[proposalId];

        // Check if the voter has already voted
        if (proposal.hasVoted[msg.sender]) {
            // If the voter wants to change their vote, update counts accordingly
            bool previousVote = proposal.voteChoice[msg.sender];
            if (previousVote && !support) {
                proposal.yesCount -= 1;
                proposal.noCount += 1;
            } else if (!previousVote && support) {
                proposal.noCount -= 1;
                proposal.yesCount += 1;
            }
        } else {
            // If the voter hasn't voted before, add their vote
            proposal.hasVoted[msg.sender] = true;
            if (support) {
                proposal.yesCount += 1;
            } else {
                proposal.noCount += 1;
            }
        }

        // Store the voter's choice (true = yes, false = no)
        proposal.voteChoice[msg.sender] = support;

        emit VoteCast(proposalId, msg.sender); // Emit the VoteCast event with the proposal ID and the voter's address
    }
}

1 Answer 1

0

Edit: Here you can find a more in depth explaination of your voting process, below find some info how to approach and structure youre contract.

  • Move the hasVoted and voteChoice mappings outside the Proposal struct to track votes more effectively
  • Then you can update newProposal function to create a new proposal using Proposal memory
  • Then you can build the castVote function to use the external mappings for tracking votes

brief overview

Define your propsal struct. Create your events, one when a new proposal is created, one for vote cast. Then we create an array where we store all the proposals. With the mappings, we track whether an address has voted & their vote choice. Then we create 3 functions: to create a new proposal, to cast a vote, to get all votes.

example code

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.2 <0.9.0;

contract Voting {

    // 1. DEFINE STRUCT PROPOSAL --------------------------------

    struct Proposal {
        address target; 
        bytes data;
        uint256 yesCount;
        uint256 noCount;
    }

    // 2. CREATE YOUR EVENTS ------------------------------------

    event ProposalCreated(uint256 indexed proposalId);
    event VoteCast(uint256 indexed proposalId, address indexed voter, bool support);

    // 3. CREATE AN ARRAY OF PROPOSALS --------------------------

    Proposal[] public proposals;

    // 4. CREATE MAPPINGS ---------------------------------------

    mapping(uint256 => mapping(address => bool)) public hasVoted;
    mapping(uint256 => mapping(address => bool)) public voteChoice; 

    // 5. FUNCTION FOR NEW PROPOSAL -----------------------------

    function newProposal(address target, bytes memory data) external {       
        // make sure target is valid
        require(target != address(0), "Target address cannot be zero");

        Proposal memory proposal = Proposal({
            target: target,
            data: data,
            yesCount: 0,
            noCount: 0
        });
        // add new proposal to Proposal array
        proposals.push(proposal); 
        // get id of new proposal
        uint256 proposalId = proposals.length - 1;

        // emit event
        emit ProposalCreated(proposalId);
    }

    // 6. FUNCTION TO CAST VOTE ON PROPOSAL ---------------------

    function castVote(uint256 proposalId, bool support) external {
     // nnsure valid proposal id      
        require(proposalId < proposals.length, "Invalid proposal ID"); 

        // Ensure user has not voted yet
        require(!hasVoted[proposalId][msg.sender], "You have already voted on this proposal"); 
        // Update the vote counts
        if (support) {
            proposals[proposalId].yesCount += 1;
        } else {
            proposals[proposalId].noCount += 1;
        }

        // Mark user has voted & store their choice
        hasVoted[proposalId][msg.sender] = true;
        voteChoice[proposalId][msg.sender] = support;

        // emit event
        emit VoteCast(proposalId, msg.sender, support);

    // 7. FUNCTION TO GET VOTES ON PROPOSAL ---------------------

    function getProposalVotes(uint256 proposalId) external view returns (uint256 yesVotes, uint256 noVotes) {
        // ensure valid proposal id
        require(proposalId < proposals.length, "Invalid proposal ID"); 
        // get proposal
        Proposal storage proposal = proposals[proposalId];
        // return vote counts
        return (proposal.yesCount, proposal.noCount);
    }
}
2
  • I followed your corrections but I still got the same error testProposal() EvmError: Revert testVote() Test Passed Commented Oct 22 at 0:58
  • @EddiePumpin you may check my updated answer.
    – timsntech
    Commented Oct 23 at 15:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.