LoginSignup
9
2

More than 5 years have passed since last update.

Solidity 5.0 delegatecall()とcall()

Posted at

はじめに

Solidityには、コントラクトから別のコントラクトを呼び出す機能が有ります。
特に気をつける点として、delegatecall() と call() で、どのコントラクトにstorageされるかが変わります。

delegate() / call()の動作確認

delegate()とcall()の引数は一つになります。
また、bool と bytes が返ってくることで、返り値を取得することができます。

<address>.delegatecall(bytes memory) returns (bool, bytes memory)
<address>.call(bytes memory) returns (bool, bytes memory)

さて、細かい説明はおいといて、まずはサンプルを動かしましょう。
動作を見たいときは、例えばRemixで、下記を貼り付けていただけたら確認できます。

Test.sol
pragma solidity ^0.5.0;

 contract Callee {
     uint256 public x;
     uint256 public y;

     function add(uint256 _x, uint256 _y) public returns(uint256, uint256) {
         x = _x + 1;
         y = _y + 1;
         return (x, y);
     }
 }

 contract Caller {
     uint256 public x;
     uint256 public y;
     uint256 public v;
     uint256 public w;
     address public callee;

     function setCallee(address _callee) public {
         callee = _callee;
     }

     function addCall(uint256 _x, uint256 _y) public {
         (bool success, bytes memory data) = callee.call(abi.encodeWithSignature("add(uint256,uint256)", _x, _y));
         require(success);
         (v, w) = bytesToUint256(data);
     }

     function addDelegateCall(uint256 _x, uint256 _y) public {
         (bool success, bytes memory data) = callee.delegatecall(abi.encodeWithSignature("add(uint256,uint256)", _x, _y));
         require(success);
         (v, w) = bytesToUint256(data);
     }

     function bytesToUint256(bytes memory _b) internal pure returns(uint256, uint256) {
         uint256 res1;
         uint256 res2;
         assembly {
             res1 := mload(add(_b, 32))
             res2 := mload(add(_b, 64))
         }
         return (res1, res2);
     }
}

call()による呼び出し

上記のaddCallで呼び出せます。
addCall()を呼び出すと、Callee.x Callee.yの値が更新され、返り値としてCaller.v Callar.wの値が入ります。

例えば、addCall(1, 2)と呼び出すと、
Callee : v=2 w=3
Caller : x=0 y=0 v=2 w=3

となります。Callerに値が保存されず、Calleeのx,yが更新されます。

つまり、call()を呼び出すと、呼び出した先のコントラクトのStorageが更新されます。

delegatecall()による呼び出し

上記のaddDelegateCallで呼び出せます。

addCall()を呼び出すと、Caller.x Caller.yの値が更新され、返り値としてCaller.v Callar.wの値が入ります。

例えば、addDelegateCall(1, 2)と呼び出すと、
Callee : x=0 y=0
Caller : x=2 y=3 v=2 w=3

となります。Calleeに値が保存されず、Callerのx,yが更新されます。

つまり、delegatecall()を呼び出すと、呼び出した元のコントラクトのStorageが更新されます。

終わりに

delegatecall()とcall()のstorageの違いを、要約すると

  • call()を呼び出すと、呼び出した先のコントラクトのStorageが更新されます。
  • delegatecall()を呼び出すと、呼び出した元のコントラクトのStorageが更新されます。
9
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
2