mcpField
S
solidity-gas-optimization

solidity-gas-optimization

github.com/pseudoyu開発4570 回インストール24 週間前に更新
リポジトリ

solidity-gas-optimization について

スマートコントラクトの開発者やレビュー担当者向けのSolidityガス最適化リファレンスです。影響度とリスクに基づいて8カテゴリの手法を整理し、安全でない手法や古いパターンにも注意を促します。

主な機能

  1. 018カテゴリにわたる最適化手法
  2. 02影響度とリスクによる優先順位
  3. 03ストレージ、デプロイ、calldataの手法
  4. 04コンパイラーとアセンブリのパターン
  5. 05危険または古い手法への警告
  6. 06ベンチマークと可読性の指針

活用シーン

  1. 01コントラクトのデプロイや実行コストの削減
  2. 02ガス削減の余地を探すコントラクトレビュー
  3. 03ストレージレイアウトや設計の比較
  4. 04低レベル最適化手法のリスク評価

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/pseudoyu/agent-skills --skill solidity-gas-optimization

インストール後、Claude Code で/solidity-gas-optimizationを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
solidity-gas-guidelines.md
references/rules/
assembly-01-basics.md
calldata-01-memory-vs-calldata.md
compiler-01-loops.md
compiler-02-math.md
crosscall-01-multicall.md
deploy-01-custom-errors.md
deploy-02-clones-proxies.md
design-01-token-standards.md
design-02-signatures-vs-merkle.md
storage-01-zero-to-one.md
storage-02-cache-variables.md
storage-03-packing.md
storage-04-constants-immutables.md

詳細

Solidity ガス最適化

概要

Solidity スマートコントラクト向けの包括的なガス最適化ガイドです。8 つのカテゴリにわたる 80 以上のテクニックを収録しています。RareSkills Book of Gas Optimization に基づいており、ルールは影響度と安全性に応じて優先順位付けされています。

適用するタイミング

次のような場合に、これらのガイドラインを参照してください。

  • Solidity スマートコントラクトを新規作成するとき
  • 既存のコントラクトをレビューまたは監査するとき
  • デプロイまたは実行時のガスコストを最適化するとき
  • コントラクトのストレージレイアウトをリファクタリングするとき
  • コントラクト間のやり取りを実装するとき
  • デザインパターン(ERC721 と ERC1155 など)を選択するとき

優先順位順のカテゴリ

優先順位カテゴリ影響度リスク
1ストレージ最適化重大低
2デプロイ最適化高低
3Calldata 最適化高低
4デザインパターン高中
5コントラクト間呼び出し中〜高中
6コンパイラ最適化中低
7アセンブリのテクニック中高
8危険なテクニック低重大

クイックリファレンス

重大:ストレージ最適化(最初に適用)

ゼロから非ゼロへの書き込み:

  • ゼロから非ゼロへのストレージ書き込みは避けてください(22,100 gas がかかります)
  • ブール値のような値には、0/1 ではなく 1/2 を使用してください
  • ERC20 コントラクトでは最低残高を維持してください

変数のパッキング:

// Bad: 3 slots
struct Unpacked {
    uint64 time;      // slot 1
    uint256 amount;   // slot 2
    address user;     // slot 3
}

// Good: 2 slots
struct Packed {
    uint64 time;      // slot 1 (with address)
    address user;     // slot 1
    uint256 amount;   // slot 2
}

キャッシュ:

// Bad: reads storage twice
function increment() public {
    require(count < 10);
    count = count + 1;
}

// Good: reads storage once
function increment() public {
    uint256 _count = count;
    require(_count < 10);
    count = _count + 1;
}

定数とイミュータブル:

uint256 constant MAX = 100;        // No storage slot
address immutable owner;           // Set in constructor, no storage
高:デプロイ最適化

カスタムエラー:

// Bad: ~64+ bytes
require(amount <= limit, "Amount exceeds limit");

// Good: ~4 bytes
error ExceedsLimit();
if (amount > limit) revert ExceedsLimit();

Payable コンストラクター:

// Saves ~200 gas on deployment
constructor() payable {}

クローンパターン:

  • 繰り返しデプロイする場合は、EIP-1167 のミニマルプロキシを使用してください
  • アップグレード可能なコントラクトには、Transparent Proxy より UUPS を使用してください
高:Calldata 最適化

Calldata と Memory:

// Bad: copies to memory
function process(bytes memory data) external {}

// Good: reads directly from calldata
function process(bytes calldata data) external {}

符号付き整数を避ける:

  • 小さな負の数はコストが高くなります(例:-1 = 0xffff...)
  • 関数パラメーターには符号なし整数を使用してください
高:デザインパターン

トークン規格:

  • NFT には ERC721 より ERC1155 を優先してください(balanceOf のオーバーヘッドがありません)
  • 複数の ERC20 を 1 つの ERC1155 に統合することを検討してください

署名と Merkle:

  • Allowlist には Merkle ツリーより ECDSA 署名を優先してください
  • 1 回の tx で approve と transfer を実行できるよう、ERC20Permit を実装してください

代替ライブラリ:

  • ガス効率を高めるには、OpenZeppelin より Solmate/Solady の使用を検討してください
中〜高:コントラクト間呼び出し

やり取りを減らす:

  • approve + transferFrom の代わりに、ERC1363 の transferAndCall を使用してください
  • 操作をバッチ処理するための multicall を実装してください
  • 外部呼び出しの結果をキャッシュしてください(例:Chainlink オラクル)

アクセスリスト:

  • ストレージを事前にウォームアップするには、ERC2930 のアクセスリストトランザクションを使用してください
中:コンパイラ最適化

ループのパターン:

// Good: unchecked increment, cached length
uint256 len = arr.length;
for (uint256 i; i < len; ) {
    // logic
    unchecked { ++i; }
}

名前付き戻り値:

// More efficient bytecode
function calc(uint256 x) pure returns (uint256 result) {
    result = x * 2;
}

ビットシフト:

// Cheaper: 3 gas
x << 1   // x * 2
x >> 2   // x / 4

// Expensive: 5 gas
x * 2
x / 4

短絡評価を使うブール式:

  • && では、失敗する可能性が高い条件を先に置いてください
  • || では、成功する可能性が高い条件を先に置いてください
中:アセンブリ(慎重に使用)

効率的なチェック:

// Check address(0) with assembly
assembly {
    if iszero(caller()) { revert(0, 0) }
}

// Even/odd check
x & 1  // instead of x % 2

メモリの再利用:

  • 小さな操作ではスクラッチ領域(0x00-0x40)を再利用してください
  • ループ内でのメモリ拡張を避けてください
回避:危険なテクニック

これらは本番環境で安全ではありません。

  • すべての関数を payable にする
  • send() の戻り値を無視する
  • 分岐に gasleft() を使用する
  • テストで block.number を操作する

古いパターン

これらは最新の Solidity では適用されません。

  • 「external は public より安価」— もはや正しくありません
  • 「!= 0 は > 0 より安価」— 0.8.12 前後で変更されました

参考資料

コード例を含む完全なドキュメント:

  • references/solidity-gas-guidelines.md - 完全ガイド
  • references/rules/ - カテゴリ別の個別パターン

特定のパターンを調べるには:

grep -l "storage" references/rules/
grep -l "assembly" references/rules/
grep -l "struct" references/rules/

references/rules/ のルールカテゴリ

  • storage-* - ストレージ最適化パターン
  • deploy-* - デプロイ時のガス削減
  • calldata-* - Calldata 最適化
  • design-* - デザインパターンの選択
  • crosscall-* - コントラクト間呼び出しの最適化
  • compiler-* - コンパイラ最適化パターン
  • assembly-* - 低レベルのアセンブリテクニック

主な原則

  1. 必ずベンチマークを実施する - コンパイラの挙動はコンテキストやバージョンによって異なります
  2. 読みやすさとのバランスを取る - すべての最適化がコードの複雑さに見合うとは限りません
  3. 両方の方法をテストする - 直感に反する最適化によって、かえってコストが増えることがあります
  4. --via-irを検討する - 最新のコンパイラオプションにより、一部のテクニックが不要になる可能性があります
  5. 代替ライブラリを使用する - Solmate/Soladyは、ガスコストの面でOpenZeppelinを上回ることがよくあります

コメント