EVM智能合约Gas优化技能 gas-optimization

本技能专注于EVM(以太坊虚拟机)智能合约的Gas成本优化技术,提供从存储布局、内存管理到汇编级优化的完整解决方案。包含存储打包、calldata与内存选择、无检查算术、自定义错误、循环优化、批量操作等核心优化策略,并集成基准测试工具进行性能对比分析。适用于区块链开发者、智能合约工程师、DeFi项目优化等场景。关键词:智能合约优化,Gas节省,EVM性能,存储优化,Solidity开发,区块链成本,DeFi优化,基准测试,汇编优化,批量交易。

智能合约 0 次安装 0 次浏览 更新于 2/23/2026

name: gas-optimization description: EVM智能合约的高级gas优化技术。涵盖存储打包、内存与calldata优化、汇编/Yul、高效数据结构、批量操作以及基于基准测试的优化策略。 allowed-tools: Read, Grep, Write, Bash, Edit, Glob, WebFetch

Gas优化技能

EVM智能合约的高级gas优化技术,包含基于基准测试的分析。

能力

  • 存储优化:存储打包、插槽管理、SLOAD/SSTORE最小化
  • 内存管理:内存与calldata优化、扩展成本
  • 汇编/Yul:关键路径的低级优化
  • 数据结构:gas高效的映射、数组和结构体
  • 批量操作:多调用模式、批量转账
  • 基准测试:gas分析、对比分析

MCP/工具集成

工具 用途 参考链接
Foundry MCP Gas报告、测试 foundry-mcp-server
EVM MCP Tools 操作码分析 evm-mcp-tools

存储优化

存储布局打包

// 差:3个存储插槽(使用96字节,分配96字节)
contract BadPacking {
    uint128 a;  // 插槽0(16字节)
    uint256 b;  // 插槽1(32字节)- 无法与a打包
    uint128 c;  // 插槽2(16字节)
}

// 好:2个存储插槽(使用80字节,分配64字节)
contract GoodPacking {
    uint128 a;  // 插槽0,字节0-15
    uint128 c;  // 插槽0,字节16-31
    uint256 b;  // 插槽1
}

// Gas节省:每次避免SSTORE约20,000 gas

最小化存储写入

// 差:多次存储写入
function badUpdate(uint256 newA, uint256 newB) external {
    a = newA;  // SSTORE:20,000 gas(冷)或2,900 gas(热)
    b = newB;  // SSTORE:2,900 gas(同一交易中的热插槽)
}

// 好:使用打包结构体的单次存储写入
struct Data {
    uint128 a;
    uint128 b;
}
Data public data;

function goodUpdate(uint128 newA, uint128 newB) external {
    data = Data(newA, newB);  // 单次SSTORE:20,000 gas
}

查找时使用映射而非数组

// 差:O(n)查找,大型数组成本高
uint256[] public values;
function exists(uint256 value) public view returns (bool) {
    for (uint i = 0; i < values.length; i++) {
        if (values[i] == value) return true;  // 每次迭代SLOAD
    }
    return false;
}

// 好:O(1)查找
mapping(uint256 => bool) public valueExists;
function exists(uint256 value) public view returns (bool) {
    return valueExists[value];  // 单次SLOAD
}

内存 vs Calldata

函数参数

// 差:将数组复制到内存
function processArray(uint256[] memory data) external {
    // 内存复制成本:每个字3 gas + 扩展
}

// 好:直接从calldata读取
function processArray(uint256[] calldata data) external {
    // 无复制,仅指向calldata的指针
    // 节省:每32字节约60 gas
}

// 注意:如果需要修改数组,则使用内存

字符串/字节处理

// 对于只读操作,使用calldata
function validate(string calldata input) external pure returns (bool) {
    return bytes(input).length > 0;
}

// 对于修改操作,使用内存
function transform(string memory input) internal pure returns (string memory) {
    bytes memory b = bytes(input);
    b[0] = 'X';
    return string(b);
}

无检查算术

// 差:每次操作都进行溢出检查(Solidity 0.8+)
function sumArray(uint256[] calldata arr) external pure returns (uint256) {
    uint256 sum = 0;
    for (uint256 i = 0; i < arr.length; i++) {
        sum += arr[i];  // 溢出检查:每次操作约40 gas
    }
    return sum;
}

// 好:溢出不可能时使用unchecked
function sumArray(uint256[] calldata arr) external pure returns (uint256) {
    uint256 sum = 0;
    uint256 length = arr.length;
    for (uint256 i = 0; i < length;) {
        unchecked {
            sum += arr[i];
            ++i;  // ++i比i++便宜
        }
    }
    return sum;
}
// 节省:每次迭代约40 gas

循环优化

缓存数组长度

// 差:每次迭代从存储读取长度
for (uint i = 0; i < array.length; i++) { }  // 每次迭代SLOAD

// 好:缓存长度
uint256 length = array.length;
for (uint i = 0; i < length; i++) { }  // 单次SLOAD

前自增

// 差:后自增创建临时变量
for (uint i = 0; i < length; i++) { }

// 好:前自增更便宜
for (uint i = 0; i < length; ++i) { }
// 节省:每次迭代约5 gas

自定义错误

// 差:字符串错误消息
require(balance >= amount, "余额不足");
// 成本:每个字符约50 gas + 内存扩展

// 好:自定义错误(Solidity 0.8.4+)
error InsufficientBalance(uint256 available, uint256 required);
if (balance < amount) revert InsufficientBalance(balance, amount);
// 成本:错误选择器固定约24 gas
// 节省:典型错误消息约50+ gas

汇编/Yul优化

高效余额检查

// Solidity
function getBalance(address account) external view returns (uint256) {
    return account.balance;
}

// 汇编(稍便宜)
function getBalance(address account) external view returns (uint256 bal) {
    assembly {
        bal := balance(account)
    }
}

高效内存操作

// 高效复制32字节
function copy32(bytes32 source) internal pure returns (bytes32 dest) {
    assembly {
        dest := source
    }
}

// 高效keccak256
function efficientHash(bytes32 a, bytes32 b) internal pure returns (bytes32 result) {
    assembly {
        mstore(0x00, a)
        mstore(0x20, b)
        result := keccak256(0x00, 0x40)
    }
}

批量操作

批量转账

// 差:单独转账
function transferToMany(address[] calldata recipients, uint256 amount) external {
    for (uint i = 0; i < recipients.length; ++i) {
        token.transfer(recipients[i], amount);  // 21000基础 + 转账成本
    }
}

// 好:批量转账(如果支持)
function batchTransfer(
    address[] calldata recipients,
    uint256[] calldata amounts
) external {
    // 单次函数调用开销
    // 减少token状态的SLOAD
}

多调用模式

function multicall(bytes[] calldata data) external returns (bytes[] memory results) {
    results = new bytes[](data.length);
    for (uint256 i = 0; i < data.length; ++i) {
        (bool success, bytes memory result) = address(this).delegatecall(data[i]);
        require(success);
        results[i] = result;
    }
}
// 在单次交易中组合多个操作

基准测试工作流

使用Foundry Gas报告

# 运行测试并生成gas报告
forge test --gas-report

# 快照gas使用情况
forge snapshot

# 与之前的快照对比
forge snapshot --check

Gas快照格式

| 合约 | 函数 | 最小 | 平均 | 最大 | 调用次数 |
|----------|----------|-----|-----|-----|---------|
| Token    | transfer | 51234 | 54123 | 65432 | 100 |
| Token    | approve  | 24356 | 24356 | 24356 | 50  |

对比测试

contract GasComparison is Test {
    function test_gasComparison_approach1() public {
        uint256 gasBefore = gasleft();
        // 方法1
        uint256 gasUsed = gasBefore - gasleft();
        emit log_named_uint("方法1 gas", gasUsed);
    }

    function test_gasComparison_approach2() public {
        uint256 gasBefore = gasleft();
        // 方法2
        uint256 gasUsed = gasBefore - gasleft();
        emit log_named_uint("方法2 gas", gasUsed);
    }
}

常见优化总结

技术 节省 风险
存储打包 20,000 gas/插槽
Calldata vs 内存 60 gas/32字节
无检查算术 40 gas/操作
自定义错误 50+ gas/错误
缓存存储读取 100-2100 gas
循环前自增 5 gas/迭代
汇编 可变

流程集成

此技能与以下集成:

  • gas-optimization.js - 完整优化流程
  • smart-contract-development-lifecycle.js - 开发最佳实践
  • amm-pool-development.js - DeFi特定优化

工具参考

工具 用途 URL
Foundry Gas报告 foundry-rs
Hardhat Gas Reporter Gas报告 hardhat-gas-reporter
evm.codes 操作码成本 evm.codes
Solidity Optimizer 编译器优化 Solidity Docs

另请参阅

  • skills/evm-analysis/SKILL.md - 字节码分析
  • agents/gas-optimizer/AGENT.md - Gas优化代理
  • references.md - Gas优化资源