Solidity智能合约开发

Solidity智能合约开发

Solidity是以太坊智能合约的主要开发语言。本章将介绍Solidity的基础语法、合约结构、高级特性以及最佳实践。

合约基础

1. 合约结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract MyContract {
    // 状态变量
    string public name;
    uint256 public balance;
    address public owner;

    // 事件
    event Transfer(address indexed from, address indexed to, uint256 value);

    // 构造函数
    constructor(string memory _name) {
        name = _name;
        owner = msg.sender;
    }

    // 修饰器
    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }

    // 函数
    function deposit() public payable {
        balance += msg.value;
        emit Transfer(msg.sender, address(this), msg.value);
    }
}

2. 数据类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
contract DataTypes {
    // 值类型
    bool public flag = true;
    uint256 public number = 42;
    int256 public signedNumber = -42;
    address public addr = 0x123...;
    bytes32 public hash = keccak256("Hello");

    // 数组
    uint256[] public dynamicArray;
    uint256[5] public fixedArray;

    // 映射
    mapping(address => uint256) public balances;
    mapping(address => mapping(address => uint256)) public allowances;

    // 结构体
    struct User {
        string name;
        uint256 balance;
        bool isActive;
    }
    User public user;

    // 枚举
    enum Status { Pending, Active, Inactive }
    Status public status;
}

函数和修饰器

1. 函数类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
contract Functions {
    // 公共函数
    function publicFunction() public pure returns (string memory) {
        return "Public function";
    }

    // 私有函数
    function privateFunction() private pure returns (string memory) {
        return "Private function";
    }

    // 内部函数
    function internalFunction() internal pure returns (string memory) {
        return "Internal function";
    }

    // 外部函数
    function externalFunction() external pure returns (string memory) {
        return "External function";
    }

    // 视图函数
    function viewFunction() public view returns (uint256) {
        return block.number;
    }

    // 纯函数
    function pureFunction(uint256 x) public pure returns (uint256) {
        return x * 2;
    }
}

2. 修饰器模式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
contract Modifiers {
    address public owner;
    bool public locked;

    constructor() {
        owner = msg.sender;
    }

    // 基本修饰器
    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }

    // 带参数的修饰器
    modifier minimumValue(uint256 value) {
        require(msg.value >= value, "Value too low");
        _;
    }

    // 防重入修饰器
    modifier noReentrant() {
        require(!locked, "Reentrant call");
        locked = true;
        _;
        locked = false;
    }

    // 使用修饰器
    function withdraw() 
        public 
        onlyOwner 
        noReentrant 
    {
        // 提款逻辑
    }
}

继承和接口

1. 合约继承

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 基础合约
contract Ownable {
    address public owner;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }
}

// 代币合约
contract Token is Ownable {
    mapping(address => uint256) public balances;

    function mint(address to, uint256 amount) public onlyOwner {
        balances[to] += amount;
    }
}

2. 接口定义

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 接口定义
interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address to, uint256 amount) external returns (bool);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

// 实现接口
contract MyToken is IERC20 {
    mapping(address => uint256) private _balances;
    mapping(address => mapping(address => uint256)) private _allowances;
    uint256 private _totalSupply;

    function totalSupply() external view override returns (uint256) {
        return _totalSupply;
    }

    function balanceOf(address account) external view override returns (uint256) {
        return _balances[account];
    }

    // 实现其他接口函数...
}

高级特性

1. 事件和日志

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
contract Events {
    // 事件定义
    event UserCreated(address indexed user, string name, uint256 age);
    event ValueChanged(address indexed user, uint256 oldValue, uint256 newValue);

    // 触发事件
    function createUser(string memory name, uint256 age) public {
        // 业务逻辑
        emit UserCreated(msg.sender, name, age);
    }

    // 带索引的事件
    function updateValue(uint256 newValue) public {
        uint256 oldValue = 100;
        // 业务逻辑
        emit ValueChanged(msg.sender, oldValue, newValue);
    }
}

2. 库合约

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 数学库
library SafeMath {
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }
}

// 使用库
contract Calculator {
    using SafeMath for uint256;

    function calculate(uint256 a, uint256 b) public pure returns (uint256) {
        return a.add(b);
    }
}

安全最佳实践

1. 重入攻击防护

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
contract Vault {
    mapping(address => uint256) public balances;
    bool private locked;

    modifier noReentrant() {
        require(!locked, "Reentrant call");
        locked = true;
        _;
        locked = false;
    }

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw() public noReentrant {
        uint256 balance = balances[msg.sender];
        require(balance > 0, "No balance");

        balances[msg.sender] = 0;
        (bool success, ) = msg.sender.call{value: balance}("");
        require(success, "Transfer failed");
    }
}

2. 整数溢出保护

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
contract SafeCounter {
    using SafeMath for uint256;

    uint256 private _counter;

    function increment() public {
        _counter = _counter.add(1);
    }

    function decrement() public {
        _counter = _counter.sub(1);
    }
}

3. 访问控制

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
contract AccessControl {
    mapping(address => bool) public admins;
    mapping(bytes32 => mapping(address => bool)) public roles;

    // 角色常量
    bytes32 public constant MINTER_ROLE = keccak256("MINTER");
    bytes32 public constant BURNER_ROLE = keccak256("BURNER");

    modifier onlyAdmin() {
        require(admins[msg.sender], "Not admin");
        _;
    }

    modifier onlyRole(bytes32 role) {
        require(roles[role][msg.sender], "Not authorized");
        _;
    }

    function grantRole(bytes32 role, address account) public onlyAdmin {
        roles[role][account] = true;
    }

    function revokeRole(bytes32 role, address account) public onlyAdmin {
        roles[role][account] = false;
    }
}

Gas优化技巧

1. 存储优化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
contract StorageOptimization {
    // 打包结构体
    struct User {
        uint128 balance;    // 16 bytes
        uint64 lastUpdate;  // 8 bytes
        uint64 index;      // 8 bytes
    } // 总共32 bytes

    // 使用定长数组
    uint256[10] public fixedArray;

    // 避免动态数组增长
    function batchProcess(uint256[] memory data) public {
        uint256 len = data.length;
        for(uint256 i = 0; i < len; i++) {
            // 处理逻辑
        }
    }
}

2. 计算优化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
contract ComputationOptimization {
    // 缓存数组长度
    function processArray(uint256[] memory data) public pure returns (uint256) {
        uint256 sum = 0;
        uint256 len = data.length;
        for(uint256 i = 0; i < len; i++) {
            sum += data[i];
        }
        return sum;
    }

    // 使用位运算
    function multiply(uint256 x) public pure returns (uint256) {
        return x << 1; // 相当于 x * 2
    }

    function divide(uint256 x) public pure returns (uint256) {
        return x >> 1; // 相当于 x / 2
    }
}

测试和部署

1. 合约测试

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const { expect } = require("chai");

describe("Token", function() {
    let token;
    let owner;
    let addr1;
    let addr2;

    beforeEach(async function() {
        const Token = await ethers.getContractFactory("Token");
        [owner, addr1, addr2] = await ethers.getSigners();
        token = await Token.deploy();
        await token.deployed();
    });

    it("Should assign total supply to owner", async function() {
        const ownerBalance = await token.balanceOf(owner.address);
        expect(await token.totalSupply()).to.equal(ownerBalance);
    });

    it("Should transfer tokens", async function() {
        await token.transfer(addr1.address, 50);
        expect(await token.balanceOf(addr1.address)).to.equal(50);
    });
});

2. 部署脚本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
async function main() {
    const [deployer] = await ethers.getSigners();
    console.log("Deploying contracts with account:", deployer.address);

    const Token = await ethers.getContractFactory("Token");
    const token = await Token.deploy();
    await token.deployed();

    console.log("Token deployed to:", token.address);
}

main()
    .then(() => process.exit(0))
    .catch((error) => {
        console.error(error);
        process.exit(1);
    });

练习题

  1. 创建一个简单的ERC20代币合约:
1
2
3
4
// 练习:实现基本的ERC20功能
contract MyToken {
    // 你的代码
}
  1. 实现一个带有访问控制的众筹合约:
1
2
3
4
// 练习:实现众筹功能
contract Crowdfunding {
    // 你的代码
}
  1. 编写一个防重入的支付合约:
1
2
3
4
// 练习:实现安全支付
contract SafePayment {
    // 你的代码
}
  1. 创建一个多签名钱包合约:
1
2
3
4
// 练习:实现多签钱包
contract MultiSigWallet {
    // 你的代码
}
  1. 实现一个代币锁定合约:
1
2
3
4
// 练习:实现代币锁定
contract TokenLock {
    // 你的代码
}

参考资源

  1. Solidity官方文档
  2. OpenZeppelin合约
  3. Solidity by Example
  4. 以太坊智能合约最佳实践
  5. Hardhat文档