练习 01:部署你的第一个智能合约
从 CryptoZombies 到 Hardhat 本地部署,走完智能合约开发的完整链路
登录后查看练习
登录以查看练习内容,并跟踪你的学习进度。
目标
完成本练习后,你应该能:
- 用 Solidity 写一个简单合约并通过编译
- 用 Hardhat 在本地链上部署和调用合约
- 把合约部署到 Sepolia 测试网,用区块浏览器验证
阶段一:CryptoZombies(~10 小时)
先在浏览器里写 Solidity,不需要任何环境配置:
完成第 1-6 课(Solidity Path 的前 6 课),你会掌握:
- 类型系统(uint, address, mapping, struct)
- 函数可见性(public, private, internal, external)
storagevsmemory的区别和成本- 事件(event)和继承
卡住时记录疑问,继续往前走——后面会反过来解释前面。
阶段二:本地开发环境
安装
mkdir my-first-dapp && cd my-first-dapp
npm init -y
npm install --save-dev hardhat
npx hardhat init
# 选择:Create a TypeScript project
写一个 Storage 合约
在 contracts/ 目录创建 SimpleStorage.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
contract SimpleStorage {
uint256 private value;
event ValueChanged(uint256 newValue);
function set(uint256 _value) public {
value = _value;
emit ValueChanged(_value);
}
function get() public view returns (uint256) {
return value;
}
}
编译 + 测试
npx hardhat compile
# 写测试 test/SimpleStorage.ts
npx hardhat test
本地部署
npx hardhat node # 启动本地链,终端 1
npx hardhat run scripts/deploy.ts --network localhost # 终端 2
阶段三:部署到 Sepolia 测试网
准备工作
- 安装 MetaMask 浏览器插件,创建钱包,切换到 Sepolia 测试网
- 在 sepoliafaucet.com 领取测试 ETH
- 在 alchemy.com 注册,创建 Sepolia 项目,获取 RPC URL
配置 hardhat.config.ts
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
const config: HardhatUserConfig = {
solidity: "0.8.19",
networks: {
sepolia: {
url: process.env.SEPOLIA_RPC_URL || "",
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [],
},
},
};
export default config;
⚠️ 私钥安全:把私钥放在 .env 文件里,确保 .env 在 .gitignore 中——永远不要把私钥提交到代码仓库。
部署
npx hardhat run scripts/deploy.ts --network sepolia
部署成功后会打印合约地址,用 sepolia.etherscan.io 搜索该地址验证。
思考问题
- 为什么合约部署后地址就固定了?如果需要升级合约逻辑,有什么方案?
storage写入操作的 Gas 成本大约是memory读取的多少倍?这对合约设计有什么影响?- 如果两个用户同时调用同一个合约的写入函数,以太坊怎么处理并发?
参考答案
Q1: 合约地址固定与升级方案 合约地址由部署者地址和 nonce 的 hash 决定,一旦部署就不可变。升级方案主要有两种:代理模式(Proxy Pattern)——用户调用代理合约,代理通过
delegatecall将逻辑转发给可替换的实现合约;CREATE2 + 迁移——用确定性地址部署新合约,但需要迁移状态。OpenZeppelin 的 TransparentProxy 和 UUPS 是最常用的代理实现。
Q2: Storage vs Memory 的 Gas 成本
SSTORE(首次写入新槽位)消耗 20,000 gas,MLOAD(内存读取)只需 3 gas,差距约 6,600 倍。这意味着合约设计时应尽量减少链上存储:能在 memory 中计算的不要写 storage,能用 event 记录的不要存状态变量,批量操作优于多次单独写入。
Q3: 以太坊如何处理并发? 以太坊没有并发——所有交易在 EVM 中串行执行。矿工/验证者将交易排入区块时确定执行顺序(通常按 gas price 优先)。两个用户同时提交的交易会被排序后逐一执行。这种串行模型简化了状态一致性,但也带来了 MEV(矿工可提取价值)问题:排序权本身变成了一种可以被利用的资源。