在 Solidity 中,合约文件的结构是编写智能合约的基础。一个典型的 Solidity 合约文件包含多个部分,每个部分都有其特定的作用和用法。以下是 Solidity 合约文件的结构及其详细解释。
1. SPDX 许可证标识
作用:指定合约的许可证类型,帮助用户了解合约的使用权限。
用法:
// SPDX-License-Identifier: MIT
常见许可证:
- MIT:宽松的开源许可证。
- GPL-3.0:强 copyleft 许可证。
- UNLICENSED:未授权,通常用于私有项目。
2. Pragma 指令
作用:指定 Solidity 编译器的版本范围,确保合约代码与编译器兼容。
用法:
pragma solidity ^0.8.0;
解释:
^0.8.0 表示使用 0.8.x 版本的编译器,但不包括 0.9.0 及以上版本。
4. 状态变量
作用:存储在区块链上的数据,合约的所有实例共享这些数据。
用法:
uint256 public myVariable;
常见类型:
- uint256:无符号整数,256 位。
- address:以太坊地址类型。
- bool:布尔类型。
- mapping:键值对映射。
5. 构造函数
作用:在合约部署时执行,用于初始化状态变量。
用法:
constructor(uint256 initialValue) {
myVariable = initialValue;
}
6. 函数
作用:定义合约的行为,可以读取或修改状态变量。
用法:
function setValue(uint256 newValue) public {
myVariable = newValue;
}
function getValue() public view returns (uint256) {
return myVariable;
}
函数修饰符:
- public:可以从外部和内部调用。
- private:只能在合约内部调用。
- external:只能从外部调用。
- internal:只能在合约内部或继承合约中调用。
- view:只读取状态变量,不修改。
- pure:不读取也不修改状态变量。
7. 事件
作用:记录合约中的重要操作,供外部监听。
用法:
event ValueChanged(uint256 oldValue, uint256 newValue);
function setValue(uint256 newValue) public {
emit ValueChanged(myVariable, newValue);
myVariable = newValue;
}
8. 修饰器(Modifier)
作用:用于修改函数的行为,通常用于权限控制或输入验证。
用法:
modifier onlyOwner() {
require(msg.sender == owner, "Only owner can call this function");
_;
}
function setValue(uint256 newValue) public onlyOwner {
myVariable = newValue;
}
9. 结构体(Struct)
作用:定义自定义数据类型,用于组织相关数据。
用法:
struct User {
uint256 id;
string name;
address wallet;
}
User[] public users;
function addUser(uint256 id, string memory name, address wallet) public {
users.push(User(id, name, wallet));
}
10. 枚举(Enum)
作用:定义一组命名的常量,用于提高代码可读性。
用法:
enum State { Created, Active, Inactive }
State public currentState;
function setState(State newState) public {
currentState = newState;
}
11. 继承(is)
作用:允许一个合约继承另一个合约的功能。
用法:
contract Parent {
uint256 public parentValue;
function setParentValue(uint256 newValue) public {
parentValue = newValue;
}
}
contract Child is Parent {
uint256 public childValue;
function setChildValue(uint256 newValue) public {
childValue = newValue;
}
}
12. 接口(Interface)
作用:定义合约的抽象接口,用于与其他合约交互。
用法:
interface IERC20 {
function transfer(address to, uint256 amount) external returns (bool);
}
contract MyContract {
IERC20 public token;
constructor(address tokenAddress) {
token = IERC20(tokenAddress);
}
function sendToken(address to, uint256 amount) public {
require(token.transfer(to, amount), "Transfer failed");
}
}
13. 库(Library)
作用:封装可复用的代码,供其他合约调用。
用法:
library Math {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
}
contract MyContract {
using Math for uint256; // 将 Math 库的函数附加到 uint256 类型,如果库函数未定义为 internal,则无法使用 using ... for 语法。
function calculate(uint256 a, uint256 b) public pure returns (uint256) {
return a.add(b); // 直接调用库函数,a 是 uint256 类型,与库函数的第一个参数类型匹配, a.add(b) 等同于 Math.add(a, b)。
}
}
14. Fallback 和 Receive 函数
作用:处理合约接收以太币的情况。
用法:
fallback() external payable {
// 处理未知函数调用
}
receive() external payable {
// 处理纯以太币转账
}
15. 完整的合约示例
以下是一个完整的 Solidity 合约示例,包含上述所有部分:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract MyContract {
// 状态变量
uint256 public myVariable;
address public owner;
// 事件
event ValueChanged(uint256 oldValue, uint256 newValue);
// 修饰器
modifier onlyOwner() {
require(msg.sender == owner, "Only owner can call this function");
_;
}
// 构造函数
constructor(uint256 initialValue) {
myVariable = initialValue;
owner = msg.sender;
}
// 函数
function setValue(uint256 newValue) public onlyOwner {
emit ValueChanged(myVariable, newValue);
myVariable = newValue;
}
function getValue() public view returns (uint256) {
return myVariable;
}
// Fallback 函数
fallback() external payable {
revert("Fallback function called");
}
// Receive 函数
receive() external payable {
revert("Receive function called");
}
}