Rise In Logo

Build on Internet Computer with ICP Rust CDK

Creating Functions 3

Creating Functions 3

Finalizing the Voting Smart Contract: end_proposal and vote Functions

In the previous video, we built the edit_proposal function. In this lesson, we finalize the smart contract by implementing the remaining two core update functions: end_proposal and vote. These complete the functionality of our decentralized voting system.

Function 1: end_proposal

This function deactivates a proposal, preventing further votes.

Logic Breakdown:

  • Retrieve the Proposal
  • Use the proposal key to fetch the entry from the state.
  • If the proposal does not exist, return a VoteError::NoSuchProposal.
  • Verify Ownership
  • Ensure the caller is the proposal’s creator.
  • If not, return a VoteError::AccessRejected.
  • Update State
  • Set is_active to false.
  • Reinsert the modified proposal into the state.
  • If insertion succeeds, return Ok(()); otherwise, return VoteError::UpdateError.

Sample Implementation Outline:

#[update]
fn end_proposal(key: u64) -> Result<(), VoteError> {
    PROPOSAL_MAP.with(|p| {
        let mut p = p.borrow_mut();
        let proposal = match p.get(&key) {
            Some(p) => p.clone(),
            None => return Err(VoteError::NoSuchProposal),
        };
        if ic_cdk::caller() != proposal.owner {
            return Err(VoteError::AccessRejected);
        }

        let mut updated = proposal;
        updated.is_active = false;

        let result = p.insert(key, updated);
        match result {
            Some(_) => Ok(()),
            None => Err(VoteError::UpdateError),
        }
    })
}

Function 2: vote

This function allows users to cast a vote (approve, reject, or pass) on an active proposal.

Logic Breakdown:

  • Retrieve the Proposal
  • Similar to the previous function, check for the proposal’s existence.
  • Return VoteError::NoSuchProposal if not found.
  • Check Voting Eligibility
  • Ensure the user has not already voted (by checking the voted list).
  • Ensure the proposal is still active.
  • If either check fails, return the appropriate VoteError.
  • Cast the Vote
  • Increment the appropriate vote count (approve, reject, or pass) based on the Choice enum.
  • Add the caller’s address to the voted vector to prevent double voting.
  • Update the State
  • Insert the updated proposal.
  • Return Ok(()) on success or VoteError::UpdateError on failure.

Sample Implementation Outline:

#[update]
fn vote(key: u64, choice: Choice) -> Result<(), VoteError> {
    PROPOSAL_MAP.with(|p| {
        let mut p = p.borrow_mut();
        let mut proposal = match p.get(&key) {
            Some(p) => p.clone(),
            None => return Err(VoteError::NoSuchProposal),
        };

        let caller = ic_cdk::caller();
        if proposal.voted.contains(&caller) {
            return Err(VoteError::AlreadyVoted);
        }
        if !proposal.is_active {
            return Err(VoteError::ProposalIsNotActive);
        }

        match choice {
            Choice::Approve => proposal.approve += 1,
            Choice::Reject => proposal.reject += 1,
            Choice::Pass => proposal.pass += 1,
        }

        proposal.voted.push(caller);

        let result = p.insert(key, proposal);
        match result {
            Some(_) => Ok(()),
            None => Err(VoteError::UpdateError),
        }
    })
}

Conclusion

With the addition of end_proposal and vote, your voting smart contract is now complete. Each function follows a consistent pattern:

  • Retrieve state data.
  • Validate it.
  • Apply logic.
  • Write it back safely.
  • Return a clear result or error.

This pattern ensures the contract is secure, maintainable, and easy to understand.

Comments

You need to enroll in the course to be able to comment!

Stay in the know

Never miss updates on new programs and opportunities.

Rise In Logo

Rise together in web3!

Disclaimer: The information, programs, and events provided on https://risein.com is strictly for upskilling and networking purposes related to the technical infrastructure of blockchain platforms. We do not provide financial or investment advice, nor do we make any representations regarding the value, profitability, or future price of any blockchain or cryptocurrency. Users are encouraged to conduct their own research and consult with licensed financial professionals before engaging in any investment activities. https://risein.com disclaims any responsibility for financial decisions made by users based on the information provided here.