// SPDX-License-Identifier: MIT pragma solidity ^0.6.12; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "./interfaces/DioneStakingInterface.sol"; contract DioneOracle is Ownable { using SafeMath for uint256; uint256 private requestCounter; uint256 constant public MAXIMUM_DELAY = 5 minutes; DioneStakingInterface public dioneStaking; struct OracleRequest { uint8 originChain; // origin blockchain for request string requestType; // rpc call type string requestParams; // rpc call params address callbackAddress; // callback address for users request contract bytes4 callbackMethodID; // method for users request contract uint256 reqID; // request counter uint256 deadline; bytes data; } mapping(uint256 => bytes32) private pendingRequests; mapping(address => bool) private activeNodes; event NewOracleRequest( uint8 originChain, string requestType, string requestParams, address callbackAddress, bytes4 callbackMethodID, uint256 reqID, uint256 deadline ); event CancelOracleRequest( uint256 reqID ); event SubmittedOracleRequest( string requestParams, address callbackAddress, bytes4 callbackMethodID, uint256 reqID, uint256 deadline, bytes data ); modifier onlyPendingRequest(uint256 _reqID) { require(pendingRequests[_reqID] != 0, "Invalid requestId"); _; } modifier onlyActiveNode() { require(activeNodes[msg.sender], "Not an active miner"); _; } constructor(DioneStakingInterface _dioneStaking) public { dioneStaking = _dioneStaking; } function requestOracles(uint8 _originChain, string memory _requestType, string memory _requestParams, address _callbackAddress, bytes4 _callbackMethodID) public returns (uint256) { requestCounter += 1; require(pendingRequests[requestCounter] == 0, "This counter is not unique"); uint256 requestDeadline = now.add(MAXIMUM_DELAY); pendingRequests[requestCounter] = keccak256(abi.encodePacked(_requestParams, _callbackAddress, _callbackMethodID, requestCounter, requestDeadline)); emit NewOracleRequest(_originChain, _requestType, _requestParams, _callbackAddress, _callbackMethodID, requestCounter, requestDeadline); return requestCounter; } function cancelOracleRequest(string memory _requestParams, bytes4 _callbackMethodID, uint256 _reqID, uint256 _requestDeadline) public { bytes32 requestHash = keccak256(abi.encodePacked(_requestParams, msg.sender, _callbackMethodID, _reqID, _requestDeadline)); require(requestHash == pendingRequests[_reqID], "Request hash do not match it's origin"); require(_requestDeadline <= now, "Request didn't reached it's deadline"); delete pendingRequests[_reqID]; emit CancelOracleRequest(_reqID); } function submitOracleRequest(string memory _requestParams, address _callbackAddress, bytes4 _callbackMethodID, uint256 _reqID, uint256 _requestDeadline, bytes memory _data) public onlyActiveNode returns (bool) { bytes32 requestHash = keccak256(abi.encodePacked(_requestParams, _callbackAddress, _callbackMethodID, _reqID, _requestDeadline)); require(pendingRequests[_reqID] == requestHash, "Params do not match request ID"); delete pendingRequests[_reqID]; dioneStaking.mine(msg.sender); (bool success, ) = _callbackAddress.call(abi.encodeWithSelector(_callbackMethodID, _reqID, _data)); emit SubmittedOracleRequest(_requestParams, _callbackAddress, _callbackMethodID, _reqID, _requestDeadline, _data); return success; } function setNodeStatus(address _miner, bool _status) public { activeNodes[_miner] = _status; } function isActiveNode(address _miner) public view returns (bool) { return activeNodes[_miner]; } }