//tips
//smart contract
Oracleの流れの確認。
先ではoracleのアドレスを変数化して関数にていつでも設定し直すことができるようにした。
ただ、現段階ではpublicにより関数を実行できるため実行者に制約を持たせるためにmodifierを使う。onlyOwnerが適切であろう。
Publicはかなりセキュリティホールになりやすそうなので自身のコントラクトでは入念にチェックした方が良い場所のよう。
public onlyOwner{で解決した。実行に際して通知を行わせるためにイベントの発行も組み込まれている。
pragma solidity 0.5.0;
import "./EthPriceOracleInterface.sol";
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
contract CallerContract is Ownable {
EthPriceOracleInterface private oracleInstance;
address private oracleAddress;
event newOracleAddressEvent(address oracleAddress);
function setOracleInstanceAddress (address _oracleInstanceAddress) public onlyOwner{
oracleAddress = _oracleInstanceAddress;
oracleInstance = EthPriceOracleInterface(oracleAddress);
emit newOracleAddressEvent(oracleAddress);
}
}
これでスマートコントラクトからoracleのコントラクトを呼ぶことができるようになったので、ethの価格の取得に移る。
getLatestEthPriceで最新のethの価格を取得したい。ただ、現実にはそちらの対応は難しいため、ethの価格の代わりにリクエストに対するunique idを返す。
その後にoracleがBinance API などから価格を取得し、スマートコントラクトに取得価格を返すことになる。
つまり、依頼から情報取得までに時差が発生する。 非同期対応であり、いつ情報が得られるかがわからないので、requestのステータスを追跡できるようにしておく必要がある。
このステータスの追跡はmappingで行う。
mapping(uint256=>bool) myRequests;
これを反映してboolで状態管理する関数を組み込んだのが下記。
contract CallerContract is Ownable {
EthPriceOracleInterface private oracleInstance;
address private oracleAddress;
mapping(uint256=>bool) myRequests;
event newOracleAddressEvent(address oracleAddress);
event ReceivedNewRequestIdEvent(uint256 id);
function setOracleInstanceAddress (address _oracleInstanceAddress) public onlyOwner {
oracleAddress = _oracleInstanceAddress;
oracleInstance = EthPriceOracleInterface(oracleAddress);
emit newOracleAddressEvent(oracleAddress);
}
function updateEthPrice() public {
uint256 id = oracleInstance.getLatestEthPrice();
myRequests[id] = true;
emit ReceivedNewRequestIdEvent(id);
}
ここまでの理解はそこまで難しくない。
updateEthPrice()を実行した後にその応答を受け取るのはcallback関数となる。最新のeth情報であることがtrueで確認されたら、callbackで受け取った値をethPriceとして格納し、リクエストと状態をdelete処理する。
ontract CallerContract is Ownable {
uint256 private ethPrice;
EthPriceOracleInterface private oracleInstance;
address private oracleAddress;
mapping(uint256=>bool) myRequests;
event newOracleAddressEvent(address oracleAddress);
event ReceivedNewRequestIdEvent(uint256 id);
event PriceUpdatedEvent(uint256 ethPrice, uint256 id);
function setOracleInstanceAddress (address _oracleInstanceAddress) public onlyOwner {
oracleAddress = _oracleInstanceAddress;
oracleInstance = EthPriceOracleInterface(oracleAddress);
emit newOracleAddressEvent(oracleAddress);
}
function updateEthPrice() public {
uint256 id = oracleInstance.getLatestEthPrice();
myRequests[id] = true;
emit ReceivedNewRequestIdEvent(id);
}
function callback(uint256 _ethPrice, uint256 _id) public onlyOracle {
require(myRequests[_id], "This request is not in my pending list.");
ethPrice = _ethPrice;
delete myRequests[_id];
emit PriceUpdatedEvent(_ethPrice, _id);
}