♦️

Solidity における call, delegatecall の違いは?

2024/04/09に公開

Solidityにおけるcalldelegatecallは、どちらも別のスマートコントラクトの関数を呼び出すための関数ですが、いくつかの重要な違いがあります。

1. 呼び出しコンテキスト

  • call:呼び出しコントラクトのコンテキストで関数を呼び出します。
  • delegatecall:呼び出しコントラクトのコンテキストで関数を呼び出します。

2. 状態変数

  • call:呼び出しコントラクトの状態変数を参照・変更します。
  • delegatecall:呼び出しコントラクトの状態変数を参照・変更します。

3. メッセージ送信者

  • call:呼び出しコントラクトのアドレスがmsg.senderとして送信されます。
  • delegatecall:呼び出しコントラクトのアドレスがmsg.senderとして送信されます。

4. 呼び出し可能な関数

  • call:すべてのpublicおよびexternal関数を呼び出すことができます。
  • delegatecallfallbackまたはreceive関数を呼び出す必要があります。

5. 使用例

  • call:外部コントラクトとの単純なデータ交換に適しています。
  • delegatecall:ライブラリの実装や、アップグレード可能なコントラクトの作成に適しています。

calldelegatecallのコード例

callの例

pragma solidity ^0.8.0;

contract Caller {
    function callOtherContract(address callee, uint256 value) public {
        // `call`を使用して`callee`コントラクトの`add`関数を呼び出す
        (bool success, bytes memory data) = callee.call(abi.encodeWithSignature("add(uint256)", value));

        // 呼び出し結果をチェック
        if (success) {
            // 呼び出し成功
            uint256 result = abi.decode(data, (uint256));
            // `result`を使用して処理を行う
        } else {
            // 呼び出し失敗
            // エラー処理を行う
        }
    }
}

contract Callee {
    function add(uint256 value) public pure returns (uint256) {
        return value + 1;
    }
}

この例では、Callerコントラクトはcallを使用してCalleeコントラクトのadd関数を呼び出します。callCalleeコントラクトのコンテキストで実行されるため、Calleeコントラクトの状態変数を参照・変更することができます。

delegatecallの例

pragma solidity ^0.8.0;

contract Caller {
    function delegatecallOtherContract(address callee, uint256 value) public {
        // `delegatecall`を使用して`callee`コントラクトの`add`関数を呼び出す
        (bool success, bytes memory data) = callee.delegatecall(abi.encodeWithSignature("add(uint256)", value));

        // 呼び出し結果をチェック
        if (success) {
            // 呼び出し成功
            uint256 result = abi.decode(data, (uint256));
            // `result`を使用して処理を行う
        } else {
            // 呼び出し失敗
            // エラー処理を行う
        }
    }
}

contract Callee {
    fallback() external {
        // `delegatecall`によって呼び出された場合、`add`関数を呼び出す
        add(msg.value);
    }

    function add(uint256 value) public pure returns (uint256) {
        return value + 1;
    }
}

この例では、Callerコントラクトはdelegatecallを使用してCalleeコントラクトのadd関数を呼び出します。delegatecallCallerコントラクトのコンテキストで実行されるため、Callerコントラクトの状態変数を参照・変更することができます。

ポイント

  • calldelegatecallは、呼び出しコンテキスト、状態変数、メッセージ送信者、呼び出し可能な関数などの違いがあります。
  • それぞれの機能を理解して、適切な方法で使い分けることが重要です。

まとめ

  • call:別のスマートコントラクトの関数を独立した関数として呼び出す場合に使用します。
  • delegatecall:別のスマートコントラクトの関数をあたかも自身の関数のように呼び出す場合に使用します。

それぞれの特徴を理解して、適切な方法で使い分けることが重要です。

Discussion