Solidity是以太坊智能合约开发的核心语言。本指南通过语法解析和实战示例,带你系统掌握智能合约开发的核心技能。
一、开发环境快速搭建
1. 在线开发(推荐初学者)
javascript
// 访问 https://remix.ethereum.org
// 创建新文件:Bank.sol
2. 本地环境配置
bash
# 安装必备工具
npm install -g hardhat @nomicfoundation/hardhat-toolbox
# 初始化项目
npx hardhat init
二、合约结构详解(含示例)
solidity
// SPDX-License-Identifier: MIT // 许可证声明
pragma solidity ^0.8.18; // 编译器版本
// 合约声明
contract Bank {
// ===== 状态变量 =====
address public owner; // 合约所有者
mapping(address => uint) public balances; // 地址到余额的映射
// ===== 构造函数 =====
constructor() {
owner = msg.sender; // 部署者设为所有者
}
// ===== 函数修饰符 =====
modifier onlyOwner() {
require(msg.sender == owner, "Only owner can call");
_; // 继续执行原函数
}
// ===== 事件定义 =====
event DepositMade(address indexed account, uint amount);
event Withdrawal(address indexed account, uint amount);
// ===== 函数实现 =====
function deposit() public payable {
balances[msg.sender] += msg.value;
emit DepositMade(msg.sender, msg.value);
}
}
三、核心数据类型与操作
1. 基础类型示例
solidity
// 布尔值
bool public isOpen = true;
// 整数(推荐使用显式位数)
uint256 public totalSupply = 1000; // 无符号整数
int public temperature = -5; // 有符号整数
// 地址类型
address public user = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;
// 字节数组
bytes32 public hash = keccak256(abi.encodePacked("Hello Solidity"));
2. 复合类型示例
solidity
// 结构体
struct User {
string name;
uint age;
address wallet;
}
// 枚举
enum Status { Pending, Approved, Rejected }
// 数组
uint[] public numbers = [1, 2, 3];
User[] public users;
// 映射(字典)
mapping(address => uint) public balances;
四、函数详解(语法+示例)
1. 函数声明
solidity
// 视图函数(不修改状态)
function getBalance(address _user) public view returns (uint) {
return balances[_user];
}
// 纯函数(不访问状态)
function calculate(uint a, uint b) public pure returns (uint) {
return a * b + 10;
}
// 支付函数(接收ETH)
function deposit() public payable {
balances[msg.sender] += msg.value;
}
// 带修饰符的函数
function withdraw(uint amount) public {
require(amount <= balances[msg.sender], "Insufficient balance");
balances[msg.sender] -= amount;
payable(msg.sender).transfer(amount);
}
2. 函数参数与返回值
solidity
// 多参数输入
function registerUser(string memory _name, uint _age) public {
users.push(User(_name, _age, msg.sender));
}
// 多返回值
function getUser(address _addr) public view returns (string memory, uint) {
for (uint i = 0; i < users.length; i++) {
if (users[i].wallet == _addr) {
return (users[i].name, users[i].age);
}
}
revert("User not found");
}
五、高级特性实战
1. 继承与接口
solidity
// 定义接口
interface IERC20 {
function transfer(address to, uint amount) external returns (bool);
}
// 基础合约
contract Ownable {
address public owner;
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
}
// 继承实现
contract MyToken is Ownable, IERC20 {
mapping(address => uint) private _balances;
function transfer(address to, uint amount) external override returns (bool) {
require(_balances[msg.sender] >= amount);
_balances[msg.sender] -= amount;
_balances[to] += amount;
return true;
}
}
2. 错误处理机制
solidity
// 自定义错误
error InsufficientBalance(uint requested, uint available);
function safeWithdraw(uint amount) public {
if (amount > balances[msg.sender]) {
revert InsufficientBalance(amount, balances[msg.sender]);
}
balances[msg.sender] -= amount;
// 发送ETH(推荐使用call)
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
}
3. 事件与日志
solidity
event Transfer(
address indexed from, // indexed 可过滤
address indexed to,
uint amount
);
function _transfer(address from, address to, uint amount) internal {
// ...转账逻辑
emit Transfer(from, to, amount); // 记录事件
}
六、安全开发实践
1. 重入攻击防护
solidity
// 使用Checks-Effects-Interactions模式
function secureWithdraw() public {
uint amount = balances[msg.sender];
// 1. 检查条件
require(amount > 0);
// 2. 先更新状态
balances[msg.sender] = 0;
// 3. 最后交互
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
}
2. 权限控制
solidity
// 使用OpenZeppelin的Ownable合约
import "@openzeppelin/contracts/access/Ownable.sol";
contract SecureContract is Ownable {
// 只有所有者可调用
function adminAction() public onlyOwner {
// 敏感操作
}
}
3. 整数溢出防护
solidity
// Solidity 0.8+ 默认启用溢出检查
function safeAdd(uint a, uint b) public pure returns (uint) {
return a + b; // 自动检测溢出
}
七、完整案例:拍卖合约
solidity
pragma solidity ^0.8.18;
contract Auction {
address public owner;
address public highestBidder;
uint public highestBid;
mapping(address => uint) public pendingReturns;
event NewBid(address bidder, uint amount);
event AuctionEnded(address winner, uint amount);
constructor() {
owner = msg.sender;
}
function bid() external payable {
require(msg.value > highestBid, "Bid too low");
// 退还前一个最高出价
if (highestBidder != address(0)) {
pendingReturns[highestBidder] += highestBid;
}
highestBidder = msg.sender;
highestBid = msg.value;
emit NewBid(msg.sender, msg.value);
}
function withdraw() external {
uint amount = pendingReturns[msg.sender];
require(amount > 0, "No funds available");
pendingReturns[msg.sender] = 0;
payable(msg.sender).transfer(amount);
}
function endAuction() external onlyOwner {
emit AuctionEnded(highestBidder, highestBid);
payable(owner).transfer(highestBid);
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
}
八、部署与测试流程
1. 编写部署脚本
javascript
// deploy.js
async function main() {
const Auction = await ethers.getContractFactory("Auction");
const auction = await Auction.deploy();
console.log("Auction deployed to:", auction.address);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
2. 运行测试
bash
npx hardhat test
3. 部署到测试网
bash
npx hardhat run scripts/deploy.js --network goerli
九、学习路径推荐
-
基础语法:
-
安全实践:
-
开发框架:
-
合约库:
关键提示:所有主网部署前必须完成:
- 单元测试覆盖率 > 90%
- 静态分析(Slither)
- 形式化验证(Certora)
- 第三方安全审计
掌握这些核心知识后,你将能够开发安全的DeFi协议、NFT市场和DAO治理等智能合约应用。智能合约一旦部署不可修改,务必遵循"测试优先、安全第一"的原则!