Create a public constructor which takes an array of address. These addresses, plus the deployer of the function, should all be allowed to create new proposals and vote on those proposals. 创建一个公共的constructor,该函数接受一个address数组作为参数。这些地址以及该函数的部署者都应被允许创建新提案并对这些提案进行投票。 If anyone else attempts to create a proposal or vote, the call should be reverted. 如果有其他人试图创建提案或进行投票,调用应被回滚。
// Mapping to track members who can create proposals and vote mapping(address => bool) public members;
// Constructor to initialize the contract with allowed members constructor(address[] memory _members) { // Add the deployer as a member members[msg.sender] = true;
// Add all addresses from the input array as members for (uint i = 0; i < _members.length; i++) { members[_members[i]] = true; } }
// Modifier to ensure only members can create proposals and vote modifier onlyMember() { require(members[msg.sender], "Not authorized to perform this action"); _; }
eventProposalCreated(uint proposalId); eventVoteCast(uint proposalId, address voter); // Mapping to track if an address has voted on a particular proposal mapping(uint => mapping(address => bool)) public hasVoted;
// Mapping to store the vote (true = yes, false = no) of each address for each proposal mapping(uint => mapping(address => bool)) public votes;
// Function to create a new proposal function newProposal(address addr, bytes calldata data) onlyMember external { Proposal memory newProposalInstance = Proposal(addr, data, 0, 0); proposals.push(newProposalInstance); emit ProposalCreated(proposals.length - 1); // proposalId is the index of the newly added proposal //每当创建新的Proposal结构体时,就触发该事件。 }
// Function to cast or change a vote function castVote(uint proposalId, bool support) onlyMember external { // Ensure the proposal exists require(proposalId < proposals.length, "Proposal does not exist");
// Retrieve the proposal to update its vote counts Proposal storage targetProposal = proposals[proposalId];
// If the voter has already voted, we need to change their vote if (hasVoted[proposalId][msg.sender]) { emit VoteCast(proposalId, msg.sender); // If the voter previously voted "yes" and now votes "no" if (votes[proposalId][msg.sender] == true && !support) { targetProposal.yesCount -= 1; // Decrease yesCount targetProposal.noCount += 1; // Increase noCount } // If the voter previously voted "no" and now votes "yes" elseif (votes[proposalId][msg.sender] == false && support) { targetProposal.noCount -= 1; // Decrease noCount targetProposal.yesCount += 1; // Increase yesCount } } else { emit VoteCast(proposalId, msg.sender); // If the voter has not voted yet, just increase the respective count if (support) { targetProposal.yesCount += 1; } else { targetProposal.noCount += 1; } }
// Update the voter's choice votes[proposalId][msg.sender] = support;
// Mark that this address has voted for this proposal hasVoted[proposalId][msg.sender] = true; } }
Your Goal: Execute 你的目标:执行
Let’s make our minimum voting threshold be 10 participants. Once 10 members have voted yes on a proposal, execute it. 让我们将最低投票门槛设为10名参与者。一旦有10名成员对某项提案投了赞成票,就执行该提案。
Update the castVote function to execute the proposal when the 10 yes votes have been registered. 更新castVote函数,以便在登记到10张赞成票时执行该提案。 Execute the vote by sending the data to the target address using the call syntax. 使用call语法将data发送到target地址来执行投票。
// Constructor to initialize the contract with allowed members constructor(address[] memory _members) { // Add the deployer as a member members[msg.sender] = true;
// Add all addresses from the input array as members for (uint i = 0; i < _members.length; i++) { members[_members[i]] = true; } }
// Modifier to ensure only members can create proposals and vote modifier onlyMember() { require(members[msg.sender], "Not authorized to perform this action"); _; } eventProposalExecuted(uint proposalId); eventProposalCreated(uint proposalId); eventVoteCast(uint proposalId, address voter); // Mapping to track if an address has voted on a particular proposal mapping(uint => mapping(address => bool)) public hasVoted;
// Mapping to store the vote (true = yes, false = no) of each address for each proposal mapping(uint => mapping(address => bool)) public votes;
mapping(uint => uint) public supportingVotes;
// Mapping to track members who can create proposals and vote mapping(address => bool) public members;
// Function to create a new proposal function newProposal(address addr, bytes calldata data) onlyMember external { Proposal memory newProposalInstance = Proposal(addr, data, 0, 0); proposals.push(newProposalInstance); emit ProposalCreated(proposals.length - 1); // proposalId is the index of the newly added proposal //每当创建新的Proposal结构体时,就触发该事件。 }
// Function to cast or change a vote function castVote(uint proposalId, bool support) onlyMember external { //number10 = 0 //这个变量从0开始,一旦有10名成员对某项提案投了赞成票,就执行该提案。 // Ensure the proposal exists require(proposalId < proposals.length, "Proposal does not exist");
// Retrieve the proposal to update its vote counts Proposal storage targetProposal = proposals[proposalId];
// If the voter has already voted, we need to change their vote if (hasVoted[proposalId][msg.sender]) { emit VoteCast(proposalId, msg.sender); // If the voter previously voted "yes" and now votes "no" if (votes[proposalId][msg.sender] == true && !support) { targetProposal.yesCount -= 1; // Decrease yesCount targetProposal.noCount += 1; // Increase noCount supportingVotes[proposalId] -= 1; // Decrease supporting votes //number10 += 1; //如果投票了,此变量就加一 } // If the voter previously voted "no" and now votes "yes" elseif (votes[proposalId][msg.sender] == false && support) { targetProposal.noCount -= 1; // Decrease noCount targetProposal.yesCount += 1; // Increase yesCount supportingVotes[proposalId] += 1; // Increase supporting votes //number10 += 1; //如果投票了,此变量就加一 } } else { emit VoteCast(proposalId, msg.sender); // If the voter has not voted yet, just increase the respective count if (support) { targetProposal.yesCount += 1; supportingVotes[proposalId] += 1; // Increase supporting votes } else { targetProposal.noCount += 1; } }
// Update the voter's choice votes[proposalId][msg.sender] = support;
// Mark that this address has voted for this proposal hasVoted[proposalId][msg.sender] = true;
// Check if the proposal has enough supporting votes to be executed if (supportingVotes[proposalId] >= 10) { executeProposal(proposalId); } emit VoteCast(proposalId, msg.sender);
} // Function to execute a proposal once it has enough supporting votes function executeProposal(uint proposalId) internal { // Ensure the proposal exists require(proposalId < proposals.length, "Proposal does not exist");
You’ll notice that the Hero.sol file has changed on this stage! Now it has a constructor which takes a health argument. 你会注意到本阶段的Hero.sol文件发生了变化!现在它有一个constructor,该函数接受一个health参数。
Let’s modify our SuperHeroes so that Warrior has an initial health of 200 while the Mage has an initial health of 50. 让我们修改我们的超级英雄,使Warrior的初始生命值为200,而Mage的初始生命值为50。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// SPDX-License-Identifier: MIT pragma solidity 0.8.20;
function takeDamage(uint damage) public { health -= damage; } }
Your Goal: SuperHero Attacks 你的目标:超级英雄攻击
You’ll notice the Hero.sol tab has changed once again! This time there’s three important things to notice: 你会注意到Hero.sol标签又一次发生了变化!这次有三件重要的事情需要注意:
The Hero contract is an abstract contract. It has a virtual function called attack which we’ll need to override in both Warrior and Mage. Hero合约是一个抽象合约。它有一个名为attack的virtual函数,我们需要在战士和法师中都重写这个函数。 An enum called AttackTypes has been added to the Hero contract to differentiate between the different types of attacks our heroes can do. Hero合约中添加了一个名为AttackTypes的enum,用于区分我们的英雄可以执行的不同攻击类型。 There’s a contract called Enemy which has a method called takeAttack on it. 有一个名为Enemy的合约,它上面有一个名为takeAttack的方法。 Your job is to implement the attack function on the Warrior and Mage contracts: 你的任务是在Warrior(战士)和Mage(法师)合约上实现attack(攻击)函数:
Add an override function called attack to both the Warrior and Mage contracts. This function should take an Enemy parameter which will be an Enemy contract. 向Warrior和Mage合约中添加一个名为attack的override函数。该函数应接受一个Enemy参数,该参数将是一个Enemy合约。 Invoke takeAttack function on the Enemy contract and change the parameter based on the hero: 调用Enemy合约上的takeAttack函数,并根据英雄修改参数: For the Warrior, invoke the enemy’s takeAttack with the Brawl attack type. 对于战士,使用Brawl攻击类型调用敌人的takeAttack。 For the Mage, invoke the enemy’s takeAttack with the Spell attack type. 对于法师,使用“法术”攻击类型调用敌人的takeAttack。