Ethereum 外部コントラクトの呼び出し方法（Remix, MetaMask連携）

【本文】
---

Ethereumのスマートコントラクトを開発する際、別のコントラクトを呼び出し実行するケースが出てくると思います。
今回は、シンプルなコードで呼び出し事例を紹介します。内容は初心者向けです。

RemixでSolidityベースのスマートコントラクトを開発し、MetaMaskを使い、Ropsten（テストネットワーク）にデプロイしています。本格的にやる場合は別ですが、少し触ってみたいとか、社内向け勉強会で使用する場合等は、特に環境構築で頑張らなくても、Google Chrome上でスマートコントラクトの開発・デプロイ・実行が簡単にできるので、このやり方は覚えておくと良いです。
なお、MetaMaskの導入方法やRemixとRopsten Test Netとの連携方法等は【参考資料】で掲載しているリンクもご参考ください。

【スマートコントラクト】
---

今回のサンプル

**testCalc**

+ calcNumメソッド：　input値(uint）を与え、加算。
+ getNumメソッド：　Storageからxに格納された値（計算結果）を参照。

>```java:testCalc.sol
pragma solidity ^0.4.24;
contract testCalc {
    uint x;
    //計算
    function calcNum(uint _x) external{
        x = x + _x;
    }
    //計算結果取得
    function getNum() public view returns(uint){
        return x;
    }
}
>```

**testCalcCaller**

+ 参照先のContract（今回は「testCalc」）をimport。
+ コンストラクタで、参照先のContractアドレスを取得しオブジェクトにする。
+ CntParcalcValueメソッド：　参照先contractの計算メソッド（calcNum）を呼び出す。

>```java:testCalcCall.sol
pragma solidity ^0.4.24;
// 参照先のコントラクトをimport
import './testCalc.sol';
contract testCalcCaller {
    testCalc public cntAddr;
    //コンストラクタ
    constructor(address _cntAddr) public {
        require(_cntAddr != 0x0);
        //オブジェクト
        cntAddr = testCalc(_cntAddr);
    }
    function CntParcalcValue(uint a) external {
        // cntAddrからcalcNumを実行する
        cntAddr.calcNum(a);
    }
}
>```

【デプロイ】
---

+ （図1）Remix (https://remix.ethereum.org/) をGoogle Chrome上で開き、上記のコントラクトをそれぞれ別ファイルとして作成する。（ファイル名：「xxx.sol」)
+ この時、Remixの右上タブで「Compile」を選択し、エラーになっていないことを確認しておく。（図は割愛。）

（**図1**）
![remix1.png](https://qiita-image-store.s3.amazonaws.com/0/167054/8eb6b972-df7f-79ed-af71-73c8a6a2288a.png)


+ （図2-3）MetaMaskでテストネットワーク（今回はRopsten）を選択しておく。MetaMaskの左上にあるキツネの絵の右隣のプルダウンメニューでMain Ethereum Networkも含め自由に選択可能。（Mainは本番用のネットワーク。）

（**図2**）
![metamask1.png](https://qiita-image-store.s3.amazonaws.com/0/167054/7e3befac-bf55-c913-d6e2-faa4ae977a5a.png)

（**図3**）
![metamask2.png](https://qiita-image-store.s3.amazonaws.com/0/167054/96c9211f-94c2-d3e5-1156-c9831c222cc0.png)

+ Remix上で「Run」より「Environment： injected Web3」（これでRopstenとRemixが連携される。）を選択し、「コントラクト名： testCalc」を選び、「Deploy」ボタンを押下。
+ （図4）MetaMaskが勝手に立ち上がるので、Gas Price（1～4辺り）を設定し、「SUBMIT」ボタンを押下。

（**図4**）
![metamask3.png](https://qiita-image-store.s3.amazonaws.com/0/167054/b3532dd5-690a-66e4-482f-3f66571dacf7.png)

+ （図5）Remixのコンソール画面上に「creation of testCalc pending...」と言うメッセージが表示され、Etherscanへのリンクが表示される。（TxをEtherscan上で確認できる。）
+ 参考として今回デプロイしたTxへのリンクを貼っておく。：「 https://ropsten.etherscan.io/tx/0x31f6e8e8855d7ab58b78e15cb6e7e9549129578c38d121802e6440bf07acddf4 」

（**図5**）
![remix2.png](https://qiita-image-store.s3.amazonaws.com/0/167054/de899d70-d450-3173-c4b5-7e5ac450f384.png)

+ （図6）Remixのコンソール上にデプロイ内容が表示され、右枠にデプロイしたContractアドレス（0x66cc348dee962a7203f5ad72f4e761b059bc09fd）とメソッド等の実行ボタンが表示される。（図例では、「calcNum」と「getNum」）このボタンを通じて、Contractを実行することが可能となる。

（**図6**）
![remix2.png](https://qiita-image-store.s3.amazonaws.com/0/167054/f7dc1ee1-31fe-a93f-5fbc-273a3eb02b88.png)

+ （図7）「getNum」実行結果、「uint256: 0」となっており、まだ計算されていないことを確認。

（**図7**）
![remix3.png](https://qiita-image-store.s3.amazonaws.com/0/167054/a8b8fa60-ea7e-1896-631d-3c577b274cd9.png)

+ （図8）Remix上で今度は「testCalcCall」コントラクトをデプロイする。やり方は、「testCalc」と同じだが、「testCalc」を参照する必要があるので、デプロイ時に「testCalc」のContractアドレス（0x66cc348dee962a7203f5ad72f4e761b059bc09fd）を指定する必要がある。指定したら、「transact」ボタンを押下し実行。
+ MetaMaskが自動的に立ち上がるが、やり方は「testCalc」と同じなので図は割愛。

（**図8**）
![remix4.png](https://qiita-image-store.s3.amazonaws.com/0/167054/c8c91f01-9e40-608c-dce5-5a6e65592a30.png)

+ （図9）Remixのコンソール上にデプロイ内容が表示され、「testCalc」と同様に、右枠にデプロイしたContractアドレス（0x323d96b422e8420fba56cc95d26229e7bc645293）とメソッド等の実行ボタンが表示される。（図例では、「CntParcalcValue」と「cntAddr」）このボタンを通じて、Contractを実行することが可能となる。
+ 参考として今回デプロイしたTxへのリンクを貼っておく。：「 https://ropsten.etherscan.io/tx/0x2418485429ce880a37cb6cd9f91ebaea7f7fe8e999d000a37838e28442390962 」

（**図9**）
![remix5.png](https://qiita-image-store.s3.amazonaws.com/0/167054/e37289fa-a487-d0c3-14c2-59aebd8b4df3.png)


【コントラクト実行】
---

+ 今回は、「testCalcCall」から「testCalc」コントラクトの「calcNum」メソッドを実行するので、Remix上で「testCalcCall」の「CntParcalcValue」メソッドに適当な正数を入力し、コントラクトを実行する。実行の度にMetaMaskが立ち上がるが、図は割愛する。（要は適当なGas Price」を入力し、「SUBMIT」ボタンを押下すればよい。）
+ （図10）始めに、「CntParcalcValue」に引数「10」を入力し、コントラクト実行。
+ 参考Tx：「 https://ropsten.etherscan.io/tx/0x572472f975b428ec5edfd117777d419438515eb56a637903d6c423685fdfdc62 」
+ Remix上で、「testCalc」の「getNum」メソッドを実行すると、「uint256: 10」となり、「testCalcCall」コントラクトから「testCall」コントラクトの「calcNum」メソッドが実行されたことがわかる。

（**図10**）
![remix6.png](https://qiita-image-store.s3.amazonaws.com/0/167054/20d26e28-6716-d267-3d90-70a6664ff648.png)


+ （図11）続いて、「CntParcalcValue」に引数「5」を入力し、コントラクト実行。
+ 参考Tx：「 https://ropsten.etherscan.io/tx/0x61af48306271f9fbca3a77a7f9d4c2ee5d1ac210c3773d9b598438a71f23be78 」
+ Remix上で、「testCalc」の「getNum」メソッドを実行すると、「uint256: 15」となり、「testCalcCall」コントラクトから「testCall」コントラクトの「calcNum」メソッドを通じて加算処理が実行されたことがわかる。

（**図11**）
![remix7.png](https://qiita-image-store.s3.amazonaws.com/0/167054/3cdb40cf-5b15-4c2f-5995-82e2a4e402c1.png)


+ ポイントの一つとして、今回のコントラクトで「getNum」は「view」修飾子を使用している。この「view」を使用することで、トランザクションを発行せずに（つまりgasをかけずに）、直接ストレージに格納された値を参照することが出来る。gasの使用はコントラクト実行者にとっても、またEthereumネットワークにとってもコストや負荷を軽減することになるので、ストレージへの書き込みが不要で読込だけで済む場合は、「view」を使用することが推奨される。

【参考資料】
---

**MetaMask,Remix関連**
・「[Learning Solidity Part 1: Contract Dev with MetaMask](https://karl.tech/learning-solidity-part-1-deploy-a-contract/)」（Karl Floersch さん）
・「[RemixとMetaMaskを使って、Smart Contractの開発環境を整えてみた](https://qiita.com/shiki_tak/items/f169476ecace3bc8d4e4)」（Qiita投稿 by @shiki_tak さん）

**Ethereumのブロックチェーン構造**
・「[Basics of the Ethereum Blockchain](https://github.com/ethereum/wiki/wiki/%5BJapanese%5D--Ethereum-Development-Tutorial#basics-of-the-ethereum-blockchain)」（GitHub: [Japanese] Ethereum Development Tutorial）

**requireとgasとの関係について**
・「[Solidityのassertとrequireとrevertの違い（アルゴリズムとかオーダーとか）](https://y-nakajo.hatenablog.com/entry/2018/01/10/151544)」（なかじょ さん）