:2026-03-24 17:21 点击:7
以太坊,作为区块链2.0的杰出代表,不仅仅是一种加密货币,更是

什么是智能合约?
智能合约是一种“那么”(If-This-Then-That)式的自动化协议,它被部署在区块链上,一旦预设的条件被触发,合约就会自动执行约定的操作,且整个过程透明、不可篡改,以太坊智能合约通常使用Solidity语言编写。
为何需要一个Demo?
一个Demo(演示程序)能够将抽象的概念具体化,通过构建一个简单的Demo,你可以:
我们的Demo目标:一个简单的“投票”合约
为了演示智能合约的基本功能,我们将创建一个简单的投票合约,这个合约将允许:
构建Demo前的准备:开发环境搭建
在开始编写合约之前,你需要准备以下工具和环境:
npx hardhat 初始化一个新的Hardhat项目。编写智能合约(Solidity)
在Hardhat项目中,你会在 contracts/ 目录下找到 Lock.sol 文件(默认模板),我们可以将其重命名并修改为 Voting.sol,然后编写如下代码:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Voting {
// 定义一个投票选项的结构体
struct Candidate {
string name;
uint256 voteCount;
}
// 存储投票选项的映射,选项名称到Candidate结构体
mapping(string => Candidate) public candidates;
// 存储地址是否已投票的映射,防止重复投票
mapping(address => bool) public hasVoted;
// 投票选项的数组
string[] public candidateNames;
// 构造函数,在部署合约时调用,用于初始化投票选项
constructor(string[] memory _candidateNames) {
candidateNames = _candidateNames;
for (uint i = 0; i < _candidateNames.length; i++) {
candidates[_candidateNames[i]] = Candidate({
name: _candidateNames[i],
voteCount: 0
});
}
}
// 投票函数
function vote(string memory candidateName) public {
// 检查投票者是否已经投过票
require(!hasVoted[msg.sender], "You have already voted.");
// 检查候选选项是否存在
require(bytes(candidates[candidateName].name).length > 0, "Candidate does not exist.");
// 记录投票
hasVoted[msg.sender] = true;
candidates[candidateName].voteCount += 1;
}
// 获取候选人的得票数
function getVoteCount(string memory candidateName) public view returns (uint256) {
return candidates[candidateName].voteCount;
}
// 获取所有候选人的名称
function getCandidateNames() public view returns (string[] memory) {
return candidateNames;
}
}
代码解释:
SPDX-License-Identifier 和 pragma solidity:Solidity合约的标准头部信息,指定许可证和编译器版本。contract Voting:定义了一个名为 Voting 的智能合约。struct Candidate:定义了候选人结构体,包含名字和得票数。mapping(string => Candidate) public candidates:一个映射,通过选项名称快速找到对应的候选人信息,并设为 public 以便区块链浏览器访问。mapping(address => bool) public hasVoted:记录每个地址是否已投票。string[] public candidateNames:存储所有候选选项名称的数组。constructor:合约部署时执行的构造函数,用于初始化候选人列表。vote(string memory candidateName):核心投票函数,包含权限检查(是否已投票、候选人是否存在),然后更新投票状态和得票数。getVoteCount 和 getCandidateNames:查询函数,分别获取特定候选人的得票数和所有候选人名称。编译与部署合约
编译合约: 在Hardhat项目根目录的终端中运行:
npx hardhat compile
如果成功,你会在 artifacts/contracts/ 目录下看到编译后的合约文件(如 Voting.json)。
编写部署脚本:
在 scripts/ 目录下,创建一个新的部署脚本,deploy.js:
async function main() {
// 获取合约工厂
const Voting = await ethers.getContractFactory("Voting");
// 部署合约,这里我们传入几个候选人名称作为示例
const candidateNames = ["Alice", "Bob", "Charlie"];
const voting = await Voting.deploy(candidateNames);
// 等待合约部署完成
await voting.deployed();
console.log("Voting contract deployed to:", voting.address);
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
配置网络:
在 hardhat.config.js 文件中,你需要配置你想要部署到的测试网(如Sepolia),你需要安装 @nomicfoundation/hardhat-toolbox 插件,并配置你的MetaMask私钥(注意:不要将私钥提交到代码仓库,建议使用环境变量)。
require("@nomicfoundation/hardhat-toolbox");
require('dotenv').config(); // 引入dotenv包来管理环境变量
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: "0.8.20",
networks: {
sepolia: {
url: process.env.SEPOLIA_URL, // 从.env文件中获取
accounts: [process.env.PRIVATE_KEY] // 从.env文件中获取
}
},
etherscan: {
apiKey: process.env.ETHERSCAN_API_KEY // 可选,用于验证合约
}
};
创建 .env 文件,并添加你的测试网RPC URL(可以从Alchemy或Infura获取)和MetaMask私钥。
部署合约: 确保你的MetaMask钱包连接到了正确的测试网(如Sepolia Test Network),并且有足够的测试ETH。 在终端中运行部署脚本:
npx hardhat run scripts/deploy.js --network sepolia
部署成功后,终端会输出合约的地址,复制这个地址,你可以在以太坊测试网浏览器(如 Sepolia Etherscan)上查看你的合约。
与智能合约交互
使用Ethers.js:
你可以编写一个简单的Node.js脚本或前端应用(如使用React + Ethers.js)来调用合约的方法。
创建一个 interact.js 脚本:
const hre = require("hardhat");
async function main() {
// 替换为你的合约地址
const contractAddress = "YOUR_CONTRACT_ADDRESS_HERE";
// 获取合约实例
const Voting = await hre.ethers.getContractFactory("Voting");
const voting = await Voting.attach
本文由用户投稿上传,若侵权请提供版权资料并联系删除!