diff --git a/contracts/UsingWitnet.sol b/contracts/UsingWitnet.sol index de2ff6ceb..89aeb3af6 100644 --- a/contracts/UsingWitnet.sol +++ b/contracts/UsingWitnet.sol @@ -88,7 +88,7 @@ abstract contract UsingWitnet { /// @param _slaParams The SLA params upon which this data request will be solved by Witnet. /// @return _id The unique identifier of the just posted data request. /// @return _reward Current reward amount escrowed by the WRB until a result gets reported. - function _witnetPostRequest(bytes32 _radHash, WitnetV2.RadonSLA memory _slaParams) + function _witnetPostRequest(bytes32 _radHash, Witnet.RadonSLA memory _slaParams) virtual internal returns (uint256 _id, uint256 _reward) { diff --git a/contracts/WitnetFeeds.sol b/contracts/WitnetFeeds.sol index 616b25489..b4cb7b058 100644 --- a/contracts/WitnetFeeds.sol +++ b/contracts/WitnetFeeds.sol @@ -14,7 +14,7 @@ abstract contract WitnetFeeds IWitnetFeedsAdmin, IWitnetFeedsEvents { - WitnetV2.RadonDataTypes immutable public override dataType; + Witnet.RadonDataTypes immutable public override dataType; WitnetBytecodes immutable public override registry; WitnetRequestBoard immutable public override witnet; @@ -22,7 +22,7 @@ abstract contract WitnetFeeds constructor( WitnetRequestBoard _wrb, - WitnetV2.RadonDataTypes _dataType, + Witnet.RadonDataTypes _dataType, string memory _prefix ) { diff --git a/contracts/WitnetPriceFeeds.sol b/contracts/WitnetPriceFeeds.sol index 60fda9612..8b430caf7 100644 --- a/contracts/WitnetPriceFeeds.sol +++ b/contracts/WitnetPriceFeeds.sol @@ -17,7 +17,7 @@ abstract contract WitnetPriceFeeds constructor(WitnetRequestBoard _wrb) WitnetFeeds( _wrb, - WitnetV2.RadonDataTypes.Integer, + Witnet.RadonDataTypes.Integer, "Price-" ) {} diff --git a/contracts/data/WitnetBoardData.sol b/contracts/data/WitnetBoardData.sol index ce9e7ff8f..05d35e0ce 100644 --- a/contracts/data/WitnetBoardData.sol +++ b/contracts/data/WitnetBoardData.sol @@ -86,7 +86,7 @@ abstract contract WitnetBoardData { /// Gets current status of given query. function _statusOf(uint256 _queryId) - internal view + virtual internal view returns (Witnet.QueryStatus) { Witnet.Query storage _query = __storage().queries[_queryId]; diff --git a/contracts/data/WitnetBytecodesData.sol b/contracts/data/WitnetBytecodesData.sol index adb92052f..a21b8edd3 100644 --- a/contracts/data/WitnetBytecodesData.sol +++ b/contracts/data/WitnetBytecodesData.sol @@ -26,19 +26,25 @@ abstract contract WitnetBytecodesData { string[][] args; bytes32 aggregator; bytes32 radHash; - WitnetV2.RadonDataTypes resultDataType; + Witnet.RadonDataTypes resultDataType; uint16 resultMaxSize; bytes32[] retrievals; bytes32 tally; } + struct DataProvider { + string authority; + uint256 totalEndpoints; + mapping (uint256 => bytes32) endpoints; + } + struct Database { - mapping (uint256 => WitnetV2.DataProvider) providers; + mapping (uint256 => DataProvider) providers; mapping (bytes32 => uint256) providersIndex; - mapping (bytes32 => WitnetV2.RadonReducer) reducers; - mapping (bytes32 => WitnetV2.RadonRetrieval) retrievals; - mapping (bytes32 => WitnetV2.RadonSLA) slas; + mapping (bytes32 => Witnet.RadonReducer) reducers; + mapping (bytes32 => Witnet.RadonRetrieval) retrievals; + mapping (bytes32 => Witnet.RadonSLA) slas; mapping (bytes32 => RadonRequest) requests; mapping (bytes32 => bytes32) rads; diff --git a/contracts/data/WitnetRequestFactoryData.sol b/contracts/data/WitnetRequestFactoryData.sol index b7e04459c..ed3229529 100644 --- a/contracts/data/WitnetRequestFactoryData.sol +++ b/contracts/data/WitnetRequestFactoryData.sol @@ -45,7 +45,7 @@ contract WitnetRequestFactoryData { /// @notice Array of retrievals hashes passed upon construction. bytes32[] retrievals; /// @notice Result data type. - WitnetV2.RadonDataTypes resultDataType; + Witnet.RadonDataTypes resultDataType; /// @notice Result max size or rank (if variable type). uint16 resultDataMaxSize; } diff --git a/contracts/impls/apps/WitnetPriceFeedsBypassV20.sol b/contracts/impls/apps/WitnetPriceFeedsBypassV20.sol new file mode 100644 index 000000000..e3884027c --- /dev/null +++ b/contracts/impls/apps/WitnetPriceFeedsBypassV20.sol @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.8.0 <0.9.0; + +import "../../impls/WitnetUpgradableBase.sol"; +import "../../interfaces/V2/IWitnetPriceFeeds.sol"; + +abstract contract WitnetPriceFeedsV07 { + function supportedFeeds() virtual external view returns (bytes4[] memory, string[] memory, bytes32[] memory); +} + +abstract contract WitnetPriceFeedsV20 { + function isUpgradableFrom(address) virtual external view returns (bool); + function latestUpdateResponseStatus(bytes4) virtual external view returns (WitnetV2.ResponseStatus); + function owner() virtual external view returns (address); + function requestUpdate(bytes4) virtual external payable returns (uint256); + function specs() virtual external view returns (bytes4); +} + +/// @title Witnet Price Feeds surrogate bypass implementation to V2.0 +/// @author The Witnet Foundation +contract WitnetPriceFeedsBypassV20 + is + WitnetUpgradableBase +{ + using Witnet for bytes4; + WitnetPriceFeedsV20 immutable public surrogate; + + constructor ( + WitnetPriceFeedsV20 _surrogate, + bool _upgradable, + bytes32 _versionTag + ) + WitnetUpgradableBase( + _upgradable, + _versionTag, + "io.witnet.proxiable.router" + ) + { + _require( + address(_surrogate).code.length > 0 + && _surrogate.specs() == type(IWitnetPriceFeeds).interfaceId, + "uncompliant surrogate" + ); + surrogate = _surrogate; + } + + // solhint-disable-next-line payable-fallback + fallback() virtual override external { /* solhint-disable no-complex-fallback */ + address _surrogate = address(surrogate); + assembly { /* solhint-disable avoid-low-level-calls */ + // Gas optimized surrogate call to the 'surrogate' immutable contract. + // Note: `msg.data`, `msg.sender` and `msg.value` will be passed over + // to actual implementation of `msg.sig` within `implementation` contract. + let ptr := mload(0x40) + calldatacopy(ptr, 0, calldatasize()) + let result := call(gas(), _surrogate, 0, ptr, calldatasize(), 0, 0) + let size := returndatasize() + returndatacopy(ptr, 0, size) + switch result + case 0 { + // pass back revert message: + revert(ptr, size) + } + default { + // pass back same data as returned by 'implementation' contract: + return(ptr, size) + } + } + } + + function class() public pure returns (string memory) { + return type(WitnetPriceFeedsBypassV20).name; + } + + + // ================================================================================================================ + // --- Overrides 'Upgradeable' ------------------------------------------------------------------------------------- + + function owner() public view override returns (address) { + return surrogate.owner(); + } + + + // ================================================================================================================ + // --- Overrides 'Upgradeable' ------------------------------------------------------------------------------------ + + /// @notice Re-initialize contract's storage context upon a new upgrade from a proxy. + /// @dev Must fail when trying to upgrade to same logic contract more than once. + function initialize(bytes memory) + public override + onlyDelegateCalls // => we don't want the logic base contract to be ever initialized + { + if ( + __proxiable().proxy == address(0) + && __proxiable().implementation == address(0) + ) { + // a proxy is being initialized for the first time... + __proxiable().proxy = address(this); + _transferOwnership(msg.sender); + } else { + // only the owner can initialize: + if (msg.sender != owner()) { + _revert("not the owner"); + } + } + + // Check that new implentation hasn't actually been initialized already: + _require( + __proxiable().implementation != base(), + "already initialized" + ); + + (bytes4[] memory _id4s,,) = WitnetPriceFeedsV07(address(this)).supportedFeeds(); + for (uint _ix = 0; _ix < _id4s.length; _ix ++) { + // Check that all supported price feeds under current implementation + // are actually supported under the surrogate immutable instance, + // and that none of them is currently in pending status: + WitnetV2.ResponseStatus _status = surrogate.latestUpdateResponseStatus(_id4s[_ix]); + _require( + _status == WitnetV2.ResponseStatus.Ready + || _status == WitnetV2.ResponseStatus.Error + || _status == WitnetV2.ResponseStatus.Delivered, + string(abi.encodePacked( + "unconsolidated feed: 0x", + _id4s[_ix].toHexString() + )) + ); + } + + // Set new implementation as initialized: + __proxiable().implementation = base(); + + // Emit event: + emit Upgraded(msg.sender, base(), codehash(), version()); + } + + function isUpgradableFrom(address _from) external view override returns (bool) { + return surrogate.isUpgradableFrom(_from); + } + + + // ================================================================================================================ + // --- Partial interception of 'IWitnetFeeds' --------------------------------------------------------------------- + + function estimateUpdateBaseFee(bytes4, uint256 _gasPrice, uint256) public view returns (uint256) { + return abi.decode( + _staticcall(abi.encodeWithSignature( + "estimateUpdateBaseFee(uint256)", + _gasPrice + )), + (uint256) + ); + } + + function estimateUpdateBaseFee(bytes4, uint256 _gasPrice, uint256, bytes32) external view returns (uint256) { + return abi.decode( + _staticcall(abi.encodeWithSignature( + "estimateUpdateBaseFee(uint256)", + _gasPrice + )), + (uint256) + ); + } + + function latestResponse(bytes4 _feedId) public view returns (Witnet.Response memory) { + WitnetV2.Response memory _responseV2 = abi.decode( + _staticcall(abi.encodeWithSignature( + "lastValidResponse(bytes4)", + _feedId + )), + (WitnetV2.Response) + ); + return Witnet.Response({ + reporter: _responseV2.reporter, + timestamp: uint256(_responseV2.resultTimestamp), + drTxHash: _responseV2.resultTallyHash, + cborBytes: _responseV2.resultCborBytes + }); + } + + function latestResult(bytes4 _feedId) public view returns (Witnet.Result memory) { + return Witnet.resultFromCborBytes( + latestResponse(_feedId).cborBytes + ); + } + + function latestUpdateRequest(bytes4 _feedId) external view returns (Witnet.Request memory) { + WitnetV2.Request memory _requestV2 = abi.decode( + _staticcall(abi.encodeWithSignature( + "latestUpdateRequest(bytes4)", + _feedId + )), + (WitnetV2.Request) + ); + return Witnet.Request({ + addr: address(0), + slaHash: abi.decode(abi.encode(_requestV2.witnetSLA), (bytes32)), + radHash: _requestV2.witnetRAD, + gasprice: tx.gasprice, + reward: uint256(_requestV2.evmReward) + }); + } + + function latestUpdateResponse(bytes4 _feedId) external view returns (Witnet.Response memory) { + WitnetV2.Response memory _responseV2 = abi.decode( + _staticcall(abi.encodeWithSignature( + "latestUpdateResponse(bytes4)", + _feedId + )), + (WitnetV2.Response) + ); + return Witnet.Response({ + reporter: _responseV2.reporter, + timestamp: uint256(_responseV2.resultTimestamp), + drTxHash: bytes32(_responseV2.resultTallyHash), + cborBytes: _responseV2.resultCborBytes + }); + } + + function latestUpdateResultStatus(bytes4 _feedId) external view returns (Witnet.ResultStatus) { + WitnetV2.ResponseStatus _status = abi.decode( + _staticcall(abi.encodeWithSignature( + "latestUpdateResponseStatus(bytes4)", + _feedId + )), + (WitnetV2.ResponseStatus) + ); + if (_status == WitnetV2.ResponseStatus.Finalizing) { + return Witnet.ResultStatus.Awaiting; + } else { + return Witnet.ResultStatus(uint8(_status)); + } + } + + function lookupBytecode(bytes4 _feedId) external view returns (bytes memory) { + return abi.decode( + _staticcall(abi.encodeWithSignature( + "lookupWitnetBytecode(bytes4)", + _feedId + )), + ((bytes)) + ); + } + + function lookupRadHash(bytes4 _feedId) external view returns (bytes32) { + return abi.decode( + _staticcall(abi.encodeWithSignature( + "lookupWitnetRadHash(bytes4)", + _feedId + )), + (bytes32) + ); + } + + function requestUpdate(bytes4 _feedId) external payable returns (uint256 _usedFunds) { + _usedFunds = surrogate.requestUpdate{ + value: msg.value + }( + _feedId + ); + if (_usedFunds < msg.value) { + // transfer back unused funds: + payable(msg.sender).transfer(msg.value - _usedFunds); + } + } + + function requestUpdate(bytes4, bytes32) external payable returns (uint256) { + _revert("deprecated"); + } + + + // ================================================================================================================ + // --- Partial interception of 'IWitnetFeedsAdmin' ---------------------------------------------------------------- + + function settleDefaultRadonSLA(Witnet.RadonSLA calldata _slaV1) external { + _require( + Witnet.isValid(_slaV1), + "invalid SLA" + ); + __call(abi.encodeWithSignature( + "settleDefaultRadonSLA((uint8,uint64))", + WitnetV2.RadonSLA({ + committeeSize: _slaV1.numWitnesses, + witnessingFeeNanoWit: _slaV1.witnessCollateral / _slaV1.numWitnesses + }) + )); + } + + + // ================================================================================================================ + // --- Internal methods ------------------------------------------------------------------------------------------- + + function _require(bool _condition, string memory _message) internal pure { + if (!_condition) { + _revert(_message); + } + } + + function _revert(string memory _reason) internal pure { + revert( + string(abi.encodePacked( + class(), + ": ", + _reason + )) + ); + } + + function _staticcall(bytes memory _encodedCall) internal view returns (bytes memory _returnData) { + bool _success; + (_success, _returnData) = address(surrogate).staticcall(_encodedCall); + _require( + _success, + string(abi.encodePacked( + "cannot surrogate static call: 0x", + msg.sig.toHexString() + )) + ); + } + + function __call(bytes memory _encodedCall) internal returns (bytes memory _returnData) { + bool _success; + (_success, _returnData) = address(surrogate).call(_encodedCall); + _require( + _success, + string(abi.encodePacked( + "cannot surrogate call: 0x", + msg.sig.toHexString() + )) + ); + } + +} \ No newline at end of file diff --git a/contracts/impls/apps/WitnetPriceFeedsUpgradable.sol b/contracts/impls/apps/WitnetPriceFeedsUpgradable.sol index 52332442b..418723c7a 100644 --- a/contracts/impls/apps/WitnetPriceFeedsUpgradable.sol +++ b/contracts/impls/apps/WitnetPriceFeedsUpgradable.sol @@ -18,8 +18,8 @@ contract WitnetPriceFeedsUpgradable WitnetPriceFeedsData, WitnetUpgradableBase { + using Witnet for Witnet.RadonSLA; using Witnet for Witnet.Result; - using WitnetV2 for WitnetV2.RadonSLA; constructor( WitnetRequestBoard _wrb, @@ -32,7 +32,15 @@ contract WitnetPriceFeedsUpgradable _version, "io.witnet.proxiable.router" ) - {} + { + settleDefaultRadonSLA(Witnet.RadonSLA({ + numWitnesses: 5, + witnessCollateral: 20 * 10 ** 9, + witnessReward: 2 * 10 ** 8, + minerCommitRevealFee: 10 ** 7, + minConsensusPercentage: 51 + })); + } // solhint-disable-next-line payable-fallback fallback() override external { @@ -88,7 +96,7 @@ contract WitnetPriceFeedsUpgradable "WitnetPriceFeedsUpgradable: already initialized" ); if (__storage().defaultSlaHash == 0) { - settleDefaultRadonSLA(WitnetV2.RadonSLA({ + settleDefaultRadonSLA(Witnet.RadonSLA({ numWitnesses: 5, witnessCollateral: 20 * 10 ** 9, witnessReward: 2 * 10 ** 8, @@ -172,7 +180,7 @@ contract WitnetPriceFeedsUpgradable function defaultRadonSLA() override public view - returns (WitnetV2.RadonSLA memory) + returns (Witnet.RadonSLA memory) { return registry.lookupRadonSLA(__storage().defaultSlaHash); } @@ -268,10 +276,10 @@ contract WitnetPriceFeedsUpgradable function lookupRetrievals(bytes4 feedId) override external view - returns (WitnetV2.RadonRetrieval[] memory _retrievals) + returns (Witnet.RadonRetrieval[] memory _retrievals) { bytes32[] memory _hashes = registry.lookupRadonRequestSources(lookupRadHash(feedId)); - _retrievals = new WitnetV2.RadonRetrieval[](_hashes.length); + _retrievals = new Witnet.RadonRetrieval[](_hashes.length); for (uint _ix = 0; _ix < _retrievals.length; _ix ++) { _retrievals[_ix] = registry.lookupRadonRetrieval(_hashes[_ix]); } @@ -381,7 +389,7 @@ contract WitnetPriceFeedsUpgradable emit DeletedFeed(msg.sender, feedId, caption); } - function settleDefaultRadonSLA(WitnetV2.RadonSLA memory sla) + function settleDefaultRadonSLA(Witnet.RadonSLA memory sla) override public onlyOwner { diff --git a/contracts/impls/apps/WitnetRandomnessProxiable.sol b/contracts/impls/apps/WitnetRandomnessProxiable.sol index eb6c68279..e995c84ff 100644 --- a/contracts/impls/apps/WitnetRandomnessProxiable.sol +++ b/contracts/impls/apps/WitnetRandomnessProxiable.sol @@ -74,7 +74,7 @@ contract WitnetRandomnessProxiable // Build own Witnet Randomness Request: bytes32[] memory _retrievals = new bytes32[](1); _retrievals[0] = _registry.verifyRadonRetrieval( - WitnetV2.DataRequestMethods.Rng, + Witnet.RadonDataRequestMethods.RNG, "", // no schema "", // no authority "", // no path @@ -83,14 +83,14 @@ contract WitnetRandomnessProxiable new string[2][](0), // no headers hex"80" // no retrieval script ); - WitnetV2.RadonFilter[] memory _filters; - bytes32 _aggregator = _registry.verifyRadonReducer(WitnetV2.RadonReducer({ - opcode: WitnetV2.RadonReducerOpcodes.Mode, + Witnet.RadonFilter[] memory _filters; + bytes32 _aggregator = _registry.verifyRadonReducer(Witnet.RadonReducer({ + opcode: Witnet.RadonReducerOpcodes.Mode, filters: _filters, // no filters script: hex"" // no aggregation script })); - bytes32 _tally = _registry.verifyRadonReducer(WitnetV2.RadonReducer({ - opcode: WitnetV2.RadonReducerOpcodes.ConcatenateAndHash, + bytes32 _tally = _registry.verifyRadonReducer(Witnet.RadonReducer({ + opcode: Witnet.RadonReducerOpcodes.ConcatenateAndHash, filters: _filters, // no filters script: hex"" // no aggregation script })); @@ -151,7 +151,7 @@ contract WitnetRandomnessProxiable Ownable.transferOwnership(_newOwner); } - function settleWitnetRandomnessSLA(WitnetV2.RadonSLA memory _radonSLA) + function settleWitnetRandomnessSLA(Witnet.RadonSLA memory _radonSLA) virtual override public onlyOwner @@ -411,7 +411,7 @@ contract WitnetRandomnessProxiable function witnetRandomnessSLA() virtual override external view - returns (WitnetV2.RadonSLA memory) + returns (Witnet.RadonSLA memory) { return witnet().registry().lookupRadonSLA(__witnetRandomnessSlaHash); } @@ -487,12 +487,12 @@ contract WitnetRandomnessProxiable } function __initializeWitnetRandomnessSlaHash() virtual internal { - settleWitnetRandomnessSLA(WitnetV2.RadonSLA({ + settleWitnetRandomnessSLA(Witnet.RadonSLA({ numWitnesses: 5, minConsensusPercentage: 51, - witnessReward: 2 * 10 ** 8, - witnessCollateral: 2 * 10 ** 9, - minerCommitRevealFee: 10 ** 7 + witnessReward: 2 * 10 ** 8, // 0.2 WIT + witnessCollateral: 2 * 10 ** 10, // 20 WIT + minerCommitRevealFee: 10 ** 7 // 0.01 WIT })); } diff --git a/contracts/impls/core/WitnetBytecodesDefault.sol b/contracts/impls/core/WitnetBytecodesDefault.sol index d4a2c93f9..2758116e7 100644 --- a/contracts/impls/core/WitnetBytecodesDefault.sol +++ b/contracts/impls/core/WitnetBytecodesDefault.sol @@ -26,12 +26,12 @@ contract WitnetBytecodesDefault using Witnet for bytes; using Witnet for string; - using WitnetEncodingLib for WitnetV2.DataRequestMethods; - using WitnetEncodingLib for WitnetV2.RadonRetrieval; - using WitnetEncodingLib for WitnetV2.RadonRetrieval[]; - using WitnetEncodingLib for WitnetV2.RadonReducer; - using WitnetEncodingLib for WitnetV2.RadonSLA; - using WitnetEncodingLib for WitnetV2.RadonDataTypes; + using WitnetEncodingLib for Witnet.RadonDataRequestMethods; + using WitnetEncodingLib for Witnet.RadonRetrieval; + using WitnetEncodingLib for Witnet.RadonRetrieval[]; + using WitnetEncodingLib for Witnet.RadonReducer; + using WitnetEncodingLib for Witnet.RadonSLA; + using WitnetEncodingLib for Witnet.RadonDataTypes; constructor( bool _upgradable, @@ -173,7 +173,7 @@ contract WitnetBytecodesDefault external view returns (bytes memory) { - WitnetV2.RadonSLA storage __sla = __database().slas[_slaHash]; + Witnet.RadonSLA storage __sla = __database().slas[_slaHash]; if (__sla.numWitnesses == 0) { revert IWitnetBytecodesErrors.UnknownRadonSLA(_slaHash); } @@ -224,7 +224,7 @@ contract WitnetBytecodesDefault virtual override returns (bytes32, uint32, uint256) { - WitnetV2.RadonSLA storage __sla = __database().slas[_slaHash]; + Witnet.RadonSLA storage __sla = __database().slas[_slaHash]; { uint _numWitnesses = __sla.numWitnesses; uint _weight = __database().radsBytecode[_radHash].length; @@ -268,7 +268,7 @@ contract WitnetBytecodesDefault external view returns (bytes32[] memory _endpoints) { - WitnetV2.DataProvider storage __provider = __database().providers[_index]; + DataProvider storage __provider = __database().providers[_index]; uint _totalEndpoints = __provider.totalEndpoints; if (_offset < _totalEndpoints){ if (_offset + _length > _totalEndpoints) { @@ -284,10 +284,10 @@ contract WitnetBytecodesDefault function lookupRadonRetrieval(bytes32 _hash) external view override - returns (WitnetV2.RadonRetrieval memory _source) + returns (Witnet.RadonRetrieval memory _source) { _source = __database().retrievals[_hash]; - if (_source.method == WitnetV2.DataRequestMethods.Unknown) { + if (_source.method == Witnet.RadonDataRequestMethods.Unknown) { revert IWitnetBytecodesErrors.UnknownRadonRetrieval(_hash); } } @@ -297,7 +297,7 @@ contract WitnetBytecodesDefault override returns (uint8) { - if (__database().retrievals[_hash].method == WitnetV2.DataRequestMethods.Unknown) { + if (__database().retrievals[_hash].method == Witnet.RadonDataRequestMethods.Unknown) { revert IWitnetBytecodesErrors.UnknownRadonRetrieval(_hash); } return __database().retrievals[_hash].argsCount; @@ -306,9 +306,9 @@ contract WitnetBytecodesDefault function lookupRadonRetrievalResultDataType(bytes32 _hash) external view override - returns (WitnetV2.RadonDataTypes) + returns (Witnet.RadonDataTypes) { - if (__database().retrievals[_hash].method == WitnetV2.DataRequestMethods.Unknown) { + if (__database().retrievals[_hash].method == Witnet.RadonDataRequestMethods.Unknown) { revert IWitnetBytecodesErrors.UnknownRadonRetrieval(_hash); } return __database().retrievals[_hash].resultDataType; @@ -317,7 +317,7 @@ contract WitnetBytecodesDefault function lookupRadonReducer(bytes32 _hash) external view override - returns (WitnetV2.RadonReducer memory _reducer) + returns (Witnet.RadonReducer memory _reducer) { _reducer = __database().reducers[_hash]; if (uint8(_reducer.opcode) == 0) { @@ -328,7 +328,7 @@ contract WitnetBytecodesDefault function lookupRadonRequestAggregator(bytes32 _radHash) external view override - returns (WitnetV2.RadonReducer memory) + returns (Witnet.RadonReducer memory) { return __database().reducers[ __requests(_radHash).aggregator @@ -338,7 +338,7 @@ contract WitnetBytecodesDefault function lookupRadonRequestResultDataType(bytes32 _radHash) external view override - returns (WitnetV2.RadonDataTypes) + returns (Witnet.RadonDataTypes) { return __requests(_radHash).resultDataType; } @@ -370,7 +370,7 @@ contract WitnetBytecodesDefault function lookupRadonRequestTally(bytes32 _radHash) external view override - returns (WitnetV2.RadonReducer memory) + returns (Witnet.RadonReducer memory) { return __database().reducers[ __requests(_radHash).tally @@ -380,7 +380,7 @@ contract WitnetBytecodesDefault function lookupRadonSLA(bytes32 _slaHash) external view override - returns (WitnetV2.RadonSLA memory sla) + returns (Witnet.RadonSLA memory sla) { sla = __database().slas[_slaHash]; if (sla.numWitnesses == 0) { @@ -393,12 +393,12 @@ contract WitnetBytecodesDefault override returns (uint) { - WitnetV2.RadonSLA storage __sla = __database().slas[_slaHash]; + Witnet.RadonSLA storage __sla = __database().slas[_slaHash]; return __sla.numWitnesses * __sla.witnessReward; } function verifyRadonRetrieval( - WitnetV2.DataRequestMethods _requestMethod, + Witnet.RadonDataRequestMethods _requestMethod, string calldata _requestURL, string calldata _requestBody, string[2][] memory _requestHeaders, @@ -413,10 +413,10 @@ contract WitnetBytecodesDefault // should it be a new data source: if ( - __database().retrievals[hash].method == WitnetV2.DataRequestMethods.Unknown + __database().retrievals[hash].method == Witnet.RadonDataRequestMethods.Unknown ) { // compose data source and save it in storage: - __database().retrievals[hash] = WitnetV2.RadonRetrieval({ + __database().retrievals[hash] = Witnet.RadonRetrieval({ argsCount: WitnetBuffer.argsCountOf( abi.encode( @@ -450,7 +450,7 @@ contract WitnetBytecodesDefault } function verifyRadonRetrieval( - WitnetV2.DataRequestMethods _requestMethod, + Witnet.RadonDataRequestMethods _requestMethod, string memory _requestSchema, string memory _requestAuthority, string memory _requestPath, @@ -476,10 +476,10 @@ contract WitnetBytecodesDefault // should it be a new data source: if ( - __database().retrievals[hash].method == WitnetV2.DataRequestMethods.Unknown + __database().retrievals[hash].method == Witnet.RadonDataRequestMethods.Unknown ) { // compose data source and save it in storage: - __database().retrievals[hash] = WitnetV2.RadonRetrieval({ + __database().retrievals[hash] = Witnet.RadonRetrieval({ argsCount: WitnetBuffer.argsCountOf( abi.encode( @@ -524,11 +524,11 @@ contract WitnetBytecodesDefault } } - function verifyRadonReducer(WitnetV2.RadonReducer memory _reducer) + function verifyRadonReducer(Witnet.RadonReducer memory _reducer) external returns (bytes32 hash) { hash = keccak256(abi.encode(_reducer)); - WitnetV2.RadonReducer storage __reducer = __database().reducers[hash]; + Witnet.RadonReducer storage __reducer = __database().reducers[hash]; if ( uint8(__reducer.opcode) == 0 && __reducer.filters.length == 0 @@ -577,15 +577,15 @@ contract WitnetBytecodesDefault } // Check sources and tally reducers: - WitnetV2.RadonReducer memory _aggregator = __database().reducers[_aggregatorId]; - WitnetV2.RadonReducer memory _tally = __database().reducers[_tallyId]; + Witnet.RadonReducer memory _aggregator = __database().reducers[_aggregatorId]; + Witnet.RadonReducer memory _tally = __database().reducers[_tallyId]; if (_tally.script.length > 0) { revert WitnetV2.UnsupportedRadonTallyScript(_tallyId); } // Check result type consistency among all sources: - WitnetV2.RadonDataTypes _resultDataType; - WitnetV2.RadonRetrieval[] memory _retrievals = new WitnetV2.RadonRetrieval[](_retrievalsIds.length); + Witnet.RadonDataTypes _resultDataType; + Witnet.RadonRetrieval[] memory _retrievals = new Witnet.RadonRetrieval[](_retrievalsIds.length); for (uint _ix = 0; _ix < _retrievals.length; _ix ++) { _retrievals[_ix] = __database().retrievals[_retrievalsIds[_ix]]; // Check all sources return same Radon data type: @@ -639,7 +639,7 @@ contract WitnetBytecodesDefault } } - function verifyRadonSLA(WitnetV2.RadonSLA calldata _sla) + function verifyRadonSLA(Witnet.RadonSLA calldata _sla) external virtual override returns (bytes32 _slaHash) @@ -697,8 +697,8 @@ contract WitnetBytecodesDefault } function __pushRadonReducerFilters( - WitnetV2.RadonReducer storage __reducer, - WitnetV2.RadonFilter[] memory _filters + Witnet.RadonReducer storage __reducer, + Witnet.RadonFilter[] memory _filters ) internal virtual diff --git a/contracts/impls/core/WitnetRequestFactoryDefault.sol b/contracts/impls/core/WitnetRequestFactoryDefault.sol index c13eb0294..0967ce287 100644 --- a/contracts/impls/core/WitnetRequestFactoryDefault.sol +++ b/contracts/impls/core/WitnetRequestFactoryDefault.sol @@ -9,6 +9,7 @@ import "../../WitnetBytecodes.sol"; import "../../WitnetRequestFactory.sol"; import "../../data/WitnetRequestFactoryData.sol"; import "../../impls/WitnetUpgradableBase.sol"; +import "../../interfaces/IWitnetRequest.sol"; import "../../patterns/Clonable.sol"; import "../../requests/WitnetRequest.sol"; @@ -83,7 +84,7 @@ contract WitnetRequestFactoryDefault returns (WitnetRequestTemplate) { // check that at least one retrieval is provided - WitnetV2.RadonDataTypes _resultDataType; + Witnet.RadonDataTypes _resultDataType; require( _retrievalsIds.length > 0, "WitnetRequestTemplate: no retrievals?" @@ -471,7 +472,7 @@ contract WitnetRequestFactoryDefault override external view onlyDelegateCalls - returns (WitnetV2.RadonDataTypes) + returns (Witnet.RadonDataTypes) { WitnetRequestTemplate _template = __witnetRequest().template; if (address(_template) != address(0)) { @@ -514,7 +515,7 @@ contract WitnetRequestFactoryDefault override external view onlyDelegateCalls - returns (WitnetV2.RadonReducer memory) + returns (Witnet.RadonReducer memory) { WitnetRequestTemplate _template = __witnetRequest().template; if (address(_template) != address(0)) { @@ -530,7 +531,7 @@ contract WitnetRequestFactoryDefault override external view onlyDelegateCalls - returns (WitnetV2.RadonRetrieval memory) + returns (Witnet.RadonRetrieval memory) { WitnetRequestTemplate _template = __witnetRequest().template; if (address(_template) != address(0)) { @@ -564,7 +565,7 @@ contract WitnetRequestFactoryDefault override external view onlyDelegateCalls - returns (WitnetV2.RadonReducer memory) + returns (Witnet.RadonReducer memory) { WitnetRequestTemplate _template = __witnetRequest().template; if (address(_template) != address(0)) { diff --git a/contracts/impls/core/customs/WitnetRequestBoardBypassV20.sol b/contracts/impls/core/customs/WitnetRequestBoardBypassV20.sol new file mode 100644 index 000000000..3b83e82d3 --- /dev/null +++ b/contracts/impls/core/customs/WitnetRequestBoardBypassV20.sol @@ -0,0 +1,721 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.8.0 <0.9.0; + +import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; + +import "../../WitnetUpgradableBase.sol"; +import "../../../WitnetRequestBoard.sol"; + +import "../../../data/WitnetBoardDataACLs.sol"; + +import "../../../interfaces/V2/IWitnetConsumer.sol"; +import "../../../interfaces/V2/IWitnetOracle.sol"; +import "../../../interfaces/V2/IWitnetOracleEvents.sol"; + +import "../../../libs/WitnetErrorsLib.sol"; + +abstract contract WitnetOracleV07 { + + WitnetRequestFactory immutable public factory; + WitnetBytecodes immutable public registry; + + constructor (WitnetRequestFactory _factory) { + require( + _factory.class() == type(WitnetRequestFactory).interfaceId, + "WitnetRequestBoardBypassV20: uncompliant factory" + ); + factory = _factory; + registry = _factory.registry(); + } +} + +abstract contract WitnetOracleV20 + is + IWitnetOracle, + IWitnetOracleEvents +{ + function specs() virtual external view returns (bytes4); +} + +/// @title Witnet Request Board bypass implementation to V2.0 +/// @author The Witnet Foundation +contract WitnetRequestBoardBypassV20 + is + IWitnetConsumer, + IWitnetOracleEvents, + IWitnetRequestBoardEvents, + WitnetUpgradableBase, + WitnetOracleV07, + WitnetBoardDataACLs +{ + using ERC165Checker for address; + + using Witnet for bytes; + using Witnet for Witnet.Result; + + WitnetOracleV07 immutable public legacy; + WitnetOracleV20 immutable public surrogate; + + uint24 immutable public legacyCallbackLimit; + + uint8 constant internal _DEFAULT_SLA_COMMITTEE_SIZE = 10; + uint64 constant internal _DEFAULT_SLA_WITNESSING_FEE_NANOWIT = 200000000; + + function defaultRadonSLA() virtual public pure returns (WitnetV2.RadonSLA memory) { + return WitnetV2.RadonSLA({ + committeeSize: _DEFAULT_SLA_COMMITTEE_SIZE, + witnessingFeeNanoWit: _DEFAULT_SLA_WITNESSING_FEE_NANOWIT + }); + } + + modifier legacyFallback(uint256 queryId) { + if (queryId <= __storage().numQueries) { + __legacyFallback(); + } else { + _; + } + } + + modifier onlySurrogate { + require( + msg.sender == address(surrogate), + "WitnetRequestBoardBypassV20: only surrogate" + ); _; + } + + constructor( + WitnetOracleV07 _legacy, + WitnetOracleV20 _surrogate, + bool _upgradable, + bytes32 _versionTag, + uint24 _legacyCallbackLimit + ) + WitnetOracleV07(_legacy.factory()) + WitnetUpgradableBase( + _upgradable, + _versionTag, + "io.witnet.proxiable.board" + ) + { + legacy = _legacy; + require( + address(_surrogate).code.length > 0 + && _surrogate.specs() == type(IWitnetOracle).interfaceId, + "WitnetRequestBoardBypassV20: uncompliant WitnetOracle" + ); + surrogate = _surrogate; + require( + _legacyCallbackLimit >= 50000, + "WitnetRequestBoardBypassV20: legacy callback too low" + ); + legacyCallbackLimit = _legacyCallbackLimit; + } + + receive() external payable { + revert("WitnetRequestBoardBypassV20: no transfers accepted"); + } + + /// @dev Fallback unhandled methods to whatever the late legacy implementation was supported + // solhint-disable-next-line payable-fallback + fallback() virtual override external { /* solhint-disable no-complex-fallback */ + __legacyFallback(); + } + + function numLegacyQueries() external view returns (uint256) { + return __storage().numQueries; + } + + + // ================================================================================================================ + // --- Implementation of IERC165 interface ------------------------------------------------------------------------ + + /// @dev See {IERC165-supportsInterface}. + function supportsInterface(bytes4 _interfaceId) public view virtual override returns (bool) { + return ( + _interfaceId == type(WitnetRequestBoard).interfaceId + || super.supportsInterface(_interfaceId) + ); + } + + + // ================================================================================================================ + // --- Implementation of 'Upgradeable' ---------------------------------------------------------------------------- + + /// @notice Re-initialize contract's storage context upon a new upgrade from a proxy. + /// @dev Must fail when trying to upgrade to same logic contract more than once. + function initialize(bytes memory) public override { + address _owner = __storage().owner; + if (_owner == address(0)) { + revert("WitnetRequestBoardBypassV20: cannot bypass uninitialized proxy"); + } else { + // only owner can initialize: + require( + msg.sender == _owner, + "WitnetRequestBoardBypassV20: only legacy owner" + ); + } + + if (__storage().base != address(0)) { + // current implementation cannot be initialized more than once: + require( + __storage().base != base(), + "WitnetRequestBoardBypassV20: already upgraded" + ); + } + __storage().base = base(); + + emit Upgraded(msg.sender, base(), codehash(), version()); + } + + /// Tells whether provided address could eventually upgrade the contract. + function isUpgradableFrom(address _from) external view override returns (bool) { + address _owner = __storage().owner; + return ( + // false if the WRB is intrinsically not upgradable, or `_from` is no owner + isUpgradable() + && _owner == _from + ); + } + + + // ================================================================================================================ + // --- Implementation of 'Ownable' -------------------------------------------------------------------------------- + + /// Gets admin/owner address. + function owner() public view override returns (address) { + return __storage().owner; + } + + /// Transfers ownership. + function transferOwnership(address _newOwner) public override onlyOwner { + address _owner = __storage().owner; + if (_newOwner != _owner) { + __storage().owner = _newOwner; + emit OwnershipTransferred(_owner, _newOwner); + } + } + + + // ================================================================================================================ + // --- Implementation of 'IWitnetConsumer' ------------------------------------------------------------------------ + + /// @notice Method to be called from the WitnetOracle contract as soon as the given Witnet `queryId` + /// @notice gets reported, if reported with no errors. + /// @dev It should revert if called from any other address different to the WitnetOracle being used + /// @dev by the WitnetConsumer contract. + /// @param _witnetQueryId The unique identifier of the Witnet query being reported. + /// @param _witnetResultCborValue The CBOR-encoded resulting value of the Witnet query being reported. + function reportWitnetQueryResult( + uint256 _witnetQueryId, + uint64, bytes32, uint256, + WitnetCBOR.CBOR calldata _witnetResultCborValue + ) + external override + onlySurrogate + { + _witnetQueryId += __storage().numQueries; + require( + _statusOf(_witnetQueryId) == Witnet.QueryStatus.Posted, + "WitnetRequestBoardBypassV20: not in Posted status" + ); + Witnet.Query storage __record = __storage().queries[_witnetQueryId]; + __record.response = Witnet.Response({ + reporter: address(0), //msg.sender, + timestamp: 0, // uint256(_witnetResultTimestamp), + drTxHash: 0, // _witnetResultTallyHash, + cborBytes: _witnetResultCborValue.buffer.data + }); + emit PostedResult(_witnetQueryId, msg.sender); + } + + /// @notice Method to be called from the WitnetOracle contract as soon as the given Witnet `queryId` + /// @notice gets reported, if reported WITH errors. + /// @dev It should revert if called from any other address different to the WitnetOracle being used + /// @dev by the WitnetConsumer contract. + /// @param _witnetQueryId The unique identifier of the Witnet query being reported. + /// @param _errorArgs Error arguments, if any. An empty buffer is to be passed if no error arguments apply. + function reportWitnetQueryError( + uint256 _witnetQueryId, + uint64, bytes32, uint256, + Witnet.ResultErrorCodes, + WitnetCBOR.CBOR calldata _errorArgs + ) + external override + onlySurrogate + { + _witnetQueryId += __storage().numQueries; + require( + _statusOf(_witnetQueryId) == Witnet.QueryStatus.Posted, + "WitnetRequestBoardBypassV20: not in Posted status" + ); + Witnet.Query storage __record = __storage().queries[_witnetQueryId]; + __record.response = Witnet.Response({ + reporter: address(0), //msg.sender, + timestamp: 0, //uint256(_witnetResultTimestamp), + drTxHash: 0, //_witnetResultTallyHash, + cborBytes: _errorArgs.buffer.data + }); + emit PostedResult(_witnetQueryId, msg.sender); + } + + + /// @notice Determines if Witnet queries can be reported from given address. + /// @dev In practice, must only be true on the WitnetOracle address that's being used by + /// @dev the WitnetConsumer to post queries. + function reportableFrom(address _from) external view override returns (bool) { + return ( + _from == address(surrogate) + ); + } + + + // ================================================================================================================ + // --- Interception of 'IWitnetRequestBoardReporter' -------------------------------------------------------------- + + function reportResult(uint256 _queryId, bytes32, bytes calldata) + external + legacyFallback(_queryId) + { + revert("WitnetRequestBoardBypassV20: not permitted"); + } + + function reportResult(uint256 _queryId, uint256, bytes32, bytes calldata) + external + legacyFallback(_queryId) + { + revert("WitnetRequestBoardBypassV20: not permitted"); + } + + function reportResultBatch(IWitnetRequestBoardReporter.BatchResult[] memory, bool) + external pure + { + revert("WitnetRequestBoardBypassV20: not permitted"); + } + + + // ================================================================================================================ + // --- Full interception of 'IWitnetRequestBoardRequestor' -------------------------------------------------------- + + /// @notice Returns query's result current status from a requester's point of view: + /// @notice - 0 => Void: the query is either non-existent or deleted; + /// @notice - 1 => Awaiting: the query has not yet been reported; + /// @notice - 2 => Ready: the query has been succesfully solved; + /// @notice - 3 => Error: the query couldn't get solved due to some issue. + /// @param _queryId The unique query identifier. + function checkResultStatus(uint256 _queryId) + public + legacyFallback(_queryId) + returns (Witnet.ResultStatus) + { + Witnet.QueryStatus _status = _statusOf(_queryId); + if (_status == Witnet.QueryStatus.Reported) { + if (__response(_queryId).cborBytes[0] == bytes1(0xd8)) { + return Witnet.ResultStatus.Error; + } else { + return Witnet.ResultStatus.Ready; + } + } else if (_status == Witnet.QueryStatus.Posted) { + return Witnet.ResultStatus.Awaiting; + } else { + return Witnet.ResultStatus.Void; + } + } + + /// @notice Gets error code identifying some possible failure on the resolution of the given query. + /// @param _queryId The unique query identifier. + function checkResultError(uint256 _queryId) + external + legacyFallback(_queryId) + returns (Witnet.ResultError memory) + { + Witnet.ResultStatus _status = checkResultStatus(_queryId); + if (_status == Witnet.ResultStatus.Awaiting) { + return Witnet.ResultError({ + code: Witnet.ResultErrorCodes.Unknown, + reason: "WitnetRequestBoardBypassV20: not yet solved" + }); + } else if (_status == Witnet.ResultStatus.Void) { + return Witnet.ResultError({ + code: Witnet.ResultErrorCodes.Unknown, + reason: "WitnetRequestBoardBypassV20: unknown query" + }); + } else { + try WitnetErrorsLib.resultErrorFromCborBytes(__response(_queryId).cborBytes) + returns (Witnet.ResultError memory _error) + { + return _error; + } + catch Error(string memory _reason) { + return Witnet.ResultError({ + code: Witnet.ResultErrorCodes.Unknown, + reason: string(abi.encodePacked("WitnetErrorsLib: ", _reason)) + }); + } + catch (bytes memory) { + return Witnet.ResultError({ + code: Witnet.ResultErrorCodes.Unknown, + reason: "WitnetErrorsLib: assertion failed" + }); + } + } + } + + /// Retrieves copy of all response data related to a previously posted request, removing the whole query from storage. + /// @dev Fails if the `_queryId` is not in 'Reported' status, or called from an address different to + /// @dev the one that actually posted the given request. + /// @param _queryId The unique query identifier. + function deleteQuery(uint256 _queryId) + external + legacyFallback(_queryId) + returns (Witnet.Response memory _response) + { + Witnet.Query storage __record = __storage().queries[_queryId]; + require( + msg.sender == __record.from, + "WitnetRequestBoardBypassV20: only requester" + ); + WitnetV2.Response memory _responseV2 = surrogate.fetchQueryResponse( + _queryId - __storage().numQueries + ); + _response = Witnet.Response({ + reporter: _responseV2.reporter, + timestamp: uint256(_responseV2.resultTimestamp), + drTxHash: _responseV2.resultTallyHash, + cborBytes: __record.response.cborBytes + }); + delete __storage().queries[_queryId]; + } + + /// Requests the execution of the given Witnet Data Request in expectation that it will be relayed and solved by the Witnet DON. + /// A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided + /// result to this request. + /// @dev Fails if: + /// @dev - provided reward is too low. + /// @dev - provided address is zero. + /// @param _witnetRequest The address of a IWitnetRequest contract, containing the actual Data Request seralized bytecode. + /// @return _queryId An unique query identifier. + function postRequest(IWitnetRequest _witnetRequest) + external payable + returns (uint256 _queryId) + { + _queryId = ( + __storage().numQueries + + surrogate.postRequestWithCallback{ + value: msg.value + }( + _witnetRequest.bytecode(), + defaultRadonSLA(), + legacyCallbackLimit + ) + ); + __storage().queries[_queryId].from = msg.sender; + __storage().queries[_queryId].request.addr = address(_witnetRequest); + __storage().queries[_queryId].request.gasprice = tx.gasprice; + } + + /// Requests the execution of the given Witnet Data Request in expectation that it will be relayed and solved by the Witnet DON. + /// A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided + /// result to this request. + /// @dev Fails if: + /// @dev - provided reward is too low. + /// @param _radHash The radHash of the Witnet Data Request. + /// @param _slaHash The slaHash of the Witnet Data Request. + function postRequest(bytes32 _radHash, bytes32 _slaHash) + external payable + returns (uint256 _queryId) + { + Witnet.RadonSLA memory _slaParams = registry.lookupRadonSLA(_slaHash); + _queryId = ( + __storage().numQueries + + surrogate.postRequestWithCallback{ + value: msg.value + }( + registry.bytecodeOf(_radHash), + WitnetV2.RadonSLA({ + committeeSize: _slaParams.numWitnesses, + witnessingFeeNanoWit: _slaParams.witnessCollateral / 100 + }), + legacyCallbackLimit + ) + ); + __storage().queries[_queryId].from = msg.sender; + __storage().queries[_queryId].request.gasprice = tx.gasprice; + __storage().queries[_queryId].request.radHash = _radHash; + __storage().queries[_queryId].request.slaHash = _slaHash; + } + + /// Requests the execution of the given Witnet Data Request in expectation that it will be relayed and solved by the Witnet DON. + /// A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided + /// result to this request. + /// @dev Fails if: + /// @dev - provided reward is too low. + /// @param _radHash The RAD hash of the data tequest to be solved by Witnet. + /// @param _slaParams The SLA param of the data request to be solved by Witnet. + function postRequest( + bytes32 _radHash, + Witnet.RadonSLA calldata _slaParams + ) + public payable + returns (uint256 _queryId) + { + _queryId = ( + __storage().numQueries + + surrogate.postRequestWithCallback{ + value: msg.value + }( + registry.bytecodeOf(_radHash), + WitnetV2.RadonSLA({ + committeeSize: _slaParams.numWitnesses, + witnessingFeeNanoWit: _slaParams.witnessCollateral / 100 + }), + legacyCallbackLimit + ) + ); + __storage().queries[_queryId].from = msg.sender; + __storage().queries[_queryId].request.gasprice = tx.gasprice; + __storage().queries[_queryId].request.radHash = _radHash; + __storage().queries[_queryId].request.slaHash = registry.verifyRadonSLA(_slaParams); + } + + /// Increments the reward of a previously posted request by adding the transaction value to it. + /// @dev Updates request `gasPrice` in case this method is called with a higher + /// @dev gas price value than the one used in previous calls to `postRequest` or + /// @dev `upgradeReward`. + /// @dev Fails if the `_queryId` is not in 'Posted' status. + /// @dev Fails also in case the request `gasPrice` is increased, and the new + /// @dev reward value gets below new recalculated threshold. + /// @param _queryId The unique query identifier. + function upgradeReward(uint256 _queryId) + external payable + legacyFallback(_queryId) + { + surrogate.upgradeQueryEvmReward{ + value: msg.value + }( + _queryId - __storage().numQueries + ); + if (__request(_queryId).gasprice < tx.gasprice) { + __request(_queryId).gasprice = tx.gasprice; + } + } + + + // ================================================================================================================ + // --- Full interception of 'IWitnetRequestBoardView' ------------------------------------------------------------- + + /// Estimates the amount of reward we need to insert for a given gas price. + /// @param _gasPrice The gas price for which we need to calculate the rewards. + function estimateReward(uint256 _gasPrice) external view returns (uint256) { + return surrogate.estimateBaseFeeWithCallback( + _gasPrice, + legacyCallbackLimit + ); + } + + /// Returns next request id to be generated by the Witnet Request Board. + function getNextQueryId() external view returns (uint256) { + return ( + __storage().numQueries + + surrogate.getNextQueryId() + ); + } + + /// Gets the whole Query data contents, if any, no matter its current status. + function getQueryData(uint256 _queryId) + external + legacyFallback(_queryId) + returns (Witnet.Query memory) + { + return Witnet.Query({ + from: __query(_queryId).from, + request: readRequest(_queryId), + response: readResponse(_queryId) + }); + } + + /// Gets current status of given query. + function getQueryStatus(uint256 _queryId) + external + legacyFallback(_queryId) + returns (Witnet.QueryStatus) + { + return Witnet.QueryStatus(uint8( + surrogate.getQueryStatus( + _queryId - __storage().numQueries + ) + )); + } + + /// Retrieves the whole Request record posted to the Witnet Request Board. + /// @dev Fails if the `_queryId` is not valid or, if it has already been reported + /// @dev or deleted. + /// @param _queryId The unique identifier of a previously posted query. + function readRequest(uint256 _queryId) + public + legacyFallback(_queryId) + returns (Witnet.Request memory _request) + { + return Witnet.Request({ + addr: __request(_queryId).addr, + slaHash: __request(_queryId).slaHash, + radHash: __request(_queryId).radHash, + gasprice: __request(_queryId).gasprice, + reward: surrogate.getQueryEvmReward(_queryId - __storage().numQueries) + }); + } + + /// Retrieves the serialized bytecode of a previously posted Witnet Data Request. + /// @dev Fails if the `_queryId` is not valid, or if the related script bytecode + /// @dev got changed after being posted. Returns empty array once it gets reported, + /// @dev or deleted. + /// @param _queryId The unique query identifier. + function readRequestBytecode(uint256 _queryId) + external + legacyFallback(_queryId) + returns (bytes memory _bytecode) + { + WitnetV2.Request memory _requestV2 = surrogate.getQueryRequest( + _queryId - __storage().numQueries + ); + return _requestV2.witnetBytecode; + } + + /// @notice Retrieves the gas price that any assigned reporter will have to pay when reporting + /// result to a previously posted Witnet data request. + /// @dev Fails if the `_queryId` is not valid or, if it has already been + /// @dev reported, or deleted. + /// @param _queryId The unique query identifie + function readRequestGasPrice(uint256 _queryId) + external + legacyFallback(_queryId) + returns (uint256) + { + return __request(_queryId).gasprice; + } + + /// Retrieves the reward currently set for a previously posted request. + /// @dev Fails if the `_queryId` is not valid or, if it has already been + /// @dev reported, or deleted. + /// @param _queryId The unique query identifier + function readRequestReward(uint256 _queryId) external legacyFallback(_queryId) returns (uint256) { + return surrogate.getQueryEvmReward( + _queryId - __storage().numQueries + ); + } + + /// Retrieves the Witnet-provided result, and metadata, to a previously posted request. + /// @dev Fails if the `_queryId` is not in 'Reported' status. + /// @param _queryId The unique query identifier + function readResponse(uint256 _queryId) + public + legacyFallback(_queryId) + returns (Witnet.Response memory _response) + { + WitnetV2.Response memory _responseV2 = surrogate.getQueryResponse( + _queryId - __storage().numQueries + ); + return Witnet.Response({ + reporter: _responseV2.reporter, + timestamp: uint256(_responseV2.resultTimestamp), + drTxHash: _responseV2.resultTallyHash, + cborBytes: __response(_queryId).cborBytes + }); + } + + /// Retrieves the hash of the Witnet transaction that actually solved the referred query. + /// @dev Fails if the `_queryId` is not in 'Reported' status. + /// @param _queryId The unique query identifier. + function readResponseDrTxHash(uint256 _queryId) + external + legacyFallback(_queryId) + returns (bytes32) + { + WitnetV2.Response memory _responseV2 = surrogate.getQueryResponse( + _queryId - __storage().numQueries + ); + return _responseV2.resultTallyHash; + } + + /// Retrieves the address that reported the result to a previously-posted request. + /// @dev Fails if the `_queryId` is not in 'Reported' status. + /// @param _queryId The unique query identifier + function readResponseReporter(uint256 _queryId) + external + legacyFallback(_queryId) + returns (address) + { + WitnetV2.Response memory _responseV2 = surrogate.getQueryResponse( + _queryId - __storage().numQueries + ); + return _responseV2.reporter; + } + + /// Retrieves the Witnet-provided CBOR-bytes result of a previously posted request. + /// @dev Fails if the `_queryId` is not in 'Reported' status. + /// @param _queryId The unique query identifier + function readResponseResult(uint256 _queryId) + external + legacyFallback(_queryId) + returns (Witnet.Result memory) + { + return Witnet.resultFromCborBytes(__response(_queryId).cborBytes); + } + + /// Retrieves the timestamp in which the result to the referred query was solved by the Witnet DON. + /// @dev Fails if the `_queryId` is not in 'Reported' status. + /// @param _queryId The unique query identifier. + function readResponseTimestamp(uint256 _queryId) + external + legacyFallback(_queryId) + returns (uint256) + { + WitnetV2.Response memory _responseV2 = surrogate.getQueryResponse( + _queryId - __storage().numQueries + ); + return uint256(_responseV2.resultTimestamp); + } + + + // ================================================================================================================ + // --- Internal functions ----------------------------------------------------------------------------------------- + + function _statusOf(uint256 _queryId) + override internal view + returns (Witnet.QueryStatus) + { + Witnet.Query storage _query = __storage().queries[_queryId]; + if (_query.response.cborBytes.length != 0) { + return Witnet.QueryStatus.Reported; + } + else if (_query.from != address(0)) { + return Witnet.QueryStatus.Posted; + } + else { + return Witnet.QueryStatus.Unknown; + } + } + + function __legacyFallback() internal { + address _legacy = address(legacy); + assembly { /* solhint-disable avoid-low-level-calls */ + // Gas optimized delegate call to 'implementation' contract. + // Note: `msg.data`, `msg.sender` and `msg.value` will be passed over + // to actual implementation of `msg.sig` within `implementation` contract. + let ptr := mload(0x40) + calldatacopy(ptr, 0, calldatasize()) + let result := delegatecall(gas(), _legacy, ptr, calldatasize(), 0, 0) + let size := returndatasize() + returndatacopy(ptr, 0, size) + switch result + case 0 { + // pass back revert message: + revert(ptr, size) + } + default { + // pass back same data as returned by 'implementation' contract: + return(ptr, size) + } + } + } +} diff --git a/contracts/impls/core/customs/WitnetRequestBoardTrustableBase.sol b/contracts/impls/core/customs/WitnetRequestBoardTrustableBase.sol index b70391bc3..389251a5d 100644 --- a/contracts/impls/core/customs/WitnetRequestBoardTrustableBase.sol +++ b/contracts/impls/core/customs/WitnetRequestBoardTrustableBase.sol @@ -533,7 +533,7 @@ abstract contract WitnetRequestBoardTrustableBase /// @dev - provided reward is too low. /// @param _radHash The RAD hash of the data tequest to be solved by Witnet. /// @param _slaParams The SLA param of the data request to be solved by Witnet. - function postRequest(bytes32 _radHash, WitnetV2.RadonSLA calldata _slaParams) + function postRequest(bytes32 _radHash, Witnet.RadonSLA calldata _slaParams) virtual override public payable returns (uint256 _queryId) diff --git a/contracts/interfaces/IWitnetRandomness.sol b/contracts/interfaces/IWitnetRandomness.sol index f3759b945..d8f2c97a6 100644 --- a/contracts/interfaces/IWitnetRandomness.sol +++ b/contracts/interfaces/IWitnetRandomness.sol @@ -101,6 +101,6 @@ interface IWitnetRandomness { function witnetRandomnessRequest() external view returns (WitnetRequest); /// @notice Returns SLA parameters that are being used every time there's a new randomness request. - function witnetRandomnessSLA() external view returns (WitnetV2.RadonSLA memory); + function witnetRandomnessSLA() external view returns (Witnet.RadonSLA memory); } \ No newline at end of file diff --git a/contracts/interfaces/IWitnetRandomnessAdmin.sol b/contracts/interfaces/IWitnetRandomnessAdmin.sol index 741eb6648..2dd7dd1b9 100644 --- a/contracts/interfaces/IWitnetRandomnessAdmin.sol +++ b/contracts/interfaces/IWitnetRandomnessAdmin.sol @@ -9,5 +9,5 @@ interface IWitnetRandomnessAdmin { function acceptOwnership() external; function pendingOwner() external returns (address); function transferOwnership(address) external; - function settleWitnetRandomnessSLA(WitnetV2.RadonSLA calldata) external returns (bytes32); + function settleWitnetRandomnessSLA(Witnet.RadonSLA calldata) external returns (bytes32); } \ No newline at end of file diff --git a/contracts/interfaces/IWitnetRequestBoardRequestor.sol b/contracts/interfaces/IWitnetRequestBoardRequestor.sol index 2dbb46537..8c0099f8f 100644 --- a/contracts/interfaces/IWitnetRequestBoardRequestor.sol +++ b/contracts/interfaces/IWitnetRequestBoardRequestor.sol @@ -3,6 +3,7 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; +import "./IWitnetRequest.sol"; import "../libs/WitnetV2.sol"; /// @title Witnet Requestor Interface @@ -59,7 +60,7 @@ interface IWitnetRequestBoardRequestor { /// @param radHash The RAD hash of the data request to be solved by Witnet. /// @param slaParams The SLA params of the data request to be solved by Witnet. /// @return _queryId Unique query identifier. - function postRequest(bytes32 radHash, WitnetV2.RadonSLA calldata slaParams) external payable returns (uint256 _queryId); + function postRequest(bytes32 radHash, Witnet.RadonSLA calldata slaParams) external payable returns (uint256 _queryId); /// @notice Increments the reward of a previously posted request by adding the transaction value to it. /// @dev Updates request `gasPrice` in case this method is called with a higher diff --git a/contracts/interfaces/V2/IWitnetBytecodes.sol b/contracts/interfaces/V2/IWitnetBytecodes.sol index 10d7f2c8c..8ad449f71 100644 --- a/contracts/interfaces/V2/IWitnetBytecodes.sol +++ b/contracts/interfaces/V2/IWitnetBytecodes.sol @@ -27,24 +27,24 @@ interface IWitnetBytecodes { function lookupDataProviderIndex(string calldata authority) external view returns (uint); function lookupDataProviderSources(uint256 index, uint256 offset, uint256 length) external view returns (bytes32[] memory); - function lookupRadonReducer(bytes32 hash) external view returns (WitnetV2.RadonReducer memory); + function lookupRadonReducer(bytes32 hash) external view returns (Witnet.RadonReducer memory); - function lookupRadonRetrieval(bytes32 hash) external view returns (WitnetV2.RadonRetrieval memory); + function lookupRadonRetrieval(bytes32 hash) external view returns (Witnet.RadonRetrieval memory); function lookupRadonRetrievalArgsCount(bytes32 hash) external view returns (uint8); - function lookupRadonRetrievalResultDataType(bytes32 hash) external view returns (WitnetV2.RadonDataTypes); + function lookupRadonRetrievalResultDataType(bytes32 hash) external view returns (Witnet.RadonDataTypes); - function lookupRadonRequestAggregator(bytes32 radHash) external view returns (WitnetV2.RadonReducer memory); + function lookupRadonRequestAggregator(bytes32 radHash) external view returns (Witnet.RadonReducer memory); function lookupRadonRequestResultMaxSize(bytes32 radHash) external view returns (uint256); - function lookupRadonRequestResultDataType(bytes32 radHash) external view returns (WitnetV2.RadonDataTypes); + function lookupRadonRequestResultDataType(bytes32 radHash) external view returns (Witnet.RadonDataTypes); function lookupRadonRequestSources(bytes32 radHash) external view returns (bytes32[] memory); function lookupRadonRequestSourcesCount(bytes32 radHash) external view returns (uint); - function lookupRadonRequestTally(bytes32 radHash) external view returns (WitnetV2.RadonReducer memory); + function lookupRadonRequestTally(bytes32 radHash) external view returns (Witnet.RadonReducer memory); - function lookupRadonSLA(bytes32 slaHash) external view returns (WitnetV2.RadonSLA memory); + function lookupRadonSLA(bytes32 slaHash) external view returns (Witnet.RadonSLA memory); function lookupRadonSLAReward(bytes32 slaHash) external view returns (uint); function verifyRadonRetrieval( - WitnetV2.DataRequestMethods requestMethod, + Witnet.RadonDataRequestMethods requestMethod, string calldata requestSchema, string calldata requestAuthority, string calldata requestPath, @@ -55,14 +55,14 @@ interface IWitnetBytecodes { ) external returns (bytes32 hash); function verifyRadonRetrieval( - WitnetV2.DataRequestMethods requestMethod, + Witnet.RadonDataRequestMethods requestMethod, string calldata requestURL, string calldata requestBody, string[2][] calldata requestHeaders, bytes calldata requestRadonScript ) external returns (bytes32 hash); - function verifyRadonReducer(WitnetV2.RadonReducer calldata reducer) + function verifyRadonReducer(Witnet.RadonReducer calldata reducer) external returns (bytes32 hash); function verifyRadonRequest( @@ -73,7 +73,7 @@ interface IWitnetBytecodes { string[][] calldata args ) external returns (bytes32 radHash); - function verifyRadonSLA(WitnetV2.RadonSLA calldata sla) + function verifyRadonSLA(Witnet.RadonSLA calldata sla) external returns (bytes32 slaHash); function totalDataProviders() external view returns (uint); diff --git a/contracts/interfaces/V2/IWitnetConsumer.sol b/contracts/interfaces/V2/IWitnetConsumer.sol new file mode 100644 index 000000000..7d1b953e2 --- /dev/null +++ b/contracts/interfaces/V2/IWitnetConsumer.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../../libs/Witnet.sol"; + +interface IWitnetConsumer { + + /// @notice Method to be called from the WitnetOracle contract as soon as the given Witnet `queryId` + /// @notice gets reported, if reported with no errors. + /// @dev It should revert if called from any other address different to the WitnetOracle being used + /// @dev by the WitnetConsumer contract. + /// @param witnetQueryId The unique identifier of the Witnet query being reported. + /// @param witnetResultTallyHash Hash of the commit/reveal witnessing act that took place in the Witnet blockahin. + /// @param witnetResultTimestamp Timestamp at which the reported value was captured by the Witnet blockchain. + /// @param witnetEvmFinalityBlock EVM block at which the provided data can be considered to be final. + /// @param witnetResultCborValue The CBOR-encoded resulting value of the Witnet query being reported. + function reportWitnetQueryResult( + uint256 witnetQueryId, + uint64 witnetResultTimestamp, + bytes32 witnetResultTallyHash, + uint256 witnetEvmFinalityBlock, + WitnetCBOR.CBOR calldata witnetResultCborValue + ) external; + + /// @notice Method to be called from the WitnetOracle contract as soon as the given Witnet `queryId` + /// @notice gets reported, if reported WITH errors. + /// @dev It should revert if called from any other address different to the WitnetOracle being used + /// @dev by the WitnetConsumer contract. + /// @param witnetQueryId The unique identifier of the Witnet query being reported. + /// @param witnetResultTallyHash Hash of the commit/reveal witnessing act that took place in the Witnet blockahin. + /// @param witnetResultTimestamp Timestamp at which the reported value was captured by the Witnet blockchain. + /// @param witnetEvmFinalityBlock EVM block at which the provided data can be considered to be final. + /// @param errorCode The error code enum identifying the error produced during resolution on the Witnet blockchain. + /// @param errorArgs Error arguments, if any. An empty buffer is to be passed if no error arguments apply. + function reportWitnetQueryError( + uint256 witnetQueryId, + uint64 witnetResultTimestamp, + bytes32 witnetResultTallyHash, + uint256 witnetEvmFinalityBlock, + Witnet.ResultErrorCodes errorCode, + WitnetCBOR.CBOR calldata errorArgs + ) external; + + /// @notice Determines if Witnet queries can be reported from given address. + /// @dev In practice, must only be true on the WitnetOracle address that's being used by + /// @dev the WitnetConsumer to post queries. + function reportableFrom(address) external view returns (bool); +} \ No newline at end of file diff --git a/contracts/interfaces/V2/IWitnetFeeds.sol b/contracts/interfaces/V2/IWitnetFeeds.sol index 56dfa705c..b9fbc4d57 100644 --- a/contracts/interfaces/V2/IWitnetFeeds.sol +++ b/contracts/interfaces/V2/IWitnetFeeds.sol @@ -5,12 +5,12 @@ pragma solidity >=0.8.0 <0.9.0; import "../../WitnetRequestBoard.sol"; interface IWitnetFeeds { - function dataType() external view returns (WitnetV2.RadonDataTypes); + function dataType() external view returns (Witnet.RadonDataTypes); function prefix() external view returns (string memory); function registry() external view returns (WitnetBytecodes); function witnet() external view returns (WitnetRequestBoard); - function defaultRadonSLA() external view returns (WitnetV2.RadonSLA memory); + function defaultRadonSLA() external view returns (Witnet.RadonSLA memory); function estimateUpdateBaseFee(bytes4 feedId, uint256 evmGasPrice, uint256 witEvmPrice) external view returns (uint); function estimateUpdateBaseFee(bytes4 feedId, uint256 evmGasPrice, uint256 witEvmPrice, bytes32 slaHash) external view returns (uint); @@ -26,7 +26,7 @@ interface IWitnetFeeds { function lookupBytecode(bytes4 feedId) external view returns (bytes memory); function lookupRadHash(bytes4 feedId) external view returns (bytes32); - function lookupRetrievals(bytes4 feedId) external view returns (WitnetV2.RadonRetrieval[] memory); + function lookupRetrievals(bytes4 feedId) external view returns (Witnet.RadonRetrieval[] memory); function requestUpdate(bytes4 feedId) external payable returns (uint256 usedFunds); function requestUpdate(bytes4 feedId, bytes32 slaHash) external payable returns (uint256 usedFunds); diff --git a/contracts/interfaces/V2/IWitnetFeedsAdmin.sol b/contracts/interfaces/V2/IWitnetFeedsAdmin.sol index 92f4694fe..9f43d46ac 100644 --- a/contracts/interfaces/V2/IWitnetFeedsAdmin.sol +++ b/contracts/interfaces/V2/IWitnetFeedsAdmin.sol @@ -7,7 +7,7 @@ import "../../requests/WitnetRequest.sol"; interface IWitnetFeedsAdmin { function deleteFeed(string calldata caption) external; - function settleDefaultRadonSLA(WitnetV2.RadonSLA calldata) external; + function settleDefaultRadonSLA(Witnet.RadonSLA calldata) external; function settleFeedRequest(string calldata caption, bytes32 radHash) external; function settleFeedRequest(string calldata caption, WitnetRequest request) external; function settleFeedRequest(string calldata caption, WitnetRequestTemplate template, string[][] calldata) external; diff --git a/contracts/interfaces/V2/IWitnetOracle.sol b/contracts/interfaces/V2/IWitnetOracle.sol new file mode 100644 index 000000000..eb8e7f44e --- /dev/null +++ b/contracts/interfaces/V2/IWitnetOracle.sol @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../../libs/WitnetV2.sol"; + +interface IWitnetOracle { + + /// @notice Estimate the minimum reward required for posting a data request. + /// @dev Underestimates if the size of returned data is greater than `resultMaxSize`. + /// @param gasPrice Expected gas price to pay upon posting the data request. + /// @param resultMaxSize Maximum expected size of returned data (in bytes). + function estimateBaseFee(uint256 gasPrice, uint16 resultMaxSize) external view returns (uint256); + + /// @notice Estimate the minimum reward required for posting a data request. + /// @dev Fails if the RAD hash was not previously verified on the WitnetRequestBytecodes registry. + /// @param gasPrice Expected gas price to pay upon posting the data request. + /// @param radHash The RAD hash of the data request to be solved by Witnet. + function estimateBaseFee(uint256 gasPrice, bytes32 radHash) external view returns (uint256); + + /// @notice Estimate the minimum reward required for posting a data request with a callback. + /// @param gasPrice Expected gas price to pay upon posting the data request. + /// @param callbackGasLimit Maximum gas to be spent when reporting the data request result. + function estimateBaseFeeWithCallback(uint256 gasPrice, uint24 callbackGasLimit) external view returns (uint256); + + /// @notice Retrieves a copy of all Witnet-provable data related to a previously posted request, + /// removing the whole query from the WRB storage. + /// @dev Fails if the query was not in 'Reported' status, or called from an address different to + /// @dev the one that actually posted the given request. + /// @param queryId The unique query identifier. + function fetchQueryResponse(uint256 queryId) external returns (WitnetV2.Response memory); + + /// @notice Gets the whole Query data contents, if any, no matter its current status. + function getQuery(uint256 queryId) external view returns (WitnetV2.Query memory); + + /// @notice Gets the current EVM reward the report can claim, if not done yet. + function getQueryEvmReward(uint256 queryId) external view returns (uint256); + + /// @notice Retrieves the RAD hash and SLA parameters of the given query. + /// @param queryId The unique query identifier. + function getQueryRequest(uint256 queryId) external view returns (WitnetV2.Request memory); + + /// @notice Retrieves the whole `Witnet.Response` record referred to a previously posted Witnet Data Request. + /// @param queryId The unique query identifier. + function getQueryResponse(uint256 queryId) external view returns (WitnetV2.Response memory); + + /// @notice Returns query's result current status from a requester's point of view: + /// @notice - 0 => Void: the query is either non-existent or deleted; + /// @notice - 1 => Awaiting: the query has not yet been reported; + /// @notice - 2 => Ready: the query response was finalized, and contains a result with no erros. + /// @notice - 3 => Error: the query response was finalized, and contains a result with errors. + /// @param queryId The unique query identifier. + function getQueryResponseStatus(uint256 queryId) external view returns (WitnetV2.ResponseStatus); + + /// @notice Retrieves the CBOR-encoded buffer containing the Witnet-provided result to the given query. + /// @param queryId The unique query identifier. + function getQueryResultCborBytes(uint256 queryId) external view returns (bytes memory); + + /// @notice Gets error code identifying some possible failure on the resolution of the given query. + /// @param queryId The unique query identifier. + function getQueryResultError(uint256 queryId) external view returns (Witnet.ResultError memory); + + /// @notice Gets current status of given query. + function getQueryStatus(uint256 queryId) external view returns (WitnetV2.QueryStatus); + + /// @notice Get current status of all given query ids. + function getQueryStatusBatch(uint256[] calldata queryIds) external view returns (WitnetV2.QueryStatus[] memory); + + /// @notice Returns next query id to be generated by the Witnet Request Board. + function getNextQueryId() external view returns (uint256); + + /// @notice Requests the execution of the given Witnet Data Request, in expectation that it will be relayed and + /// @notice solved by the Witnet blockchain. A reward amount is escrowed by the Witnet Request Board that will be + /// @notice transferred to the reporter who relays back the Witnet-provable result to this request. + /// @dev Reasons to fail: + /// @dev - the RAD hash was not previously verified by the WitnetRequestBytecodes registry; + /// @dev - invalid SLA parameters were provided; + /// @dev - insufficient value is paid as reward. + /// @param queryRAD The RAD hash of the data request to be solved by Witnet. + /// @param querySLA The data query SLA to be fulfilled on the Witnet blockchain. + /// @return queryId Unique query identifier. + function postRequest( + bytes32 queryRAD, + WitnetV2.RadonSLA calldata querySLA + ) external payable returns (uint256 queryId); + + /// @notice Requests the execution of the given Witnet Data Request, in expectation that it will be relayed and solved by + /// @notice the Witnet blockchain. A reward amount is escrowed by the Witnet Request Board that will be transferred to the + /// @notice reporter who relays back the Witnet-provable result to this request. The Witnet-provable result will be reported + /// @notice directly to the requesting contract. If the report callback fails for any reason, an `WitnetQueryResponseDeliveryFailed` + /// @notice will be triggered, and the Witnet audit trail will be saved in storage, but not so the actual CBOR-encoded result. + /// @dev Reasons to fail: + /// @dev - the caller is not a contract implementing the IWitnetConsumer interface; + /// @dev - the RAD hash was not previously verified by the WitnetRequestBytecodes registry; + /// @dev - invalid SLA parameters were provided; + /// @dev - insufficient value is paid as reward. + /// @param queryRAD The RAD hash of the data request to be solved by Witnet. + /// @param querySLA The data query SLA to be fulfilled on the Witnet blockchain. + /// @param queryCallbackGasLimit Maximum gas to be spent when reporting the data request result. + /// @return queryId Unique query identifier. + function postRequestWithCallback( + bytes32 queryRAD, + WitnetV2.RadonSLA calldata querySLA, + uint24 queryCallbackGasLimit + ) external payable returns (uint256 queryId); + + /// @notice Requests the execution of the given Witnet Data Request, in expectation that it will be relayed and solved by + /// @notice the Witnet blockchain. A reward amount is escrowed by the Witnet Request Board that will be transferred to the + /// @notice reporter who relays back the Witnet-provable result to this request. The Witnet-provable result will be reported + /// @notice directly to the requesting contract. If the report callback fails for any reason, a `WitnetQueryResponseDeliveryFailed` + /// @notice event will be triggered, and the Witnet audit trail will be saved in storage, but not so the CBOR-encoded result. + /// @dev Reasons to fail: + /// @dev - the caller is not a contract implementing the IWitnetConsumer interface; + /// @dev - the provided bytecode is empty; + /// @dev - invalid SLA parameters were provided; + /// @dev - insufficient value is paid as reward. + /// @param queryUnverifiedBytecode The (unverified) bytecode containing the actual data request to be solved by the Witnet blockchain. + /// @param querySLA The data query SLA to be fulfilled on the Witnet blockchain. + /// @param queryCallbackGasLimit Maximum gas to be spent when reporting the data request result. + /// @return queryId Unique query identifier. + function postRequestWithCallback( + bytes calldata queryUnverifiedBytecode, + WitnetV2.RadonSLA calldata querySLA, + uint24 queryCallbackGasLimit + ) external payable returns (uint256 queryId); + + /// @notice Increments the reward of a previously posted request by adding the transaction value to it. + /// @param queryId The unique query identifier. + function upgradeQueryEvmReward(uint256 queryId) external payable; + +} diff --git a/contracts/interfaces/V2/IWitnetOracleEvents.sol b/contracts/interfaces/V2/IWitnetOracleEvents.sol new file mode 100644 index 000000000..0cefb627e --- /dev/null +++ b/contracts/interfaces/V2/IWitnetOracleEvents.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../../libs/WitnetV2.sol"; + +interface IWitnetOracleEvents { + + /// Emitted every time a new query containing some verified data request is posted to the WRB. + event WitnetQuery( + uint256 indexed id, + uint256 evmReward, + WitnetV2.RadonSLA witnetSLA + ); + + /// Emitted when a query with no callback gets reported into the WRB. + event WitnetQueryResponse( + uint256 id, + uint256 evmGasPrice + ); + + /// Emitted when a query with a callback gets successfully reported into the WRB. + event WitnetQueryResponseDelivered( + uint256 indexed id, + uint256 evmGasPrice, + uint256 evmCallbackGas + ); + + /// Emitted when a query with a callback cannot get reported into the WRB. + event WitnetQueryResponseDeliveryFailed( + uint256 indexed id, + bytes resultCborBytes, + uint256 evmGasPrice, + uint256 evmCallbackActualGas, + string evmCallbackRevertReason + ); + + /// Emitted when the reward of some not-yet reported query is upgraded. + event WitnetQueryRewardUpgraded( + uint256 indexed id, + uint256 evmReward + ); + +} diff --git a/contracts/interfaces/V2/IWitnetPriceFeeds.sol b/contracts/interfaces/V2/IWitnetPriceFeeds.sol index e221c6c3e..0b4b7e12c 100644 --- a/contracts/interfaces/V2/IWitnetPriceFeeds.sol +++ b/contracts/interfaces/V2/IWitnetPriceFeeds.sol @@ -5,6 +5,7 @@ pragma solidity >=0.8.0 <0.9.0; import "./IWitnetPriceSolver.sol"; interface IWitnetPriceFeeds { + /// ====================================================================================================== /// --- IFeeds extension --------------------------------------------------------------------------------- diff --git a/contracts/libs/Witnet.sol b/contracts/libs/Witnet.sol index 07e50c786..075d7da20 100644 --- a/contracts/libs/Witnet.sol +++ b/contracts/libs/Witnet.sol @@ -3,7 +3,6 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "../interfaces/IWitnetRequest.sol"; import "./WitnetCBOR.sol"; library Witnet { @@ -29,14 +28,14 @@ library Witnet { /// Data kept in EVM-storage for every Request posted to the Witnet Request Board. struct Request { - address addr; // Address of the IWitnetRequest contract containing Witnet data request raw bytecode. + address addr; // Address of the (deprecated) IWitnetRequest contract containing Witnet data request raw bytecode. bytes32 slaHash; // Radon SLA hash of the Witnet data request. bytes32 radHash; // Radon radHash of the Witnet data request. uint256 gasprice; // Minimum gas price the DR resolver should pay on the solving tx. uint256 reward; // Escrowed reward to be paid to the DR resolver. } - /// Data kept in EVM-storage containing Witnet-provided response metadata and result. + /// Data kept in EVM-storage containing the Witnet-provided response metadata and CBOR-encoded result. struct Response { address reporter; // Address from which the result was reported. uint256 timestamp; // Timestamp of the Witnet-provided result. @@ -67,124 +66,522 @@ library Witnet { enum ResultErrorCodes { /// 0x00: Unknown error. Something went really bad! Unknown, + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// Script format errors ============================================================================================= - /// 0x01: At least one of the source scripts is not a valid CBOR-encoded value. - SourceScriptNotCBOR, - /// 0x02: The CBOR value decoded from a source script is not an Array. - SourceScriptNotArray, - /// 0x03: The Array value decoded form a source script is not a valid Data Request. - SourceScriptNotRADON, - /// Unallocated - ScriptFormat0x04, ScriptFormat0x05, ScriptFormat0x06, ScriptFormat0x07, ScriptFormat0x08, ScriptFormat0x09, - ScriptFormat0x0A, ScriptFormat0x0B, ScriptFormat0x0C, ScriptFormat0x0D, ScriptFormat0x0E, ScriptFormat0x0F, + /// Source-specific format error sub-codes ============================================================================ + /// 0x01: At least one of the source scripts is not a valid CBOR-encoded value. + SourceScriptNotCBOR, + /// 0x02: The CBOR value decoded from a source script is not an Array. + SourceScriptNotArray, + /// 0x03: The Array value decoded form a source script is not a valid Data Request. + SourceScriptNotRADON, + /// 0x04: The request body of at least one data source was not properly formated. + SourceRequestBody, + /// 0x05: The request headers of at least one data source was not properly formated. + SourceRequestHeaders, + /// 0x06: The request URL of at least one data source was not properly formated. + SourceRequestURL, + /// Unallocated + SourceFormat0x07, SourceFormat0x08, SourceFormat0x09, SourceFormat0x0A, SourceFormat0x0B, SourceFormat0x0C, + SourceFormat0x0D, SourceFormat0x0E, SourceFormat0x0F, + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// Complexity errors ================================================================================================ - /// 0x10: The request contains too many sources. - RequestTooManySources, - /// 0x11: The script contains too many calls. - ScriptTooManyCalls, - /// Unallocated - Complexity0x12, Complexity0x13, Complexity0x14, Complexity0x15, Complexity0x16, Complexity0x17, Complexity0x18, - Complexity0x19, Complexity0x1A, Complexity0x1B, Complexity0x1C, Complexity0x1D, Complexity0x1E, Complexity0x1F, + /// Complexity error sub-codes ======================================================================================== + /// 0x10: The request contains too many sources. + RequestTooManySources, + /// 0x11: The script contains too many calls. + ScriptTooManyCalls, + /// Unallocated + Complexity0x12, Complexity0x13, Complexity0x14, Complexity0x15, Complexity0x16, Complexity0x17, Complexity0x18, + Complexity0x19, Complexity0x1A, Complexity0x1B, Complexity0x1C, Complexity0x1D, Complexity0x1E, Complexity0x1F, + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Lack of support error sub-codes =================================================================================== + /// 0x20: Some Radon operator code was found that is not supported (1+ args). + UnsupportedOperator, + /// 0x21: Some Radon filter opcode is not currently supported (1+ args). + UnsupportedFilter, + /// 0x22: Some Radon request type is not currently supported (1+ args). + UnsupportedHashFunction, + /// 0x23: Some Radon reducer opcode is not currently supported (1+ args) + UnsupportedReducer, + /// 0x24: Some Radon hash function is not currently supported (1+ args). + UnsupportedRequestType, + /// 0x25: Some Radon encoding function is not currently supported (1+ args). + UnsupportedEncodingFunction, + /// Unallocated + Operator0x26, Operator0x27, + /// 0x28: Wrong number (or type) of arguments were passed to some Radon operator. + WrongArguments, + /// Unallocated + Operator0x29, Operator0x2A, Operator0x2B, Operator0x2C, Operator0x2D, Operator0x2E, Operator0x2F, + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Retrieve-specific circumstantial error sub-codes ================================================================================ + /// 0x30: A majority of data sources returned an HTTP status code other than 200 (1+ args): + HttpErrors, + /// 0x31: A majority of data sources timed out: + RetrievalsTimeout, + /// Unallocated + RetrieveCircumstance0x32, RetrieveCircumstance0x33, RetrieveCircumstance0x34, RetrieveCircumstance0x35, + RetrieveCircumstance0x36, RetrieveCircumstance0x37, RetrieveCircumstance0x38, RetrieveCircumstance0x39, + RetrieveCircumstance0x3A, RetrieveCircumstance0x3B, RetrieveCircumstance0x3C, RetrieveCircumstance0x3D, + RetrieveCircumstance0x3E, RetrieveCircumstance0x3F, + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// Operator errors =================================================================================================== - /// 0x20: The operator does not exist. - UnsupportedOperator, - /// Unallocated - Operator0x21, Operator0x22, Operator0x23, Operator0x24, Operator0x25, Operator0x26, Operator0x27, Operator0x28, - Operator0x29, Operator0x2A, Operator0x2B, Operator0x2C, Operator0x2D, Operator0x2E, Operator0x2F, + /// Scripting-specific runtime error sub-code ========================================================================= + /// 0x40: Math operator caused an underflow. + MathUnderflow, + /// 0x41: Math operator caused an overflow. + MathOverflow, + /// 0x42: Math operator tried to divide by zero. + MathDivisionByZero, + /// 0x43:Wrong input to subscript call. + WrongSubscriptInput, + /// 0x44: Value cannot be extracted from input binary buffer. + BufferIsNotValue, + /// 0x45: Value cannot be decoded from expected type. + Decode, + /// 0x46: Unexpected empty array. + EmptyArray, + /// 0x47: Value cannot be encoded to expected type. + Encode, + /// 0x48: Failed to filter input values (1+ args). + Filter, + /// 0x49: Failed to hash input value. + Hash, + /// 0x4A: Mismatching array ranks. + MismatchingArrays, + /// 0x4B: Failed to process non-homogenous array. + NonHomegeneousArray, + /// 0x4C: Failed to parse syntax of some input value, or argument. + Parse, + /// 0x4E: Parsing logic limits were exceeded. + ParseOverflow, + /// 0x4F: Unallocated + ScriptError0x4F, + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// Retrieval-specific errors ========================================================================================= - /// 0x30: At least one of the sources could not be retrieved, but returned HTTP error. - HTTP, - /// 0x31: Retrieval of at least one of the sources timed out. - RetrievalTimeout, - /// Unallocated - Retrieval0x32, Retrieval0x33, Retrieval0x34, Retrieval0x35, Retrieval0x36, Retrieval0x37, Retrieval0x38, - Retrieval0x39, Retrieval0x3A, Retrieval0x3B, Retrieval0x3C, Retrieval0x3D, Retrieval0x3E, Retrieval0x3F, + /// Actual first-order result error codes ============================================================================= + /// 0x50: Not enough reveals were received in due time: + InsufficientReveals, + /// 0x51: No actual reveal majority was reached on tally stage: + InsufficientMajority, + /// 0x52: Not enough commits were received before tally stage: + InsufficientCommits, + /// 0x53: Generic error during tally execution (to be deprecated after WIP #0028) + TallyExecution, + /// 0x54: A majority of data sources could either be temporarily unresponsive or failing to report the requested data: + CircumstantialFailure, + /// 0x55: At least one data source is inconsistent when queried through multiple transports at once: + InconsistentSources, + /// 0x56: Any one of the (multiple) Retrieve, Aggregate or Tally scripts were badly formated: + MalformedDataRequest, + /// 0x57: Values returned from a majority of data sources don't match the expected schema: + MalformedResponses, + /// Unallocated: + OtherError0x58, OtherError0x59, OtherError0x5A, OtherError0x5B, OtherError0x5C, OtherError0x5D, OtherError0x5E, + /// 0x5F: Size of serialized tally result exceeds allowance: + OversizedTallyResult, + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// Math errors ======================================================================================================= - /// 0x40: Math operator caused an underflow. - Underflow, - /// 0x41: Math operator caused an overflow. - Overflow, - /// 0x42: Tried to divide by zero. - DivisionByZero, - /// Unallocated - Math0x43, Math0x44, Math0x45, Math0x46, Math0x47, Math0x48, Math0x49, - Math0x4A, Math0x4B, Math0x4C, Math0x4D, Math0x4E, Math0x4F, + /// Inter-stage runtime error sub-codes =============================================================================== + /// 0x60: Data aggregation reveals could not get decoded on the tally stage: + MalformedReveals, + /// 0x61: The result to data aggregation could not get encoded: + EncodeReveals, + /// 0x62: A mode tie ocurred when calculating some mode value on the aggregation or the tally stage: + ModeTie, + /// Unallocated: + OtherError0x63, OtherError0x64, OtherError0x65, OtherError0x66, OtherError0x67, OtherError0x68, OtherError0x69, + OtherError0x6A, OtherError0x6B, OtherError0x6C, OtherError0x6D, OtherError0x6E, OtherError0x6F, + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// Other errors ====================================================================================================== - /// 0x50: Received zero reveals - NoReveals, - /// 0x51: Insufficient consensus in tally precondition clause - InsufficientConsensus, - /// 0x52: Received zero commits - InsufficientCommits, - /// 0x53: Generic error during tally execution - TallyExecution, - /// Unallocated - OtherError0x54, OtherError0x55, OtherError0x56, OtherError0x57, OtherError0x58, OtherError0x59, - OtherError0x5A, OtherError0x5B, OtherError0x5C, OtherError0x5D, OtherError0x5E, OtherError0x5F, - /// 0x60: Invalid reveal serialization (malformed reveals are converted to this value) - MalformedReveal, - /// Unallocated - OtherError0x61, OtherError0x62, OtherError0x63, OtherError0x64, OtherError0x65, OtherError0x66, - OtherError0x67, OtherError0x68, OtherError0x69, OtherError0x6A, OtherError0x6B, OtherError0x6C, - OtherError0x6D, OtherError0x6E,OtherError0x6F, + /// Runtime access error sub-codes ==================================================================================== + /// 0x70: Tried to access a value from an array using an index that is out of bounds (1+ args): + ArrayIndexOutOfBounds, + /// 0x71: Tried to access a value from a map using a key that does not exist (1+ args): + MapKeyNotFound, + /// 0X72: Tried to extract value from a map using a JSON Path that returns no values (+1 args): + JsonPathNotFound, + /// Unallocated: + OtherError0x73, OtherError0x74, OtherError0x75, OtherError0x76, OtherError0x77, OtherError0x78, + OtherError0x79, OtherError0x7A, OtherError0x7B, OtherError0x7C, OtherError0x7D, OtherError0x7E, OtherError0x7F, + OtherError0x80, OtherError0x81, OtherError0x82, OtherError0x83, OtherError0x84, OtherError0x85, OtherError0x86, + OtherError0x87, OtherError0x88, OtherError0x89, OtherError0x8A, OtherError0x8B, OtherError0x8C, OtherError0x8D, + OtherError0x8E, OtherError0x8F, OtherError0x90, OtherError0x91, OtherError0x92, OtherError0x93, OtherError0x94, + OtherError0x95, OtherError0x96, OtherError0x97, OtherError0x98, OtherError0x99, OtherError0x9A, OtherError0x9B, + OtherError0x9C, OtherError0x9D, OtherError0x9E, OtherError0x9F, OtherError0xA0, OtherError0xA1, OtherError0xA2, + OtherError0xA3, OtherError0xA4, OtherError0xA5, OtherError0xA6, OtherError0xA7, OtherError0xA8, OtherError0xA9, + OtherError0xAA, OtherError0xAB, OtherError0xAC, OtherError0xAD, OtherError0xAE, OtherError0xAF, OtherError0xB0, + OtherError0xB1, OtherError0xB2, OtherError0xB3, OtherError0xB4, OtherError0xB5, OtherError0xB6, OtherError0xB7, + OtherError0xB8, OtherError0xB9, OtherError0xBA, OtherError0xBB, OtherError0xBC, OtherError0xBD, OtherError0xBE, + OtherError0xBF, OtherError0xC0, OtherError0xC1, OtherError0xC2, OtherError0xC3, OtherError0xC4, OtherError0xC5, + OtherError0xC6, OtherError0xC7, OtherError0xC8, OtherError0xC9, OtherError0xCA, OtherError0xCB, OtherError0xCC, + OtherError0xCD, OtherError0xCE, OtherError0xCF, OtherError0xD0, OtherError0xD1, OtherError0xD2, OtherError0xD3, + OtherError0xD4, OtherError0xD5, OtherError0xD6, OtherError0xD7, OtherError0xD8, OtherError0xD9, OtherError0xDA, + OtherError0xDB, OtherError0xDC, OtherError0xDD, OtherError0xDE, OtherError0xDF, + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// Access errors ===================================================================================================== - /// 0x70: Tried to access a value from an array using an index that is out of bounds - ArrayIndexOutOfBounds, - /// 0x71: Tried to access a value from a map using a key that does not exist - MapKeyNotFound, - /// Unallocated - OtherError0x72, OtherError0x73, OtherError0x74, OtherError0x75, OtherError0x76, OtherError0x77, OtherError0x78, - OtherError0x79, OtherError0x7A, OtherError0x7B, OtherError0x7C, OtherError0x7D, OtherError0x7E, OtherError0x7F, - OtherError0x80, OtherError0x81, OtherError0x82, OtherError0x83, OtherError0x84, OtherError0x85, OtherError0x86, - OtherError0x87, OtherError0x88, OtherError0x89, OtherError0x8A, OtherError0x8B, OtherError0x8C, OtherError0x8D, - OtherError0x8E, OtherError0x8F, OtherError0x90, OtherError0x91, OtherError0x92, OtherError0x93, OtherError0x94, - OtherError0x95, OtherError0x96, OtherError0x97, OtherError0x98, OtherError0x99, OtherError0x9A, OtherError0x9B, - OtherError0x9C, OtherError0x9D, OtherError0x9E, OtherError0x9F, OtherError0xA0, OtherError0xA1, OtherError0xA2, - OtherError0xA3, OtherError0xA4, OtherError0xA5, OtherError0xA6, OtherError0xA7, OtherError0xA8, OtherError0xA9, - OtherError0xAA, OtherError0xAB, OtherError0xAC, OtherError0xAD, OtherError0xAE, OtherError0xAF, OtherError0xB0, - OtherError0xB1, OtherError0xB2, OtherError0xB3, OtherError0xB4, OtherError0xB5, OtherError0xB6, OtherError0xB7, - OtherError0xB8, OtherError0xB9, OtherError0xBA, OtherError0xBB, OtherError0xBC, OtherError0xBD, OtherError0xBE, - OtherError0xBF, OtherError0xC0, OtherError0xC1, OtherError0xC2, OtherError0xC3, OtherError0xC4, OtherError0xC5, - OtherError0xC6, OtherError0xC7, OtherError0xC8, OtherError0xC9, OtherError0xCA, OtherError0xCB, OtherError0xCC, - OtherError0xCD, OtherError0xCE, OtherError0xCF, OtherError0xD0, OtherError0xD1, OtherError0xD2, OtherError0xD3, - OtherError0xD4, OtherError0xD5, OtherError0xD6, OtherError0xD7, OtherError0xD8, OtherError0xD9, OtherError0xDA, - OtherError0xDB, OtherError0xDC, OtherError0xDD, OtherError0xDE, OtherError0xDF, + /// Inter-client generic error codes ================================================================================== + /// Data requests that cannot be relayed into the Witnet blockchain should be reported + /// with one of these errors. + /// 0xE0: Requests that cannot be parsed must always get this error as their result. + BridgeMalformedDataRequest, + /// 0xE1: Witnesses exceeds 100 + BridgePoorIncentives, + /// 0xE2: The request is rejected on the grounds that it may cause the submitter to spend or stake an + /// amount of value that is unjustifiably high when compared with the reward they will be getting + BridgeOversizedTallyResult, + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// Bridge errors: errors that only belong in inter-client communication ============================================== - /// 0xE0: Requests that cannot be parsed must always get this error as their result. - /// However, this is not a valid result in a Tally transaction, because invalid requests - /// are never included into blocks and therefore never get a Tally in response. - BridgeMalformedRequest, - /// 0xE1: Witnesses exceeds 100 - BridgePoorIncentives, - /// 0xE2: The request is rejected on the grounds that it may cause the submitter to spend or stake an - /// amount of value that is unjustifiably high when compared with the reward they will be getting - BridgeOversizedResult, - /// Unallocated - OtherError0xE3, OtherError0xE4, OtherError0xE5, OtherError0xE6, OtherError0xE7, OtherError0xE8, OtherError0xE9, - OtherError0xEA, OtherError0xEB, OtherError0xEC, OtherError0xED, OtherError0xEE, OtherError0xEF, OtherError0xF0, - OtherError0xF1, OtherError0xF2, OtherError0xF3, OtherError0xF4, OtherError0xF5, OtherError0xF6, OtherError0xF7, - OtherError0xF8, OtherError0xF9, OtherError0xFA, OtherError0xFB, OtherError0xFC, OtherError0xFD, OtherError0xFE, + /// Unallocated ======================================================================================================= + OtherError0xE3, OtherError0xE4, OtherError0xE5, OtherError0xE6, OtherError0xE7, OtherError0xE8, OtherError0xE9, + OtherError0xEA, OtherError0xEB, OtherError0xEC, OtherError0xED, OtherError0xEE, OtherError0xEF, OtherError0xF0, + OtherError0xF1, OtherError0xF2, OtherError0xF3, OtherError0xF4, OtherError0xF5, OtherError0xF6, OtherError0xF7, + OtherError0xF8, OtherError0xF9, OtherError0xFA, OtherError0xFB, OtherError0xFC, OtherError0xFD, OtherError0xFE, + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// 0xFF: Some tally error is not intercepted but should + /// 0xFF: Some tally error is not intercepted but it should (0+ args) UnhandledIntercept } + function isCircumstantial(ResultErrorCodes self) internal pure returns (bool) { + return (self == ResultErrorCodes.CircumstantialFailure); + } + + function lackOfConsensus(ResultErrorCodes self) internal pure returns (bool) { + return ( + self == ResultErrorCodes.InsufficientCommits + || self == ResultErrorCodes.InsufficientMajority + || self == ResultErrorCodes.InsufficientReveals + ); + } + + function isRetriable(ResultErrorCodes self) internal pure returns (bool) { + return ( + lackOfConsensus(self) + || isCircumstantial(self) + || poorIncentives(self) + ); + } + + function poorIncentives(ResultErrorCodes self) internal pure returns (bool) { + return ( + self == ResultErrorCodes.OversizedTallyResult + || self == ResultErrorCodes.InsufficientCommits + || self == ResultErrorCodes.BridgePoorIncentives + || self == ResultErrorCodes.BridgeOversizedTallyResult + ); + } + + + /// Possible Radon data request methods that can be used within a Radon Retrieval. + enum RadonDataRequestMethods { + /* 0 */ Unknown, + /* 1 */ HttpGet, + /* 2 */ RNG, + /* 3 */ HttpPost, + /* 4 */ HttpHead + } + + /// Possible types either processed by Witnet Radon Scripts or included within results to Witnet Data Requests. + enum RadonDataTypes { + /* 0x00 */ Any, + /* 0x01 */ Array, + /* 0x02 */ Bool, + /* 0x03 */ Bytes, + /* 0x04 */ Integer, + /* 0x05 */ Float, + /* 0x06 */ Map, + /* 0x07 */ String, + Unused0x08, Unused0x09, Unused0x0A, Unused0x0B, + Unused0x0C, Unused0x0D, Unused0x0E, Unused0x0F, + /* 0x10 */ Same, + /* 0x11 */ Inner, + /* 0x12 */ Match, + /* 0x13 */ Subscript + } + + /// Structure defining some data filtering that can be applied at the Aggregation or the Tally stages + /// within a Witnet Data Request resolution workflow. + struct RadonFilter { + RadonFilterOpcodes opcode; + bytes args; + } + + /// Filtering methods currently supported on the Witnet blockchain. + enum RadonFilterOpcodes { + /* 0x00 */ Reserved0x00, //GreaterThan, + /* 0x01 */ Reserved0x01, //LessThan, + /* 0x02 */ Reserved0x02, //Equals, + /* 0x03 */ Reserved0x03, //AbsoluteDeviation, + /* 0x04 */ Reserved0x04, //RelativeDeviation + /* 0x05 */ StandardDeviation, + /* 0x06 */ Reserved0x06, //Top, + /* 0x07 */ Reserved0x07, //Bottom, + /* 0x08 */ Mode, + /* 0x09 */ Reserved0x09 //LessOrEqualThan + } + + /// Structure defining the array of filters and reducting function to be applied at either the Aggregation + /// or the Tally stages within a Witnet Data Request resolution workflow. + struct RadonReducer { + RadonReducerOpcodes opcode; + RadonFilter[] filters; + bytes script; + } + + /// Reducting functions currently supported on the Witnet blockchain. + enum RadonReducerOpcodes { + /* 0x00 */ Reserved0x00, //Minimum, + /* 0x01 */ Reserved0x01, //Maximum, + /* 0x02 */ Mode, + /* 0x03 */ AverageMean, + /* 0x04 */ Reserved0x04, //AverageMeanWeighted, + /* 0x05 */ AverageMedian, + /* 0x06 */ Reserved0x06, //AverageMedianWeighted, + /* 0x07 */ StandardDeviation, + /* 0x08 */ Reserved0x08, //AverageDeviation, + /* 0x09 */ Reserved0x09, //MedianDeviation, + /* 0x0A */ Reserved0x10, //MaximumDeviation, + /* 0x0B */ ConcatenateAndHash + } + + /// Structure containing all the parameters that fully describe a Witnet Radon Retrieval within a Witnet Data Request. + struct RadonRetrieval { + uint8 argsCount; + RadonDataRequestMethods method; + RadonDataTypes resultDataType; + string url; + string body; + string[2][] headers; + bytes script; + } + + /// Structure containing the Retrieve-Attestation-Delivery parts of a Witnet Data Request. + struct RadonRAD { + RadonRetrieval[] retrieve; + RadonReducer aggregate; + RadonReducer tally; + } + + /// Structure containing the Service Level Aggreement parameters of a Witnet Data Request. + struct RadonSLA { + uint8 numWitnesses; + uint8 minConsensusPercentage; + uint64 witnessReward; + uint64 witnessCollateral; + uint64 minerCommitRevealFee; + } + /// =============================================================================================================== - /// --- 'Witnet.Result' helper methods ---------------------------------------------------------------------------- + /// --- 'Witnet.RadonSLA' helper methods ------------------------------------------------------------------------ - modifier _isError(Result memory result) { - require(!result.success, "Witnet: no actual errors"); - _; + function equalOrGreaterThan(RadonSLA memory a, RadonSLA memory b) + internal pure returns (bool) + { + return ( + a.numWitnesses >= b.numWitnesses + && a.minConsensusPercentage >= b.minConsensusPercentage + && a.witnessReward >= b.witnessReward + && a.witnessCollateral >= b.witnessCollateral + && a.minerCommitRevealFee >= b.minerCommitRevealFee + ); + } + + function isValid(RadonSLA calldata sla) internal pure returns (bool) { + return ( + sla.numWitnesses > 0 + && sla.numWitnesses <= 127 + && sla.minConsensusPercentage >= 51 + && sla.witnessReward > 0 + && sla.witnessCollateral > 20 * 10 ** 9 + && sla.witnessCollateral / sla.witnessReward <= 125 + ); + } + + + /// =============================================================================================================== + /// --- 'uint*' helper methods ------------------------------------------------------------------------------------ + + /// @notice Convert a `uint8` into a 2 characters long `string` representing its two less significant hexadecimal values. + function toHexString(uint8 _u) + internal pure + returns (string memory) + { + bytes memory b2 = new bytes(2); + uint8 d0 = uint8(_u / 16) + 48; + uint8 d1 = uint8(_u % 16) + 48; + if (d0 > 57) + d0 += 7; + if (d1 > 57) + d1 += 7; + b2[0] = bytes1(d0); + b2[1] = bytes1(d1); + return string(b2); + } + + /// @notice Convert a `uint8` into a 1, 2 or 3 characters long `string` representing its. + /// three less significant decimal values. + function toString(uint8 _u) + internal pure + returns (string memory) + { + if (_u < 10) { + bytes memory b1 = new bytes(1); + b1[0] = bytes1(uint8(_u) + 48); + return string(b1); + } else if (_u < 100) { + bytes memory b2 = new bytes(2); + b2[0] = bytes1(uint8(_u / 10) + 48); + b2[1] = bytes1(uint8(_u % 10) + 48); + return string(b2); + } else { + bytes memory b3 = new bytes(3); + b3[0] = bytes1(uint8(_u / 100) + 48); + b3[1] = bytes1(uint8(_u % 100 / 10) + 48); + b3[2] = bytes1(uint8(_u % 10) + 48); + return string(b3); + } + } + + /// @notice Convert a `uint` into a string` representing its value. + function toString(uint v) + internal pure + returns (string memory) + { + uint maxlength = 100; + bytes memory reversed = new bytes(maxlength); + uint i = 0; + do { + uint8 remainder = uint8(v % 10); + v = v / 10; + reversed[i ++] = bytes1(48 + remainder); + } while (v != 0); + bytes memory buf = new bytes(i); + for (uint j = 1; j <= i; j ++) { + buf[j - 1] = reversed[i - j]; + } + return string(buf); + } + + + /// =============================================================================================================== + /// --- 'bytes' helper methods ------------------------------------------------------------------------------------ + + /// @dev Transform given bytes into a Witnet.Result instance. + /// @param cborBytes Raw bytes representing a CBOR-encoded value. + /// @return A `Witnet.Result` instance. + function resultFromCborBytes(bytes memory cborBytes) + internal pure + returns (Witnet.Result memory) + { + WitnetCBOR.CBOR memory cborValue = WitnetCBOR.fromBytes(cborBytes); + return _resultFromCborValue(cborValue); + } + + function toAddress(bytes memory _value) internal pure returns (address) { + return address(toBytes20(_value)); + } + + function toBytes4(bytes memory _value) internal pure returns (bytes4) { + return bytes4(toFixedBytes(_value, 4)); + } + + function toBytes20(bytes memory _value) internal pure returns (bytes20) { + return bytes20(toFixedBytes(_value, 20)); + } + + function toBytes32(bytes memory _value) internal pure returns (bytes32) { + return toFixedBytes(_value, 32); + } + + function toFixedBytes(bytes memory _value, uint8 _numBytes) + internal pure + returns (bytes32 _bytes32) + { + assert(_numBytes <= 32); + unchecked { + uint _len = _value.length > _numBytes ? _numBytes : _value.length; + for (uint _i = 0; _i < _len; _i ++) { + _bytes32 |= bytes32(_value[_i] & 0xff) >> (_i * 8); + } + } + } + + + /// =============================================================================================================== + /// --- 'bytes4' helper methods ----------------------------------------------------------------------------------- + + function toHexString(bytes4 word) internal pure returns (string memory) { + return string(abi.encodePacked( + toHexString(uint8(bytes1(word))), + toHexString(uint8(bytes1(word << 8))), + toHexString(uint8(bytes1(word << 16))), + toHexString(uint8(bytes1(word << 24))) + )); + } + + + /// =============================================================================================================== + /// --- 'string' helper methods ----------------------------------------------------------------------------------- + + function toLowerCase(string memory str) + internal pure + returns (string memory) + { + bytes memory lowered = new bytes(bytes(str).length); + unchecked { + for (uint i = 0; i < lowered.length; i ++) { + uint8 char = uint8(bytes(str)[i]); + if (char >= 65 && char <= 90) { + lowered[i] = bytes1(char + 32); + } else { + lowered[i] = bytes1(char); + } + } + } + return string(lowered); + } + + /// @notice Converts bytes32 into string. + function toString(bytes32 _bytes32) + internal pure + returns (string memory) + { + bytes memory _bytes = new bytes(_toStringLength(_bytes32)); + for (uint _i = 0; _i < _bytes.length;) { + _bytes[_i] = _bytes32[_i]; + unchecked { + _i ++; + } + } + return string(_bytes); + } + + function tryUint(string memory str) + internal pure + returns (uint res, bool) + { + unchecked { + for (uint256 i = 0; i < bytes(str).length; i++) { + if ( + (uint8(bytes(str)[i]) - 48) < 0 + || (uint8(bytes(str)[i]) - 48) > 9 + ) { + return (0, false); + } + res += (uint8(bytes(str)[i]) - 48) * 10 ** (bytes(str).length - i - 1); + } + return (res, true); + } } + + + /// =============================================================================================================== + /// --- 'Witnet.Result' helper methods ---------------------------------------------------------------------------- modifier _isReady(Result memory result) { require(result.success, "Witnet: tried to decode value from errored result."); @@ -344,170 +741,6 @@ library Witnet { } - /// =============================================================================================================== - /// --- 'bytes' helper methods ------------------------------------------------------------------------------------ - - /// @dev Transform given bytes into a Witnet.Result instance. - /// @param bytecode Raw bytes representing a CBOR-encoded value. - /// @return A `Witnet.Result` instance. - function resultFromCborBytes(bytes memory bytecode) - internal pure - returns (Witnet.Result memory) - { - WitnetCBOR.CBOR memory cborValue = WitnetCBOR.fromBytes(bytecode); - return _resultFromCborValue(cborValue); - } - - function toAddress(bytes memory _value) internal pure returns (address) { - return address(toBytes20(_value)); - } - - function toBytes4(bytes memory _value) internal pure returns (bytes4) { - return bytes4(toFixedBytes(_value, 4)); - } - - function toBytes20(bytes memory _value) internal pure returns (bytes20) { - return bytes20(toFixedBytes(_value, 20)); - } - - function toBytes32(bytes memory _value) internal pure returns (bytes32) { - return toFixedBytes(_value, 32); - } - - function toFixedBytes(bytes memory _value, uint8 _numBytes) - internal pure - returns (bytes32 _bytes32) - { - assert(_numBytes <= 32); - unchecked { - uint _len = _value.length > _numBytes ? _numBytes : _value.length; - for (uint _i = 0; _i < _len; _i ++) { - _bytes32 |= bytes32(_value[_i] & 0xff) >> (_i * 8); - } - } - } - - - /// =============================================================================================================== - /// --- 'string' helper methods ----------------------------------------------------------------------------------- - - function toLowerCase(string memory str) - internal pure - returns (string memory) - { - bytes memory lowered = new bytes(bytes(str).length); - unchecked { - for (uint i = 0; i < lowered.length; i ++) { - uint8 char = uint8(bytes(str)[i]); - if (char >= 65 && char <= 90) { - lowered[i] = bytes1(char + 32); - } else { - lowered[i] = bytes1(char); - } - } - } - return string(lowered); - } - - /// @notice Converts bytes32 into string. - function toString(bytes32 _bytes32) - internal pure - returns (string memory) - { - bytes memory _bytes = new bytes(_toStringLength(_bytes32)); - for (uint _i = 0; _i < _bytes.length;) { - _bytes[_i] = _bytes32[_i]; - unchecked { - _i ++; - } - } - return string(_bytes); - } - - function tryUint(string memory str) - internal pure - returns (uint res, bool) - { - unchecked { - for (uint256 i = 0; i < bytes(str).length; i++) { - if ( - (uint8(bytes(str)[i]) - 48) < 0 - || (uint8(bytes(str)[i]) - 48) > 9 - ) { - return (0, false); - } - res += (uint8(bytes(str)[i]) - 48) * 10 ** (bytes(str).length - i - 1); - } - return (res, true); - } - } - - - /// =============================================================================================================== - /// --- 'uint8' helper methods ------------------------------------------------------------------------------------ - - /// @notice Convert a `uint8` into a 2 characters long `string` representing its two less significant hexadecimal values. - function toHexString(uint8 _u) - internal pure - returns (string memory) - { - bytes memory b2 = new bytes(2); - uint8 d0 = uint8(_u / 16) + 48; - uint8 d1 = uint8(_u % 16) + 48; - if (d0 > 57) - d0 += 7; - if (d1 > 57) - d1 += 7; - b2[0] = bytes1(d0); - b2[1] = bytes1(d1); - return string(b2); - } - - /// @notice Convert a `uint8` into a 1, 2 or 3 characters long `string` representing its. - /// three less significant decimal values. - function toString(uint8 _u) - internal pure - returns (string memory) - { - if (_u < 10) { - bytes memory b1 = new bytes(1); - b1[0] = bytes1(uint8(_u) + 48); - return string(b1); - } else if (_u < 100) { - bytes memory b2 = new bytes(2); - b2[0] = bytes1(uint8(_u / 10) + 48); - b2[1] = bytes1(uint8(_u % 10) + 48); - return string(b2); - } else { - bytes memory b3 = new bytes(3); - b3[0] = bytes1(uint8(_u / 100) + 48); - b3[1] = bytes1(uint8(_u % 100 / 10) + 48); - b3[2] = bytes1(uint8(_u % 10) + 48); - return string(b3); - } - } - - /// @notice Convert a `uint` into a string` representing its value. - function toString(uint v) - internal pure - returns (string memory) - { - uint maxlength = 100; - bytes memory reversed = new bytes(maxlength); - uint i = 0; - do { - uint8 remainder = uint8(v % 10); - v = v / 10; - reversed[i ++] = bytes1(48 + remainder); - } while (v != 0); - bytes memory buf = new bytes(i); - for (uint j = 1; j <= i; j ++) { - buf[j - 1] = reversed[i - j]; - } - return string(buf); - } - - /// =============================================================================================================== /// --- Witnet library private methods ---------------------------------------------------------------------------- diff --git a/contracts/libs/WitnetEncodingLib.sol b/contracts/libs/WitnetEncodingLib.sol index 15618f9f3..e5b70260e 100644 --- a/contracts/libs/WitnetEncodingLib.sol +++ b/contracts/libs/WitnetEncodingLib.sol @@ -26,12 +26,12 @@ library WitnetEncodingLib { /// =============================================================================================================== /// --- WitnetLib internal methods -------------------------------------------------------------------------------- - function size(WitnetV2.RadonDataTypes _type) internal pure returns (uint16) { - if (_type == WitnetV2.RadonDataTypes.Integer - || _type == WitnetV2.RadonDataTypes.Float + function size(Witnet.RadonDataTypes _type) internal pure returns (uint16) { + if (_type == Witnet.RadonDataTypes.Integer + || _type == Witnet.RadonDataTypes.Float ) { return 9; - } else if (_type == WitnetV2.RadonDataTypes.Bool) { + } else if (_type == Witnet.RadonDataTypes.Bool) { return 1; } else { // undetermined @@ -46,11 +46,11 @@ library WitnetEncodingLib { /// @notice Encode bytes array into given major type (UTF-8 not yet supported) /// @param buf Bytes array /// @return Marshaled bytes - function encode(bytes memory buf, uint majorType) + function encode(bytes memory buf, uint256 majorType) public pure returns (bytes memory) { - uint len = buf.length; + uint256 len = buf.length; if (len < 23) { return abi.encodePacked( uint8((majorType << 5) | uint8(len)), @@ -131,7 +131,7 @@ library WitnetEncodingLib { } } - function encode(WitnetV2.RadonRetrieval memory source) + function encode(Witnet.RadonRetrieval memory source) public pure returns (bytes memory) { @@ -159,7 +159,7 @@ library WitnetEncodingLib { } bytes memory _encodedHeaders; if (source.headers.length > 0) { - for (uint _ix = 0; _ix < source.headers.length; _ix ++) { + for (uint256 _ix = 0; _ix < source.headers.length; _ix ++) { bytes memory _headers = abi.encodePacked( encode(uint64(bytes(source.headers[_ix][0]).length), bytes1(0x0a)), bytes(source.headers[_ix][0]), @@ -173,7 +173,7 @@ library WitnetEncodingLib { ); } } - uint _innerSize = ( + uint256 _innerSize = ( _encodedMethod.length + _encodedUrl.length + _encodedScript.length @@ -191,7 +191,7 @@ library WitnetEncodingLib { } function encode( - WitnetV2.RadonRetrieval[] memory sources, + Witnet.RadonRetrieval[] memory sources, string[][] memory args, bytes memory aggregatorInnerBytecode, bytes memory tallyInnerBytecode, @@ -201,7 +201,7 @@ library WitnetEncodingLib { returns (bytes memory) { bytes[] memory encodedSources = new bytes[](sources.length); - for (uint ix = 0; ix < sources.length; ix ++) { + for (uint256 ix = 0; ix < sources.length; ix ++) { replaceWildcards(sources[ix], args[ix]); encodedSources[ix] = encode(sources[ix]); } @@ -218,12 +218,12 @@ library WitnetEncodingLib { ); } - function encode(WitnetV2.RadonReducer memory reducer) + function encode(Witnet.RadonReducer memory reducer) public pure returns (bytes memory bytecode) { if (reducer.script.length == 0) { - for (uint ix = 0; ix < reducer.filters.length; ix ++) { + for (uint256 ix = 0; ix < reducer.filters.length; ix ++) { bytecode = abi.encodePacked( bytecode, encode(reducer.filters[ix]) @@ -241,7 +241,7 @@ library WitnetEncodingLib { } } - function encode(WitnetV2.RadonFilter memory filter) + function encode(Witnet.RadonFilter memory filter) public pure returns (bytes memory bytecode) { @@ -259,7 +259,7 @@ library WitnetEncodingLib { ); } - function encode(WitnetV2.RadonReducerOpcodes opcode) + function encode(Witnet.RadonReducerOpcodes opcode) public pure returns (bytes memory) { @@ -267,7 +267,7 @@ library WitnetEncodingLib { return encode(uint64(opcode), bytes1(0x10)); } - function encode(WitnetV2.RadonSLA memory sla) + function encode(Witnet.RadonSLA memory sla) public pure returns (bytes memory) { @@ -299,19 +299,19 @@ library WitnetEncodingLib { return cbor.buffer.data; } - function replaceWildcards(WitnetV2.RadonRetrieval memory self, string[] memory args) + function replaceWildcards(Witnet.RadonRetrieval memory self, string[] memory args) public pure { self.url = WitnetBuffer.replace(self.url, args); self.body = WitnetBuffer.replace(self.body, args); self.script = replaceCborStringsFromBytes(self.script, args); - for (uint _ix = 0 ; _ix < self.headers.length; _ix ++) { + for (uint256 _ix = 0 ; _ix < self.headers.length; _ix ++) { self.headers[_ix][1] = WitnetBuffer.replace(self.headers[_ix][1], args); } } function validate( - WitnetV2.DataRequestMethods method, + Witnet.RadonDataRequestMethods method, string memory url, string memory body, string[2][] memory headers, @@ -323,11 +323,11 @@ library WitnetEncodingLib { if (!( bytes(url).length > 0 && ( - method == WitnetV2.DataRequestMethods.HttpGet - || method == WitnetV2.DataRequestMethods.HttpPost - || method == WitnetV2.DataRequestMethods.HttpHead + method == Witnet.RadonDataRequestMethods.HttpGet + || method == Witnet.RadonDataRequestMethods.HttpPost + || method == Witnet.RadonDataRequestMethods.HttpHead ) - || method == WitnetV2.DataRequestMethods.Rng + || method == Witnet.RadonDataRequestMethods.RNG && bytes(url).length == 0 && headers.length == 0 && script.length >= 1 @@ -343,7 +343,7 @@ library WitnetEncodingLib { } function validate( - WitnetV2.DataRequestMethods method, + Witnet.RadonDataRequestMethods method, string memory schema, string memory authority, string memory path, @@ -356,9 +356,9 @@ library WitnetEncodingLib { returns (bytes32) { if (!( - (method == WitnetV2.DataRequestMethods.HttpGet - || method == WitnetV2.DataRequestMethods.HttpPost - || method == WitnetV2.DataRequestMethods.HttpHead + (method == Witnet.RadonDataRequestMethods.HttpGet + || method == Witnet.RadonDataRequestMethods.HttpPost + || method == Witnet.RadonDataRequestMethods.HttpHead ) && bytes(authority).length > 0 && ( @@ -366,7 +366,7 @@ library WitnetEncodingLib { || keccak256(bytes(schema)) == keccak256(bytes("https://")) || keccak256(bytes(schema)) == keccak256(bytes("http://")) ) - || method == WitnetV2.DataRequestMethods.Rng + || method == Witnet.RadonDataRequestMethods.RNG && bytes(schema).length == 0 && bytes(authority).length == 0 && bytes(path).length == 0 @@ -395,18 +395,18 @@ library WitnetEncodingLib { } function validate( - WitnetV2.RadonDataTypes dataType, + Witnet.RadonDataTypes dataType, uint16 maxDataSize ) public pure returns (uint16) { if ( - dataType == WitnetV2.RadonDataTypes.Any - || dataType == WitnetV2.RadonDataTypes.String - || dataType == WitnetV2.RadonDataTypes.Bytes - || dataType == WitnetV2.RadonDataTypes.Array - || dataType == WitnetV2.RadonDataTypes.Map + dataType == Witnet.RadonDataTypes.Any + || dataType == Witnet.RadonDataTypes.String + || dataType == Witnet.RadonDataTypes.Bytes + || dataType == Witnet.RadonDataTypes.Array + || dataType == Witnet.RadonDataTypes.Map ) { if (/*maxDataSize == 0 ||*/maxDataSize > 2048) { revert WitnetV2.UnsupportedRadonDataType( @@ -416,9 +416,9 @@ library WitnetEncodingLib { } return maxDataSize; } else if ( - dataType == WitnetV2.RadonDataTypes.Integer - || dataType == WitnetV2.RadonDataTypes.Float - || dataType == WitnetV2.RadonDataTypes.Bool + dataType == Witnet.RadonDataTypes.Integer + || dataType == Witnet.RadonDataTypes.Float + || dataType == Witnet.RadonDataTypes.Bool ) { return 0; // TBD: size(dataType); } else { @@ -429,18 +429,18 @@ library WitnetEncodingLib { } } - function validate(WitnetV2.RadonFilter memory filter) + function validate(Witnet.RadonFilter memory filter) public pure { if ( - filter.opcode == WitnetV2.RadonFilterOpcodes.StandardDeviation + filter.opcode == Witnet.RadonFilterOpcodes.StandardDeviation ) { // check filters that require arguments if (filter.args.length == 0) { revert WitnetV2.RadonFilterMissingArgs(uint8(filter.opcode)); } } else if ( - filter.opcode == WitnetV2.RadonFilterOpcodes.Mode + filter.opcode == Witnet.RadonFilterOpcodes.Mode ) { // check filters that don't require any arguments if (filter.args.length > 0) { @@ -452,20 +452,20 @@ library WitnetEncodingLib { } } - function validate(WitnetV2.RadonReducer memory reducer) + function validate(Witnet.RadonReducer memory reducer) public pure { if (reducer.script.length == 0) { if (!( - reducer.opcode == WitnetV2.RadonReducerOpcodes.AverageMean - || reducer.opcode == WitnetV2.RadonReducerOpcodes.StandardDeviation - || reducer.opcode == WitnetV2.RadonReducerOpcodes.Mode - || reducer.opcode == WitnetV2.RadonReducerOpcodes.ConcatenateAndHash - || reducer.opcode == WitnetV2.RadonReducerOpcodes.AverageMedian + reducer.opcode == Witnet.RadonReducerOpcodes.AverageMean + || reducer.opcode == Witnet.RadonReducerOpcodes.StandardDeviation + || reducer.opcode == Witnet.RadonReducerOpcodes.Mode + || reducer.opcode == Witnet.RadonReducerOpcodes.ConcatenateAndHash + || reducer.opcode == Witnet.RadonReducerOpcodes.AverageMedian )) { revert WitnetV2.UnsupportedRadonReducerOpcode(uint8(reducer.opcode)); } - for (uint ix = 0; ix < reducer.filters.length; ix ++) { + for (uint256 ix = 0; ix < reducer.filters.length; ix ++) { validate(reducer.filters[ix]); } } else { @@ -479,7 +479,7 @@ library WitnetEncodingLib { } } - function validate(WitnetV2.RadonSLA memory sla) + function validate(Witnet.RadonSLA memory sla) public pure { if (sla.witnessReward == 0) { @@ -503,7 +503,7 @@ library WitnetEncodingLib { function verifyRadonScriptResultDataType(bytes memory script) public pure - returns (WitnetV2.RadonDataTypes) + returns (Witnet.RadonDataTypes) { return _verifyRadonScriptResultDataType( WitnetCBOR.fromBytes(script), @@ -520,10 +520,10 @@ library WitnetEncodingLib { string[] memory args ) private pure { - uint _rewind = self.len; - uint _start = self.buffer.cursor; + uint256 _rewind = self.len; + uint256 _start = self.buffer.cursor; bytes memory _peeks = bytes(self.readString()); - (bytes memory _pokes, uint _replacements) = WitnetBuffer.replace(_peeks, args); + (bytes memory _pokes, uint256 _replacements) = WitnetBuffer.replace(_peeks, args); if (_replacements > 0) { bytes memory _encodedPokes = encode(string(_pokes)); self.buffer.cursor = _start - _rewind; @@ -538,7 +538,7 @@ library WitnetEncodingLib { function _verifyRadonScriptResultDataType(WitnetCBOR.CBOR memory self, bool flip) private pure - returns (WitnetV2.RadonDataTypes) + returns (Witnet.RadonDataTypes) { if (self.majorType == WitnetCBOR.MAJOR_TYPE_ARRAY) { WitnetCBOR.CBOR[] memory items = self.readArray(); @@ -548,23 +548,23 @@ library WitnetEncodingLib { : _verifyRadonScriptResultDataType(items[items.length - 2], true) ; } else { - return WitnetV2.RadonDataTypes.Any; + return Witnet.RadonDataTypes.Any; } } else if (self.majorType == WitnetCBOR.MAJOR_TYPE_INT) { - uint cursor = self.buffer.cursor; - uint opcode = self.readUint(); + uint256 cursor = self.buffer.cursor; + uint256 opcode = self.readUint(); uint8 dataType = (opcode > WITNET_RADON_OPCODES_RESULT_TYPES.length ? 0xff : uint8(WITNET_RADON_OPCODES_RESULT_TYPES[opcode]) ); - if (dataType > uint8(type(WitnetV2.RadonDataTypes).max)) { + if (dataType > uint8(type(Witnet.RadonDataTypes).max)) { revert WitnetV2.UnsupportedRadonScriptOpcode( self.buffer.data, cursor, uint8(opcode) ); } - return WitnetV2.RadonDataTypes(dataType); + return Witnet.RadonDataTypes(dataType); } else { revert WitnetCBOR.UnexpectedMajorType( WitnetCBOR.MAJOR_TYPE_INT, diff --git a/contracts/libs/WitnetErrorsLib.sol b/contracts/libs/WitnetErrorsLib.sol index 54c017569..0aa5eea3b 100644 --- a/contracts/libs/WitnetErrorsLib.sol +++ b/contracts/libs/WitnetErrorsLib.sol @@ -127,7 +127,7 @@ library WitnetErrorsLib { "'." )); } else if ( - _error.code == Witnet.ResultErrorCodes.HTTP + _error.code == Witnet.ResultErrorCodes.HttpErrors && errors.length > 2 ) { _error.reason = string(abi.encodePacked( @@ -136,35 +136,35 @@ library WitnetErrorsLib { " error." )); } else if ( - _error.code == Witnet.ResultErrorCodes.RetrievalTimeout + _error.code == Witnet.ResultErrorCodes.RetrievalsTimeout && errors.length > 1 ) { _error.reason = string(abi.encodePacked( "Witnet: Retrieval: timeout." )); } else if ( - _error.code == Witnet.ResultErrorCodes.Underflow + _error.code == Witnet.ResultErrorCodes.MathUnderflow && errors.length > 1 ) { _error.reason = string(abi.encodePacked( "Witnet: Aggregation: math underflow." )); } else if ( - _error.code == Witnet.ResultErrorCodes.Overflow + _error.code == Witnet.ResultErrorCodes.MathOverflow && errors.length > 1 ) { _error.reason = string(abi.encodePacked( "Witnet: Aggregation: math overflow." )); } else if ( - _error.code == Witnet.ResultErrorCodes.DivisionByZero + _error.code == Witnet.ResultErrorCodes.MathDivisionByZero && errors.length > 1 ) { _error.reason = string(abi.encodePacked( "Witnet: Aggregation: division by zero." )); } else if ( - _error.code == Witnet.ResultErrorCodes.BridgeMalformedRequest + _error.code == Witnet.ResultErrorCodes.BridgeMalformedDataRequest ) { _error.reason = "Witnet: Bridge: malformed data request cannot be processed."; } else if ( @@ -172,11 +172,11 @@ library WitnetErrorsLib { ) { _error.reason = "Witnet: Bridge: rejected due to poor witnessing incentives."; } else if ( - _error.code == Witnet.ResultErrorCodes.BridgeOversizedResult + _error.code == Witnet.ResultErrorCodes.BridgeOversizedTallyResult ) { _error.reason = "Witnet: Bridge: rejected due to poor bridging incentives."; } else if ( - _error.code == Witnet.ResultErrorCodes.InsufficientConsensus + _error.code == Witnet.ResultErrorCodes.InsufficientMajority && errors.length > 3 ) { uint reached = (errors[1].additionalInformation == 25 @@ -226,11 +226,11 @@ library WitnetErrorsLib { "\") that was not found." )); } else if ( - _error.code == Witnet.ResultErrorCodes.NoReveals + _error.code == Witnet.ResultErrorCodes.InsufficientReveals ) { _error.reason = "Witnet: Tally: no reveals."; } else if ( - _error.code == Witnet.ResultErrorCodes.MalformedReveal + _error.code == Witnet.ResultErrorCodes.MalformedReveals ) { _error.reason = "Witnet: Tally: malformed reveal."; } else if ( diff --git a/contracts/libs/WitnetV2.sol b/contracts/libs/WitnetV2.sol index 4b9c0912c..e325c0e47 100644 --- a/contracts/libs/WitnetV2.sol +++ b/contracts/libs/WitnetV2.sol @@ -6,208 +6,139 @@ import "./Witnet.sol"; library WitnetV2 { - error IndexOutOfBounds(uint256 index, uint256 range); - error InsufficientBalance(uint256 weiBalance, uint256 weiExpected); - error InsufficientFee(uint256 weiProvided, uint256 weiExpected); - error Unauthorized(address violator); - - error RadonFilterMissingArgs(uint8 opcode); - - error RadonRequestNoSources(); - error RadonRequestSourcesArgsMismatch(uint expected, uint actual); - error RadonRequestMissingArgs(uint index, uint expected, uint actual); - error RadonRequestResultsMismatch(uint index, uint8 read, uint8 expected); - error RadonRequestTooHeavy(bytes bytecode, uint weight); - - error RadonSlaNoReward(); - error RadonSlaNoWitnesses(); - error RadonSlaTooManyWitnesses(uint256 numWitnesses); - error RadonSlaConsensusOutOfRange(uint256 percentage); - error RadonSlaLowCollateral(uint256 witnessCollateral); - - error UnsupportedDataRequestMethod(uint8 method, string schema, string body, string[2][] headers); - error UnsupportedRadonDataType(uint8 datatype, uint256 maxlength); - error UnsupportedRadonFilterOpcode(uint8 opcode); - error UnsupportedRadonFilterArgs(uint8 opcode, bytes args); - error UnsupportedRadonReducerOpcode(uint8 opcode); - error UnsupportedRadonReducerScript(uint8 opcode, bytes script, uint256 offset); - error UnsupportedRadonScript(bytes script, uint256 offset); - error UnsupportedRadonScriptOpcode(bytes script, uint256 cursor, uint8 opcode); - error UnsupportedRadonTallyScript(bytes32 hash); - - function toEpoch(uint _timestamp) internal pure returns (uint) { - return 1 + (_timestamp - 11111) / 15; + /// Struct containing both request and response data related to every query posted to the Witnet Request Board + struct Query { + Request request; + Response response; } - function toTimestamp(uint _epoch) internal pure returns (uint) { - return 111111+ _epoch * 15; + /// Possible status of a Witnet query. + enum QueryStatus { + Unknown, + Posted, + Reported, + Finalized } - struct Beacon { - uint256 escrow; - uint256 evmBlock; - uint256 gasprice; - address relayer; - address slasher; - uint256 superblockIndex; - uint256 superblockRoot; + /// Data kept in EVM-storage for every Request posted to the Witnet Request Board. + struct Request { + address requester; // EVM address from which the request was posted. + uint24 gasCallback; // Max callback gas limit upon response, if a callback is required. + uint72 evmReward; // EVM amount in wei eventually to be paid to the legit result reporter. + bytes witnetBytecode; // Optional: Witnet Data Request bytecode to be solved by the Witnet blockchain. + bytes32 witnetRAD; // Optional: Previously verified hash of the Witnet Data Request to be solved. + Witnet.RadonSLA witnetSLA; // Minimum Service-Level parameters to be committed by the Witnet blockchain. + } + + /// Response metadata and result as resolved by the Witnet blockchain. + struct Response { + address reporter; // EVM address from which the Data Request result was reported. + uint64 finality; // EVM block number at which the reported data will be considered to be finalized. + uint32 resultTimestamp; // Unix timestamp (seconds) at which the data request was resolved in the Witnet blockchain. + bytes32 resultTallyHash; // Unique hash of the commit/reveal act in the Witnet blockchain that resolved the data request. + bytes resultCborBytes; // CBOR-encode result to the request, as resolved in the Witnet blockchain. + } + + /// Response status from a requester's point of view. + enum ResponseStatus { + Void, + Awaiting, + Ready, + Error, + Finalizing, + Delivered } - enum BeaconStatus { - Idle + struct RadonSLA { + /// @notice Number of nodes in the Witnet blockchain that will take part in solving the data request. + uint8 committeeSize; + + /// @notice Fee in $nanoWIT paid to every node in the Witnet blockchain involved in solving the data request. + /// @dev Witnet nodes participating as witnesses will have to stake as collateral 100x this amount. + uint64 witnessingFeeNanoWit; } - struct Block { - bytes32 blockHash; - bytes32 drTxsRoot; - bytes32 drTallyTxsRoot; - } - enum BlockStatus { - Idle - } + /// =============================================================================================================== + /// --- 'WitnetV2.RadonSLA' helper methods ------------------------------------------------------------------------ - struct DrPost { - uint256 block; - DrPostStatus status; - DrPostRequest request; - DrPostResponse response; - } - - /// Data kept in EVM-storage for every Request posted to the Witnet Request Board. - struct DrPostRequest { - uint256 epoch; - address requester; - address reporter; - bytes32 radHash; - bytes32 slaHash; - uint256 weiReward; + function equalOrGreaterThan(RadonSLA memory a, RadonSLA memory b) + internal pure returns (bool) + { + return (a.committeeSize >= b.committeeSize); } - - /// Data kept in EVM-storage containing Witnet-provided response metadata and result. - struct DrPostResponse { - address disputer; - address reporter; - uint256 escrowed; - uint256 drCommitTxEpoch; - uint256 drTallyTxEpoch; - bytes32 drTallyTxHash; - bytes drTallyResultCborBytes; + + function isValid(RadonSLA calldata sla) internal pure returns (bool) { + return ( + sla.witnessingFeeNanoWit > 0 + && sla.committeeSize > 0 && sla.committeeSize <= 127 + // v1.7.x requires witnessing collateral to be greater or equal to 20 WIT: + && sla.witnessingFeeNanoWit * 100 >= 20 * 10 ** 9 + ); } - enum DrPostStatus { - Void, - Deleted, - Expired, - Posted, - Disputed, - Reported, - Finalized, - Accepted, - Rejected + function toV1(RadonSLA memory self) internal pure returns (Witnet.RadonSLA memory) { + return Witnet.RadonSLA({ + numWitnesses: self.committeeSize, + minConsensusPercentage: 51, + witnessReward: self.witnessingFeeNanoWit, + witnessCollateral: self.witnessingFeeNanoWit * 100, + minerCommitRevealFee: self.witnessingFeeNanoWit / self.committeeSize + }); } - struct DataProvider { - string authority; - uint256 totalEndpoints; - mapping (uint256 => bytes32) endpoints; + function nanoWitTotalFee(RadonSLA storage self) internal view returns (uint64) { + return self.witnessingFeeNanoWit * (self.committeeSize + 3); } - enum DataRequestMethods { - /* 0 */ Unknown, - /* 1 */ HttpGet, - /* 2 */ Rng, - /* 3 */ HttpPost, - /* 4 */ HttpHead - } - enum RadonDataTypes { - /* 0x00 */ Any, - /* 0x01 */ Array, - /* 0x02 */ Bool, - /* 0x03 */ Bytes, - /* 0x04 */ Integer, - /* 0x05 */ Float, - /* 0x06 */ Map, - /* 0x07 */ String, - Unused0x08, Unused0x09, Unused0x0A, Unused0x0B, - Unused0x0C, Unused0x0D, Unused0x0E, Unused0x0F, - /* 0x10 */ Same, - /* 0x11 */ Inner, - /* 0x12 */ Match, - /* 0x13 */ Subscript - } + /// =============================================================================================================== + /// --- P-RNG generators ------------------------------------------------------------------------------------------ - struct RadonFilter { - RadonFilterOpcodes opcode; - bytes args; + /// Generates a pseudo-random uint32 number uniformly distributed within the range `[0 .. range)`, based on + /// the given `nonce` and `seed` values. + function randomUint32(uint32 range, uint256 nonce, bytes32 seed) + internal pure + returns (uint32) + { + uint256 _number = uint256( + keccak256( + abi.encode(seed, nonce) + ) + ) & uint256(2 ** 224 - 1); + return uint32((_number * range) >> 224); } - enum RadonFilterOpcodes { - /* 0x00 */ GreaterThan, - /* 0x01 */ LessThan, - /* 0x02 */ Equals, - /* 0x03 */ AbsoluteDeviation, - /* 0x04 */ RelativeDeviation, - /* 0x05 */ StandardDeviation, - /* 0x06 */ Top, - /* 0x07 */ Bottom, - /* 0x08 */ Mode, - /* 0x09 */ LessOrEqualThan - } - struct RadonReducer { - RadonReducerOpcodes opcode; - RadonFilter[] filters; - bytes script; - } + /// =============================================================================================================== + /// --- Runtime Custom errors ------------------------------------------------------------------------------------- - enum RadonReducerOpcodes { - /* 0x00 */ Minimum, - /* 0x01 */ Maximum, - /* 0x02 */ Mode, - /* 0x03 */ AverageMean, - /* 0x04 */ AverageMeanWeighted, - /* 0x05 */ AverageMedian, - /* 0x06 */ AverageMedianWeighted, - /* 0x07 */ StandardDeviation, - /* 0x08 */ AverageDeviation, - /* 0x09 */ MedianDeviation, - /* 0x0A */ MaximumDeviation, - /* 0x0B */ ConcatenateAndHash - } + error IndexOutOfBounds(uint256 index, uint256 range); + error InsufficientBalance(uint256 weiBalance, uint256 weiExpected); + error InsufficientFee(uint256 weiProvided, uint256 weiExpected); + error Unauthorized(address violator); - struct RadonRetrieval { - uint8 argsCount; - DataRequestMethods method; - RadonDataTypes resultDataType; - string url; - string body; - string[2][] headers; - bytes script; - } + error RadonFilterMissingArgs(uint8 opcode); - struct RadonSLA { - uint numWitnesses; - uint minConsensusPercentage; - uint witnessReward; - uint witnessCollateral; - uint minerCommitRevealFee; - } + error RadonRequestNoSources(); + error RadonRequestSourcesArgsMismatch(uint256 expected, uint256 actual); + error RadonRequestMissingArgs(uint256 index, uint256 expected, uint256 actual); + error RadonRequestResultsMismatch(uint256 index, uint8 read, uint8 expected); + error RadonRequestTooHeavy(bytes bytecode, uint256 weight); - /// @notice Returns `true` if all witnessing parameters in `b` have same - /// @notice value or greater than the ones in `a`. - function equalOrGreaterThan(RadonSLA memory a, RadonSLA memory b) - internal pure - returns (bool) - { - return ( - a.numWitnesses >= b.numWitnesses - && a.minConsensusPercentage >= b.minConsensusPercentage - && a.witnessReward >= b.witnessReward - && a.witnessCollateral >= b.witnessCollateral - && a.minerCommitRevealFee >= b.minerCommitRevealFee - ); - } + error RadonSlaNoReward(); + error RadonSlaNoWitnesses(); + error RadonSlaTooManyWitnesses(uint256 numWitnesses); + error RadonSlaConsensusOutOfRange(uint256 percentage); + error RadonSlaLowCollateral(uint256 witnessCollateral); + error UnsupportedDataRequestMethod(uint8 method, string schema, string body, string[2][] headers); + error UnsupportedRadonDataType(uint8 datatype, uint256 maxlength); + error UnsupportedRadonFilterOpcode(uint8 opcode); + error UnsupportedRadonFilterArgs(uint8 opcode, bytes args); + error UnsupportedRadonReducerOpcode(uint8 opcode); + error UnsupportedRadonReducerScript(uint8 opcode, bytes script, uint256 offset); + error UnsupportedRadonScript(bytes script, uint256 offset); + error UnsupportedRadonScriptOpcode(bytes script, uint256 cursor, uint8 opcode); + error UnsupportedRadonTallyScript(bytes32 hash); } \ No newline at end of file diff --git a/contracts/requests/WitnetRequestMalleableBase.sol b/contracts/requests/WitnetRequestMalleableBase.sol index 241f05ca9..b6ab0e1d5 100644 --- a/contracts/requests/WitnetRequestMalleableBase.sol +++ b/contracts/requests/WitnetRequestMalleableBase.sol @@ -2,6 +2,7 @@ pragma solidity >=0.7.0 <0.9.0; +import "../interfaces/IWitnetRequest.sol"; import "../libs/Witnet.sol"; import "../patterns/Clonable.sol"; import "../patterns/Ownable.sol"; diff --git a/contracts/requests/WitnetRequestTemplate.sol b/contracts/requests/WitnetRequestTemplate.sol index f180e5060..503377353 100644 --- a/contracts/requests/WitnetRequestTemplate.sol +++ b/contracts/requests/WitnetRequestTemplate.sol @@ -17,14 +17,14 @@ abstract contract WitnetRequestTemplate function aggregator() virtual external view returns (bytes32); function parameterized() virtual external view returns (bool); function resultDataMaxSize() virtual external view returns (uint16); - function resultDataType() virtual external view returns (WitnetV2.RadonDataTypes); + function resultDataType() virtual external view returns (Witnet.RadonDataTypes); function retrievals() virtual external view returns (bytes32[] memory); function tally() virtual external view returns (bytes32); - function getRadonAggregator() virtual external view returns (WitnetV2.RadonReducer memory); - function getRadonRetrievalByIndex(uint256) virtual external view returns (WitnetV2.RadonRetrieval memory); + function getRadonAggregator() virtual external view returns (Witnet.RadonReducer memory); + function getRadonRetrievalByIndex(uint256) virtual external view returns (Witnet.RadonRetrieval memory); function getRadonRetrievalsCount() virtual external view returns (uint256); - function getRadonTally() virtual external view returns (WitnetV2.RadonReducer memory); + function getRadonTally() virtual external view returns (Witnet.RadonReducer memory); function buildRequest(string[][] calldata args) virtual external returns (address); function verifyRadonRequest(string[][] calldata args) virtual external returns (bytes32); diff --git a/migrations/ops/rng/sla/1_set-randomness-sla.js b/migrations/ops/rng/sla/1_set-randomness-sla.js index 0e53eeef1..793b64c3b 100644 --- a/migrations/ops/rng/sla/1_set-randomness-sla.js +++ b/migrations/ops/rng/sla/1_set-randomness-sla.js @@ -14,7 +14,7 @@ module.exports = async function (_deployer, network) { console.log("> WitnetRandomness address:", randomizer.address) console.log("> WitnetRequestRandomness address:", request.address) - console.log("> WitnetRequestRadnomness owner:", owner) + console.log("> WitnetRequestRandomness owner:", owner) console.log("> Current commit/reval fee:", radonSLA.witnessingUnitaryFee) console.log("> Current number of witnesses:", radonSLA.numWitnesses) console.log("> Current witnessing reward:", radonSLA.witnessingReward) diff --git a/migrations/scripts/5_WitnetRequestBoard.js b/migrations/scripts/5_WitnetRequestBoard.js index a7d6c1151..a50a584b6 100644 --- a/migrations/scripts/5_WitnetRequestBoard.js +++ b/migrations/scripts/5_WitnetRequestBoard.js @@ -27,7 +27,11 @@ module.exports = async function (deployer, network, [, from, reporter]) { if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} const artifactsName = merge(settings.artifacts.default, settings.artifacts[ecosystem], settings.artifacts[network]) - const WitnetRequestBoardImplementation = artifacts.require(artifactsName.WitnetRequestBoard) + const artifactNames = artifactsName.WitnetRequestBoard.split(":") + const bypass = artifactNames.length > 1 + const implName = artifactNames[0] + + const WitnetRequestBoardImplementation = artifacts.require(implName) const create2FactoryAddr = addresses[ecosystem][network]?.Create2Factory let proxy @@ -80,21 +84,40 @@ module.exports = async function (deployer, network, [, from, reporter]) { let board if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetRequestBoardImplementation)) { await deployer.link(WitnetErrorsLib, WitnetRequestBoardImplementation) - await deployer.deploy( - WitnetRequestBoardImplementation, - WitnetRequestFactory.address, - /* _isUpgradeable */ true, - /* _versionTag */ utils.fromAscii(version), - ...( - // if defined, use network-specific constructor parameters: - settings.constructorParams[network]?.WitnetRequestBoard || - // otherwise, use ecosystem-specific parameters, if any: - settings.constructorParams[ecosystem]?.WitnetRequestBoard || - // or, default defined parameters for WRBs, if any: - settings.constructorParams?.default?.WitnetRequestBoard - ), - { from } - ) + if (bypass) { + await deployer.deploy( + WitnetRequestBoardImplementation, + /* _legacy impl */ addresses[ecosystem][network][artifactNames[1]], + /* _v20 address */ addresses[ecosystem][network]?.WitnetOracleV20 || addresses.commons.WitnetOracleV20, + /* _isUpgradeable */ true, + /* _versionTag */ utils.fromAscii(version), + ...( + // if defined, use network-specific constructor parameters: + settings.constructorParams[network]?.WitnetRequestBoard || + // otherwise, use ecosystem-specific parameters, if any: + settings.constructorParams[ecosystem]?.WitnetRequestBoard || + // or, default defined parameters for WRBs, if any: + settings.constructorParams?.default?.WitnetRequestBoard + ), + { from } + ) + } else { + await deployer.deploy( + WitnetRequestBoardImplementation, + WitnetRequestFactory.address, + /* _isUpgradeable */ true, + /* _versionTag */ utils.fromAscii(version), + ...( + // if defined, use network-specific constructor parameters: + settings.constructorParams[network]?.WitnetRequestBoard || + // otherwise, use ecosystem-specific parameters, if any: + settings.constructorParams[ecosystem]?.WitnetRequestBoard || + // or, default defined parameters for WRBs, if any: + settings.constructorParams?.default?.WitnetRequestBoard + ), + { from } + ) + } board = await WitnetRequestBoardImplementation.deployed() addresses[ecosystem][network].WitnetRequestBoardImplementation = board.address if (!isDryRun) { diff --git a/migrations/scripts/6_WitnetRandomness.js b/migrations/scripts/6_WitnetRandomness.js index 2df37b91b..3acca3b1d 100644 --- a/migrations/scripts/6_WitnetRandomness.js +++ b/migrations/scripts/6_WitnetRandomness.js @@ -31,12 +31,11 @@ module.exports = async function (deployer, network, [, from]) { return } - const create2Factory = await Create2Factory.deployed() - const artifactNames = merge(settings.artifacts.default, settings.artifacts[ecosystem], settings.artifacts[network]) const WitnetRandomnessImplementation = artifacts.require(artifactNames.WitnetRandomness) if (addresses[ecosystem][network].WitnetRandomnessImplementation !== undefined) { + const create2Factory = await Create2Factory.deployed() let proxy if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetRandomness)) { if ( diff --git a/migrations/scripts/7_WitnetPriceFeeds.js b/migrations/scripts/7_WitnetPriceFeeds.js index 9e891e8e1..352bf6ad9 100644 --- a/migrations/scripts/7_WitnetPriceFeeds.js +++ b/migrations/scripts/7_WitnetPriceFeeds.js @@ -33,8 +33,12 @@ module.exports = async function (deployer, network, [, from]) { return } - const artifactNames = merge(settings.artifacts.default, settings.artifacts[ecosystem], settings.artifacts[network]) - const WitnetPriceFeedsImplementation = artifacts.require(artifactNames.WitnetPriceFeeds) + const artifactsName = merge(settings.artifacts.default, settings.artifacts[ecosystem], settings.artifacts[network]) + const artifactNames = artifactsName.WitnetPriceFeeds?.split(":") + const bypass = artifactNames.length > 1 + const implName = artifactNames[0] + + const WitnetPriceFeedsImplementation = artifacts.require(implName) if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetPriceFeedsLib)) { await deployer.deploy(WitnetPriceFeedsLib, { from }) @@ -99,13 +103,21 @@ module.exports = async function (deployer, network, [, from]) { } let router if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetPriceFeedsImplementation)) { - await deployer.deploy( - WitnetPriceFeedsImplementation, - WitnetRequestBoard.address, - true, - utils.fromAscii(version), - { from } - ) + if (bypass) { + await deployer.deploy( + WitnetPriceFeedsImplementation, + /* _v20 address */ addresses[ecosystem][network]?.WitnetPriceFeedsV20 || addresses.commons.WitnetPriceFeedsV20, + /* _isUpgradeable */ true, + /* _versionTag */ utils.fromAscii(version), + { from } + ) + } else { + await deployer.deploy( + WitnetPriceFeedsImplementation, + WitnetRequestBoard.address, true, utils.fromAscii(version), + { from } + ) + } router = await WitnetPriceFeedsImplementation.deployed() addresses[ecosystem][network].WitnetPriceFeedsImplementation = router.address if (!isDryRun) { @@ -134,7 +146,9 @@ module.exports = async function (deployer, network, [, from]) { ["y", "yes"].includes((await utils.prompt(" > Upgrade the proxy ? [y/N] ")).toLowerCase().trim()) ) { try { - const tx = await proxy.upgradeTo(router.address, "0x", { from }) + const tx = await proxy.upgradeTo(router.address, "0x", { + from: bypass ? "0xF121b71715E71DDeD592F1125a06D4ED06F0694D" : from, + }) console.info(" => transaction hash :", tx.receipt.transactionHash) console.info(" => transaction gas :", tx.receipt.gasUsed) console.info(" > Done.") diff --git a/migrations/witnet.addresses.json b/migrations/witnet.addresses.json index c03fb0506..7ea9e1df7 100644 --- a/migrations/witnet.addresses.json +++ b/migrations/witnet.addresses.json @@ -1,40 +1,25 @@ { + "commons": { + "WitnetOracleV20": "0x77703aE126B971c9946d562F41Dd47071dA00777", + "WitnetPriceFeedsV20": "0x1111AbA2164AcdC6D291b08DfB374280035E1111" + }, "default": { - "ethereum.goerli": { - "WitnetProxy": "0xB5447342cA17A40e59d410b340ba412E22e36201", - "Create2Factory": "0xDe312a6f7fA35320E8DD109c8ea42e82806DC45b", - "WitnetBytecodes": "0x0000000e3a3d22d7510B36BdC88994dab11eadc8", - "WitnetPriceFeeds": "0x9999999d139bdBFbF25923ba39F63bBFc7593400", - "WitnetPriceRouter": "0x1cF3Aa9DBF4880d797945726B94B9d29164211BE", - "WitnetRandomness": "0x0123456fbBC59E181D76B6Fe8771953d1953B51a", - "WitnetRequestBoard": "0xb58D05247d16b3F1BD6B59c52f7f61fFef02BeC8", - "WitnetRequestFactory": "0x1111111FDE7dC956E3d7922Bc779D9E2349Afb63", - "WitnetErrorsLib": "0xc71A87657b13A370594967A04b4301a3AcEAF007", - "WitnetEncodingLib": "0x1f35F6d6BE5Bd574b2B00Ac2Dc0BeCAfcc04Ed51", - "WitnetPriceFeedsLib": "0x7A6C2Aad6b4b08De09477D0F663b8f90b0db9662", - "WitnetBytecodesImplementation": "0xA9cC3101735b248964e90fA8506219A9CF0b1091", - "WitnetPriceFeedsImplementation": "0xBfFA2ec6225390C517A1bEB83b27a171C6734294", - "WitnetRandomnessImplementation": "0x685528FA605c31aE076e1ee1707041B7Cb356573", - "WitnetRandomnessImplementationV061": "0x6Eb87EcCe6218Cd0e97299331D2aa5d2e53da5cD", - "WitnetRequestBoardImplementation": "0x0e86a89D9Ae5D6182a853375F19dB23e5c600268", - "WitnetRequestFactoryImplementation": "0xeDA4f244FEe1D6a3EA0fB2c0Fc6b7D1c49fEF01D" - }, "ethereum.sepolia": { "WitnetProxy": "0xf6d52770453166de85B6B6260Cf22196bC460E88", "Create2Factory": "0xDe312a6f7fA35320E8DD109c8ea42e82806DC45b", "WitnetBytecodes": "0x0000000e3a3d22d7510B36BdC88994dab11eadc8", "WitnetPriceFeeds": "0x9999999d139bdBFbF25923ba39F63bBFc7593400", "WitnetPriceRouter": "0xdC101573cB42EB7006Ad6C7E08ce8C91fEAcB62C", - "WitnetRandomness": "0x012345000Db5417269d8c70B0142Ae3eF36d7f3e", + "WitnetRandomness": "0xa579563E3ee6884e3b4cdE1BBb2fF6305686A83f", "WitnetRequestBoard": "0x777777772C24e6CD34B464D1d71616C444254537", "WitnetRequestFactory": "0x1111111FDE7dC956E3d7922Bc779D9E2349Afb63", "WitnetErrorsLib": "0x20f4B1793bb81FFa357E1705AD954BdC232Edc00", "WitnetEncodingLib": "0xc71A87657b13A370594967A04b4301a3AcEAF007", "WitnetPriceFeedsLib": "0xBfFA2ec6225390C517A1bEB83b27a171C6734294", "WitnetBytecodesImplementation": "0xa45206cC3Ae76630Cc4D47A730590Ff9B6d8Ee54", - "WitnetPriceFeedsImplementation": "0x7a56A80A9B169c046EdD1d8f584455a394bc9C71", - "WitnetRandomnessImplementation": "0x7A6C2Aad6b4b08De09477D0F663b8f90b0db9662", - "WitnetRequestBoardImplementation": "0xd8875D7D3087DEec0103d47d4cE0C4a5414874E1", + "WitnetPriceFeedsImplementation": "0xDe2464F0ac0EA829BE25AA0c36056EB64bCbe2C9", + "WitnetRequestBoardImplementation": "0x14417b205ef242a364Dc68540Eb42F974b1Ea909", + "WitnetRequestBoardTrustableDefault": "0xd8875D7D3087DEec0103d47d4cE0C4a5414874E1", "WitnetRequestFactoryImplementation": "0x6F68A4d58cEd8e094b42511350527Ed628ACB970" }, "ethereum.mainnet": { @@ -62,10 +47,11 @@ "WitnetErrorsLib": "0xf6d52770453166de85B6B6260Cf22196bC460E88", "WitnetEncodingLib": "0x69891cE36F6dFbef4A7BdD0E95A15CBA916f206b", "WitnetBytecodesImplementation": "0xd8875D7D3087DEec0103d47d4cE0C4a5414874E1", - "WitnetPriceFeedsImplementation": "0x620e20d91C9b0e11ecAE439E7b85138DA2a1003F", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0x078EE90E16e2e5332EDaA87da19d2743cD8C64DD", "WitnetRandomnessImplementationV061": "0xB0C5d40A7658b2ab28360aFa6eB5bAeb2fFe86c3", - "WitnetRequestBoardImplementation": "0x7ab66AB288A143D4e07Aff9b729165bFb71DB73a", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x7ab66AB288A143D4e07Aff9b729165bFb71DB73a", "WitnetRequestFactoryImplementation": "0xb5F3c9Dc6Ca7C1078cE5c51c1cE030D6BEEd57E2", "WitnetPriceFeedsLib": "0x4874cb1732eE1167A006E0Ab047D940ACF04D771" }, @@ -82,9 +68,10 @@ "WitnetErrorsLib": "0x56E44A9f86C2e3a53e816335cBE6deaE440b0856", "WitnetEncodingLib": "0xB68c0127e74dC705d18162621035f9782b23D609", "WitnetBytecodesImplementation": "0xE794D90AfaAC834DBaC58A7A283548C09aB266aE", - "WitnetPriceFeedsImplementation": "0x6020665A4F6dcEFfBDb9655C8bF904C51CB94951", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0xa239729c399c9eBae7fdc188A1Dbb2c4a06Cd4Bb", - "WitnetRequestBoardImplementation": "0xf85A3B52D306B1F4Bb5B63A84D2C4D190F45f068", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0xf85A3B52D306B1F4Bb5B63A84D2C4D190F45f068", "WitnetRequestFactoryImplementation": "0x9a83a23066766991E6cA113eB425fFe806f62ecF", "WitnetPriceFeedsLib": "0xB1D870ce58D6521A17BDBB2D209558bc605e78D6" } @@ -103,10 +90,11 @@ "WitnetEncodingLib": "0x0e86a89D9Ae5D6182a853375F19dB23e5c600268", "WitnetPriceFeedsLib": "0xBfFA2ec6225390C517A1bEB83b27a171C6734294", "WitnetBytecodesImplementation": "0xE490b89AfADE571d8Afa158446C603D530608ceA", - "WitnetPriceFeedsImplementation": "0x8762508A67e71Df04212B256E19faB1771F9a2F4", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0x685528FA605c31aE076e1ee1707041B7Cb356573", "WitnetRandomnessImplementationV061": "0xD47fc24C99fD94f33bD2f33FE373b1447bB10724", - "WitnetRequestBoardImplementation": "0x0b75886DeB58F80A75E5cAF10702C5d15FA54437", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x0b75886DeB58F80A75E5cAF10702C5d15FA54437", "WitnetRequestFactoryImplementation": "0x364E2b91a4C7563288C3ccF7256BA172935CC550" }, "avalanche.mainnet": { @@ -130,9 +118,10 @@ "WitnetEncodingLib": "", "WitnetPriceFeedsLib": "0x5c1dD29563203883A5D5C3136783D3119B2C4e57", "WitnetBytecodesImplementation": "", - "WitnetPriceFeedsImplementation": "0xd0f725Bf11bA75D291506d396FbcbeCAb5384e95", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0x08a6a53B8bCE95677fFA85813C32Bb8228cd114c", - "WitnetRequestBoardImplementation": "0x276Da4D5720EFaD1fBE417d27BD838707e61ba8C", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableOvm2": "0x276Da4D5720EFaD1fBE417d27BD838707e61ba8C", "WitnetRequestFactoryImplementation": "0xce66333c9D7BE37D61d3c5b57D6D41ff082Ca92f" }, "boba.bnb.mainnet": { @@ -148,31 +137,13 @@ "WitnetEncodingLib": "", "WitnetPriceFeedsLib": "0x7AA219C444f68eDBD5789d89076efA8A3f09996b", "WitnetBytecodesImplementation": "", - "WitnetPriceFeedsImplementation": "0xc45c93083F7B97Cdb700D4D2ADE6a727E04793ff", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0xC467B6E0F700D3E044C9F20BB76957eEC0B33c8C", "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableOvm2": "0xD111C0ef9A8FA71a66E37255d255abd8879D143C", "WitnetRequestFactoryImplementation": "0x4756097b9184327713D07b3ac4C2a898468220B1", "WitnetRequestRandomness": "0xA99B485363DBAe90D17B10F988C4e1Ae895048e0" }, - "boba.ethereum.goerli": { - "WitnetProxy": "0x1b91eAB33362f10A5F803Fe3f0d181F42caFaac3", - "Create2Factory": "0xDe312a6f7fA35320E8DD109c8ea42e82806DC45b", - "WitnetBytecodes": "0x0000000e3a3d22d7510B36BdC88994dab11eadc8", - "WitnetPriceFeeds": "0x9999999d139bdBFbF25923ba39F63bBFc7593400", - "WitnetPriceRouter": "0xB4B2E2e00e9d6E5490d55623E4F403EC84c6D33f", - "WitnetRandomness": "0x0123456fbBC59E181D76B6Fe8771953d1953B51a", - "WitnetRequestBoard": "0x58D8ECe142c60f5707594a7C1D90e46eAE5AF431", - "WitnetRequestFactory": "0x1111111FDE7dC956E3d7922Bc779D9E2349Afb63", - "WitnetErrorsLib": "0xf6d52770453166de85B6B6260Cf22196bC460E88", - "WitnetEncodingLib": "", - "WitnetPriceFeedsLib": "0x6dc0E2AC80550F901cd4d5F5a4C48333A0ca97Ee", - "WitnetBytecodesImplementation": "", - "WitnetPriceFeedsImplementation": "0x4874cb1732eE1167A006E0Ab047D940ACF04D771", - "WitnetRandomnessImplementation": "0xd8875D7D3087DEec0103d47d4cE0C4a5414874E1", - "WitnetRandomnessImplementationV061": "0xeD074DA2A76FD2Ca90C1508930b4FB4420e413B0", - "WitnetRequestBoardImplementation": "0x685528FA605c31aE076e1ee1707041B7Cb356573", - "WitnetRequestFactoryImplementation": "0x364E2b91a4C7563288C3ccF7256BA172935CC550" - }, "boba.ethereum.mainnet": { "WitnetLib": "0x6473063EBEabC0606A4159b7d9F79BB306ED0D2A", "WitnetPriceRouter": "0x93f61D0D5F623144e7C390415B70102A9Cc90bA5", @@ -194,10 +165,11 @@ "WitnetEncodingLib": "0x9ebaCbe3B5b03e164E9dfd15Ad8e86697f6d5bF6", "WitnetPriceFeedsLib": "0x50AA08187D2F648Dd428784AF6489c3F12e942CC", "WitnetBytecodesImplementation": "0x71D5D7F2ed2436062946727DB84E44588F765D02", - "WitnetPriceFeedsImplementation": "0x654B79823f244c2476907F21EBD20cFebC04D0A5", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0xFB36b14df6D319A5A7F418C80b0700664A4f9e6a", "WitnetRandomnessImplementationV061": "0xbD804467270bCD832b4948242453CA66972860F5", - "WitnetRequestBoardImplementation": "0xe381f706f2932049A844791f41b2863884c4e6CA", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0xe381f706f2932049A844791f41b2863884c4e6CA", "WitnetRequestFactoryImplementation": "0x4874cb1732eE1167A006E0Ab047D940ACF04D771" }, "celo.mainnet": { @@ -213,10 +185,11 @@ "WitnetEncodingLib": "0x88e7Ab71cC18B9f6Fb091fc53Fe3Be467808E0F6", "WitnetPriceFeedsLib": "0x760C146699B76c84Cc8050f57728F2Dc374cbf25", "WitnetBytecodesImplementation": "0x2573D4d998117b3c2a5a4Ea3c216b6Ebc0039780", - "WitnetPriceFeedsImplementation": "0x76ffF94D527504e90DaCB12d710590ba8227299E", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0x6Af31B632A20185ff96FC47a8576a6980Cd99FEC", "WitnetRandomnessImplementationV061": "0x6023fF93A3b37791a94B15D6AEaD488933b01Db3", - "WitnetRequestBoardImplementation": "0x5A13430A283701BE24cE7E1712B38F31d4B9ac58", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x5A13430A283701BE24cE7E1712B38F31d4B9ac58", "WitnetRequestFactoryImplementation": "0x0d13c6058DDE86da77565ED6038C065Af71e9208" } }, @@ -232,12 +205,15 @@ "WitnetRequestFactory": "0x83eFF90a51D7da324AE1580eab6Ee0c9D45ad509", "WitnetErrorsLib": "0x8d5Fda8c48dF35f321301e69c3c605AABCA474b1", "WitnetEncodingLib": "0x8B84cba430E98E3DfD18D24823B1E327188b01F3", + "WitnetPriceFeedsLib": "0x87cA78592Cb691BA3a1919c2d83Ed578e8E0Ae0a", "WitnetBytecodesImplementation": "0x8B71361a331513023534d6A64Ce65123aa1E7B79", - "WitnetPriceFeedsImplementation": "0x81f3EB9a7853F8e1357f6BB61E7BB610F73605F1", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementationV061": "0x887bC8Db7D91413D1575071925Ee8d77fE2CBc81", - "WitnetRequestBoardImplementation": "0x8d19a968CeAA0d31cD9E0434574C8dC5710ddBac", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x8d19a968CeAA0d31cD9E0434574C8dC5710ddBac", "WitnetRequestFactoryImplementation": "0x89a49b46864049b16dFcf185740Ac89Eec8Fd670", - "WitnetPriceFeedsLib": "0x87cA78592Cb691BA3a1919c2d83Ed578e8E0Ae0a" + "WitnetOracleV20": "", + "WitnetPriceFeedsV20": "" }, "conflux.core.mainnet": { "WitnetLib": "0x8A026e6956B4DB3E81bb113401798e59cFBEA4C6", @@ -258,10 +234,11 @@ "WitnetEncodingLib": "0x2163DBCBdbBeC066EF8d8Adab75Af8b0B9A5cfAA", "WitnetPriceFeedsLib": "0x7A6C2Aad6b4b08De09477D0F663b8f90b0db9662", "WitnetBytecodesImplementation": "0x87cB87b649A75c608402Cb9F030129510e201BB4", - "WitnetPriceFeedsImplementation": "0x6bF6F65Ad0859e9Ee869DAD252a29c9daAa27449", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0x0b75886DeB58F80A75E5cAF10702C5d15FA54437", "WitnetRandomnessImplementationV061": "0xa784093826e2894Ab3Db315f4e05F0F26407BBfF", - "WitnetRequestBoardImplementation": "0x1f35F6d6BE5Bd574b2B00Ac2Dc0BeCAfcc04Ed51", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x1f35F6d6BE5Bd574b2B00Ac2Dc0BeCAfcc04Ed51", "WitnetRequestFactoryImplementation": "0xeDA4f244FEe1D6a3EA0fB2c0Fc6b7D1c49fEF01D" }, "conflux.espace.mainnet": { @@ -285,66 +262,24 @@ "WitnetEncodingLib": "0x3280539A77C578C3eF698f53f29CDba00eC9B72E", "WitnetPriceFeedsLib": "0xB1Ee13a85B2593D5191f3a2A08f175b1c918B9bb", "WitnetBytecodesImplementation": "0x5256D112d446Ba1d904b6BF3B2812B17336766f5", - "WitnetPriceFeedsImplementation": "0x7538f6Bff94B0F7F0A0802376238Aab0D2528521", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0xe145A4D3335D5F78d7e9cB6a3C1832155cB4Be01", "WitnetRandomnessImplementationV061": "0x0017A464A86f48B342Cae3b8Fe29cFCDaA7b0643", - "WitnetRequestBoardImplementation": "0x3093731aECf4d9Be53b153E27A36D2E02647479F", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x3093731aECf4d9Be53b153E27A36D2E02647479F", "WitnetRequestFactoryImplementation": "0xA8767A6EA3099De344499B35f725A38E3cD15562" }, "cronos.mainnet": { "WitnetLib": "0x1D9c4a8f8B7b5F9B8e2641D81927f8F8Cc7fF079", "WitnetPriceRouter": "0xD39D4d972C7E166856c4eb29E54D3548B4597F53", "WitnetRandomness": "0x3737be6FcFf5B3B0f9DCc9a9ae1Da56561D0d0d3", - "WitnetRequestBoard": "0xd653fbd7c736838289262F0F41A458f35393C88a" - } - }, - "cube": { - "cube.testnet": { - "WitnetProxy": "", - "Create2Factory": "", - "WitnetBytecodes": "", - "WitnetPriceFeeds": "", - "WitnetPriceRouter": "0xB4B2E2e00e9d6E5490d55623E4F403EC84c6D33f", - "WitnetRandomness": "", - "WitnetRequestBoard": "0x58D8ECe142c60f5707594a7C1D90e46eAE5AF431", - "WitnetRequestFactory": "", - "WitnetErrorsLib": "", - "WitnetEncodingLib": "", - "WitnetPriceFeedsLib": "", - "WitnetBytecodesImplementation": "", - "WitnetPriceFeedsImplementation": "", - "WitnetRandomnessImplementation": "", - "WitnetRandomnessImplementationV061": "0xeD074DA2A76FD2Ca90C1508930b4FB4420e413B0", - "WitnetRequestBoardImplementation": "", - "WitnetRequestFactoryImplementation": "" - }, - "cube.mainnet": { - "WitnetLib": "0x1D9c4a8f8B7b5F9B8e2641D81927f8F8Cc7fF079", - "WitnetPriceRouter": "0xE22f48DDdcb34BD34489fE224d7fFC1b0a361D87", - "WitnetRandomness": "0xD39D4d972C7E166856c4eb29E54D3548B4597F53", - "WitnetRequestBoard": "0xd653fbd7c736838289262F0F41A458f35393C88a" + "WitnetRequestBoard": "0xd653fbd7c736838289262F0F41A458f35393C88a", + "WitnetErrorsLib": "0xe33bD10fb2f1C5F4c6eF4259aAd4cE8A5868c222", + "WitnetEncodingLib": "0xf56E739C436EA6e65A17DBfaC9D7E57062D19422", + "WitnetBytecodes": "0x4756097b9184327713D07b3ac4C2a898468220B1" } }, "dogechain": { - "dogechain.testnet": { - "WitnetProxy": "0x1b91eAB33362f10A5F803Fe3f0d181F42caFaac3", - "Create2Factory": "0xDe312a6f7fA35320E8DD109c8ea42e82806DC45b", - "WitnetBytecodes": "0x0000000e3a3d22d7510B36BdC88994dab11eadc8", - "WitnetPriceFeeds": "0x9999999d139bdBFbF25923ba39F63bBFc7593400", - "WitnetPriceRouter": "0x9E943Ab1FD0D35B3BaDe31AA78D60C485EA1a604", - "WitnetRandomness": "0x0123456fbBC59E181D76B6Fe8771953d1953B51a", - "WitnetRequestBoard": "0x58D8ECe142c60f5707594a7C1D90e46eAE5AF431", - "WitnetRequestFactory": "0x1111111FDE7dC956E3d7922Bc779D9E2349Afb63", - "WitnetErrorsLib": "0xf6d52770453166de85B6B6260Cf22196bC460E88", - "WitnetEncodingLib": "", - "WitnetPriceFeedsLib": "0x6dc0E2AC80550F901cd4d5F5a4C48333A0ca97Ee", - "WitnetBytecodesImplementation": "", - "WitnetPriceFeedsImplementation": "0xdC101573cB42EB7006Ad6C7E08ce8C91fEAcB62C", - "WitnetRandomnessImplementation": "0x8762508A67e71Df04212B256E19faB1771F9a2F4", - "WitnetRandomnessImplementationV061": "0xD9465D38f50f364b3263Cb219e58d4dB2D584530", - "WitnetRequestBoardImplementation": "0xb6E0e5a64C7c02Fa477A5254dca35ED967570DF5", - "WitnetRequestFactoryImplementation": "0x364E2b91a4C7563288C3ccF7256BA172935CC550" - }, "dogechain.mainnet": { "WitnetLib": "0xD39D4d972C7E166856c4eb29E54D3548B4597F53", "WitnetPriceRouter": "0xD7f7933992c25A504e9Ddf7e76a3c1D6c432b25D", @@ -366,10 +301,11 @@ "WitnetEncodingLib": "0x632147c657743906F332EB05E5C775B738254e1b", "WitnetPriceFeedsLib": "0xC1266fA3D24f5d63E2e34633b3F829E9156be0d6", "WitnetBytecodesImplementation": "0x556eeaf0860De4Acf550Ced5D915a71673042466", - "WitnetPriceFeedsImplementation": "0xdA489690BDfd6e4d76DE3b937f40342bAd281bc9", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0x83587BcfD1f75B5D08c4e27F098F99783cc693cb", "WitnetRandomnessImplementationV079": "0x9597b5708CDB58fF057ca494574951Fc3d9163f7", - "WitnetRequestBoardImplementation": "0xfC62b6B0ec3eCF1Fa031B31b468be51E025a36f1", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0xfC62b6B0ec3eCF1Fa031B31b468be51E025a36f1", "WitnetRequestFactoryImplementation": "0x4779A692aC089E02FD1301B0b53Fa1a02985a83F" }, "elastos.mainnet": { @@ -384,9 +320,10 @@ "WitnetErrorsLib": "0xEb9293996Da011D95720fC791C57CE1647065b44", "WitnetEncodingLib": "0x226633F2b74E043Ef46D22D747005cb616263629", "WitnetBytecodesImplementation": "0x1d0203958ad87A28cecF43614A029adAb6aBf3df", - "WitnetPriceFeedsImplementation": "0x79c27c0555C95DBfd38e97023c3257376aaa154d", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0x92a68143Ee3C2527C2B07e4354efAF89fd75a359", - "WitnetRequestBoardImplementation": "0x88e7Ab71cC18B9f6Fb091fc53Fe3Be467808E0F6", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x88e7Ab71cC18B9f6Fb091fc53Fe3Be467808E0F6", "WitnetRequestFactoryImplementation": "0x7AA219C444f68eDBD5789d89076efA8A3f09996b", "WitnetRequestRandomness": "0x217C32Cf5755aB281809f29F21c107cD0E4652B3", "WitnetPriceFeedsLib": "0x62a1b1D6E5bA031846894FC5C3609f586c78D23D" @@ -405,11 +342,12 @@ "WitnetErrorsLib": "0x123a7AcE0879C4645b19A69c2ba8B3E4d01fBfD6", "WitnetEncodingLib": "0x9bcD148e7933312240959CABA0F3ff943A8116C3", "WitnetPriceFeedsLib": "0xEeA1423D8cAf1e9440495842613Ec042046065aC", - "WitnetBytecodesImplementation": "0xf66DCA7C473707EdFB50eAd488EEc15e882B59cE", + "WitnetBytecodesImplementation": "", "WitnetPriceFeedsImplementation": "0x3280539A77C578C3eF698f53f29CDba00eC9B72E", "WitnetRandomnessImplementation": "0x1e7e21B4b1102cf3b8bD5e110bbBdc80D43A9dEa", "WitnetRandomnessImplementationV079": "0x7A6C2Aad6b4b08De09477D0F663b8f90b0db9662", - "WitnetRequestBoardImplementation": "0xda5223Df6c769B91C50517C9C0b1563F618A89e4", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0xda5223Df6c769B91C50517C9C0b1563F618A89e4", "WitnetRequestFactoryImplementation": "0x83e8f5B6D4D94CAC5943689616B96786c2465c9A" } }, @@ -427,10 +365,11 @@ "WitnetEncodingLib": "0xA9cC3101735b248964e90fA8506219A9CF0b1091", "WitnetPriceFeedsLib": "0x69891cE36F6dFbef4A7BdD0E95A15CBA916f206b", "WitnetBytecodesImplementation": "0x2163DBCBdbBeC066EF8d8Adab75Af8b0B9A5cfAA", - "WitnetPriceFeedsImplementation": "0xd8875D7D3087DEec0103d47d4cE0C4a5414874E1", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0x9597b5708CDB58fF057ca494574951Fc3d9163f7", "WitnetRandomnessImplementationv079": "0x4874cb1732eE1167A006E0Ab047D940ACF04D771", - "WitnetRequestBoardImplementation": "0xF58115533e681295CC1F07A135539E72c5116855", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0xF58115533e681295CC1F07A135539E72c5116855", "WitnetRequestFactoryImplementation": "0x6F68A4d58cEd8e094b42511350527Ed628ACB970" } }, @@ -448,10 +387,11 @@ "WitnetEncodingLib": "0x98DbB216138aA6a0b3ff2ae9bBdeC254398E5B2E", "WitnetPriceFeedsLib": "0xBfFA2ec6225390C517A1bEB83b27a171C6734294", "WitnetBytecodesImplementation": "0x6395d83C9Aa803498980A5ab78217785d4db7bE7", - "WitnetPriceFeedsImplementation": "0x6bF6F65Ad0859e9Ee869DAD252a29c9daAa27449", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0xA9cC3101735b248964e90fA8506219A9CF0b1091", "WitnetRandomnessImplementationV061": "0xeD074DA2A76FD2Ca90C1508930b4FB4420e413B0", - "WitnetRequestBoardImplementation": "0x8684d396366C21AA01B120F69df2070f840aC134", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x8684d396366C21AA01B120F69df2070f840aC134", "WitnetRequestFactoryImplementation": "0x60768ce66aF2f3957e7280c6CfC4ab9c575a7FCF" }, "kava.mainnet": { @@ -467,9 +407,10 @@ "WitnetEncodingLib": "0xc42656C501623859565C6d080a7Feb1f2B72b55a", "WitnetPriceFeedsLib": "0xe33bD10fb2f1C5F4c6eF4259aAd4cE8A5868c222", "WitnetBytecodesImplementation": "0x0fa3a073f48c985151875A0979A7222615F642E4", - "WitnetPriceFeedsImplementation": "0x0Aa147F25CE8BfaA4E6B4B2CCa91f595bD732CD4", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementationV06": "0x1ebd93231a7fe551e1d6405404df34909eff4c2c", - "WitnetRequestBoardImplementation": "0xa239729c399c9eBae7fdc188A1Dbb2c4a06Cd4Bb", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0xa239729c399c9eBae7fdc188A1Dbb2c4a06Cd4Bb", "WitnetRequestFactoryImplementation": "0xF1Aba51c5097487a62DA9c72fb9Aa7B0c98676C1" } }, @@ -487,10 +428,11 @@ "WitnetEncodingLib": "0x71D5D7F2ed2436062946727DB84E44588F765D02", "WitnetPriceFeedsLib": "0x65772461641A4A6E8B10c81bae1a132E04e77262", "WitnetBytecodesImplementation": "0x2Ce7843C1c2fce51DE54a06dB3516103fbde0F6D", - "WitnetPriceFeedsImplementation": "0x4874cb1732eE1167A006E0Ab047D940ACF04D771", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0x98DbB216138aA6a0b3ff2ae9bBdeC254398E5B2E", "WitnetRandomnessImplementationV061": "0x76c72518060952FAec3f90666F047e39E3333f7E", - "WitnetRequestBoardImplementation": "0xeF262eCBF9c61A0e71688D90d8fe75B0C3a48901", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0xeF262eCBF9c61A0e71688D90d8fe75B0C3a48901", "WitnetRequestFactoryImplementation": "0x4374a050f808d1FF18bCcf73270daE3EdF8D0865" }, "kcc.mainnet": { @@ -506,9 +448,10 @@ "WitnetEncodingLib": "0xb99FA0430C73E7B82604Aa99d351d6aFdCe46A16", "WitnetPriceFeedsLib": "0xE8487FDd172D551319A8b030c5c9C7cE5FFb7f5d", "WitnetBytecodesImplementation": "0x6Af31B632A20185ff96FC47a8576a6980Cd99FEC", - "WitnetPriceFeedsImplementation": "0x9890ef27B5d0e5b191ee355013Dd37E221c50A9C", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementationV061": "0x1ebd93231a7fe551e1d6405404df34909eff4c2c", - "WitnetRequestBoardImplementation": "0x62a1b1D6E5bA031846894FC5C3609f586c78D23D", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x62a1b1D6E5bA031846894FC5C3609f586c78D23D", "WitnetRequestFactoryImplementation": "0xc45c93083F7B97Cdb700D4D2ADE6a727E04793ff" } }, @@ -526,10 +469,11 @@ "WitnetEncodingLib": "0x49d3f1C57C320f833FF96bd9786Ae7DB8854B680", "WitnetPriceFeedsLib": "0x65772461641A4A6E8B10c81bae1a132E04e77262", "WitnetBytecodesImplementation": "0x17189FaFd8Dda06ccc2086e12A11693ee552B807", - "WitnetPriceFeedsImplementation": "0xBfFA2ec6225390C517A1bEB83b27a171C6734294", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0xd6d4B24219751A7725ce972E68B1067Ee57CC85a", "WitnetRandomnessImplementationV061": "0xB4B2E2e00e9d6E5490d55623E4F403EC84c6D33f", - "WitnetRequestBoardImplementation": "0x1f35F6d6BE5Bd574b2B00Ac2Dc0BeCAfcc04Ed51", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x1f35F6d6BE5Bd574b2B00Ac2Dc0BeCAfcc04Ed51", "WitnetRequestFactoryImplementation": "0xeDA4f244FEe1D6a3EA0fB2c0Fc6b7D1c49fEF01D" }, "klaytn.mainnet": { @@ -546,7 +490,8 @@ "WitnetPriceFeedsLib": "0xe936a946FA591eCed937996Ef3df5c89d59f4dbb", "WitnetBytecodesImplementation": "0x92a68143Ee3C2527C2B07e4354efAF89fd75a359", "WitnetRandomnessImplementationV061": "0x1ebD93231a7fE551E1d6405404Df34909eff4c2C", - "WitnetRequestBoardImplementation": "0x0Aa147F25CE8BfaA4E6B4B2CCa91f595bD732CD4", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x0Aa147F25CE8BfaA4E6B4B2CCa91f595bD732CD4", "WitnetRequestFactoryImplementation": "0xf56E739C436EA6e65A17DBfaC9D7E57062D19422" } }, @@ -564,9 +509,10 @@ "WitnetRequestBoard": "0x777777772C24e6CD34B464D1d71616C444254537", "WitnetRequestFactory": "0x1111111FDE7dC956E3d7922Bc779D9E2349Afb63", "WitnetBytecodesImplementation": "0x1f35F6d6BE5Bd574b2B00Ac2Dc0BeCAfcc04Ed51", - "WitnetPriceFeedsImplementation": "0xB4f1f8E27799256ec95C5b5A8d2A5722Bd542E69", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0x620e20d91C9b0e11ecAE439E7b85138DA2a1003F", - "WitnetRequestBoardImplementation": "0xAa3BE012baab697c1AEAC34A96bb16aa381FA7F7", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableOvm2": "0xAa3BE012baab697c1AEAC34A96bb16aa381FA7F7", "WitnetRequestFactoryImplementation": "0xb5F3c9Dc6Ca7C1078cE5c51c1cE030D6BEEd57E2" }, "mantle.mainnet": { @@ -582,9 +528,10 @@ "WitnetRequestBoard": "0x777777772C24e6CD34B464D1d71616C444254537", "WitnetRequestFactory": "0x1111111FDE7dC956E3d7922Bc779D9E2349Afb63", "WitnetBytecodesImplementation": "0xE794D90AfaAC834DBaC58A7A283548C09aB266aE", - "WitnetPriceFeedsImplementation": "0x4756097b9184327713D07b3ac4C2a898468220B1", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0x92a68143Ee3C2527C2B07e4354efAF89fd75a359", - "WitnetRequestBoardImplementation": "0x3eA2fa27D997A938925299f91e49215218Ec4f7d", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableOvm2": "0x3eA2fa27D997A938925299f91e49215218Ec4f7d", "WitnetRequestFactoryImplementation": "0xc42656C501623859565C6d080a7Feb1f2B72b55a" } }, @@ -602,10 +549,11 @@ "WitnetEncodingLib": "0x3EE6CbceEa1837737F86ce1D597fDd9390065Bdc", "WitnetPriceFeedsLib": "0xaB7FEec38465EA6E1Cf216E188F3Bd11355824dc", "WitnetBytecodesImplementation": "0x0C53d1765E4E866B468Af8A816eCD051Cf228abb", - "WitnetPriceFeedsImplementation": "0xD62848a74c0d08BA233D625d8691ea5Fee7d7719", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0xde9988f1397C0a7D4887707ec8A2Ea265D4E0572", "WitnetRandomnessImplementationV061": "0xa254632ae454bae18ff0221c2040aa387f044f0e", - "WitnetRequestBoardImplementation": "0x7a624e7742F7A26f7BddDde06Ad7d9e7A6804298", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x7a624e7742F7A26f7BddDde06Ad7d9e7A6804298", "WitnetRequestFactoryImplementation": "0xf1fb7170cB8832213Fb4C506f883bca0a910861D" }, "meter.mainnet": { @@ -621,31 +569,14 @@ "WitnetEncodingLib": "0xADAD6b7e9A1B13b4eca5C629bfdD159B92B82adE", "WitnetPriceFeedsLib": "0x4A4caCaFAA7c9dFF377e784FEA5a02B3F0bb7022", "WitnetBytecodesImplementation": "0xB0032e41bD6628443e81Ac06039104b911ef465c", - "WitnetPriceFeedsImplementation": "0x0ebE395aD5052F6Cea7b7Ee7773Bc95F5086D57c", - "WitnetRequestBoardImplementation": "0xF2699144feE0c2Df40199b4Bc3107f43f95337D8", + "WitnetPriceFeedsImplementation": "", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0xF2699144feE0c2Df40199b4Bc3107f43f95337D8", "WitnetRequestFactoryImplementation": "0xb698F75F432C40eD658ed500FF8feFC2794f5eC5" } }, "metis": { - "metis.goerli": { - "WitnetProxy": "0x1b91eAB33362f10A5F803Fe3f0d181F42caFaac3", - "Create2Factory": "0xDe312a6f7fA35320E8DD109c8ea42e82806DC45b", - "WitnetBytecodes": "0x0000000e3a3d22d7510B36BdC88994dab11eadc8", - "WitnetPriceFeeds": "0x9999999d139bdBFbF25923ba39F63bBFc7593400", - "WitnetPriceRouter": "0xBfFA2ec6225390C517A1bEB83b27a171C6734294", - "WitnetRandomness": "0x0123456fbBC59E181D76B6Fe8771953d1953B51a", - "WitnetRequestBoard": "0x777777772C24e6CD34B464D1d71616C444254537", - "WitnetRequestFactory": "0x1111111FDE7dC956E3d7922Bc779D9E2349Afb63", - "WitnetErrorsLib": "0xc229345B9B95515C69A64842182e37cAdB52A00d", - "WitnetEncodingLib": "0xCFf84e16db3c705aD3C6e96b5575ab9111C874B9", - "WitnetPriceFeedsLib": "0x4a0264714E368A6888c5D755F47Bd924549Fd625", - "WitnetBytecodesImplementation": "0xd3E293c5Be8a742A94F7E3092Ce9F297E651De02", - "WitnetPriceFeedsImplementation": "0x88a456C0Bd557DDA942FBc1DB86C0E35c529A6AE", - "WitnetRandomnessImplementation": "0x4326d5b067EC4Bb5c2F71909E278Def8e4906B19", - "WitnetRandomnessImplementationV079": "0x7A6C2Aad6b4b08De09477D0F663b8f90b0db9662", - "WitnetRequestBoardImplementation": "0x7833F9B08F4236D77ec6287d667F533bc2F1c1EE", - "WitnetRequestFactoryImplementation": "0x07024BBdFbE0b7560A0f5B49745A372e15954d08" - }, + "metis.sepolia": {}, "metis.mainnet": { "WitnetLib": "0x1D9c4a8f8B7b5F9B8e2641D81927f8F8Cc7fF079", "WitnetPriceRouter": "0xD39D4d972C7E166856c4eb29E54D3548B4597F53", @@ -667,10 +598,11 @@ "WitnetEncodingLib": "0xA7952bc98AB11b95aa51E52ae61d017D0F084eB8", "WitnetPriceFeedsLib": "0x6f0da7F65Aaa090C48B371ADEfA1997e4e3cE39a", "WitnetBytecodesImplementation": "0xe145A4D3335D5F78d7e9cB6a3C1832155cB4Be01", - "WitnetPriceFeedsImplementation": "0x2F0912fa566B5B3215e746Dc108d85fDd4A8113A", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0xcf9F6DD90221d5A23a6c4E2252bF690acdf6eedC", "WitnetRandomnessImplementationv079": "0x65772461641A4A6E8B10c81bae1a132E04e77262", - "WitnetRequestBoardImplementation": "0xCA9e7861643febcEa7C657eA8F012645D6acceC4", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0xCA9e7861643febcEa7C657eA8F012645D6acceC4", "WitnetRequestFactoryImplementation": "0x6395d83C9Aa803498980A5ab78217785d4db7bE7" }, "moonbeam.moonriver": { @@ -692,9 +624,10 @@ "WitnetEncodingLib": "0xA99B485363DBAe90D17B10F988C4e1Ae895048e0", "WitnetPriceFeedsLib": "0xE8487FDd172D551319A8b030c5c9C7cE5FFb7f5d", "WitnetBytecodesImplementation": "0xC467B6E0F700D3E044C9F20BB76957eEC0B33c8C", - "WitnetPriceFeedsImplementation": "0x5545EFE72ACfB823d4B7059bB9BfB2CC639759D6", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementationV061": "0x1ebD93231a7fE551E1d6405404Df34909eff4c2C", - "WitnetRequestBoardImplementation": "0x79c27c0555C95DBfd38e97023c3257376aaa154d", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x79c27c0555C95DBfd38e97023c3257376aaa154d", "WitnetRequestFactoryImplementation": "0x760C146699B76c84Cc8050f57728F2Dc374cbf25" } }, @@ -712,10 +645,11 @@ "WitnetEncodingLib": "0xd8875D7D3087DEec0103d47d4cE0C4a5414874E1", "WitnetPriceFeedsLib": "0x6dc0E2AC80550F901cd4d5F5a4C48333A0ca97Ee", "WitnetBytecodesImplementation": "0x12E5FBdaB02cC2336114353CA7BE9e2cc8E4Cc25", - "WitnetPriceFeedsImplementation": "0x7A6C2Aad6b4b08De09477D0F663b8f90b0db9662", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0x078EE90E16e2e5332EDaA87da19d2743cD8C64DD", "WitnetRandomnessImplementationV061": "0xeD074DA2A76FD2Ca90C1508930b4FB4420e413B0", - "WitnetRequestBoardImplementation": "0x20f4B1793bb81FFa357E1705AD954BdC232Edc00", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x20f4B1793bb81FFa357E1705AD954BdC232Edc00", "WitnetRequestFactoryImplementation": "0x364E2b91a4C7563288C3ccF7256BA172935CC550" }, "okx.okxchain.mainnet": { @@ -737,36 +671,49 @@ "WitnetRequestFactory": "0x1111111FDE7dC956E3d7922Bc779D9E2349Afb63", "WitnetRequestBoard": "0x777777772C24e6CD34B464D1d71616C444254537", "WitnetBytecodesImplementation": "0xc71A87657b13A370594967A04b4301a3AcEAF007", - "WitnetPriceFeedsImplementation": "0x7A6C2Aad6b4b08De09477D0F663b8f90b0db9662", - "WitnetRequestBoardImplementation": "0xeDA4f244FEe1D6a3EA0fB2c0Fc6b7D1c49fEF01D", + "WitnetPriceFeedsImplementation": "", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0xeDA4f244FEe1D6a3EA0fB2c0Fc6b7D1c49fEF01D", "WitnetRequestFactoryImplementation": "" } }, "optimism": { - "optimism.goerli": { - "WitnetProxy": "0x1b91eAB33362f10A5F803Fe3f0d181F42caFaac3", + "optimism.sepolia": { "Create2Factory": "0xDe312a6f7fA35320E8DD109c8ea42e82806DC45b", + "WitnetProxy": "0x08a6a53B8bCE95677fFA85813C32Bb8228cd114c", + "WitnetErrorsLib": "0x2Ce7843C1c2fce51DE54a06dB3516103fbde0F6D", + "WitnetEncodingLib": "0x03D884F4fF7f8f78310Df6879eF4031e1229bb07", + "WitnetPriceFeedsLib": "0x0F17043BB821F609670Dbcce36B6F19FD42829B2", "WitnetBytecodes": "0x0000000e3a3d22d7510B36BdC88994dab11eadc8", - "WitnetPriceFeeds": "0x9999999d139bdBFbF25923ba39F63bBFc7593400", - "WitnetPriceRouter": "0xD9465D38f50f364b3263Cb219e58d4dB2D584530", + "WitnetPriceFeeds": "0xf0f823034C1652d96aaFd0b255CCB4b05b8EE7B6", + "WitnetPriceRouter": "0x4326d5b067EC4Bb5c2F71909E278Def8e4906B19", "WitnetRandomness": "0x0123456fbBC59E181D76B6Fe8771953d1953B51a", - "WitnetRequestBoard": "0x0985FDe9f424fe4f5AC516F66bAf5591e18aCBEb", + "WitnetRequestBoard": "0x777777772C24e6CD34B464D1d71616C444254537", "WitnetRequestFactory": "0x1111111FDE7dC956E3d7922Bc779D9E2349Afb63", - "WitnetErrorsLib": "0xf6d52770453166de85B6B6260Cf22196bC460E88", - "WitnetEncodingLib": "", - "WitnetPriceFeedsLib": "0x6dc0E2AC80550F901cd4d5F5a4C48333A0ca97Ee", - "WitnetBytecodesImplementation": "", - "WitnetPriceFeedsImplementation": "0x7A6C2Aad6b4b08De09477D0F663b8f90b0db9662", - "WitnetRandomnessImplementation": "0x12E5FBdaB02cC2336114353CA7BE9e2cc8E4Cc25", - "WitnetRandomnessImplementationV061": "0x9E943Ab1FD0D35B3BaDe31AA78D60C485EA1a604", - "WitnetRequestBoardImplementation": "0xAa3BE012baab697c1AEAC34A96bb16aa381FA7F7", - "WitnetRequestFactoryImplementation": "0x364E2b91a4C7563288C3ccF7256BA172935CC550" + "WitnetBytecodesImplementation": "0x578F143c36654DD361FdD51F6D2693b4621ac455", + "WitnetPriceFeedsImplementation": "0x2f8efDF55330248D072020e112aF622083360814", + "WitnetPriceFeedsUpgradable": "0xA7952bc98AB11b95aa51E52ae61d017D0F084eB8", + "WitnetRandomnessImplementation": "0x606E3E55827f82493D481d3dBC2727298e015879", + "WitnetRequestBoardImplementation": "0x123a7AcE0879C4645b19A69c2ba8B3E4d01fBfD6", + "WitnetRequestBoardTrustableOvm2": "0xDb248F9D510aF57A6f7d009712e45f6cDDEA776d", + "WitnetRequestFactoryImplementation": "0xc228d93908bd3E9E9015f83f125d1514803eDC06" }, "optimism.mainnet": { - "WitnetLib": "0x1D9c4a8f8B7b5F9B8e2641D81927f8F8Cc7fF079", - "WitnetPriceRouter": "0xD39D4d972C7E166856c4eb29E54D3548B4597F53", - "WitnetRandomness": "0x1ebD93231a7fE551E1d6405404Df34909eff4c2C", - "WitnetRequestBoard": "0xd653fbd7c736838289262F0F41A458f35393C88a" + "Create2Factory": "0xDe312a6f7fA35320E8DD109c8ea42e82806DC45b", + "WitnetProxy": "0xF503A52bEcF03d9d5fc85459906a4d280142B1cd", + "WitnetErrorsLib": "0x5832e99368877a63dd1c2cea941C2b43E1F6b16A", + "WitnetEncodingLib": "0xf71a184108Db1B6E7B449B88934F8a757E094353", + "WitnetPriceFeedsLib": "0x7AA219C444f68eDBD5789d89076efA8A3f09996b", + "WitnetBytecodes": "0x0000000e3a3d22d7510B36BdC88994dab11eadc8", + "WitnetPriceFeeds": "0x1111AbA2164AcdC6D291b08DfB374280035E1111", + "WitnetPriceRouter": "0x4326d5b067EC4Bb5c2F71909E278Def8e4906B19", + "WitnetRandomnessV06": "0x1ebD93231a7fE551E1d6405404Df34909eff4c2C", + "WitnetRequestBoard": "0xd653fbd7c736838289262F0F41A458f35393C88a", + "WitnetRequestFactory": "0x1111111FDE7dC956E3d7922Bc779D9E2349Afb63", + "WitnetBytecodesImplementation": "0xc42656C501623859565C6d080a7Feb1f2B72b55a", + "WitnetRequestBoardImplementation": "0xC467B6E0F700D3E044C9F20BB76957eEC0B33c8C", + "WitnetRequestBoardTrustableOvm2": "0xF1Aba51c5097487a62DA9c72fb9Aa7B0c98676C1", + "WitnetRequestFactoryImplementation": "0x0e4F5763f417BB13AF759da4d36af50d13F02730" } }, "polygon": { @@ -786,7 +733,8 @@ "WitnetPriceFeedsImplementation": "0x632147c657743906F332EB05E5C775B738254e1b", "WitnetRandomnessImplementation": "0xD7C67eA4BFB2e85b5a8a07E295c640F2d1811e41", "WitnetRandomnessImplementationv079": "0x24Cc52D0603F161E16c3DB29Da4c2bCc07d17C4b", - "WitnetRequestBoardImplementation": "0x2bD210b8193780A9A74A2864E6Eb007745244092", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x2bD210b8193780A9A74A2864E6Eb007745244092", "WitnetRequestFactoryImplementation": "0x5Acb0fEf96A307660c6B2fBdB271af12Dcdb3E68" }, "polygon.mainnet": { @@ -795,17 +743,18 @@ "WitnetBytecodes": "0x0000000e3a3d22d7510B36BdC88994dab11eadc8", "WitnetPriceFeeds": "0x9999999d139bdBFbF25923ba39F63bBFc7593400", "WitnetPriceRouter": "0x3806311c7138ddF2bAF2C2093ff3633E5A73AbD4", - "WitnetRandomness": "0x0123456fbBC59E181D76B6Fe8771953d1953B51a", + "WitnetRandomness": "0xc8c0d4dB2D7801D6E2A863934597cFD31689f7D5", "WitnetRequestBoard": "0xd653fbd7c736838289262F0F41A458f35393C88a", "WitnetRequestFactory": "0x1111111FDE7dC956E3d7922Bc779D9E2349Afb63", "WitnetErrorsLib": "0x1225A47bC743199dFef9FEEf065b3B76695AaaaC", "WitnetEncodingLib": "0x6c3FD0dD07dd67c4FFfDE297453CB5A4E316f439", "WitnetPriceFeedsLib": "0xa239729c399c9eBae7fdc188A1Dbb2c4a06Cd4Bb", "WitnetBytecodesImplementation": "0x5211De36aC1756742B4520466604bCab34781866", - "WitnetPriceFeedsImplementation": "0xf56E739C436EA6e65A17DBfaC9D7E57062D19422", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0xF1Aba51c5097487a62DA9c72fb9Aa7B0c98676C1", "WitnetRandomnessImplementationv061": "0xc8c0d4dB2D7801D6E2A863934597cFD31689f7D5", - "WitnetRequestBoardImplementation": "0xF395CEeb77cE9cDc44Fd276bE5Ff307B1902D3f7", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0xF395CEeb77cE9cDc44Fd276bE5Ff307B1902D3f7", "WitnetRequestFactoryImplementation": "0xc42656C501623859565C6d080a7Feb1f2B72b55a" }, "polygon.zkevm.goerli": { @@ -822,10 +771,11 @@ "WitnetEncodingLib": "0x6D198FC7F1573E3bf4AEd1f9307fff6b2A05e38e", "WitnetPriceFeedsLib": "0xFB2A291CaE095a63f50846a63aE729506A3D1C40", "WitnetBytecodesImplementation": "0xda5223Df6c769B91C50517C9C0b1563F618A89e4", - "WitnetPriceFeedsImplementation": "0xA14a1fD9b1C6023f87f3A7E97DbdFdf1a9413D0A", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0x89A0EF4eDEEfA128931b353bdf494Bad97a3D448", "WitnetRandomnessImplementationV079": "0x3f189fAc162d3CC6d84EF72c8177afAd8f3DBeE1", - "WitnetRequestBoardImplementation": "0x49030E216d49Fbf443CBe3692De5A6B97AEcFFCA", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x49030E216d49Fbf443CBe3692De5A6B97AEcFFCA", "WitnetRequestFactoryImplementation": "0xB740E58D185558FF4FaaBf430fc87a6801208f38" }, "polygon.zkevm.mainnet": { @@ -848,29 +798,13 @@ } }, "reef": { - "reef.testnet": { - "WitnetProxy": "", - "Create2Factory": "", - "WitnetBytecodes": "", - "WitnetPriceFeeds": "", - "WitnetPriceRouter": "", - "WitnetRandomness": "", - "WitnetRequestBoard": "", - "WitnetRequestFactory": "", - "WitnetRequestRandomness": "", - "WitnetErrorsLib": "", - "WitnetEncodingLib": "", - "WitnetBytecodesImplementation": "", - "WitnetPriceFeedsImplementation": "", - "WitnetRandomnessImplementation": "", - "WitnetRequestBoardImplementation": "", - "WitnetRequestFactoryImplementation": "" - }, "reef.mainnet": { "WitnetParserLib": "0xD3e5A6F4653C5D596d16c947cfA30973C5aa9f34", "WitnetPriceRouter": "0xa22AbF47Fd1eDDf7C0967C9d7fF06FB3c42B26E2", "WitnetRandomness": "0x03e82c280ae03af908edb250d3d187db0018e501", - "WitnetRequestBoard": "0x61E11e5f496936Ef7f9600f6D1E81b1E7c12b172" + "WitnetRequestBoard": "0x61E11e5f496936Ef7f9600f6D1E81b1E7c12b172", + "WitnetOracleV20": "", + "WitnetPriceFeedsV20": "" } }, "scroll": { @@ -887,9 +821,10 @@ "WitnetEncodingLib": "0xB5447342cA17A40e59d410b340ba412E22e36201", "WitnetPriceFeedsLib": "0xBfFA2ec6225390C517A1bEB83b27a171C6734294", "WitnetBytecodesImplementation": "0x705E076F3387cFd59708D8D8508CECe3e1C65C87", - "WitnetPriceFeedsImplementation": "0x6bF6F65Ad0859e9Ee869DAD252a29c9daAa27449", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0x7A6C2Aad6b4b08De09477D0F663b8f90b0db9662", - "WitnetRequestBoardImplementation": "0x60768ce66aF2f3957e7280c6CfC4ab9c575a7FCF", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x60768ce66aF2f3957e7280c6CfC4ab9c575a7FCF", "WitnetRequestFactoryImplementation": "0x4374a050f808d1FF18bCcf73270daE3EdF8D0865" }, "scroll.mainnet": { @@ -905,30 +840,14 @@ "WitnetEncodingLib": "0x30e7D86b3DcdC0CC90509b1F7C27eA8e5481FAc5", "WitnetPriceFeedsLib": "0xe33bD10fb2f1C5F4c6eF4259aAd4cE8A5868c222", "WitnetBytecodesImplementation": "0x5832e99368877a63dd1c2cea941C2b43E1F6b16A", - "WitnetPriceFeedsImplementation": "0x4756097b9184327713D07b3ac4C2a898468220B1", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0x92a68143Ee3C2527C2B07e4354efAF89fd75a359", - "WitnetRequestBoardImplementation": "0x0e4F5763f417BB13AF759da4d36af50d13F02730", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x0e4F5763f417BB13AF759da4d36af50d13F02730", "WitnetRequestFactoryImplementation": "0xc42656C501623859565C6d080a7Feb1f2B72b55a" } }, "syscoin": { - "syscoin.testnet": { - "WitnetProxy": "", - "Create2Factory": "", - "WitnetBytecodes": "", - "WitnetPriceFeeds": "", - "WitnetPriceRouter": "0x9E943Ab1FD0D35B3BaDe31AA78D60C485EA1a604", - "WitnetRandomness": "0x56834Ff8D4b27db647Da97CA3bd8540f7fA0e89D", - "WitnetRequestBoard": "0x58D8ECe142c60f5707594a7C1D90e46eAE5AF431", - "WitnetRequestFactory": "", - "WitnetErrorsLib": "", - "WitnetEncodingLib": "", - "WitnetPriceFeedsLib": "", - "WitnetBytecodesImplementation": "", - "WitnetPriceFeedsImplementation": "", - "WitnetRequestBoardImplementation": "", - "WitnetRequestFactoryImplementation": "" - }, "syscoin.mainnet": { "WitnetLib": "0x1D9c4a8f8B7b5F9B8e2641D81927f8F8Cc7fF079", "WitnetPriceRouter": "0xE22f48DDdcb34BD34489fE224d7fFC1b0a361D87", @@ -939,7 +858,7 @@ "WitnetProxy": "0x60768ce66aF2f3957e7280c6CfC4ab9c575a7FCF", "Create2Factory": "0xDe312a6f7fA35320E8DD109c8ea42e82806DC45b", "WitnetErrorsLib": "0x1b91eAB33362f10A5F803Fe3f0d181F42caFaac3", - "WitnetEncodingLib": "", + "WitnetEncodingLib": "0x9F026F081b5E1f60d583CE380f30A0a4eF0AB97a", "WitnetPriceFeedsLib": "0xBfFA2ec6225390C517A1bEB83b27a171C6734294", "WitnetBytecodes": "0x0000000e3a3d22d7510B36BdC88994dab11eadc8", "WitnetPriceFeeds": "0x9999999d139bdBFbF25923ba39F63bBFc7593400", @@ -947,30 +866,14 @@ "WitnetRandomness": "0x0123456fbBC59E181D76B6Fe8771953d1953B51a", "WitnetRequestBoard": "0x777777772C24e6CD34B464D1d71616C444254537", "WitnetRequestFactory": "0x1111111FDE7dC956E3d7922Bc779D9E2349Afb63", - "WitnetBytecodesImplementation": "", - "WitnetPriceFeedsImplementation": "0xdC101573cB42EB7006Ad6C7E08ce8C91fEAcB62C", + "WitnetBytecodesImplementation": "0x7538f6Bff94B0F7F0A0802376238Aab0D2528521", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0x6dc0E2AC80550F901cd4d5F5a4C48333A0ca97Ee", - "WitnetRequestBoardImplementation": "0x9f9bAB64229680E170835BC9cC1c96F2C63f7d16", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x9f9bAB64229680E170835BC9cC1c96F2C63f7d16", "WitnetRequestFactoryImplementation": "0x4743325168af9195Aa5b25e491E9bE87d87E7F93" } }, - "ten": { - "ten.testnet": { - "Create2Factory": "0xDe312a6f7fA35320E8DD109c8ea42e82806DC45b", - "WitnetBytecodes": "0x0000000e3a3d22d7510B36BdC88994dab11eadc8", - "WitnetPriceFeeds": "0x9999999d139bdBFbF25923ba39F63bBFc7593400", - "WitnetPriceRouter": "0xE490b89AfADE571d8Afa158446C603D530608ceA", - "WitnetRequestBoard": "0x777777772C24e6CD34B464D1d71616C444254537", - "WitnetRequestFactory": "0x1111111FDE7dC956E3d7922Bc779D9E2349Afb63", - "WitnetErrorsLib": "0x6bF6F65Ad0859e9Ee869DAD252a29c9daAa27449", - "WitnetEncodingLib": "0xB4f1f8E27799256ec95C5b5A8d2A5722Bd542E69", - "WitnetPriceFeedsLib": "0x9597b5708CDB58fF057ca494574951Fc3d9163f7", - "WitnetBytecodesImplementation": "0xdC101573cB42EB7006Ad6C7E08ce8C91fEAcB62C", - "WitnetPriceFeedsImplementation": "0x8684d396366C21AA01B120F69df2070f840aC134", - "WitnetRequestBoardImplementation": "0xA9cC3101735b248964e90fA8506219A9CF0b1091", - "WitnetRequestFactoryImplementation": "0xF58115533e681295CC1F07A135539E72c5116855" - } - }, "ultron": { "ultron.testnet": { "WitnetProxy": "0x4374a050f808d1FF18bCcf73270daE3EdF8D0865", @@ -985,10 +888,11 @@ "WitnetEncodingLib": "0xA14a1fD9b1C6023f87f3A7E97DbdFdf1a9413D0A", "WitnetPriceFeedsLib": "0x9f9bAB64229680E170835BC9cC1c96F2C63f7d16", "WitnetBytecodesImplementation": "0xcf9F6DD90221d5A23a6c4E2252bF690acdf6eedC", - "WitnetPriceFeedsImplementation": "0x50AA08187D2F648Dd428784AF6489c3F12e942CC", + "WitnetPriceFeedsImplementation": "", "WitnetRandomnessImplementation": "0x07024BBdFbE0b7560A0f5B49745A372e15954d08", "WitnetRandomnessImplementationV061": "0xeD074DA2A76FD2Ca90C1508930b4FB4420e413B0", - "WitnetRequestBoardImplementation": "0x88a456C0Bd557DDA942FBc1DB86C0E35c529A6AE", + "WitnetRequestBoardImplementation": "", + "WitnetRequestBoardTrustableDefault": "0x88a456C0Bd557DDA942FBc1DB86C0E35c529A6AE", "WitnetRequestFactoryImplementation": "0x4874cb1732eE1167A006E0Ab047D940ACF04D771" }, "ultron.mainnet": { diff --git a/migrations/witnet.settings.js b/migrations/witnet.settings.js index 1f73fa444..40828a3dd 100644 --- a/migrations/witnet.settings.js +++ b/migrations/witnet.settings.js @@ -2,13 +2,13 @@ module.exports = { artifacts: { default: { WitnetBytecodes: "WitnetBytecodesDefault", - WitnetPriceFeeds: "WitnetPriceFeedsUpgradable", + WitnetPriceFeeds: "WitnetPriceFeedsBypassV20:", WitnetRandomness: "WitnetRandomnessProxiable", - WitnetRequestBoard: "WitnetRequestBoardTrustableDefault", + WitnetRequestBoard: "WitnetRequestBoardBypassV20:WitnetRequestBoardTrustableDefault", WitnetRequestFactory: "WitnetRequestFactoryDefault", }, boba: { - WitnetRequestBoard: "WitnetRequestBoardTrustableOvm2", + WitnetRequestBoard: "WitnetRequestBoardBypassV20:WitnetRequestBoardTrustableOvm2", }, conflux: { WitnetRequestFactory: "WitnetRequestFactoryCfxCore", @@ -20,7 +20,7 @@ module.exports = { WitnetBytecodes: "WitnetBytecodesNoSha256", }, optimism: { - WitnetRequestBoard: "WitnetRequestBoardTrustableOvm2", + WitnetRequestBoard: "WitnetRequestBoardBypassV20:WitnetRequestBoardTrustableOvm2", }, "polygon.zkevm.goerli": { WitnetBytecodes: "WitnetBytecodesNoSha256", @@ -29,17 +29,14 @@ module.exports = { WitnetBytecodes: "WitnetBytecodesNoSha256", }, reef: { - WitnetRequestBoard: "WitnetRequestBoardTrustableReef", + WitnetRequestBoard: "WitnetRequestBoardBypassV20:WitnetRequestBoardTrustableReef", }, scroll: { WitnetBytecodes: "WitnetBytecodesNoSha256", }, "syscoin.rollux.testnet": { - WitnetRequestBoard: "WitnetRequestBoardTrustableOvm2", - }, - ten: { - WitnetRequestBoard: "WitnetRequestBoardTrustableObscuro", - }, + WitnetRequestBoard: "WitnetRequestBoardBypassV20:WitnetRequestBoardTrustableOvm2", + } }, compilers: { default: { @@ -312,7 +309,7 @@ module.exports = { host: "localhost", port: 8540, network_id: 1, - gasPrice: 10, + gasPrice: 10 ** 9, skipDryRun: true, }, "conflux.core.mainnet": { @@ -640,11 +637,26 @@ module.exports = { explorerUrl: "https://optimism-goerli.blockscout.com/", }, }, + "optimism.sepolia": { + host: "localhost", + port: 8503, + network_id: 11155420, + verify: { + apiKey: process.env.ETHERSCAN_OPTIMISM_API_KEY, + apiUrl: "https://api-sepolia-optimistic.etherscan.io/api", + explorerUrl: "https://sepolia-optimism.etherscan.io/address", + }, + }, "optimism.mainnet": { host: "localhost", port: 9520, network_id: 10, skipDryRun: true, + verify: { + apiKey: process.env.ETHERSCAN_OPTIMISM_API_KEY, + apiUrl: "https://api-optimistic.etherscan.io/api", + explorerUrl: "https://optimistic.etherscan.io", + }, }, }, polygon: { diff --git a/package.json b/package.json index 51a67e72c..20abb857c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "witnet-solidity-bridge", - "version": "0.7.17", + "version": "0.7.18", "description": "Witnet Solidity Bridge contracts for EVM-compatible chains", "main": "", "scripts": { diff --git a/test/TestWitnetEncodingLib.sol b/test/TestWitnetEncodingLib.sol index ba2db8d31..64628a4ab 100644 --- a/test/TestWitnetEncodingLib.sol +++ b/test/TestWitnetEncodingLib.sol @@ -42,18 +42,18 @@ contract TestWitnetEncodingLib { function testEncodeRadonReducerOpcodes() external { bytes memory bytecode = WitnetEncodingLib.encode( - WitnetV2.RadonReducerOpcodes.StandardDeviation + Witnet.RadonReducerOpcodes.StandardDeviation ); Assert.equal( keccak256(bytecode), keccak256(hex"1007"), - "bad encode(WitnetV2.RadonReducerOpcodes)" + "bad encode(Witnet.RadonReducerOpcodes)" ); } function testEncodeRadonSLA() external { bytes memory bytecode = WitnetEncodingLib.encode( - WitnetV2.RadonSLA({ + Witnet.RadonSLA({ numWitnesses: 10, minConsensusPercentage: 51, minerCommitRevealFee: 1000000, @@ -65,28 +65,28 @@ contract TestWitnetEncodingLib { Assert.equal( keccak256(bytecode), keccak256(hex"10c0843d180a20c0843d283330c096b102"), - "bad encode(WitnetV2.RadonSLA)" + "bad encode(Witnet.RadonSLA)" ); } function testEncodeRadonReducer1Filter() external { - WitnetV2.RadonReducer memory reducer; - reducer.opcode = WitnetV2.RadonReducerOpcodes.Mode; - reducer.filters = new WitnetV2.RadonFilter[](1); - reducer.filters[0].opcode = WitnetV2.RadonFilterOpcodes.StandardDeviation; + Witnet.RadonReducer memory reducer; + reducer.opcode = Witnet.RadonReducerOpcodes.Mode; + reducer.filters = new Witnet.RadonFilter[](1); + reducer.filters[0].opcode = Witnet.RadonFilterOpcodes.StandardDeviation; reducer.filters[0].args = hex"fa40200000"; bytes memory bytecode = WitnetEncodingLib.encode(reducer); // emit Log(bytecode); Assert.equal( keccak256(bytecode), keccak256(hex"0a0908051205fa402000001002"), - "bad encode(WitnetV2.RadonReducer)" + "bad encode(Witnet.RadonReducer)" ); } function testEncodeRadonRetrievalUrlOnly() external { - WitnetV2.RadonRetrieval memory source; - source.method = WitnetV2.DataRequestMethods.HttpGet; + Witnet.RadonRetrieval memory source; + source.method = Witnet.RadonDataRequestMethods.HttpGet; source.url = "https://data.messar.io/api/v1/assets/\\0\\/metrics/market-data?fields=market_data/price_\\1\\"; source.script = hex"861877821866646461746182186664706f6f6c8218646b746f6b656e3150726963658218571a000f4240185b"; bytes memory bytecode = WitnetEncodingLib.encode(source); @@ -94,13 +94,13 @@ contract TestWitnetEncodingLib { Assert.equal( keccak256(bytecode), keccak256(hex"128b010801125968747470733a2f2f646174612e6d65737361722e696f2f6170692f76312f6173736574732f5c305c2f6d6574726963732f6d61726b65742d646174613f6669656c64733d6d61726b65745f646174612f70726963655f5c315c1a2c861877821866646461746182186664706f6f6c8218646b746f6b656e3150726963658218571a000f4240185b"), - "bad encode(WitnetV2.RadonRetrieval)" + "bad encode(Witnet.RadonRetrieval)" ); } function testEncodeRadonRetrievalUrlBodyHeaders() external { - WitnetV2.RadonRetrieval memory source; - source.method = WitnetV2.DataRequestMethods.HttpPost; + Witnet.RadonRetrieval memory source; + source.method = Witnet.RadonDataRequestMethods.HttpPost; source.url = "https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3"; source.body = "{\"query\":\"{pool(id:\\\"0xc2a856c3aff2110c1171b8f942256d40e980c726\\\"){token1Price}}\"}"; source.headers = new string[2][](2); @@ -113,7 +113,7 @@ contract TestWitnetEncodingLib { keccak256(bytecode), keccak256( hex"1285020803123a68747470733a2f2f6170692e74686567726170682e636f6d2f7375626772617068732f6e616d652f756e69737761702f756e69737761702d76331a2c861877821866646461746182186664706f6f6c8218646b746f6b656e3150726963658218571a000f4240185b22527b227175657279223a227b706f6f6c2869643a5c223078633261383536633361666632313130633131373162386639343232353664343065393830633732365c22297b746f6b656e3150726963657d7d227d2a190a0a757365722d6167656e74120b7769746e65742d727573742a280a0c636f6e74656e742d747970651218746578742f68746d6c3b20636861727365743d7574662d38"), - "bad encode(WitnetV2.RadonRetrieval)" + "bad encode(Witnet.RadonRetrieval)" ); } @@ -134,7 +134,7 @@ contract TestWitnetEncodingLib { function testVerifyRadonScriptOk1() external { Assert.equal( uint(WitnetEncodingLib.verifyRadonScriptResultDataType(hex"861877821866646461746182186664706f6f6c8218646b746f6b656e3150726963658218571a000f4240185b")), - uint(WitnetV2.RadonDataTypes.Integer), + uint(Witnet.RadonDataTypes.Integer), "unexpected result data type" ); } @@ -142,7 +142,7 @@ contract TestWitnetEncodingLib { function testVerifyRadonScriptOk2() external { Assert.equal( uint(WitnetEncodingLib.verifyRadonScriptResultDataType(hex"80")), - uint(WitnetV2.RadonDataTypes.Any), + uint(Witnet.RadonDataTypes.Any), "unexpected result data type" ); } @@ -150,7 +150,7 @@ contract TestWitnetEncodingLib { function testVerifyRadonScriptOk3() external { Assert.equal( uint(WitnetEncodingLib.verifyRadonScriptResultDataType(hex"8218778218676445746167")), - uint(WitnetV2.RadonDataTypes.String), + uint(Witnet.RadonDataTypes.String), "unexpected result data type" ); } @@ -158,7 +158,7 @@ contract TestWitnetEncodingLib { function testVerifyRadonScriptOk4() external { Assert.equal( uint(WitnetEncodingLib.verifyRadonScriptResultDataType(hex"880B821866646461746182186165706169727382118282186762696483187582635C305CF5F4821818F48218646D746F6B656E5C315C50726963658218571A000F4240185B")), - uint(WitnetV2.RadonDataTypes.Integer), + uint(Witnet.RadonDataTypes.Integer), "unexpected result data type" ); } @@ -166,7 +166,7 @@ contract TestWitnetEncodingLib { function testVerifyRadonScriptOk5() external { Assert.equal( uint(WitnetEncodingLib.verifyRadonScriptResultDataType(hex"851876821182821867657469746c65831875a1635c315cf5f4821183821867696d65726765645f617418748218430082181800821867657374617465")), - uint(WitnetV2.RadonDataTypes.String), + uint(Witnet.RadonDataTypes.String), "unexpected result data type" ); } diff --git a/test/TestWitnetErrorsLib.sol b/test/TestWitnetErrorsLib.sol index 486e112d7..aecefc513 100644 --- a/test/TestWitnetErrorsLib.sol +++ b/test/TestWitnetErrorsLib.sol @@ -70,28 +70,28 @@ contract TestWitnetErrorsLib { ); Assert.equal( uint(error0x30.code), - uint(Witnet.ResultErrorCodes.HTTP), - "error code `0x30` should be `Witnet.ResultErrorCodes.HTTP`" + uint(Witnet.ResultErrorCodes.HttpErrors), + "error code `0x30` should be `Witnet.ResultErrorCodes.HttpErrors`" ); Assert.equal( uint(error0x31.code), - uint(Witnet.ResultErrorCodes.RetrievalTimeout), - "Error code 0x31 should be `Witnet.ResultErrorCodes.RetrievalTimeout`" + uint(Witnet.ResultErrorCodes.RetrievalsTimeout), + "Error code 0x31 should be `Witnet.ResultErrorCodes.RetrievalsTimeout`" ); Assert.equal( uint(error0x40.code), - uint(Witnet.ResultErrorCodes.Underflow), - "error code `0x40` should be `Witnet.ResultErrorCodes.Underflow`" + uint(Witnet.ResultErrorCodes.MathUnderflow), + "error code `0x40` should be `Witnet.ResultErrorCodes.MathUnderflow`" ); Assert.equal( uint(error0x41.code), - uint(Witnet.ResultErrorCodes.Overflow), - "error code `0x41` should be `Witnet.ResultErrorCodes.Overflow`" + uint(Witnet.ResultErrorCodes.MathOverflow), + "error code `0x41` should be `Witnet.ResultErrorCodes.MathOverflow`" ); Assert.equal( uint(error0x42.code), - uint(Witnet.ResultErrorCodes.DivisionByZero), - "Error code #0x42 should be `Witnet.ResultErrorCodes.DivisionByZero`" + uint(Witnet.ResultErrorCodes.MathDivisionByZero), + "Error code #0x42 should be `Witnet.ResultErrorCodes.MathDivisionByZero`" ); } @@ -109,13 +109,13 @@ contract TestWitnetErrorsLib { Witnet.ResultError memory error0xff = WitnetErrorsLib.resultErrorFromCborBytes(hex"D8278118FF"); Assert.equal( uint(error0x50.code), - uint(Witnet.ResultErrorCodes.NoReveals), - "Error code #0x50 should be `Witnet.ResultErrorCodes.NoReveals`" + uint(Witnet.ResultErrorCodes.InsufficientReveals), + "Error code #0x50 should be `Witnet.ResultErrorCodes.InsufficientReveals`" ); Assert.equal( uint(error0x51.code), - uint(Witnet.ResultErrorCodes.InsufficientConsensus), - "Error code #0x51 should be `Witnet.ResultErrorCodes.InsufficientConsensus`" + uint(Witnet.ResultErrorCodes.InsufficientMajority), + "Error code #0x51 should be `Witnet.ResultErrorCodes.InsufficientMajority`" ); Assert.equal( uint(error0x52.code), @@ -129,8 +129,8 @@ contract TestWitnetErrorsLib { ); Assert.equal( uint(error0x60.code), - uint(Witnet.ResultErrorCodes.MalformedReveal), - "Error code #0x60 should be `Witnet.ResultErrorCodes.MalformedReveal`" + uint(Witnet.ResultErrorCodes.MalformedReveals), + "Error code #0x60 should be `Witnet.ResultErrorCodes.MalformedReveals`" ); Assert.equal( uint(error0x70.code), @@ -144,8 +144,8 @@ contract TestWitnetErrorsLib { ); Assert.equal( uint(error0xe0.code), - uint(Witnet.ResultErrorCodes.BridgeMalformedRequest), - "Error code #0xE0 should be `Witnet.ResultErrorCodes.BridgeMalformedRequest`" + uint(Witnet.ResultErrorCodes.BridgeMalformedDataRequest), + "Error code #0xE0 should be `Witnet.ResultErrorCodes.BridgeMalformedDataRequest`" ); Assert.equal( uint(error0xe1.code), @@ -154,8 +154,8 @@ contract TestWitnetErrorsLib { ); Assert.equal( uint(error0xe2.code), - uint(Witnet.ResultErrorCodes.BridgeOversizedResult), - "Error code #0xE2 should be `Witnet.ResultErrorCodes.BridgeOversizedResult`" + uint(Witnet.ResultErrorCodes.BridgeOversizedTallyResult), + "Error code #0xE2 should be `Witnet.ResultErrorCodes.BridgeOversizedTallyResult`" ); Assert.equal( uint(error0xff.code), @@ -222,27 +222,27 @@ contract TestWitnetErrorsLib { Assert.equal( error0x30.reason, "Witnet: Retrieval: HTTP/404 error.", - "Error message for error code `0x30` (`Witnet.ResultErrorCodes.HTTP`) should be properly formatted" + "Error message for error code `0x30` (`Witnet.ResultErrorCodes.HttpErrors`) should be properly formatted" ); Assert.equal( error0x31.reason, "Witnet: Retrieval: timeout.", - "Error message for error code `0x31` (`Witnet.ResultErrorCodes.RetrievalTimeout`) should be properly formatted" + "Error message for error code `0x31` (`Witnet.ResultErrorCodes.RetrievalsTimeout`) should be properly formatted" ); Assert.equal( error0x40.reason, "Witnet: Aggregation: math underflow.", - "Error message for error code `0x40` (`Witnet.ResultErrorCodes.Underflow`) should be properly formatted" + "Error message for error code `0x40` (`Witnet.ResultErrorCodes.MathUnderflow`) should be properly formatted" ); Assert.equal( error0x41.reason, "Witnet: Aggregation: math overflow.", - "Error message for error code `0x41` (`Witnet.ResultErrorCodes.Overflow`) should be properly formatted" + "Error message for error code `0x41` (`Witnet.ResultErrorCodes.MathOverflow`) should be properly formatted" ); Assert.equal( error0x42.reason, "Witnet: Aggregation: division by zero.", - "Error message for e rror code `0x42` (`Witnet.ResultErrorCodes.DivisionByZero`) should be properly formatted" + "Error message for e rror code `0x42` (`Witnet.ResultErrorCodes.MathDivisionByZero`) should be properly formatted" ); } @@ -278,17 +278,17 @@ contract TestWitnetErrorsLib { Assert.equal( error0x50.reason, "Witnet: Tally: no reveals.", - "Error message for error code `0x50` (`Witnet.ResultErrorCodes.NoReveals`) should be properly formatted" + "Error message for error code `0x50` (`Witnet.ResultErrorCodes.InsufficientReveals`) should be properly formatted" ); Assert.equal( error0x51.reason, "Witnet: Tally: insufficient consensus: 3% <= 51%.", - "Error message for error code `0x51` (`Witnet.ResultErrorCodes.InsufficientConsensus`) should be properly formatted" + "Error message for error code `0x51` (`Witnet.ResultErrorCodes.InsufficientMajority`) should be properly formatted" ); Assert.equal( error0x51b.reason, "Witnet: Tally: insufficient consensus: 49% <= 51%.", - "Error message for error code `0x51` (`Witnet.ResultErrorCodes.InsufficientConsensus`) should be properly formatted" + "Error message for error code `0x51` (`Witnet.ResultErrorCodes.InsufficientMajority`) should be properly formatted" ); Assert.equal( error0x52.reason, @@ -298,7 +298,7 @@ contract TestWitnetErrorsLib { Assert.equal( error0x60.reason, "Witnet: Tally: malformed reveal.", - "Error message for error code `0x60` (`Witnet.ResultErrorCodes.MalformedReveal`) should be properly formatted" + "Error message for error code `0x60` (`Witnet.ResultErrorCodes.MalformedReveals`) should be properly formatted" ); Assert.equal( error0xff.reason, diff --git a/test/helpers/UsingWitnetTestHelper.sol b/test/helpers/UsingWitnetTestHelper.sol deleted file mode 100644 index f5c2429e7..000000000 --- a/test/helpers/UsingWitnetTestHelper.sol +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.7.0 <0.9.0; -pragma experimental ABIEncoderV2; - -import "../../contracts/UsingWitnet.sol"; - -/** - * @title Test Helper for the UsingWitnet contract - * @dev The aim of this contract is: - * 1. Raise the visibility modifier of UsingWitnet contract functions for testing purposes - * @author Witnet Foundation - */ -contract UsingWitnetTestHelper is UsingWitnet { - - Witnet.Result public result; - - constructor (WitnetRequestBoard _wrb) - UsingWitnet(_wrb) - {} - - receive() external payable {} - - function witnetPostRequest(IWitnetRequest _request) - external payable - returns(uint256 _id) - { - uint256 _reward; - (_id, _reward) = _witnetPostRequest(_request); - if (_reward < msg.value) { - payable(msg.sender).transfer(msg.value - _reward); - } - } - - function witnetUpgradeReward(uint256 _id) - external payable - { - uint256 _value = msg.value; - uint256 _used = _witnetUpgradeReward(_id); - if (_used < _value) { - payable(msg.sender).transfer(_value - _used); - } - } - - function witnetReadResult(uint256 _requestId) - external - returns (Witnet.Result memory) - { - result = _witnetReadResult(_requestId); - return result; - } - - function witnetCurrentReward(uint256 _requestId) - external view - returns (uint256) - { - return witnet.readRequestReward(_requestId); - } - - function witnetEstimateReward(uint256 _gasPrice) external view returns (uint256) { - return witnet.estimateReward(_gasPrice); - } - - function witnetAsUint64() external view returns (uint) { - return witnet.asUint64(result); - } - - function witnetCheckRequestResolved(uint256 _id) external view returns (bool) { - return _witnetCheckResultAvailability(_id); - } -} diff --git a/test/helpers/WitnetRequestBoardTestHelper.sol b/test/helpers/WitnetRequestBoardTestHelper.sol deleted file mode 100644 index ec3b05537..000000000 --- a/test/helpers/WitnetRequestBoardTestHelper.sol +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.7.0 <0.9.0; -pragma experimental ABIEncoderV2; - -import "../../contracts/impls/boards/trustable/WitnetRequestBoardTrustableDefault.sol"; - -/** - * @title Witnet Requests Board Version 1 - * @notice Contract to bridge requests to Witnet - * @dev This contract enables posting requests that Witnet bridges will insert into the Witnet network - * The result of the requests will be posted back to this contract by the bridge nodes too. - * The contract has been created for testing purposes - * @author Witnet Foundation - */ -contract WitnetRequestBoardTestHelper - is - WitnetRequestBoardTrustableDefault -{ - address public witnet; - - constructor (address[] memory _committee, bool _upgradable) - WitnetRequestBoardTrustableDefault(_upgradable, "WitnetRequestBoardTestHelper", 120547) - { - witnet = msg.sender; - setReporters(_committee); - } - - /// @dev Estimate the amount of reward we need to insert for a given gas price. - /// @return The rewards to be included for the given gas price as inclusionReward, resultReward, blockReward. - function estimateReward(uint256) - public pure - override - returns(uint256) - { - return 0; - } - - /// @dev Posts a data request into the WRB, with immediate mock result. - /// @param _request The contract containing the Witnet Witnet data request actual bytecode. - /// @return _id The unique identifier of the data request. - function postRequest(IWitnetRequest _request) - public payable - override - returns(uint256 _id) - { - _id = super.postRequest(_request); - __storage().queries[_id].response.drTxHash = keccak256("hello"); - __storage().queries[_id].response.cborBytes = "hello"; - } -} diff --git a/test/helpers/WitnetRequestTestHelper.sol b/test/helpers/WitnetRequestTestHelper.sol deleted file mode 100644 index 66daf60ee..000000000 --- a/test/helpers/WitnetRequestTestHelper.sol +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.7.0 <0.9.0; -import "../../contracts/libs/Witnet.sol"; - -/** - * @title The serialized form of a Witnet data request - */ -contract WitnetRequestTestHelper is IWitnetRequest { - - using Witnet for bytes; - - constructor(bytes memory _bytecode) { - bytecode = _bytecode; - } - - /// Contains a well-formed Witnet Data Request, encoded using Protocol Buffers. - bytes public override bytecode; - - /// Applies Witnet-compatible hash function over the `bytecode()` in order to - /// uniquely identify every possible well-formed Data Request. - function hash() public view override returns (bytes32) { - return bytecode.hash(); - } - - /// Modifies the Witnet Data Request bytecode. - function modifyBytecode(bytes memory _bytecode) public { - bytecode = _bytecode; - } -} diff --git a/test/using_witnet.test.js b/test/using_witnet.test.js deleted file mode 100644 index 24474478f..000000000 --- a/test/using_witnet.test.js +++ /dev/null @@ -1,293 +0,0 @@ -const settings = require("../migrations/witnet.settings") - -const { expectRevert } = require("@openzeppelin/test-helpers") - -const WRB = artifacts.require(settings.artifacts.default.WitnetRequestBoard) -const WRBProxy = artifacts.require(settings.artifacts.default.WitnetProxy) -const WitnetLib = artifacts.require(settings.artifacts.default.WitnetLib) - -const UsingWitnetTestHelper = artifacts.require("UsingWitnetTestHelper") -const WitnetRequest = artifacts.require("WitnetRequestTestHelper") - -const truffleAssert = require("truffle-assertions") - -contract("UsingWitnet", accounts => { - describe("UsingWitnet \"happy path\" test case. " + - "This covers pretty much all the life cycle of a Witnet request:", () => { - const requestHex = "0x01" - const resultHex = "0x1a002fefd8" - const resultDecimal = 3141592 - const drTxHash = "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" - - let witnet, clientContract, wrb, proxy, request, requestId, result - let lastAccount1Balance, lastReward - - const ownerAccount = accounts[0] - const reporterAccount = accounts[1] - - before(async () => { - witnet = await WitnetLib.deployed() - await WRB.link(WitnetLib, witnet.address) - if (!proxy) { - // create one and only proxy contract: - proxy = await WRBProxy.new({ from: ownerAccount }) - // let 'wrb' artifact always point to proxy address - wrb = await WRB.at(proxy.address) - } - // notwithstanding, upgrade proxy on each iteration... - await proxy.upgradeTo( - // ...to new implementation instance: - (await WRB.new( - ...settings.constructorParams.default.WitnetRequestBoard, - { from: ownerAccount } - ) - ).address, - // ...resetting reporters ACL: - web3.eth.abi.encodeParameter("address[]", [reporterAccount]), - // ...from owner account. - { from: ownerAccount } - ) - await UsingWitnetTestHelper.link(WitnetLib, witnet.address) - clientContract = await UsingWitnetTestHelper.new(proxy.address) - lastAccount1Balance = await web3.eth.getBalance(accounts[1]) - }) - - it("should create a data request", async () => { - request = await WitnetRequest.new(requestHex) - const internalBytes = await request.bytecode() - assert.equal(internalBytes, requestHex) - }) - - it("should post a data request into the wrb", async () => { - const gasPrice = 1e9 - lastReward = await clientContract.witnetEstimateReward(gasPrice) - requestId = await returnData(clientContract.witnetPostRequest( - request.address, - { - from: accounts[1], - value: lastReward * 2, - gasPrice, - } - )) - assert.equal(requestId, 1) - }) - - it("should have posted and read the same bytes", async () => { - const internalBytes = await wrb.readRequestBytecode(requestId) - assert.equal(internalBytes, requestHex) - }) - - it("should have set the correct rewards", async () => { - // Retrieve rewards - const drInfo = await wrb.readRequest(requestId) - const drReward = drInfo.reward.toString() - assert.equal(drReward, lastReward) - }) - - it("requester balance should decrease", async () => { - const afterBalance = await web3.eth.getBalance(accounts[1]) - assert(parseInt(afterBalance) < parseInt(lastAccount1Balance)) - lastAccount1Balance = afterBalance - }) - - it("client contract balance should remain stable", async () => { - const usingWitnetBalance = await web3.eth.getBalance(clientContract.address) - assert.equal(usingWitnetBalance, 0) - }) - - it("WRB balance should have increased in the exact fare", async () => { - const wrbBalance = await web3.eth.getBalance(wrb.address) - assert.equal(wrbBalance, lastReward) - }) - - it("should upgrade the rewards of an existing data request", async () => { - const gasPrice = 2e9 - lastReward = await clientContract.witnetEstimateReward(gasPrice) - const currentReward = await clientContract.witnetCurrentReward.call(requestId) - await returnData(clientContract.witnetUpgradeReward(requestId, { - from: accounts[1], - value: (lastReward - currentReward) * 2, - gasPrice, - })) - }) - - it("should have upgraded the rewards correctly", async () => { - // Retrieve reward - const drInfo = await wrb.readRequest(requestId) - assert.equal(drInfo.reward.toString(), lastReward.toString()) - }) - - it("requester balance should decrease after rewards upgrade", async () => { - const afterBalance = await web3.eth.getBalance(accounts[1]) - assert(parseInt(afterBalance) < parseInt(lastAccount1Balance)) - lastAccount1Balance = afterBalance - }) - - it("client contract balance should remain stable after rewards upgrade", async () => { - const usingWitnetBalance = await web3.eth.getBalance(clientContract.address) - assert.equal(usingWitnetBalance, 0) - }) - - it("WRB balance should increase after rewards upgrade", async () => { - const wrbBalance = await web3.eth.getBalance(wrb.address) - assert.equal(wrbBalance, lastReward) - }) - - it("should fail if posting result from unauthorized reporter", async () => { - await expectRevert( - wrb.reportResult(requestId, drTxHash, resultHex, { from: ownerAccount }), - "unauthorized reporter" - ) - }) - - it("should post the result of the request into the WRB", async () => { - await returnData(wrb.reportResult(requestId, drTxHash, resultHex, { - from: reporterAccount, - })) - const result = await wrb.readResponseResult.call(requestId) - assert.equal(result.value.buffer.data, resultHex) - }) - - it("should check if the request is resolved", async () => { - assert.equal(await clientContract.witnetCheckRequestResolved(requestId), true) - }) - - it("should pull the result from the WRB back into the client contract", async () => { - await clientContract.witnetReadResult(requestId, { from: accounts[0] }) - result = await clientContract.result() - assert.equal(result.success, true) - assert.equal(result.value.buffer.data, resultHex) - }) - - it("should decode result successfully", async () => { - const actualResultDecimal = await clientContract.witnetAsUint64.call() - assert.equal(actualResultDecimal.toString(), resultDecimal.toString()) - }) - }) - - describe("UsingWitnet \"happy path\" test case with a false result:", () => { - const requestHex = "0x02" - const resultHex = "0xd82701" - const drTxHash = "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" - - const reward = web3.utils.toWei("1", "ether") - - const ownerAccount = accounts[0] - const reporterAccount = accounts[1] - - const gasPrice = 1e9 - - let witnet, clientContract, wrb, proxy, request, requestId, result - - before(async () => { - witnet = await WitnetLib.deployed() - if (!proxy) { - // create one and only proxy contract: - proxy = await WRBProxy.new() - // let 'wrb' artifact always point to proxy address - wrb = await WRB.at(proxy.address) - // initialize 'wrb' artifact, - // setting 'ownerAccount' as owner - // and 'reporterAccount' as authorized reporter: - await proxy.upgradeTo( - (await WRB.new( - ...settings.constructorParams.default.WitnetRequestBoard - ) - ).address, - web3.eth.abi.encodeParameter("address[]", [reporterAccount]), - { from: ownerAccount } - ) - } - await UsingWitnetTestHelper.link(WitnetLib, witnet.address) - clientContract = await UsingWitnetTestHelper.new(wrb.address) - }) - - it("should create a data request", async () => { - request = await WitnetRequest.new(requestHex) - const internalBytes = await request.bytecode() - assert.equal(internalBytes, requestHex) - }) - - it("should pass the data request to the wrb", async () => { - requestId = await returnData(clientContract.witnetPostRequest( - request.address, - { - from: accounts[0], - value: reward, - gasPrice, - } - )) - assert.equal(requestId, 1) - }) - - it("should check the request is not yet resolved", async () => { - assert.equal(await clientContract.witnetCheckRequestResolved(requestId), false) - }) - - it("should fail if posting result from unauthorized reporter", async () => { - await expectRevert( - wrb.reportResult(requestId, drTxHash, resultHex, { from: ownerAccount }), - "unauthorized reporter" - ) - }) - - it("should report the result in the WRB", async () => { - await returnData(wrb.reportResult(requestId, drTxHash, resultHex, { - from: reporterAccount, - })) - const result = await wrb.readResponseResult(requestId) - assert.equal(result.value.buffer.data, resultHex) - }) - - it("should pull the result from the WRB back to the client contract", async () => { - await clientContract.witnetReadResult(requestId, { from: accounts[1] }) - result = await clientContract.result() - assert.equal(result.value.buffer.data, resultHex) - }) - - it("should detect the result is false", async () => { - await clientContract.witnetReadResult(requestId, { from: accounts[1] }) - result = await clientContract.result() - assert.equal(result.success, false) - }) - - it("should be able to estimate gas cost and post the DR", async () => { - const estimatedReward = await clientContract.witnetEstimateReward.call(gasPrice) - await truffleAssert.passes( - clientContract.witnetPostRequest(request.address, { - from: accounts[1], - value: estimatedReward, - gasPrice, - }), - "Estimated rewards should cover the gas costs" - ) - }) - }) -}) - -function waitForHash (tx) { - return new Promise((resolve, reject) => - tx.on("transactionHash", resolve).catch(reject) - ) -} - -async function returnData (tx) { - const txHash = await waitForHash(tx) - const txReceipt = await web3.eth.getTransactionReceipt(txHash) - if (txReceipt.logs && txReceipt.logs.length > 0) { - const decoded = web3.eth.abi.decodeLog( - [ - { - type: "uint256", - name: "id", - }, { - type: "address", - name: "from", - }, - ], - txReceipt.logs[0].data, - txReceipt.logs[0].topics - ) - return decoded.id - } -} diff --git a/test/witnet_bytecodes.test.js b/test/witnet_bytecodes.test.js index b3cd827d3..6557d8137 100644 --- a/test/witnet_bytecodes.test.js +++ b/test/witnet_bytecodes.test.js @@ -104,7 +104,7 @@ contract("WitnetBytecodes", (accounts) => { let btcUsdPriceFeedHash context("verifyRadonRetrieval(..)", async () => { - context("WitnetV2.DataRequestMethods.Rng", async () => { + context("Witnet.RadonDataRequestMethods.RNG", async () => { it("emits appropiate single event when verifying randomness data source for the first time", async () => { const tx = await bytecodes.verifyRadonRetrieval( 2, // requestMethod @@ -150,7 +150,7 @@ contract("WitnetBytecodes", (accounts) => { }) // ... reverts }) - context("WitnetV2.DataRequestMethods.HttpGet", async () => { + context("Witnet.RadonDataRequestMethods.HttpGet", async () => { it( "emits new data provider and source events when verifying a new http-get source for the first time", async () => { const tx = await bytecodes.verifyRadonRetrieval( @@ -201,7 +201,7 @@ contract("WitnetBytecodes", (accounts) => { ) }) }) - context("WitnetV2.DataRequestMethods.HttpPost", async () => { + context("Witnet.RadonDataRequestMethods.HttpPost", async () => { it( "emits new data provider and source events when verifying a new http-post source for the first time", async () => { const tx = await bytecodes.verifyRadonRetrieval( diff --git a/test/wrb.test.js b/test/wrb.test.js deleted file mode 100644 index c993ae8a4..000000000 --- a/test/wrb.test.js +++ /dev/null @@ -1,759 +0,0 @@ -const settings = require("../migrations/witnet.settings") - -const { - BN, - expectEvent, - expectRevert, - balance, - ether, -} = require("@openzeppelin/test-helpers") -const { expect, assert } = require("chai") - -// Contracts -const WRB = artifacts.require(settings.artifacts.default.WitnetRequestBoard) -const WitnetLib = artifacts.require("WitnetLib") -const WitnetRequest = artifacts.require("WitnetRequestTestHelper") -const WitnetRequestTestHelper = artifacts.require("WitnetRequestTestHelper") - -// WitnetRequest definition -const queryId = new BN(1) -// eslint-disable-next-line no-multi-str -const requestHex = "0x0abb0108bd8cb8fa05123b122468747470733a2f2f7777772e6269747374616d702e6e65742f6170692f7469636b65722\ -f1a13841877821864646c6173748218571903e8185b125c123168747470733a2f2f6170692e636f696e6465736b2e636f6d2f76312f6270692f6375\ -7272656e7470726963652e6a736f6e1a2786187782186663627069821866635553448218646a726174655f666c6f61748218571903e8185b1a0d0a0\ -908051205fa3fc00000100322090a0508051201011003100a1804200128\ -46308094ebdc03" -const resultHex = "0x1a000702c8" -const drTxHash = "0x0000000000000000000000000000000000000000000000000000000000000001" - -contract("WitnetRequestBoard", ([ - requester, - owner, - committeeMember, - other, -]) => { - beforeEach(async () => { - await WRB.link(WitnetLib, WitnetLib.address) - this.WitnetRequestBoard = await WRB.new( - ...settings.constructorParams.default.WitnetRequestBoard, - { from: owner } - ) - await this.WitnetRequestBoard.initialize( - web3.eth.abi.encodeParameter("address[]", - [owner, committeeMember]), - { from: owner } - ) - this.WitnetRequest = await WitnetRequest.new(requestHex, { from: requester }) - }) - - describe("deployments", async () => { - it("deploys WitnetRequestBoard successfully", async () => { - expect(this.WitnetRequestBoard.address != null) - }) - }) - - describe("post data request", async () => { - it("creator can post a data request", async () => { - // Initial balance - const contractBalanceTracker = await balance.tracker(this.WitnetRequestBoard.address) - const contractInitialBalance = await contractBalanceTracker.get() - - // Post Data Request - const postDataRequestTx = await this.WitnetRequestBoard.postRequest( - this.WitnetRequest.address, - { - from: requester, - value: ether("1"), - } - ) - - // Check `PostedRequest` event - expectEvent( - postDataRequestTx, - "PostedRequest", - { - queryId, - } - ) - expect(postDataRequestTx.logs[0].args.queryId, "match data request id").to.be.bignumber.equal(queryId) - - // Check contract balance (increased by reward) - const contractFinalBalance = await contractBalanceTracker.get() - expect( - contractFinalBalance.eq(contractInitialBalance - .add(ether("1")) - ), - "contract balance should have increase after the request creation by 1 eth", - ).to.equal(true) - }) - it("creator can post data requests with sequential identifiers", async () => { - // Post Data Requests - const postDataRequestTx1 = await this.WitnetRequestBoard.postRequest( - this.WitnetRequest.address, - { - from: requester, - value: ether("1"), - }) - const postDataRequestTx2 = await this.WitnetRequestBoard.postRequest( - this.WitnetRequest.address, - { - from: requester, - value: ether("1"), - }) - - // Check `PostedRequest` events - expectEvent( - postDataRequestTx1, - "PostedRequest", - { - queryId, - }) - expect(postDataRequestTx1.logs[0].args.queryId, "match data request id").to.be.bignumber.equal(queryId) - // Check `PostedRequest` events - expectEvent( - postDataRequestTx2, - "PostedRequest", - { - queryId: queryId.add(new BN(1)), - }) - expect( - postDataRequestTx2.logs[0].args.queryId, - "match data request id" - ).to.be.bignumber.equal(queryId.add(new BN(1))) - }) - it("fails if creator is not covering DR reward", async () => { - // Transaction value < reward - await expectRevert( - this.WitnetRequestBoard.postRequest( - this.WitnetRequest.address, - { - from: requester, - value: ether("0"), - gasPrice: 1, - } - ), - "reward too low." - ) - }) - it("fails if creator is not covering DR result report gas cost", async () => { - // Tally reward < ESTIMATED_REPORT_RESULT_GAS - await expectRevert( - this.WitnetRequestBoard.postRequest( - this.WitnetRequest.address, - { - from: requester, - value: new BN("1"), - gasPrice: 1, - } - ), - "reward too low." - ) - }) - it("reading bytecode from unsolved query works if the request was not modified before being solved", async () => { - await this.WitnetRequestBoard.postRequest(this.WitnetRequest.address, { from: requester, value: ether("1") }) - assert.equal( - await this.WitnetRequest.bytecode.call(), - await this.WitnetRequestBoard.readRequestBytecode.call(1) - ) - }) - it("reading bytecode from unsolved query fails if the request gets modified before being solved", async () => { - await this.WitnetRequestBoard.postRequest(this.WitnetRequest.address, { from: requester, value: ether("1") }) - const newDrBytes = web3.utils.fromAscii("This is a different DR") - await this.WitnetRequest.modifyBytecode(newDrBytes) - await expectRevert( - this.WitnetRequestBoard.readRequestBytecode.call(1), - "bytecode changed after posting" - ) - }) - }) - - describe("upgrade data request", async () => { - beforeEach(async () => { - await this.WitnetRequestBoard.postRequest( - this.WitnetRequest.address, - { - from: requester, - value: ether("1"), - gasPrice: 1e9, - } - ) - }) - it("anyone can upgrade existing data request increasing the reward", async () => { - // Initial balance - const contractBalanceTracker = await balance.tracker(this.WitnetRequestBoard.address) - const contractInitialBalance = await contractBalanceTracker.get() - - // Update data request (increased reward) - await this.WitnetRequestBoard.upgradeReward(queryId, { - from: other, - value: ether("1"), - gasPrice: 2e9, - }) - - // Check contract balance (increased by reward) - const contractFinalBalance = await contractBalanceTracker.get() - expect( - contractFinalBalance.eq(contractInitialBalance - .add(ether("1")) - ), - "contract balance should have increased after request upgrade by 1 eth", - ).to.equal(true) - }) - it("anyone can upgrade existing data request gas price", async () => { - // Update data request (increased reward) - await this.WitnetRequestBoard.upgradeReward(queryId, { - from: other, - value: ether("1"), - gasPrice: 3e9, - }) - - // Read data request gas price from WitnetRequestBoard by `queryId` - const gasPrice = await this.WitnetRequestBoard.readRequestGasPrice.call(queryId, { from: other }) - - // Check that gas price has been updated to 3 wei - expect( - gasPrice.eq(new BN(3e9)), - "data request gas price should have been set to 3 gwei", - ).to.equal(true) - }) - it("creator cannot decrease existing data request gas price", async () => { - // Update data request (increased reward) - await this.WitnetRequestBoard.upgradeReward(queryId, { - from: requester, - value: ether("1"), - gasPrice: 3e9, - }) - // Read data request gas price from WitnetRequestBoard by `queryId` - const gasPrice = await this.WitnetRequestBoard.readRequestGasPrice.call(queryId, { from: other }) - // Check that gas price has not been updated to 1 wei - expect( - gasPrice.eq(new BN(3e9)), - "data request gas price should not have been set to 1 gwei", - ).to.equal(true) - }) - it("fails if anyone upgrades DR with new gas price that decreases reward below gas limit", async () => { - // Report result reward < ESTIMATED_REPORT_RESULT_GAS * newGasPrice - const newGasPrice = ether("0.01") - await expectRevert( - this.WitnetRequestBoard.upgradeReward(queryId, { - from: requester, - value: ether("0"), - gasPrice: newGasPrice, - }), - "reward too low" - ) - }) - it("fails if result is already reported", async () => { - await this.WitnetRequestBoard.reportResult( - queryId, drTxHash, resultHex, - { from: owner, gasPrice: 1e9 } - ) - // Update data request (increased reward) - await expectRevert( - this.WitnetRequestBoard.upgradeReward(queryId, { - from: requester, - value: ether("1"), - gasPrice: 3e9, - }), - "not in Posted status" - ) - }) - }) - - describe("report data request result", async () => { - beforeEach(async () => { - // Post data request - await this.WitnetRequestBoard.postRequest(this.WitnetRequest.address, { - from: requester, - value: ether("1"), - gasPrice: 1e9, - }) - }) - it("committee members can report a request result from Witnet and it should receive the reward", async () => { - // Initial balances - const contractBalanceTracker = await balance.tracker(this.WitnetRequestBoard.address) - const ownerBalanceTracker = await balance.tracker(owner) - const contractInitialBalance = await contractBalanceTracker.get() - const ownerInitialBalance = await ownerBalanceTracker.get() - - // Report data request result from Witnet to WitnetRequestBoard - const reportResultTx = await this.WitnetRequestBoard.reportResult( - queryId, drTxHash, resultHex, - { from: owner, gasPrice: 1e9 } - ) - - // Check `PostedRequest` event - expectEvent( - reportResultTx, - "PostedResult", - { - queryId, - }, - ) - expect(reportResultTx.logs[0].args.queryId, "match data request id").to.be.bignumber.equal(queryId) - - // Check balances (contract decreased and claimer increased) - const contractFinalBalance = await contractBalanceTracker.get() - const ownerFinalBalance = await ownerBalanceTracker.get() - - expect( - contractFinalBalance.eq(contractInitialBalance - .sub(ether("1")) - ), - "contract balance should have decreased after reporting dr request result by 1 eth", - ).to.equal(true) - expect( - ownerFinalBalance.gt(ownerInitialBalance), - "Owner balance should have increased after reporting result", - ).to.equal(true) - }) - it("fails if reporter is not a committee member", async () => { - await expectRevert( - this.WitnetRequestBoard.reportResult(queryId, drTxHash, resultHex, { - from: other, - gasPrice: 1e9, - }), - "unauthorized reporter" - ) - }) - it("fails if trying to report with zero as Witnet drTxHash", async () => { - await expectRevert( - this.WitnetRequestBoard.reportResult( - queryId, "0x0", resultHex, - { from: owner, gasPrice: 1e9 } - ), - "drTxHash cannot be zero" - ) - }) - it("fails if result was already reported", async () => { - // Report data request result from Witnet to WitnetRequestBoard - await this.WitnetRequestBoard.reportResult( - queryId, drTxHash, resultHex, - { from: owner, gasPrice: 1e9 } - ) - - // Try to report the result of the previous data request - await expectRevert( - this.WitnetRequestBoard.reportResult(queryId, drTxHash, resultHex, { - from: committeeMember, - gasPrice: 1e9, - }), - "not in Posted status" - ) - }) - it("fails if data request has not been posted", async () => { - await expectRevert( - this.WitnetRequestBoard.reportResult( - queryId.add(new BN(1)), drTxHash, resultHex, - { from: owner, gasPrice: 1e9 } - ), - "not in Posted status" - ) - }) - it("retrieves null array if trying to read bytecode from solved data request", async () => { - await this.WitnetRequestBoard.reportResult( - queryId, drTxHash, resultHex, - { from: owner, gasPrice: 1e9 } - ) - const bytecode = await this.WitnetRequestBoard.readRequestBytecode.call(queryId) - assert(bytecode == null) - }) - }) - - describe("batch report multiple results", async () => { - beforeEach(async () => { - for (let j = 0; j < 3; j++) { - await this.WitnetRequestBoard.postRequest( - this.WitnetRequest.address, { - from: requester, - value: ether("1"), - gasPrice: 1e9, - } - ) - } - }) - it("fails if trying to batch report valid results from unauthorized address", async () => { - await expectRevert( - this.WitnetRequestBoard.reportResultBatch( - [ - [1, 0, drTxHash, resultHex], - [2, 0, drTxHash, resultHex], - [3, 0, drTxHash, resultHex], - ], - true, - { from: other, gasPrice: 1e9 } - ), - "unauthorized reporter" - ) - }) - it("committee member can batch report multiple results, and receive the sum of all rewards", async () => { - // Initial balances - const contractBalanceTracker = await balance.tracker(this.WitnetRequestBoard.address) - const ownerBalanceTracker = await balance.tracker(owner) - const contractInitialBalance = await contractBalanceTracker.get() - const ownerInitialBalance = await ownerBalanceTracker.get() - - // Report data request result from Witnet to WitnetRequestBoard - const tx = await this.WitnetRequestBoard.reportResultBatch( - [ - [1, 0, drTxHash, resultHex], - [2, 0, drTxHash, resultHex], - [3, 0, drTxHash, resultHex], - ], - false, - { from: owner, gasPrice: 1e9 } - ) - - // Check balances (contract decreased and claimer increased) - const contractFinalBalance = await contractBalanceTracker.get() - const ownerFinalBalance = await ownerBalanceTracker.get() - expect( - contractFinalBalance.eq(contractInitialBalance - .sub(ether("3")) - ), - "contract balance should have decreased after reporting dr request result by 3 eth", - ).to.equal(true) - expect( - ownerFinalBalance.gt(ownerInitialBalance), - "Owner balance should have increased after reporting result", - ).to.equal(true) - - // Check number of PostedResult events - expect( - tx.logs.filter(log => log.event === "PostedResult").length, - "PostedResult event should have been emitted three times" - ).to.equal(3) - }) - it( - "trying to verbose batch report same query twice, should pay reward once and emit error event once", - async () => { - // Initial balances - const contractBalanceTracker = await balance.tracker(this.WitnetRequestBoard.address) - const ownerBalanceTracker = await balance.tracker(owner) - const contractInitialBalance = await contractBalanceTracker.get() - const ownerInitialBalance = await ownerBalanceTracker.get() - - // Report data request result from Witnet to WitnetRequestBoard - const tx = await this.WitnetRequestBoard.reportResultBatch( - [ - [3, 0, drTxHash, resultHex], - [3, 0, drTxHash, resultHex], - ], - true, - { from: owner, gasPrice: 1e9 } - ) - - // Check balances (contract decreased and claimer increased) - const contractFinalBalance = await contractBalanceTracker.get() - const ownerFinalBalance = await ownerBalanceTracker.get() - expect( - contractFinalBalance.eq(contractInitialBalance - .sub(ether("1")) - ), - "contract balance should have decreased after reporting dr request result by 3 eth", - ).to.equal(true) - expect( - ownerFinalBalance.gt(ownerInitialBalance), - "Owner balance should have increased after reporting result", - ).to.equal(true) - - // Check number of emitted PostedResult events: - expect( - tx.logs.filter(log => log.event === "PostedResult").length, - "PostedResult event should have been emitted once" - ).to.equal(1) - - // Check number and quality of BatchReportError events: - const errors = tx.logs.filter(log => log.event === "BatchReportError") - expect( - errors.length, - "BatchReportResult event should have been emitted just once" - ).to.equal(1) - expect( - errors[0].args.queryId.toString(), - "BatchReportResult event refers unexpected query id" - ).to.equal("3") - expect( - errors[0].args.reason, - "BatchReportResult manifest wrong reason" - ).to.contain("bad queryId") - }) - it( - "reporting bad drTxHash within non-verbose batch, should pay rewards for valid results and emit no error event", - async () => { - // Initial balances - const contractBalanceTracker = await balance.tracker(this.WitnetRequestBoard.address) - const ownerBalanceTracker = await balance.tracker(owner) - const contractInitialBalance = await contractBalanceTracker.get() - const ownerInitialBalance = await ownerBalanceTracker.get() - - // Report data request result from Witnet to WitnetRequestBoard - const tx = await this.WitnetRequestBoard.reportResultBatch( - [ - [1, 0, drTxHash, resultHex], - [2, 0, "0x0000000000000000000000000000000000000000000000000000000000000000", resultHex], - [3, 0, drTxHash, resultHex], - ], - false, - { from: owner, gasPrice: 1e9 } - ) - - // Check balances (contract decreased and claimer increased) - const contractFinalBalance = await contractBalanceTracker.get() - const ownerFinalBalance = await ownerBalanceTracker.get() - expect( - contractFinalBalance.eq(contractInitialBalance - .sub(ether("2")) - ), - "contract balance should have decreased after reporting dr request result by 2 eth", - ).to.equal(true) - expect( - ownerFinalBalance.gt(ownerInitialBalance), - "Owner balance should have increased after reporting result", - ).to.equal(true) - - // Check number of emitted PostedResult events: - expect( - tx.logs.filter(log => log.event === "PostedResult").length, - "PostedResult event should have been emitted three times" - ).to.equal(2) - - // Check number of BatchReportError events: - const errors = tx.logs.filter(log => log.event === "BatchReportError") - expect( - errors.length, - "No BatchReportResult events should have been emitted" - ).to.equal(0) - }) - it( - "reporting bad results within verbose batch, should pay no reward and emit no PostedResult events", async () => { - // Initial balances - const contractBalanceTracker = await balance.tracker(this.WitnetRequestBoard.address) - const contractInitialBalance = await contractBalanceTracker.get() - - // Report data request result from Witnet to WitnetRequestBoard - const tx = await this.WitnetRequestBoard.reportResultBatch( - [ - [1, 0, drTxHash, "0x"], - [3, 0, "0x0000000000000000000000000000000000000000000000000000000000000000", resultHex], - [2, 4070905200 /* 2099-01-01 00:00:00 UTC */, drTxHash, resultHex], - ], - true, - { from: owner, gasPrice: 1e9 } - ) - - // Check balances (contract decreased and claimer increased) - const contractFinalBalance = await contractBalanceTracker.get() - expect( - contractFinalBalance.eq( - contractInitialBalance - ), - "contract balance should have not changed", - ).to.equal(true) - - // Check number of emitted PostedResult events: - expect( - tx.logs.filter(log => log.event === "PostedResult").length, - "Should have not emitted any PostedResult event" - ).to.equal(0) - - // Check number and quality of BatchReportError events: - const errors = tx.logs.filter(log => log.event === "BatchReportError") - expect( - errors.length, - "Three BatchReportResult events should have been emitted" - ).to.equal(3) - expect( - errors[0].args.queryId.toString(), - "First BatchReportResult event refers to unexpected query id" - ).to.equal("1") - expect( - errors[0].args.reason, - "First BatchReportResult manifests wrong reason" - ).to.contain("bad cborBytes") - expect( - errors[1].args.queryId.toString(), - "Second BatchReportResult event refers to unexpected query id" - ).to.equal("3") - expect( - errors[1].args.reason, - "Second BatchReportResult manifests wrong reason" - ).to.contain("bad drTxHash") - expect( - errors[2].args.queryId.toString(), - "Third BatchReportResult event refers to unexpected query id" - ).to.equal("2") - expect( - errors[2].args.reason, - "Third BatchReportResult manifests wrong reason" - ).to.contain("bad timestamp") - }) - }) - - describe("read data request result", async () => { - let requestTestHelper - beforeEach(async () => { - requestTestHelper = await WitnetRequestTestHelper.new(requestHex, { from: requester }) - // Post data request - await this.WitnetRequestBoard.postRequest(requestTestHelper.address, { - from: requester, - value: ether("1"), - }) - // Report data request result from Witnet to WitnetRequestBoard - await this.WitnetRequestBoard.reportResult(queryId, drTxHash, resultHex, { - from: committeeMember, - gasPrice: 1e9, - }) - }) - it("anyone can read the data request result", async () => { - // Read data request result from WitnetRequestBoard by `queryId` - const result = await this.WitnetRequestBoard.readResponseResult(queryId, { from: requester }) - expect(result.value.buffer.data).to.be.equal(resultHex) - }) - it("should revert reading data for non-existent Ids", async () => { - await expectRevert(this.WitnetRequestBoard.readRequestBytecode.call(200), "not yet posted") - await expectRevert(this.WitnetRequestBoard.readResponseDrTxHash.call(200), "not in Reported status") - await expectRevert(this.WitnetRequestBoard.readResponseResult.call(200), "not in Reported status") - }) - }) - - describe("read data request gas price", async () => { - beforeEach(async () => { - await this.WitnetRequestBoard.postRequest( - this.WitnetRequest.address, - { - from: requester, - value: ether("1"), - gasPrice: 1e9, - } - ) - }) - it("anyone can read data request gas price", async () => { - // Read data request gas price from WitnetRequestBoard by `queryId` - const gasPrice = await this.WitnetRequestBoard.readRequestGasPrice.call(queryId, { from: other }) - expect( - gasPrice.eq(new BN(1e9)), - "data request gas price should have been set to 1 gwei", - ).to.equal(true) - }) - }) - - describe("estimate gas cost", async () => { - it("anyone can estime a data request gas cost", async () => { - // Gas price = 1 - const maxResRe = new BN(135000) - const reward = await this.WitnetRequestBoard.estimateReward.call(1) - expect( - reward.lte(maxResRe), - `The estimated maximum gas cost for result reward should be less than ${maxResRe.toString()}` - ).to.equal(true) - } - ) - }) - - describe("delete data request", async () => { - let drId - beforeEach(async () => { - const tx = await this.WitnetRequestBoard.postRequest( - this.WitnetRequest.address, - { - from: requester, - value: ether("0.1"), - gasPrice: 1e9, - } - ) - drId = tx.logs[0].args[0] - }) - it("fails if trying to delete data request from non requester address", async () => { - await this.WitnetRequestBoard.reportResult( - drId, drTxHash, resultHex, - { from: owner, gasPrice: 1e9 } - ) - await expectRevert( - this.WitnetRequestBoard.deleteQuery(drId, { from: other }), - "only requester" - ) - }) - it("unsolved data request cannot be deleted", async () => { - await expectRevert( - this.WitnetRequestBoard.deleteQuery(drId, { from: requester }), - "not in Reported status" - ) - }) - it("requester can delete solved data request", async () => { - await this.WitnetRequestBoard.reportResult( - drId, drTxHash, resultHex, - { from: owner, gasPrice: 1e9 } - ) - await this.WitnetRequestBoard.deleteQuery(drId, { from: requester }) - }) - it("fails if reporting result on deleted data request", async () => { - await this.WitnetRequestBoard.reportResult( - drId, drTxHash, resultHex, - { from: owner, gasPrice: 1e9 } - ) - await this.WitnetRequestBoard.deleteQuery(drId, { from: requester }) - await expectRevert( - this.WitnetRequestBoard.reportResult( - drId, drTxHash, resultHex, - { from: owner, gasPrice: 1e9 } - ), - "not in Posted status" - ) - }) - it("retrieves null array if trying to read bytecode from deleted data request", async () => { - await this.WitnetRequestBoard.reportResult( - drId, drTxHash, resultHex, - { from: owner, gasPrice: 1e9 } - ) - await this.WitnetRequestBoard.deleteQuery(drId, { from: requester }) - const bytecode = await this.WitnetRequestBoard.readRequestBytecode.call(drId) - assert(bytecode == null) - }) - }) - - describe("interfaces", async () => { - describe("Upgradeable:", async () => { - it("initialization fails if called from non owner address", async () => { - await expectRevert( - this.WitnetRequestBoard.initialize( - web3.eth.abi.encodeParameter("address[]", [other]), - { from: other } - ), - "only owner" - ) - }) - it("cannot initialize same instance more than once", async () => { - await expectRevert( - this.WitnetRequestBoard.initialize( - web3.eth.abi.encodeParameter("address[]", [other]), - { from: owner } - ), - "already upgraded" - ) - }) - }) - - describe("Destructible:", async () => { - it("fails if trying to destruct from non owner address", async () => { - await expectRevert( - this.WitnetRequestBoard.destruct({ from: other }), - "not the owner" - ) - }) - it("instance gets actually destructed", async () => { - await this.WitnetRequestBoard.destruct({ from: owner }) - await expectRevert( - this.WitnetRequestBoard.getNextQueryId(), - "Out of Gas?" - ) - }) - it("fails if trying to delete unposted DR", async () => { - await expectRevert( - this.WitnetRequestBoard.deleteQuery(200, { from: owner }), - "not in Reported status" - ) - }) - }) - }) -}) diff --git a/test/wrb_proxy.test.js b/test/wrb_proxy.test.js deleted file mode 100644 index 5551efe52..000000000 --- a/test/wrb_proxy.test.js +++ /dev/null @@ -1,258 +0,0 @@ -const settings = require("../migrations/witnet.settings") - -const { assert } = require("chai") -const truffleAssert = require("truffle-assertions") - -const WitnetLib = artifacts.require(settings.artifacts.default.WitnetLib) - -const WitnetRequest = artifacts.require("WitnetRequestTestHelper") -const WitnetRequestBoard = artifacts.require("WitnetRequestBoardTestHelper") -const WrbProxyHelper = artifacts.require("WrbProxyTestHelper") -const TrojanHorseNotUpgradable = artifacts.require("WitnetRequestBoardTrojanHorseNotUpgradable") -const TrojanHorseBadProxiable = artifacts.require("WitnetRequestBoardTrojanHorseBadProxiable") - -contract("Witnet Requests Board Proxy", accounts => { - describe("Witnet Requests Board Proxy test suite:", () => { - const contractOwner = accounts[0] - const requestSender = accounts[1] - - let witnet - let wrbInstance1 - let wrbInstance2 - let wrbInstance3 - let proxy - let wrb - - before(async () => { - witnet = await WitnetLib.deployed() - await WitnetRequestBoard.link(WitnetLib, witnet.address) - wrbInstance1 = await WitnetRequestBoard.new([contractOwner], true) - wrbInstance2 = await WitnetRequestBoard.new([contractOwner], true) - wrbInstance3 = await WitnetRequestBoard.new([contractOwner], false) - proxy = await WrbProxyHelper.new({ from: accounts[2] }) - proxy.upgradeWitnetRequestBoard(wrbInstance1.address, { from: contractOwner }) - wrb = await WitnetRequestBoard.at(proxy.address) - }) - - it("should revert when inserting id 0", async () => { - // It should revert because of non-existent id 0 - await truffleAssert.reverts( - wrb.upgradeReward(0, { from: requestSender }), - "not in Posted" - ) - }) - - it("should post a data request and update the getNextQueryId meter", async () => { - // The data request to be posted - const drBytes = web3.utils.fromAscii("This is a DR") - const request = await WitnetRequest.new(drBytes) - - // Post the data request through the Proxy - const tx1 = wrb.postRequest(request.address, { - from: requestSender, - value: web3.utils.toWei("0.5", "ether"), - }) - const txHash1 = await waitForHash(tx1) - const txReceipt1 = await web3.eth.getTransactionReceipt(txHash1) - - // The id of the data request - const id1 = parseInt(decodeWitnetLogs(txReceipt1.logs, 0).id) - const nextId = await wrb.getNextQueryId.call() - - // check the nextId has been updated in the Proxy when posting the data request - assert.equal((id1 + 1).toString(), nextId.toString()) - }) - - it("fails if trying to upgrade to null contract", async () => { - await truffleAssert.reverts( - proxy.upgradeWitnetRequestBoard("0x0000000000000000000000000000000000000000", { from: contractOwner }), - "null implementation" - ) - }) - - it("fails if owner tries to upgrade to same implementation instance as current one", async () => { - await truffleAssert.reverts( - proxy.upgradeWitnetRequestBoard(await proxy.implementation.call(), { from: contractOwner }), - "nothing to upgrade" - ) - }) - - it("fails if owner tries to upgrade to non-Initializable implementation", async () => { - await truffleAssert.reverts( - proxy.upgradeWitnetRequestBoard(proxy.address, { from: contractOwner }), - "" - ) - }) - - it("fails if foreigner tries to upgrade to compliant new implementation", async () => { - await truffleAssert.reverts( - proxy.upgradeWitnetRequestBoard(wrbInstance2.address, { from: requestSender }), - "not authorized" - ) - }) - - it("fails if owner tries to upgrade to not Upgradeable-compliant implementation", async () => { - const troyHorse = await TrojanHorseNotUpgradable.new() - await truffleAssert.reverts( - proxy.upgradeWitnetRequestBoard(troyHorse.address, { from: contractOwner }), - "not compliant" - ) - }) - - it("fails if owner tries to upgrade to a bad Proxiable-compliant implementation", async () => { - const troyHorse = await TrojanHorseBadProxiable.new() - await truffleAssert.reverts( - proxy.upgradeWitnetRequestBoard(troyHorse.address, { from: contractOwner }), - "proxiableUUIDs mismatch" - ) - }) - - it("should upgrade proxy to compliant new implementation, if called from owner address", async () => { - // The data request to be posted - const drBytes = web3.utils.fromAscii("This is a DR") - const request = await WitnetRequest.new(drBytes) - - // Post the data request through the Proxy - const tx1 = wrb.postRequest(request.address, { - from: requestSender, - value: web3.utils.toWei("0.5", "ether"), - }) - const txHash1 = await waitForHash(tx1) - const txReceipt1 = await web3.eth.getTransactionReceipt(txHash1) - - // The id of the data request, it should be equal 2 since is the second DR - const id1 = decodeWitnetLogs(txReceipt1.logs, 0).id - assert.equal(id1, 2) - - // Upgrade the WRB address to wrbInstance2 (destroying wrbInstance1) - await proxy.upgradeWitnetRequestBoard(wrbInstance2.address, { from: contractOwner }) - - // The current wrb in the proxy should be equal to wrbInstance2 - assert.equal(await proxy.implementation.call(), wrbInstance2.address) - }) - - it("fails if foreigner tries to re-initialize current implementation", async () => { - await truffleAssert.reverts( - wrb.initialize(web3.eth.abi.encodeParameter("address[]", [requestSender]), { from: requestSender }), - "only owner" - ) - }) - - it("fails also if the owner tries to re-initialize current implementation", async () => { - await truffleAssert.reverts( - wrb.initialize(web3.eth.abi.encodeParameter("address[]", [requestSender]), { from: contractOwner }), - "already upgraded" - ) - }) - - it("should post a data request to new WRB and keep previous data request routes", async () => { - // The data request to be posted - const drBytes = web3.utils.fromAscii("This is a DR") - const request = await WitnetRequest.new(drBytes) - - // The id of the data request - const id2 = await wrb.postRequest.call(request.address, { - from: requestSender, - value: web3.utils.toWei("0.5", "ether"), - }) - assert.equal(id2, 3) - - // Post the data request through the Proxy - await waitForHash( - wrb.postRequest(request.address, { - from: requestSender, - value: web3.utils.toWei("0.5", "ether"), - }) - ) - - // Reading previous query (<3) should work: - await wrb.getQueryData.call(2) - }) - - it("should post a data request to WRB and read the result", async () => { - // The data request to be posted - const drBytes = web3.utils.fromAscii("This is a DR") - const request = await WitnetRequest.new(drBytes) - - // The id of the data request with result "hello" - const id2 = await wrb.postRequest.call(request.address, { - from: requestSender, - value: web3.utils.toWei("0.5", "ether"), - }) - assert.equal(id2, 4) - - // Post the data request through the Proxy - await waitForHash( - wrb.postRequest(request.address, { - from: requestSender, - value: web3.utils.toWei("0.5", "ether"), - }) - ) - - // Read the actual result of the DR - const result = await wrb.readResponseResult.call(id2) - assert.equal(result.value.buffer.data, web3.utils.fromAscii("hello")) - }) - - it("should read the result of a dr of an old wrb", async () => { - // Upgrade the WRB address to wrbInstance3 - await proxy.upgradeWitnetRequestBoard(wrbInstance3.address, { - from: contractOwner, - }) - - // Read the actual result of the DR - const result = await wrb.readResponseResult.call(4) - assert.equal(result.value.buffer.data, web3.utils.fromAscii("hello")) - }) - - it("a solved data request can only be deleted by actual requester", async () => { - // Read the result of the DR just before destruction: - const response = await wrb.deleteQuery.call(4, { from: requestSender }) - const result = await wrb.resultFromCborBytes.call(response.cborBytes) - assert.equal(result.value.buffer.data, web3.utils.fromAscii("hello")) - - await truffleAssert.reverts( - wrb.deleteQuery(4, { from: contractOwner }), - "only requester" - ) - const tx = await wrb.deleteQuery(4, { from: requestSender }) // should work - assert.equal(tx.logs[0].args[1], requestSender) - }) - - it("retrieves null array if trying to get bytecode from deleted DRs", async () => { - const bytecode = await wrb.readRequestBytecode.call(4) - assert(bytecode == null) - }) - - it("fails if trying to upgrade a non upgradable implementation", async () => { - // It should revert when trying to upgrade the wrb since wrbInstance3 is not upgradable - await truffleAssert.reverts( - proxy.upgradeWitnetRequestBoard(wrbInstance1.address, { from: contractOwner }), - "not upgradable" - ) - }) - }) -}) - -const waitForHash = txQ => - new Promise((resolve, reject) => - txQ.on("transactionHash", resolve).catch(reject) - ) - -function decodeWitnetLogs (logs, index) { - if (logs.length > index) { - return web3.eth.abi.decodeLog( - [ - { - type: "uint256", - name: "id", - }, { - type: "address", - name: "from", - }, - ], - logs[index].data, - logs[index].topcis - ) - } -} diff --git a/truffle-config.js b/truffle-config.js index b97a944c2..a607c835c 100644 --- a/truffle-config.js +++ b/truffle-config.js @@ -44,6 +44,7 @@ module.exports = { cronos: process.env.CRONOSCAN_API_KEY, etherscan: process.env.ETHERSCAN_API_KEY, moonscan: process.env.MOONSCAN_API_KEY, + optimistic_etherscan: process.env.ETHERSCAN_OPTIMISM_API_KEY, polygonscan: process.env.POLYGONSCAN_API_KEY, routescan: process.env.ROUTESCAN_API_KEY, scrollscan: process.env.SCROLLSCAN_API_KEY,