合约结构 #
一、合约组成 #
1.1 完整合约结构 #
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract CompleteContract {
// 1. 状态变量
uint256 public count;
address public owner;
// 2. 事件
event CountChanged(uint256 newCount);
// 3. 修饰器
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
// 4. 构造函数
constructor() {
owner = msg.sender;
}
// 5. 函数
function increment() public {
count++;
emit CountChanged(count);
}
// 6. 接收函数
receive() external payable {}
// 7. 回退函数
fallback() external payable {}
}
1.2 组成部分说明 #
| 组成部分 | 说明 | 示例 |
|---|---|---|
| SPDX声明 | 许可证标识 | // SPDX-License-Identifier: MIT |
| pragma | 编译器版本 | pragma solidity ^0.8.0; |
| import | 导入文件 | import "./Other.sol"; |
| 状态变量 | 永久存储 | uint256 public count; |
| 事件 | 日志记录 | event Transfer(...); |
| 修饰器 | 函数修饰 | modifier onlyOwner() {...} |
| 构造函数 | 初始化 | constructor() {...} |
| 函数 | 业务逻辑 | function foo() {...} |
| 接收函数 | 接收ETH | receive() external payable {} |
| 回退函数 | 未知调用 | fallback() external payable {} |
二、状态变量 #
2.1 状态变量声明 #
solidity
contract StateVariables {
// 基本类型
uint256 public count;
int256 private balance;
bool internal active;
address public owner;
// 复合类型
string public name;
bytes32 public hash;
// 引用类型
uint256[] public numbers;
mapping(address => uint256) public balances;
// 结构体
struct User {
address wallet;
string name;
}
User public user;
// 枚举
enum Status { Pending, Active, Completed }
Status public status;
}
2.2 可见性 #
solidity
contract StateVariableVisibility {
// public:自动生成getter函数
uint256 public publicVar;
// private:仅本合约可访问
uint256 private privateVar;
// internal:本合约和子合约可访问
uint256 internal internalVar;
// 状态变量不能是external
// uint256 external externalVar; // 错误
}
2.3 常量与不可变 #
solidity
contract ConstantsAndImmutables {
// constant:编译时确定,不占用storage
uint256 public constant MAX_SUPPLY = 1000000;
address public constant ZERO_ADDRESS = address(0);
// immutable:部署时确定,不占用storage
address public immutable owner;
uint256 public immutable createdAt;
constructor() {
owner = msg.sender;
createdAt = block.timestamp;
}
// constant和immutable的区别:
// constant:编译时确定值
// immutable:部署时确定值
}
三、函数 #
3.1 函数声明 #
solidity
contract FunctionDeclaration {
// 基本函数
function getValue() public pure returns (uint256) {
return 1;
}
// 带参数函数
function add(uint256 a, uint256 b) public pure returns (uint256) {
return a + b;
}
// 多返回值
function getMultiple() public pure returns (uint256, bool) {
return (1, true);
}
// 命名返回值
function getNamed() public pure returns (uint256 number, bool flag) {
number = 1;
flag = true;
}
}
3.2 函数可见性 #
solidity
contract FunctionVisibility {
// public:任何地方可调用
function publicFunction() public pure returns (string memory) {
return "public";
}
// private:仅本合约可调用
function privateFunction() private pure returns (string memory) {
return "private";
}
// internal:本合约和子合约可调用
function internalFunction() internal pure returns (string memory) {
return "internal";
}
// external:仅外部可调用
function externalFunction() external pure returns (string memory) {
return "external";
}
}
四、事件 #
4.1 事件声明 #
solidity
contract EventDeclaration {
// 基本事件
event Transfer(address indexed from, address indexed to, uint256 value);
// 带indexed参数
event Deposit(address indexed user, uint256 amount);
// 无indexed参数
event StatusChanged(string newStatus);
// 多个indexed参数(最多3个)
event MultiIndexed(
address indexed sender,
address indexed recipient,
uint256 indexed amount
);
}
4.2 触发事件 #
solidity
contract EventEmission {
event Transfer(address indexed from, address indexed to, uint256 value);
event Deposit(address indexed user, uint256 amount);
mapping(address => uint256) public balances;
function transfer(address to, uint256 amount) public {
require(balances[msg.sender] >= amount, "Insufficient balance");
balances[msg.sender] -= amount;
balances[to] += amount;
// 触发事件
emit Transfer(msg.sender, to, amount);
}
function deposit() public payable {
require(msg.value > 0, "Must send ETH");
balances[msg.sender] += msg.value;
// 触发事件
emit Deposit(msg.sender, msg.value);
}
}
4.3 indexed的作用 #
solidity
contract IndexedExample {
// indexed参数可以被过滤查询
event Transfer(
address indexed from, // 可过滤
address indexed to, // 可过滤
uint256 value // 不可过滤
);
// 查询示例(在Web3中):
// contract.queryFilter(
// contract.filters.Transfer(fromAddress, null)
// )
// 可以快速找到所有从fromAddress发出的转账
}
五、修饰器 #
5.1 修饰器声明 #
solidity
contract ModifierDeclaration {
address public owner;
// 基本修饰器
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_; // 继续执行函数体
}
// 带参数的修饰器
modifier minAmount(uint256 amount) {
require(msg.value >= amount, "Insufficient ETH");
_;
}
// 复杂修饰器
modifier validAddress(address addr) {
require(addr != address(0), "Invalid address");
_;
}
}
5.2 使用修饰器 #
solidity
contract ModifierUsage {
address public owner;
bool public paused;
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
modifier whenNotPaused() {
require(!paused, "Contract paused");
_;
}
modifier minAmount(uint256 amount) {
require(msg.value >= amount, "Insufficient ETH");
_;
}
constructor() {
owner = msg.sender;
}
// 单个修饰器
function setPaused(bool _paused) public onlyOwner {
paused = _paused;
}
// 多个修饰器
function sensitiveOperation() public onlyOwner whenNotPaused {
// 敏感操作
}
// 带参数的修饰器
function deposit() public payable minAmount(1 ether) {
// 存款操作
}
}
5.3 修饰器执行顺序 #
solidity
contract ModifierOrder {
modifier mod1() {
// 1. mod1开始
_;
// 4. mod1结束
}
modifier mod2() {
// 2. mod2开始
_;
// 3. mod2结束
}
function test() public mod1 mod2 {
// 3. 函数体
}
// 执行顺序:mod1开始 -> mod2开始 -> 函数体 -> mod2结束 -> mod1结束
}
六、结构体与枚举 #
6.1 结构体 #
solidity
contract StructExample {
struct User {
address wallet;
string name;
uint256 balance;
bool verified;
}
User public owner;
User[] public users;
mapping(address => User) public userMap;
function createUser(
address _wallet,
string memory _name,
uint256 _balance
) public {
User memory newUser = User({
wallet: _wallet,
name: _name,
balance: _balance,
verified: false
});
users.push(newUser);
userMap[_wallet] = newUser;
}
function updateUser(address _wallet, string memory _name) public {
User storage user = userMap[_wallet];
user.name = _name;
}
}
6.2 枚举 #
solidity
contract EnumExample {
enum Status { Pending, Active, Completed, Cancelled }
Status public status;
function setStatus(Status _status) public {
status = _status;
}
function getStatus() public view returns (Status) {
return status;
}
function getStatusValue() public view returns (uint8) {
return uint8(status);
}
function nextStatus() public {
if (status == Status.Pending) {
status = Status.Active;
} else if (status == Status.Active) {
status = Status.Completed;
}
}
}
七、综合示例 #
7.1 代币合约 #
solidity
contract Token {
// 状态变量
string public name;
string public symbol;
uint8 public decimals;
uint256 public totalSupply;
address public owner;
// 映射
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
// 事件
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
// 修饰器
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
// 构造函数
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals,
uint256 _totalSupply
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
totalSupply = _totalSupply;
owner = msg.sender;
balanceOf[msg.sender] = _totalSupply;
emit Transfer(address(0), msg.sender, _totalSupply);
}
// 函数
function transfer(address to, uint256 amount) public returns (bool) {
require(to != address(0), "Invalid recipient");
require(balanceOf[msg.sender] >= amount, "Insufficient balance");
balanceOf[msg.sender] -= amount;
balanceOf[to] += amount;
emit Transfer(msg.sender, to, amount);
return true;
}
function approve(address spender, uint256 amount) public returns (bool) {
require(spender != address(0), "Invalid spender");
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public returns (bool) {
require(from != address(0), "Invalid from");
require(to != address(0), "Invalid to");
require(balanceOf[from] >= amount, "Insufficient balance");
require(allowance[from][msg.sender] >= amount, "Insufficient allowance");
balanceOf[from] -= amount;
balanceOf[to] += amount;
allowance[from][msg.sender] -= amount;
emit Transfer(from, to, amount);
return true;
}
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0), "Invalid new owner");
address previousOwner = owner;
owner = newOwner;
emit OwnershipTransferred(previousOwner, newOwner);
}
}
八、最佳实践 #
8.1 代码组织 #
solidity
contract CodeOrganization {
// 1. 状态变量(按可见性分组)
uint256 public publicVar;
uint256 internal internalVar;
uint256 private privateVar;
// 2. 事件
event ValueChanged(uint256 newValue);
// 3. 修饰器
modifier validValue(uint256 value) {
require(value > 0, "Invalid value");
_;
}
// 4. 构造函数
constructor() {
// 初始化
}
// 5. 接收函数
receive() external payable {}
// 6. 回退函数
fallback() external payable {}
// 7. external函数
function externalFunction() external pure returns (uint256) {
return 1;
}
// 8. public函数
function publicFunction() public pure returns (uint256) {
return 1;
}
// 9. internal函数
function internalFunction() internal pure returns (uint256) {
return 1;
}
// 10. private函数
function privateFunction() private pure returns (uint256) {
return 1;
}
}
8.2 命名约定 #
solidity
contract NamingConventions {
// 状态变量:小驼峰
uint256 public totalSupply;
address public owner;
// 常量:全大写下划线分隔
uint256 public constant MAX_SUPPLY = 1000000;
// 私有变量:下划线前缀
uint256 private _balance;
// 事件:大驼峰
event Transfer(address indexed from, address indexed to, uint256 value);
// 修饰器:小驼峰,表达条件
modifier onlyOwner() {
_;
}
// 函数:小驼峰
function transfer(address to, uint256 amount) public returns (bool) {
return true;
}
// 内部函数:下划线前缀
function _validateAddress(address addr) internal pure returns (bool) {
return addr != address(0);
}
}
九、总结 #
合约结构要点:
| 组成部分 | 说明 | 推荐位置 |
|---|---|---|
| 状态变量 | 永久存储 | 合约顶部 |
| 事件 | 日志记录 | 状态变量后 |
| 修饰器 | 函数修饰 | 事件后 |
| 构造函数 | 初始化 | 修饰器后 |
| 函数 | 业务逻辑 | 构造函数后 |
使用建议:
- 按照推荐顺序组织代码
- 使用有意义的命名
- 添加必要的注释
- 遵循代码规范
接下来,让我们学习状态变量!
最后更新:2026-03-27