solidityから外部APIを呼び出す(Oracle Pattern)

# 記事の内容
solidityから外部APIを呼び出すライブラリがあります。
solidityでそんなことが出来ていいのか？と疑問に思いましたが、ブロックチェーンのOracle問題を解決するための仕組みの様です。

[Provable](https://docs.provable.xyz/)

以下のサイトにも記載されています。

[solidity-patterns Oracle](https://fravoll.github.io/solidity-patterns/oracle.html)

# Oracle Pattern
このOracle PatternではブロックチェーンのOracle問題の対策の一つになり得ます。
ブロックチェーンは登録されたデータが改ざんされることはありませんが、そもそものインプットとなる情報が正しいのかどうかを保証する術はありません。
スマートコントラクトも同様です。

コントラクトに渡されるデータが例えば、天気や運行情報、株価、為替レートなど刻一刻と変わっていく情報だった場合にコントラクト側でそれが正しいかを判断することが出来ません。
このOracle Patternではこういった情報を信頼できる外部のプロバイダーから取得し、正しい情報を使ってコントラクトを実行するというものになります。

# 実装
デザインパターンのまとめサイトにも載ってはいるのですが、ライブラリで提供されているものを呼び出すだけです。
実装は参考にさせていただいたサイトのコードをv0.5.16用に書き替えました。

~~~ ExampleContract.sol
pragma solidity ^0.5.16;

import "github.com/provable-things/ethereum-api/provableAPI_0.5.sol";

contract ExampleContract is usingProvable {

   string public ETHUSD;
   event LogConstructorInitiated(string nextStep);
   event LogPriceUpdated(string price);
   event LogNewProvableQuery(string description);

   function Constructor() public payable {
       emit LogConstructorInitiated("Constructor was initiated. Call 'updatePrice()' to send the Provable Query.");
   }

   function __callback(bytes32 myid, string memory result) public {
       if (msg.sender != provable_cbAddress()) revert();
       ETHUSD = result;
       emit LogPriceUpdated(result);
   }

   function updatePrice() public payable {
       if (provable_getPrice("URL") > address(this).balance) {
           emit LogNewProvableQuery("Provable query was NOT sent, please add some ETH to cover for the query fee");
       } else {
           emit LogNewProvableQuery("Provable query was sent, standing by for the answer..");
           provable_query("URL", "json(https://api.pro.coinbase.com/products/ETH-USD/ticker).price");
       }
   }
}
~~~

updatePrice関数の中で取引所coinbaseのAPIを呼び出しています。
呼び出しているAPIは1ETHとUSDのレートを取得するものになります。

Remixで動かしてみます。

実行結果

~~~
VM error: revert.
revert	The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the value you send should be less than your current balance.	Debug the transaction to get more information.
~~~

デプロイでエラーになりました。


ドキュメントを読んでみるとRemixで動かす場合、プラグインを有効化する必要があるみたいです。
Remixのプラグインマネージャー「Provable - oracle service」を有効化します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476876/1990a1a8-637d-4d1b-442d-c2b3a9d2f8d1.png)


再デプロイ

成功
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476876/1243da6d-7e56-a7a4-ba67-3737af46efa7.png)

updatePrice関数の実行結果

~~~
[
	{
		"from": "0x3c210e984182c331873e235e2fb084188c53941c",
		"topic": "0xc4dc360d0a9c0677a3379ae0a3d81e887f761e65fdf3d7e00859d1bcd3c47389",
		"event": "LogNewProvableQuery",
		"args": {
			"0": "Provable query was sent, standing by for the answer..",
			"description": "Provable query was sent, standing by for the answer..",
			"length": 1
		}
	},
	{
		"from": "0x74c65624deafb25864108d2491fc7093a540bc03",
		"data": "0x0000000000000000000000003c210e984182c331873e235e2fb084188c53941cb616d9ecfb7a3233b6f88e3b840509dc0b80e8b5113f315e568d2d6f247981150000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000030d4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000355524c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000406a736f6e2868747470733a2f2f6170692e70726f2e636f696e626173652e636f6d2f70726f64756374732f4554482d5553442f7469636b6572292e7072696365",
		"topics": [
			"0xb76d0edd90c6a07aa3ff7a222d7f5933e29c6acc660c059c97837f05c4ca1a84"
		]
	}
]
~~~

ETHUSDの値を確認すると$230が設定されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476876/335b02b3-b27f-047d-0d49-0a22cf944fb4.png)

# 感想
solidityだと外部APIの呼び出しは出来ないと思ってました。
これが出来ることでスマートコントラクト実行時のOracle問題も解決出来るものもあると思います。
色々使い道を考えてみようと思います。