简单投票合约(Solidity示例)
投票是最常见的民主决策机制,而以太坊智能合约可以提供一个透明、防篡改的投票系统。
合约功能:
- 部署时创建多个候选人选项。
- 只有注册的投票者(地址)才能投票,且只能投一次票。
- 投票过程公开透明,结果实时可查,直到投票结束。
- 投票结束后,可以统计并公布各候选人的得票数。
Solidity代码简化示例:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SimpleVoting {
// 候选人结构体
struct Candidate {
string name;
uint voteCount;
}
// 存储候选人,名字到索引的映射
mapping(string => uint) public candidateNames;
// 存储候选人列表
Candidate[] public candidates;
// 存储投票者,地址到是否已投票的映射
mapping(address => bool) public voters;
// 投票状态
bool public votingOpen = true;
// 构造函数,初始化候选人
constructor(string[] memory candidateList) {
for (uint i = 0; i < candidateList.length; i++) {
candidates.push(Candidate({
name: candidateList[i],
voteCount: 0
}));
candidateNames[candidateList[i]] = i;
}
}
// 投票函数
function vote(string memory candidateName) public {
require(votingOpen, "Voting is closed");
require(!voters[msg.sender], "You have already voted");
uint candidateIndex = candidateNames[candidateName];
require(candidateIndex < candidates.length, "Invalid candidate");
candidates[candidateIndex].voteCount++;
voters[msg.sender] = true;
}
// 关闭投票函数(通常由特定角色调用,或设定时间自动关闭)
function closeVoting() public {
votingOpen = false;
}
// 获取候选人票数
function getVoteCount(string memory candidateName) public view returns (uint) {
return candidates[candidateNames[candidateName]].voteCount;
}
}
解析:
struct Candidate:定义了候选人的数据结构,包含名字和票数。mapping(string => uint) public candidateNames:通过候选人名字快速找到其在数组中的索引。Candidate[] public candidates:动态数组存储所有候选人信息。mapping(address => bool) public voters:记录每个地址是否已投票,防止重复投票。constructor:合约部署时初始化候选人列表。vote:核心投票函数,进行权限检查后更新候选人票数和投票者状态。closeVoting:关闭投票,之后不能再投票。getVoteCount:查询指定候选人的当前票数。
这个例子展示了智能合约的基本要素:状态变量(存储数据)、函数(修改和读取数据)、访问控制(require语句)和逻辑封装。
代币合约(ERC20标准示例)
代币是以太坊上最广泛的应用之一,ERC20是以太坊上代币的通用标准,确保了不同代币之间的兼容性。
合约功能(遵循ERC20标准):
- 定义代币名称(Token Name)、符号(Symbol)、小数位数(Decimals)。
- 记录每个地址的代币余额(
mapping(address => uint256) balanceOf)。 - 支持代币转账(
transfer函数):从调用者地址向指定地址转移代币。 - 支持授权转账(
approve和transferFrom函数):地址A授权地址B从A账户中转移代币,常用于交易所或合约交互。 - 记录授权情况(
mapping(address => mapping(address => uint256)) allowance)。
Solidity代码简化示例(基于OpenZeppelin的ERC20模板):
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
constructor(string memory name, string memory symbol) ERC20(name, symbol) {
_mint(msg.sender, 1000000 * 10**decimals()); // 初始发行100万个代币,考虑小数位数
}
}
解析:
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";:引入OpenZeppelin库的ERC20标准实现,这是目前最安全、最广泛使用的ERC20合约模板。contract MyToken is ERC20:我们的代币合约继承自ERC20合约,自动获得了所有ERC20标准的功能。constructor(string memory name, string memory symbol) ERC20(name, symbol):构造函数,设置代币名称和符号,并调用父合约ERC20的构造函数。_mint(msg.sender, 1000000 * 10**decimals()):_mint是ERC20合约中的内部函数,用于增发代币,这里给合约部署者(msg.sender)初始发行100万个代币。decimals()通常返回18,表示代币可分割到小数点后18位,所以实际发行量是1000000 * 10^18个最小单位。
这个例子展示了智能合约的标准化和可复用性,开发者无需从头实现复杂的代币逻辑,只需基于标准库进行少量定制即可。
简单众筹合约(Crowdsourcing示例)
众筹是一种向大众募集资金的方式,智能合约可以确保资金使用的透明度和项目方的履约能力。
合约功能:
- 设定众筹目标金额(goal)和截止时间(deadline)。
- 投资者(支持者)可以向合约地址发送以太币(ETH)进行支持。
- 如果众筹成功(在截止时间前达到或超过目标金额),项目方可以提取筹集到的资金。
- 如果众筹失败,投资者可以申请退还其支持的ETH。
Solidity代码简化示例:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SimpleCrowdfunding {
address public creator;
uint public goal;
uint public deadline;
mapping(address => uint) public contributions;
bool public fundingSuccessful;
bool public fundsClaimed;
event Funded(address indexed backer, uint amount);
event CreatorWithdrawn(uint amount);
event Refunded(address indexed backer, uint amount);
constructor(uint _goal, uint _durationInDays) {
creator = msg.sender;
goal = _goal * 1 ether; // 假设goal是以太,乘以1 ether转换为wei
deadline = block.timestamp + _durationInDays * 1 days;
}
function fund() public payable {
require(block.timestamp < deadline, "Deadline passed");
require(msg.value > 0, "Must send ETH");
contributions[msg.sender] += msg.value;
emit Funded(msg.sender, msg.value);
}
function withdrawFunds() public {
require(msg.sender == creator, "Only creator can withdraw");
require(block.timestamp >= deadline, "Deadline not reached");
require(!fundsClaimed, "Funds already claimed");
if (address(this).balance >= goal) {
fundingSuccessful = true;
payable(creator).transfer(address(this).balance);
emit CreatorWithdrawn(address(this).balance);
}
fundsClaimed = true;
}
function refund() public {
require(block.timestamp >= deadline, "Deadline not reached");
require(!fundingSuccessful, "Funding successful, no refund");
require(contributions[msg.sender] > 0, "No contribution to refund");
uint amount = contributions[msg.sender];
contributions[msg.sender] = 0;
payable(msg.sender).transfer(amount);
emit Refunded(msg.sender, amount);
}
}
解析:
creator:项目方创建者地址。goal:众筹目标金额(以wei为单位)。deadline:众筹截止时间戳。contributions:记录每个投资者的贡献金额。fundingSuccessful:标记众筹是否成功。li>
fund():投资者调用此函数发送ETH,并记录贡献。withdrawFunds():项目方在截止时间后调用,如果达到目标则提取资金。refund():投资者在截止时间后且众筹失败时调用,取回其贡献的ETH。event:用于记录链上重要操作,方便外部应用监听