From 0d79109e5bdae5f7edf8150dea4c43cfd42c44be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Mon, 6 Nov 2023 17:43:52 +0100 Subject: [PATCH 01/86] feat: WitnetBytecodes.class() --- contracts/impls/core/WitnetBytecodesDefault.sol | 4 +++- contracts/interfaces/V2/IWitnetBytecodes.sol | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/contracts/impls/core/WitnetBytecodesDefault.sol b/contracts/impls/core/WitnetBytecodesDefault.sol index d4a2c93f9..29a8da4b7 100644 --- a/contracts/impls/core/WitnetBytecodesDefault.sol +++ b/contracts/impls/core/WitnetBytecodesDefault.sol @@ -31,7 +31,9 @@ contract WitnetBytecodesDefault using WitnetEncodingLib for WitnetV2.RadonRetrieval[]; using WitnetEncodingLib for WitnetV2.RadonReducer; using WitnetEncodingLib for WitnetV2.RadonSLA; - using WitnetEncodingLib for WitnetV2.RadonDataTypes; + using WitnetEncodingLib for WitnetV2.RadonDataTypes; + + bytes4 public immutable override class = type(IWitnetBytecodes).interfaceId; constructor( bool _upgradable, diff --git a/contracts/interfaces/V2/IWitnetBytecodes.sol b/contracts/interfaces/V2/IWitnetBytecodes.sol index 10d7f2c8c..4a0af9d62 100644 --- a/contracts/interfaces/V2/IWitnetBytecodes.sol +++ b/contracts/interfaces/V2/IWitnetBytecodes.sol @@ -9,6 +9,8 @@ interface IWitnetBytecodes { function bytecodeOf(bytes32 radHash) external view returns (bytes memory); function bytecodeOf(bytes32 radHash, bytes32 slahHash) external view returns (bytes memory); + function class() external view returns (bytes4); + function hashOf( bytes32[] calldata sources, bytes32 aggregator, From 232944da67b6d17c387e6e11cb638d37e2d93fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Mon, 6 Nov 2023 17:51:12 +0100 Subject: [PATCH 02/86] refactor: WitnetRequestFactory, WitnetRequestTemplate --- contracts/data/WitnetRequestFactoryData.sol | 2 +- contracts/impls/core/WitnetRequestFactoryDefault.sol | 12 ++++-------- .../core/customs/WitnetRequestFactoryCfxCore.sol | 2 +- contracts/interfaces/V2/IWitnetRequestFactory.sol | 6 +++--- contracts/requests/WitnetRequestTemplate.sol | 6 +++--- 5 files changed, 12 insertions(+), 16 deletions(-) diff --git a/contracts/data/WitnetRequestFactoryData.sol b/contracts/data/WitnetRequestFactoryData.sol index b7e04459c..daa0e3d08 100644 --- a/contracts/data/WitnetRequestFactoryData.sol +++ b/contracts/data/WitnetRequestFactoryData.sol @@ -37,7 +37,7 @@ contract WitnetRequestFactoryData { /// @notice Aggregator reducer hash. bytes32 aggregator; /// @notice Parent IWitnetRequestFactory from which this template was built. - WitnetRequestFactory factory; + IWitnetRequestFactory factory; /// Whether any of the sources is parameterized. bool parameterized; /// @notice Tally reducer hash. diff --git a/contracts/impls/core/WitnetRequestFactoryDefault.sol b/contracts/impls/core/WitnetRequestFactoryDefault.sol index c13eb0294..bc95c6f93 100644 --- a/contracts/impls/core/WitnetRequestFactoryDefault.sol +++ b/contracts/impls/core/WitnetRequestFactoryDefault.sol @@ -3,8 +3,6 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; - import "../../WitnetBytecodes.sol"; import "../../WitnetRequestFactory.sol"; import "../../data/WitnetRequestFactoryData.sol"; @@ -20,10 +18,8 @@ contract WitnetRequestFactoryDefault WitnetRequestFactoryData, WitnetUpgradableBase { - using ERC165Checker for address; - /// @notice Reference to Witnet Data Requests Bytecode Registry - WitnetBytecodes immutable public override(IWitnetRequestFactory, WitnetRequestTemplate) registry; + IWitnetBytecodes immutable public override(IWitnetRequestFactory, WitnetRequestTemplate) registry; modifier onlyDelegateCalls override(Clonable, Upgradeable) { require( @@ -51,7 +47,7 @@ contract WitnetRequestFactoryDefault } constructor( - WitnetBytecodes _registry, + IWitnetBytecodes _registry, bool _upgradable, bytes32 _versionTag ) @@ -62,7 +58,7 @@ contract WitnetRequestFactoryDefault ) { require( - address(_registry).supportsInterface(type(WitnetBytecodes).interfaceId), + _registry.class() == type(WitnetBytecodes).interfaceId, "WitnetRequestFactoryDefault: uncompliant registry" ); registry = _registry; @@ -415,7 +411,7 @@ contract WitnetRequestFactoryDefault override external view onlyDelegateCalls - returns (WitnetRequestFactory) + returns (IWitnetRequestFactory) { WitnetRequestTemplate _template = __witnetRequest().template; if (address(_template) != address(0)) { diff --git a/contracts/impls/core/customs/WitnetRequestFactoryCfxCore.sol b/contracts/impls/core/customs/WitnetRequestFactoryCfxCore.sol index 87090fb62..faa836f73 100644 --- a/contracts/impls/core/customs/WitnetRequestFactoryCfxCore.sol +++ b/contracts/impls/core/customs/WitnetRequestFactoryCfxCore.sol @@ -7,7 +7,7 @@ import "../WitnetRequestFactoryDefault.sol"; contract WitnetRequestFactoryCfxCore is WitnetRequestFactoryDefault { constructor( - WitnetBytecodes _registry, + IWitnetBytecodes _registry, bool _upgradable, bytes32 _versionTag ) diff --git a/contracts/interfaces/V2/IWitnetRequestFactory.sol b/contracts/interfaces/V2/IWitnetRequestFactory.sol index d706ae9a7..81890a095 100644 --- a/contracts/interfaces/V2/IWitnetRequestFactory.sol +++ b/contracts/interfaces/V2/IWitnetRequestFactory.sol @@ -2,7 +2,7 @@ pragma solidity >=0.7.0 <0.9.0; -import "../../WitnetBytecodes.sol"; +import "./IWitnetBytecodes.sol"; interface IWitnetRequestFactory { event WitnetRequestTemplateBuilt(address template, bool parameterized); @@ -13,5 +13,5 @@ interface IWitnetRequestFactory { uint16 resultDataMaxSize ) external returns (address template); function class() external view returns (bytes4); - function registry() external view returns (WitnetBytecodes); -} \ No newline at end of file + function registry() external view returns (IWitnetBytecodes); +} diff --git a/contracts/requests/WitnetRequestTemplate.sol b/contracts/requests/WitnetRequestTemplate.sol index f180e5060..34cdd3e3f 100644 --- a/contracts/requests/WitnetRequestTemplate.sol +++ b/contracts/requests/WitnetRequestTemplate.sol @@ -3,15 +3,15 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "../WitnetRequestFactory.sol"; +import "../interfaces/V2/IWitnetRequestFactory.sol"; abstract contract WitnetRequestTemplate { event WitnetRequestBuilt(address indexed request, bytes32 indexed radHash, string[][] args); function class() virtual external view returns (bytes4); - function factory() virtual external view returns (WitnetRequestFactory); - function registry() virtual external view returns (WitnetBytecodes); + function factory() virtual external view returns (IWitnetRequestFactory); + function registry() virtual external view returns (IWitnetBytecodes); function version() virtual external view returns (string memory); function aggregator() virtual external view returns (bytes32); From 089dd5f6ffd0b30473660b573b6a9550e2f2dacb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Mon, 6 Nov 2023 18:03:31 +0100 Subject: [PATCH 03/86] feat: WitnetRequestBoard.{class(), factory(), registry()} --- contracts/WitnetRequestBoard.sol | 29 ++++++------------- .../WitnetRequestBoardTrustableDefault.sol | 4 ++- .../WitnetRequestBoardTrustableBase.sol | 10 +++++-- .../WitnetRequestBoardTrustableBoba.sol | 2 +- .../WitnetRequestBoardTrustableOvm2.sol | 2 +- .../WitnetRequestBoardTrustableReef.sol | 2 +- .../interfaces/V2/IWitnetRequestBoard.sol | 24 +++++++++++++++ 7 files changed, 46 insertions(+), 27 deletions(-) create mode 100644 contracts/interfaces/V2/IWitnetRequestBoard.sol diff --git a/contracts/WitnetRequestBoard.sol b/contracts/WitnetRequestBoard.sol index 315d15c78..9f003e5e9 100644 --- a/contracts/WitnetRequestBoard.sol +++ b/contracts/WitnetRequestBoard.sol @@ -3,33 +3,22 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "./WitnetBytecodes.sol"; -import "./WitnetRequestFactory.sol"; - -import "./interfaces/IWitnetRequestBoardEvents.sol"; -import "./interfaces/IWitnetRequestBoardReporter.sol"; -import "./interfaces/IWitnetRequestBoardRequestor.sol"; -import "./interfaces/IWitnetRequestBoardView.sol"; - -import "./interfaces/IWitnetRequestBoardDeprecating.sol"; +import "./interfaces/V2/IWitnetRequestBoard.sol"; +import "./interfaces/V2/IWitnetRequestFactory.sol"; /// @title Witnet Request Board functionality base contract. /// @author The Witnet Foundation. -abstract contract WitnetRequestBoard is - IWitnetRequestBoardDeprecating, - IWitnetRequestBoardEvents, - IWitnetRequestBoardReporter, - IWitnetRequestBoardRequestor, - IWitnetRequestBoardView +abstract contract WitnetRequestBoard + is + IWitnetRequestBoard { - WitnetRequestFactory immutable public factory; - WitnetBytecodes immutable public registry; - constructor (WitnetRequestFactory _factory) { + IWitnetRequestFactory immutable public override factory; + + constructor (IWitnetRequestFactory _factory) { require( - _factory.class() == type(WitnetRequestFactory).interfaceId, + _factory.class() == type(IWitnetRequestFactory).interfaceId, "WitnetRequestBoard: uncompliant factory" ); factory = _factory; - registry = _factory.registry(); } } \ No newline at end of file diff --git a/contracts/impls/core/WitnetRequestBoardTrustableDefault.sol b/contracts/impls/core/WitnetRequestBoardTrustableDefault.sol index bde65694f..e28bb19c4 100644 --- a/contracts/impls/core/WitnetRequestBoardTrustableDefault.sol +++ b/contracts/impls/core/WitnetRequestBoardTrustableDefault.sol @@ -20,8 +20,10 @@ contract WitnetRequestBoardTrustableDefault { uint256 internal immutable _ESTIMATED_REPORT_RESULT_GAS; + bytes4 public immutable override class = type(WitnetRequestBoard).interfaceId; + constructor( - WitnetRequestFactory _factory, + IWitnetRequestFactory _factory, bool _upgradable, bytes32 _versionTag, uint256 _reportResultGasLimit diff --git a/contracts/impls/core/customs/WitnetRequestBoardTrustableBase.sol b/contracts/impls/core/customs/WitnetRequestBoardTrustableBase.sol index 4a992376f..6417686d0 100644 --- a/contracts/impls/core/customs/WitnetRequestBoardTrustableBase.sol +++ b/contracts/impls/core/customs/WitnetRequestBoardTrustableBase.sol @@ -28,7 +28,7 @@ abstract contract WitnetRequestBoardTrustableBase using Witnet for Witnet.Result; constructor( - WitnetRequestFactory _factory, + IWitnetRequestFactory _factory, bool _upgradable, bytes32 _versionTag, address _currency @@ -42,6 +42,10 @@ abstract contract WitnetRequestBoardTrustableBase WitnetRequestBoard(_factory) {} + function registry() public view virtual override returns (IWitnetBytecodes) { + return factory.registry(); + } + receive() external payable { revert("WitnetRequestBoardTrustableBase: no transfers accepted"); } @@ -540,7 +544,7 @@ abstract contract WitnetRequestBoardTrustableBase { return postRequest( _radHash, - registry.verifyRadonSLA(_slaParams) + registry().verifyRadonSLA(_slaParams) ); } @@ -646,7 +650,7 @@ abstract contract WitnetRequestBoardTrustableBase if (_request.addr != address(0)) { _bytecode = IWitnetRequest(_request.addr).bytecode(); } else if (_request.radHash != bytes32(0)) { - _bytecode = registry.bytecodeOf( + _bytecode = registry().bytecodeOf( _request.radHash, _request.slaHash ); diff --git a/contracts/impls/core/customs/WitnetRequestBoardTrustableBoba.sol b/contracts/impls/core/customs/WitnetRequestBoardTrustableBoba.sol index e6c3a33f4..e917dcb7c 100644 --- a/contracts/impls/core/customs/WitnetRequestBoardTrustableBoba.sol +++ b/contracts/impls/core/customs/WitnetRequestBoardTrustableBoba.sol @@ -33,7 +33,7 @@ contract WitnetRequestBoardTrustableBoba } constructor( - WitnetRequestFactory _factory, + IWitnetRequestFactory _factory, bool _upgradable, bytes32 _versionTag, uint256 _layer2ReportResultGasLimit, diff --git a/contracts/impls/core/customs/WitnetRequestBoardTrustableOvm2.sol b/contracts/impls/core/customs/WitnetRequestBoardTrustableOvm2.sol index 369bd398b..e5b1ae03b 100644 --- a/contracts/impls/core/customs/WitnetRequestBoardTrustableOvm2.sol +++ b/contracts/impls/core/customs/WitnetRequestBoardTrustableOvm2.sol @@ -25,7 +25,7 @@ contract WitnetRequestBoardTrustableOvm2 OVM_GasPriceOracle immutable public gasPriceOracleL1; constructor( - WitnetRequestFactory _factory, + IWitnetRequestFactory _factory, bool _upgradable, bytes32 _versionTag, uint256 _reportResultGasLimit diff --git a/contracts/impls/core/customs/WitnetRequestBoardTrustableReef.sol b/contracts/impls/core/customs/WitnetRequestBoardTrustableReef.sol index f99ec4628..f3d688928 100644 --- a/contracts/impls/core/customs/WitnetRequestBoardTrustableReef.sol +++ b/contracts/impls/core/customs/WitnetRequestBoardTrustableReef.sol @@ -18,7 +18,7 @@ contract WitnetRequestBoardTrustableReef WitnetRequestBoardTrustableDefault { constructor( - WitnetRequestFactory _factory, + IWitnetRequestFactory _factory, bool _upgradable, bytes32 _versionTag, uint256 _reportResultGasLimit diff --git a/contracts/interfaces/V2/IWitnetRequestBoard.sol b/contracts/interfaces/V2/IWitnetRequestBoard.sol new file mode 100644 index 000000000..140441018 --- /dev/null +++ b/contracts/interfaces/V2/IWitnetRequestBoard.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.7.0 <0.9.0; + +import "../IWitnetRequestBoardDeprecating.sol"; +import "../IWitnetRequestBoardEvents.sol"; +import "../IWitnetRequestBoardReporter.sol"; +import "../IWitnetRequestBoardRequestor.sol"; +import "../IWitnetRequestBoardView.sol"; + +import "./IWitnetRequestFactory.sol"; + +abstract contract IWitnetRequestBoard + is + IWitnetRequestBoardDeprecating, + IWitnetRequestBoardEvents, + IWitnetRequestBoardReporter, + IWitnetRequestBoardRequestor, + IWitnetRequestBoardView +{ + function class() virtual external view returns (bytes4); + function factory() virtual external view returns (IWitnetRequestFactory); + function registry() virtual external view returns (IWitnetBytecodes); +} From 478ab18c1ea11f62e47940b9015a069cf55a2cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Mon, 6 Nov 2023 18:06:15 +0100 Subject: [PATCH 04/86] refactor: WitnetRandomness --- contracts/impls/apps/WitnetRandomnessProxiable.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/impls/apps/WitnetRandomnessProxiable.sol b/contracts/impls/apps/WitnetRandomnessProxiable.sol index 678c3dd8c..12a11c13b 100644 --- a/contracts/impls/apps/WitnetRandomnessProxiable.sol +++ b/contracts/impls/apps/WitnetRandomnessProxiable.sol @@ -68,8 +68,8 @@ contract WitnetRandomnessProxiable || address(_wrb).supportsInterface(type(WitnetRequestBoard).interfaceId), "WitnetRandomnessProxiable: uncompliant request board" ); - WitnetBytecodes _registry = witnet().registry(); - WitnetRequestFactory _factory = witnet().factory(); + IWitnetRequestFactory _factory = witnet().factory(); + IWitnetBytecodes _registry = _factory.registry(); { // Build own Witnet Randomness Request: bytes32[] memory _retrievals = new bytes32[](1); From c9ca54d8ed46adebf50f7b6c41da596567a8f553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Mon, 6 Nov 2023 18:07:57 +0100 Subject: [PATCH 05/86] refactor: WitnetFeeds, WitnetPriceFeeds --- contracts/WitnetFeeds.sol | 6 ++---- contracts/WitnetPriceFeeds.sol | 2 +- .../impls/apps/WitnetPriceFeedsUpgradable.sol | 20 +++++++++++-------- contracts/interfaces/V2/IWitnetFeeds.sol | 7 ++++--- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/contracts/WitnetFeeds.sol b/contracts/WitnetFeeds.sol index 616b25489..594a59615 100644 --- a/contracts/WitnetFeeds.sol +++ b/contracts/WitnetFeeds.sol @@ -15,19 +15,17 @@ abstract contract WitnetFeeds IWitnetFeedsEvents { WitnetV2.RadonDataTypes immutable public override dataType; - WitnetBytecodes immutable public override registry; - WitnetRequestBoard immutable public override witnet; + IWitnetRequestBoard immutable public override witnet; bytes32 immutable internal __prefix; constructor( - WitnetRequestBoard _wrb, + IWitnetRequestBoard _wrb, WitnetV2.RadonDataTypes _dataType, string memory _prefix ) { witnet = _wrb; - registry = witnet.registry(); dataType = _dataType; __prefix = Witnet.toBytes32(bytes(_prefix)); } diff --git a/contracts/WitnetPriceFeeds.sol b/contracts/WitnetPriceFeeds.sol index 60fda9612..ec14897e9 100644 --- a/contracts/WitnetPriceFeeds.sol +++ b/contracts/WitnetPriceFeeds.sol @@ -14,7 +14,7 @@ abstract contract WitnetPriceFeeds IWitnetPriceSolverDeployer, WitnetFeeds { - constructor(WitnetRequestBoard _wrb) + constructor(IWitnetRequestBoard _wrb) WitnetFeeds( _wrb, WitnetV2.RadonDataTypes.Integer, diff --git a/contracts/impls/apps/WitnetPriceFeedsUpgradable.sol b/contracts/impls/apps/WitnetPriceFeedsUpgradable.sol index 515a640c9..c97da1925 100644 --- a/contracts/impls/apps/WitnetPriceFeedsUpgradable.sol +++ b/contracts/impls/apps/WitnetPriceFeedsUpgradable.sol @@ -22,7 +22,7 @@ contract WitnetPriceFeedsUpgradable using WitnetV2 for WitnetV2.RadonSLA; constructor( - WitnetRequestBoard _wrb, + IWitnetRequestBoard _wrb, bool _upgradable, bytes32 _version ) @@ -174,7 +174,7 @@ contract WitnetPriceFeedsUpgradable public view returns (WitnetV2.RadonSLA memory) { - return registry.lookupRadonSLA(__storage().defaultSlaHash); + return registry().lookupRadonSLA(__storage().defaultSlaHash); } function estimateUpdateBaseFee(bytes4, uint256 _evmGasPrice, uint256) @@ -253,7 +253,7 @@ contract WitnetPriceFeedsUpgradable __record.radHash != 0, "WitnetPriceFeedsUpgradable: no RAD hash" ); - return registry.bytecodeOf( + return registry().bytecodeOf( __record.radHash, __storage().defaultSlaHash ); @@ -270,13 +270,17 @@ contract WitnetPriceFeedsUpgradable override external view returns (WitnetV2.RadonRetrieval[] memory _retrievals) { - bytes32[] memory _hashes = registry.lookupRadonRequestSources(lookupRadHash(feedId)); + bytes32[] memory _hashes = registry().lookupRadonRequestSources(lookupRadHash(feedId)); _retrievals = new WitnetV2.RadonRetrieval[](_hashes.length); for (uint _ix = 0; _ix < _retrievals.length; _ix ++) { - _retrievals[_ix] = registry.lookupRadonRetrieval(_hashes[_ix]); + _retrievals[_ix] = registry().lookupRadonRetrieval(_hashes[_ix]); } } + function registry() public view virtual override returns (IWitnetBytecodes) { + return witnet.registry(); + } + function requestUpdate(bytes4 feedId) external payable virtual override @@ -291,7 +295,7 @@ contract WitnetPriceFeedsUpgradable returns (uint256 _usedFunds) { require( - registry.lookupRadonSLA(_slaHash).equalOrGreaterThan(defaultRadonSLA()), + registry().lookupRadonSLA(_slaHash).equalOrGreaterThan(defaultRadonSLA()), "WitnetPriceFeedsUpgradable: unsecure update" ); return _requestUpdate(feedId, _slaHash); @@ -385,7 +389,7 @@ contract WitnetPriceFeedsUpgradable override public onlyOwner { - __storage().defaultSlaHash = registry.verifyRadonSLA(sla); + __storage().defaultSlaHash = registry().verifyRadonSLA(sla); } function settleFeedRequest(string calldata caption, bytes32 radHash) @@ -393,7 +397,7 @@ contract WitnetPriceFeedsUpgradable onlyOwner { require( - registry.lookupRadonRequestResultDataType(radHash) == dataType, + registry().lookupRadonRequestResultDataType(radHash) == dataType, "WitnetPriceFeedsUpgradable: bad result data type" ); bytes4 feedId = hash(caption); diff --git a/contracts/interfaces/V2/IWitnetFeeds.sol b/contracts/interfaces/V2/IWitnetFeeds.sol index 56dfa705c..b1300ff4f 100644 --- a/contracts/interfaces/V2/IWitnetFeeds.sol +++ b/contracts/interfaces/V2/IWitnetFeeds.sol @@ -2,13 +2,14 @@ pragma solidity >=0.8.0 <0.9.0; -import "../../WitnetRequestBoard.sol"; +import "./IWitnetBytecodes.sol"; +import "./IWitnetRequestBoard.sol"; interface IWitnetFeeds { function dataType() external view returns (WitnetV2.RadonDataTypes); function prefix() external view returns (string memory); - function registry() external view returns (WitnetBytecodes); - function witnet() external view returns (WitnetRequestBoard); + function registry() external view returns (IWitnetBytecodes); + function witnet() external view returns (IWitnetRequestBoard); function defaultRadonSLA() external view returns (WitnetV2.RadonSLA memory); From 3f820b9c346284c9ce78867459612fcb32385eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Mon, 6 Nov 2023 18:47:16 +0100 Subject: [PATCH 06/86] chore: make migration script work w/ latest refactorings --- contracts/WitnetFeeds.sol | 3 --- contracts/WitnetPriceFeeds.sol | 3 +-- contracts/WitnetRequestBoard.sol | 13 +------------ .../impls/apps/WitnetPriceFeedsUpgradable.sol | 12 ++++++++++-- .../impls/core/WitnetBytecodesDefault.sol | 2 +- .../WitnetRequestBoardTrustableDefault.sol | 2 -- .../WitnetRequestBoardTrustableBase.sol | 19 ++++++++++++++----- 7 files changed, 27 insertions(+), 27 deletions(-) diff --git a/contracts/WitnetFeeds.sol b/contracts/WitnetFeeds.sol index 594a59615..39c4be992 100644 --- a/contracts/WitnetFeeds.sol +++ b/contracts/WitnetFeeds.sol @@ -15,17 +15,14 @@ abstract contract WitnetFeeds IWitnetFeedsEvents { WitnetV2.RadonDataTypes immutable public override dataType; - IWitnetRequestBoard immutable public override witnet; bytes32 immutable internal __prefix; constructor( - IWitnetRequestBoard _wrb, WitnetV2.RadonDataTypes _dataType, string memory _prefix ) { - witnet = _wrb; dataType = _dataType; __prefix = Witnet.toBytes32(bytes(_prefix)); } diff --git a/contracts/WitnetPriceFeeds.sol b/contracts/WitnetPriceFeeds.sol index ec14897e9..930dde290 100644 --- a/contracts/WitnetPriceFeeds.sol +++ b/contracts/WitnetPriceFeeds.sol @@ -14,9 +14,8 @@ abstract contract WitnetPriceFeeds IWitnetPriceSolverDeployer, WitnetFeeds { - constructor(IWitnetRequestBoard _wrb) + constructor() WitnetFeeds( - _wrb, WitnetV2.RadonDataTypes.Integer, "Price-" ) diff --git a/contracts/WitnetRequestBoard.sol b/contracts/WitnetRequestBoard.sol index 9f003e5e9..6e146857e 100644 --- a/contracts/WitnetRequestBoard.sol +++ b/contracts/WitnetRequestBoard.sol @@ -4,21 +4,10 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; import "./interfaces/V2/IWitnetRequestBoard.sol"; -import "./interfaces/V2/IWitnetRequestFactory.sol"; /// @title Witnet Request Board functionality base contract. /// @author The Witnet Foundation. abstract contract WitnetRequestBoard is IWitnetRequestBoard -{ - IWitnetRequestFactory immutable public override factory; - - constructor (IWitnetRequestFactory _factory) { - require( - _factory.class() == type(IWitnetRequestFactory).interfaceId, - "WitnetRequestBoard: uncompliant factory" - ); - factory = _factory; - } -} \ No newline at end of file +{} \ No newline at end of file diff --git a/contracts/impls/apps/WitnetPriceFeedsUpgradable.sol b/contracts/impls/apps/WitnetPriceFeedsUpgradable.sol index c97da1925..7647677c0 100644 --- a/contracts/impls/apps/WitnetPriceFeedsUpgradable.sol +++ b/contracts/impls/apps/WitnetPriceFeedsUpgradable.sol @@ -4,6 +4,7 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; import "../../WitnetPriceFeeds.sol"; +import "../../WitnetRequestBoard.sol"; import "../../data/WitnetPriceFeedsData.sol"; import "../../impls/WitnetUpgradableBase.sol"; @@ -20,19 +21,26 @@ contract WitnetPriceFeedsUpgradable { using Witnet for Witnet.Result; using WitnetV2 for WitnetV2.RadonSLA; + + IWitnetRequestBoard immutable public override witnet; constructor( IWitnetRequestBoard _wrb, bool _upgradable, bytes32 _version ) - WitnetPriceFeeds(_wrb) WitnetUpgradableBase( _upgradable, _version, "io.witnet.proxiable.router" ) - {} + { + require( + _wrb.class() == type(WitnetRequestBoard).interfaceId, + "WitnetPriceFeedsUpgradable: uncompliant request board" + ); + witnet = _wrb; + } // solhint-disable-next-line payable-fallback fallback() override external { diff --git a/contracts/impls/core/WitnetBytecodesDefault.sol b/contracts/impls/core/WitnetBytecodesDefault.sol index 29a8da4b7..94f6723a4 100644 --- a/contracts/impls/core/WitnetBytecodesDefault.sol +++ b/contracts/impls/core/WitnetBytecodesDefault.sol @@ -33,7 +33,7 @@ contract WitnetBytecodesDefault using WitnetEncodingLib for WitnetV2.RadonSLA; using WitnetEncodingLib for WitnetV2.RadonDataTypes; - bytes4 public immutable override class = type(IWitnetBytecodes).interfaceId; + bytes4 public immutable override class = type(WitnetBytecodes).interfaceId; constructor( bool _upgradable, diff --git a/contracts/impls/core/WitnetRequestBoardTrustableDefault.sol b/contracts/impls/core/WitnetRequestBoardTrustableDefault.sol index e28bb19c4..d51221db4 100644 --- a/contracts/impls/core/WitnetRequestBoardTrustableDefault.sol +++ b/contracts/impls/core/WitnetRequestBoardTrustableDefault.sol @@ -20,8 +20,6 @@ contract WitnetRequestBoardTrustableDefault { uint256 internal immutable _ESTIMATED_REPORT_RESULT_GAS; - bytes4 public immutable override class = type(WitnetRequestBoard).interfaceId; - constructor( IWitnetRequestFactory _factory, bool _upgradable, diff --git a/contracts/impls/core/customs/WitnetRequestBoardTrustableBase.sol b/contracts/impls/core/customs/WitnetRequestBoardTrustableBase.sol index 6417686d0..8fcd213d7 100644 --- a/contracts/impls/core/customs/WitnetRequestBoardTrustableBase.sol +++ b/contracts/impls/core/customs/WitnetRequestBoardTrustableBase.sol @@ -5,11 +5,12 @@ pragma experimental ABIEncoderV2; import "../../WitnetUpgradableBase.sol"; import "../../../WitnetRequestBoard.sol"; +import "../../../WitnetRequestFactory.sol"; + import "../../../data/WitnetBoardDataACLs.sol"; import "../../../interfaces/IWitnetRequestBoardAdminACLs.sol"; -import "../../../patterns/Payable.sol"; - import "../../../libs/WitnetErrorsLib.sol"; +import "../../../patterns/Payable.sol"; /// @title Witnet Request Board "trustable" base implementation contract. /// @notice Contract to bridge requests to Witnet Decentralized Oracle Network. @@ -26,6 +27,9 @@ abstract contract WitnetRequestBoardTrustableBase { using Witnet for bytes; using Witnet for Witnet.Result; + + bytes4 public immutable override class = type(WitnetRequestBoard).interfaceId; + IWitnetRequestFactory immutable public override factory; constructor( IWitnetRequestFactory _factory, @@ -39,8 +43,13 @@ abstract contract WitnetRequestBoardTrustableBase _versionTag, "io.witnet.proxiable.board" ) - WitnetRequestBoard(_factory) - {} + { + require( + _factory.class() == type(WitnetRequestFactory).interfaceId, + "WitnetRequestBoard: uncompliant factory" + ); + factory = _factory; + } function registry() public view virtual override returns (IWitnetBytecodes) { return factory.registry(); @@ -838,4 +847,4 @@ abstract contract WitnetRequestBoardTrustableBase // Request data won't be needed anymore, so it can just get deleted right now: delete _query.request; } -} +} \ No newline at end of file From d98ea965408557fd5e2c0c072e1c50300d373eac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Mon, 6 Nov 2023 18:48:57 +0100 Subject: [PATCH 07/86] chore: bump package version to 2.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fb87efad1..6923e900d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "witnet-solidity-bridge", - "version": "0.7.16", + "version": "2.0.0", "description": "Witnet Solidity Bridge contracts for EVM-compatible chains", "main": "", "scripts": { From 2290209070b2fe79413cfc19086ec2b69c7893bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 9 Nov 2023 08:08:24 +0100 Subject: [PATCH 08/86] feat: counter-factually bind core artifacts --- contracts/WitnetBytecodes.sol | 10 +- contracts/{requests => }/WitnetRequest.sol | 0 contracts/WitnetRequestBoard.sol | 11 +- contracts/WitnetRequestFactory.sol | 6 +- .../{requests => }/WitnetRequestTemplate.sol | 7 +- contracts/core/WitnetDeployer.sol | 86 +++++++++ contracts/{impls => core}/WitnetProxy.sol | 20 +- .../{impls => core}/WitnetUpgradableBase.sol | 26 +-- contracts/data/WitnetRequestFactoryData.sol | 4 +- contracts/interfaces/IWitnetRequestBoard.sol | 177 ++++++++++++++++++ .../IWitnetRequestBoardDeprecating.sol | 41 ---- .../interfaces/IWitnetRequestBoardEvents.sol | 17 -- .../IWitnetRequestBoardRequestor.sol | 73 -------- .../interfaces/IWitnetRequestBoardView.sol | 75 -------- contracts/interfaces/V2/IWitnetBytecodes.sol | 13 +- .../interfaces/V2/IWitnetBytecodesErrors.sol | 10 - .../interfaces/V2/IWitnetBytecodesEvents.sol | 11 -- .../interfaces/V2/IWitnetRequestBoard.sol | 24 --- .../interfaces/V2/IWitnetRequestFactory.sol | 9 +- contracts/libs/Create3.sol | 113 +++++++++++ contracts/patterns/Create2Factory.sol | 44 ----- contracts/patterns/Destructible.sol | 8 - 22 files changed, 432 insertions(+), 353 deletions(-) rename contracts/{requests => }/WitnetRequest.sol (100%) rename contracts/{requests => }/WitnetRequestTemplate.sol (86%) create mode 100644 contracts/core/WitnetDeployer.sol rename contracts/{impls => core}/WitnetProxy.sol (87%) rename contracts/{impls => core}/WitnetUpgradableBase.sol (78%) create mode 100644 contracts/interfaces/IWitnetRequestBoard.sol delete mode 100644 contracts/interfaces/IWitnetRequestBoardDeprecating.sol delete mode 100644 contracts/interfaces/IWitnetRequestBoardEvents.sol delete mode 100644 contracts/interfaces/IWitnetRequestBoardRequestor.sol delete mode 100644 contracts/interfaces/IWitnetRequestBoardView.sol delete mode 100644 contracts/interfaces/V2/IWitnetBytecodesErrors.sol delete mode 100644 contracts/interfaces/V2/IWitnetBytecodesEvents.sol delete mode 100644 contracts/interfaces/V2/IWitnetRequestBoard.sol create mode 100644 contracts/libs/Create3.sol delete mode 100644 contracts/patterns/Create2Factory.sol delete mode 100644 contracts/patterns/Destructible.sol diff --git a/contracts/WitnetBytecodes.sol b/contracts/WitnetBytecodes.sol index 3752d0dbe..f96fc4c10 100644 --- a/contracts/WitnetBytecodes.sol +++ b/contracts/WitnetBytecodes.sol @@ -4,12 +4,10 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; import "./interfaces/V2/IWitnetBytecodes.sol"; -import "./interfaces/V2/IWitnetBytecodesErrors.sol"; -import "./interfaces/V2/IWitnetBytecodesEvents.sol"; abstract contract WitnetBytecodes is - IWitnetBytecodes, - IWitnetBytecodesErrors, - IWitnetBytecodesEvents -{} \ No newline at end of file + IWitnetBytecodes +{ + function class() virtual external view returns (bytes4); +} \ No newline at end of file diff --git a/contracts/requests/WitnetRequest.sol b/contracts/WitnetRequest.sol similarity index 100% rename from contracts/requests/WitnetRequest.sol rename to contracts/WitnetRequest.sol diff --git a/contracts/WitnetRequestBoard.sol b/contracts/WitnetRequestBoard.sol index 6e146857e..8f47e1ba5 100644 --- a/contracts/WitnetRequestBoard.sol +++ b/contracts/WitnetRequestBoard.sol @@ -1,13 +1,18 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.7.0 <0.9.0; -pragma experimental ABIEncoderV2; -import "./interfaces/V2/IWitnetRequestBoard.sol"; +import "./WitnetBytecodes.sol"; +import "./WitnetRequestFactory.sol"; +import "./interfaces/IWitnetRequestBoard.sol"; /// @title Witnet Request Board functionality base contract. /// @author The Witnet Foundation. abstract contract WitnetRequestBoard is IWitnetRequestBoard -{} \ No newline at end of file +{ + function class() virtual external view returns (bytes4); + function factory() virtual external view returns (WitnetRequestFactory); + function registry() virtual external view returns (WitnetBytecodes); +} \ No newline at end of file diff --git a/contracts/WitnetRequestFactory.sol b/contracts/WitnetRequestFactory.sol index 221e74134..83bcf5a77 100644 --- a/contracts/WitnetRequestFactory.sol +++ b/contracts/WitnetRequestFactory.sol @@ -3,9 +3,13 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; +import "./WitnetBytecodes.sol"; import "./interfaces/V2/IWitnetRequestFactory.sol"; abstract contract WitnetRequestFactory is IWitnetRequestFactory -{} \ No newline at end of file +{ + function class() virtual external view returns (bytes4); + function registry() virtual external view returns (WitnetBytecodes); +} \ No newline at end of file diff --git a/contracts/requests/WitnetRequestTemplate.sol b/contracts/WitnetRequestTemplate.sol similarity index 86% rename from contracts/requests/WitnetRequestTemplate.sol rename to contracts/WitnetRequestTemplate.sol index 34cdd3e3f..54a3d9a3a 100644 --- a/contracts/requests/WitnetRequestTemplate.sol +++ b/contracts/WitnetRequestTemplate.sol @@ -3,15 +3,16 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "../interfaces/V2/IWitnetRequestFactory.sol"; +import "./WitnetBytecodes.sol"; +import "./WitnetRequestFactory.sol"; abstract contract WitnetRequestTemplate { event WitnetRequestBuilt(address indexed request, bytes32 indexed radHash, string[][] args); function class() virtual external view returns (bytes4); - function factory() virtual external view returns (IWitnetRequestFactory); - function registry() virtual external view returns (IWitnetBytecodes); + function factory() virtual external view returns (WitnetRequestFactory); + function registry() virtual external view returns (WitnetBytecodes); function version() virtual external view returns (string memory); function aggregator() virtual external view returns (bytes32); diff --git a/contracts/core/WitnetDeployer.sol b/contracts/core/WitnetDeployer.sol new file mode 100644 index 000000000..99250caf4 --- /dev/null +++ b/contracts/core/WitnetDeployer.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.8.0 <0.9.0; + +import "./WitnetProxy.sol"; +import "../libs/Create3.sol"; + +/// @notice WitnetDeployer contract used both as CREATE2 (EIP-1014) factory for Witnet artifacts, +/// @notice and CREATE3 (EIP-3171) factory for Witnet proxies. +/// @author Guillermo Díaz + +contract WitnetDeployer { + + /// @notice Use given `_initCode` and `_salt` to deploy a contract into a deterministic address. + /// @dev The address of deployed address will be determined by both the `_initCode` and the `_salt`, but not the address + /// @dev nor the nonce of the caller (i.e. see EIP-1014). + /// @param _initCode Creation code, including construction logic and input parameters. + /// @param _salt Arbitrary value to modify resulting address. + /// @return _deployed Just deployed contract address. + function deploy(bytes memory _initCode, bytes32 _salt) + external + returns (address _deployed) + { + _deployed = determineAddr(_initCode, _salt); + if (_deployed.code.length == 0) { + // address _justDeployed; + assembly { + _deployed := create2(0, add(_initCode, 0x20), mload(_initCode), _salt) + } + require(_deployed != address(0), "WitnetDeployer: deployment failed"); + } + } + + /// @notice Determine counter-factual address of the contract that would be deployed by the given `_initCode` and a `_salt`. + /// @param _initCode Creation code, including construction logic and input parameters. + /// @param _salt Arbitrary value to modify resulting address. + /// @return Deterministic contract address. + function determineAddr(bytes memory _initCode, bytes32 _salt) + public view + returns (address) + { + return address( + uint160(uint(keccak256( + abi.encodePacked( + bytes1(0xff), + address(this), + _salt, + keccak256(_initCode) + ) + ))) + ); + } + + function determineProxyAddr(bytes32 _salt) + public view + returns (address) + { + return Create3.determineAddr(_salt); + } + + function proxify(bytes32 _proxySalt, address _firstImplementation, bytes memory _initData) + external + returns (WitnetProxy) + { + address _proxyAddr = determineProxyAddr(_proxySalt); + if (_proxyAddr.code.length == 0) { + // deploy the WitnetProxy + Create3.deploy(_proxySalt, type(WitnetProxy).creationCode); + // settle first implementation address, + WitnetProxy(payable(_proxyAddr)).upgradeTo( + _firstImplementation, + // and initialize it, providing + abi.encode( + // the owner (i.e. the caller of this function) + msg.sender, + // and some (optional) initialization data + _initData + ) + ); + return WitnetProxy(payable(_proxyAddr)); + } else { + revert("WitnetDeployer: already proxified"); + } + } + +} \ No newline at end of file diff --git a/contracts/impls/WitnetProxy.sol b/contracts/core/WitnetProxy.sol similarity index 87% rename from contracts/impls/WitnetProxy.sol rename to contracts/core/WitnetProxy.sol index d640592a8..fb5249e1d 100644 --- a/contracts/impls/WitnetProxy.sol +++ b/contracts/core/WitnetProxy.sol @@ -6,7 +6,7 @@ pragma experimental ABIEncoderV2; import "../patterns/Upgradeable.sol"; /// @title WitnetProxy: upgradable delegate-proxy contract. -/// @author The Witnet Foundation. +/// @author Guillermo Díaz contract WitnetProxy { /// Event emitted every time the implementation gets updated. @@ -75,7 +75,7 @@ contract WitnetProxy { msg.sender ) ); - require(_wasCalled, "WitnetProxy: not compliant"); + require(_wasCalled, "WitnetProxy: uncompliant implementation"); require(abi.decode(_result, (bool)), "WitnetProxy: not authorized"); require( Upgradeable(_oldImplementation).proxiableUUID() == Upgradeable(_newImplementation).proxiableUUID(), @@ -84,16 +84,26 @@ contract WitnetProxy { } // Initialize new implementation within proxy-context storage: - (bool _wasInitialized,) = _newImplementation.delegatecall( + (bool _wasInitialized, bytes memory _returnData) = _newImplementation.delegatecall( abi.encodeWithSignature( "initialize(bytes)", _initData ) ); - require(_wasInitialized, "WitnetProxy: unable to initialize"); + if (!_wasInitialized) { + if (_returnData.length < 68) { + revert("WitnetProxy: initialization failed"); + } else { + assembly { + _returnData := add(_returnData, 0x04) + } + revert(abi.decode(_returnData, (string))); + } + } // If all checks and initialization pass, update implementation address: __proxySlot().implementation = _newImplementation; + emit Upgraded(_newImplementation); // Asserts new implementation complies w/ minimal implementation of Upgradeable interface: @@ -101,7 +111,7 @@ contract WitnetProxy { return _isUpgradable; } catch { - revert ("WitnetProxy: not compliant"); + revert ("WitnetProxy: uncompliant implementation"); } } diff --git a/contracts/impls/WitnetUpgradableBase.sol b/contracts/core/WitnetUpgradableBase.sol similarity index 78% rename from contracts/impls/WitnetUpgradableBase.sol rename to contracts/core/WitnetUpgradableBase.sol index 5d6bc17a6..57b316272 100644 --- a/contracts/impls/WitnetUpgradableBase.sol +++ b/contracts/core/WitnetUpgradableBase.sol @@ -4,7 +4,6 @@ pragma solidity >=0.8.0 <0.9.0; -import "../patterns/ERC165.sol"; import "../patterns/Ownable2Step.sol"; import "../patterns/ReentrancyGuard.sol"; import "../patterns/Upgradeable.sol"; @@ -12,20 +11,16 @@ import "../patterns/Upgradeable.sol"; import "./WitnetProxy.sol"; /// @title Witnet Request Board base contract, with an Upgradeable (and Destructible) touch. -/// @author The Witnet Foundation. +/// @author Guillermo Díaz abstract contract WitnetUpgradableBase is - ERC165, Ownable2Step, Upgradeable, ReentrancyGuard { bytes32 internal immutable _WITNET_UPGRADABLE_VERSION; - error AlreadyUpgraded(address implementation); - error NotCompliant(bytes4 interfaceId); - error NotUpgradable(address self); - error OnlyOwner(address owner); + address public immutable deployer = msg.sender; constructor( bool _upgradable, @@ -43,22 +38,7 @@ abstract contract WitnetUpgradableBase revert("WitnetUpgradableBase: not implemented"); } - - // ================================================================================================================ - // --- Overrides IERC165 interface -------------------------------------------------------------------------------- - - /// @dev See {IERC165-supportsInterface}. - function supportsInterface(bytes4 _interfaceId) - public view - virtual override - returns (bool) - { - return _interfaceId == type(Ownable2Step).interfaceId - || _interfaceId == type(Upgradeable).interfaceId - || super.supportsInterface(_interfaceId); - } - - + // ================================================================================================================ // --- Overrides 'Proxiable' -------------------------------------------------------------------------------------- diff --git a/contracts/data/WitnetRequestFactoryData.sol b/contracts/data/WitnetRequestFactoryData.sol index daa0e3d08..c2111fd30 100644 --- a/contracts/data/WitnetRequestFactoryData.sol +++ b/contracts/data/WitnetRequestFactoryData.sol @@ -3,7 +3,7 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "../requests/WitnetRequest.sol"; +import "../WitnetRequest.sol"; contract WitnetRequestFactoryData { @@ -37,7 +37,7 @@ contract WitnetRequestFactoryData { /// @notice Aggregator reducer hash. bytes32 aggregator; /// @notice Parent IWitnetRequestFactory from which this template was built. - IWitnetRequestFactory factory; + WitnetRequestFactory factory; /// Whether any of the sources is parameterized. bool parameterized; /// @notice Tally reducer hash. diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol new file mode 100644 index 000000000..a4a61fcbf --- /dev/null +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.7.0 <0.9.0; + +import "../libs/WitnetV2.sol"; + +interface IWitnetRequestBoard { + + /// Emitted when a Witnet Data Request is posted to the WRB. + event PostedRequest(uint256 queryId, address from); + + /// Emitted when a Witnet-solved result is reported to the WRB. + event PostedResult(uint256 queryId, address from); + + /// Emitted when all data related to given query is deleted from the WRB. + event DeletedQuery(uint256 queryId, address from); + + + /// =============================================================================================================== + /// --- Requestor interface --------------------------------------------------------------------------------------- + + /// @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) external view returns (Witnet.ResultStatus); + + /// @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 view returns (Witnet.ResultError memory); + + /// @notice Retrieves a copy of all Witnet-provided data related to a previously posted request, removing the whole query from the WRB 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 returns (Witnet.Response memory); + + /// @notice Requests the execution of the given Witnet Data Request in expectation that it will be relayed and solved by the Witnet DON. + /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided + /// @notice result to this request. + /// @dev Fails if: + /// @dev - provided reward is too low. + /// @dev - provided script is zero address. + /// @dev - provided script bytecode is empty. + /// @param addr The address of the IWitnetRequest contract that can provide the actual Data Request bytecode. + /// @return _queryId Unique query identifier. + function postRequest(IWitnetRequest addr) 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 the Witnet DON. + /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided + /// @notice result to this request. + /// @dev Fails if, provided reward is too low. + /// @param radHash The RAD hash of the data request to be solved by Witnet. + /// @param slaHash The SLA hash of the data request to be solved by Witnet. + /// @return _queryId Unique query identifier. + function postRequest(bytes32 radHash, bytes32 slaHash) 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 the Witnet DON. + /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided + /// @notice result to this request. + /// @dev Fails if, provided reward is too low. + /// @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); + + /// @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 + /// @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; + + + /// =============================================================================================================== + /// --- Reader interface ------------------------------------------------------------------------------------------ + + /// @notice 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); + + /// @notice Returns next query id to be generated by the Witnet Request Board. + function getNextQueryId() external view returns (uint256); + + /// @notice Gets the whole Query data contents, if any, no matter its current status. + function getQueryData(uint256 _queryId) external view returns (Witnet.Query memory); + + /// @notice Gets current status of given query. + function getQueryStatus(uint256 _queryId) external view returns (Witnet.QueryStatus); + + /// @notice 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) external view returns (Witnet.Request memory); + + /// @notice 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 view returns (bytes memory); + + /// @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 view returns (uint256); + + /// @notice Retrieves the reward currently set for the referred query. + /// @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 view returns (uint256); + + /// @notice Retrieves the whole `Witnet.Response` record referred to a previously posted Witnet Data Request. + /// @dev Fails if the `_queryId` is not in 'Reported' status. + /// @param _queryId The unique query identifier. + function readResponse(uint256 _queryId) external view returns (Witnet.Response memory); + + /// @notice Retrieves error codes of given query. + /// @dev Fails if the `_queryId` is not in 'Reported' status, or if no actual error. + /// @param _queryId The unique query identifier. + function readResponseDrTxHash(uint256 _queryId) external view returns (bytes32); + + /// @notice 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 view returns (address); + + /// @notice 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 view returns (Witnet.Result memory); + + /// @notice 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 view returns (uint256); + + + /// =============================================================================================================== + /// --- Deprecating funcionality v0.5 ----------------------------------------------------------------------------- + + /// Tell if a Witnet.Result is successful. + /// @param _result An instance of Witnet.Result. + /// @return `true` if successful, `false` if errored. + function isOk(Witnet.Result memory _result) external pure returns (bool); + + /// Decode a bytes value from a Witnet.Result as a `bytes32` value. + /// @param _result An instance of Witnet.Result. + /// @return The `bytes32` decoded from the Witnet.Result. + function asBytes32(Witnet.Result memory _result) external pure returns (bytes32); + + /// Generate a suitable error message for a member of `Witnet.ResultErrorCodes` and its corresponding arguments. + /// @dev WARN: Note that client contracts should wrap this function into a try-catch foreseing potential errors generated in this function + /// @param _result An instance of `Witnet.Result`. + /// @return A tuple containing the `CBORValue.Error memory` decoded from the `Witnet.Result`, plus a loggable error message. + function asErrorMessage(Witnet.Result memory _result) external pure returns (Witnet.ResultErrorCodes, string memory); + + /// Decode a natural numeric value from a Witnet.Result as a `uint` value. + /// @param _result An instance of Witnet.Result. + /// @return The `uint` decoded from the Witnet.Result. + function asUint64(Witnet.Result memory _result) external pure returns (uint64); + + /// Decode raw CBOR 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) external pure returns (Witnet.Result memory); + +} diff --git a/contracts/interfaces/IWitnetRequestBoardDeprecating.sol b/contracts/interfaces/IWitnetRequestBoardDeprecating.sol deleted file mode 100644 index 7e9a6cd09..000000000 --- a/contracts/interfaces/IWitnetRequestBoardDeprecating.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.7.0 <0.9.0; -pragma experimental ABIEncoderV2; - -import "../libs/Witnet.sol"; - -/// @title Witnet Request Board info interface. -/// @author The Witnet Foundation. -interface IWitnetRequestBoardDeprecating { - - /// =============================================================================================================== - /// --- Deprecating funcionality v0.5 ----------------------------------------------------------------------------- - - /// Tell if a Witnet.Result is successful. - /// @param _result An instance of Witnet.Result. - /// @return `true` if successful, `false` if errored. - function isOk(Witnet.Result memory _result) external pure returns (bool); - - /// Decode a bytes value from a Witnet.Result as a `bytes32` value. - /// @param _result An instance of Witnet.Result. - /// @return The `bytes32` decoded from the Witnet.Result. - function asBytes32(Witnet.Result memory _result) external pure returns (bytes32); - - /// Generate a suitable error message for a member of `Witnet.ResultErrorCodes` and its corresponding arguments. - /// @dev WARN: Note that client contracts should wrap this function into a try-catch foreseing potential errors generated in this function - /// @param _result An instance of `Witnet.Result`. - /// @return A tuple containing the `CBORValue.Error memory` decoded from the `Witnet.Result`, plus a loggable error message. - function asErrorMessage(Witnet.Result memory _result) external pure returns (Witnet.ResultErrorCodes, string memory); - - /// Decode a natural numeric value from a Witnet.Result as a `uint` value. - /// @param _result An instance of Witnet.Result. - /// @return The `uint` decoded from the Witnet.Result. - function asUint64(Witnet.Result memory _result) external pure returns (uint64); - - /// Decode raw CBOR 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) external pure returns (Witnet.Result memory); - -} diff --git a/contracts/interfaces/IWitnetRequestBoardEvents.sol b/contracts/interfaces/IWitnetRequestBoardEvents.sol deleted file mode 100644 index 54eb31ab4..000000000 --- a/contracts/interfaces/IWitnetRequestBoardEvents.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.7.0 <0.9.0; - -/// @title Witnet Request Board emitting events interface. -/// @author The Witnet Foundation. -interface IWitnetRequestBoardEvents { - - /// Emitted when a Witnet Data Request is posted to the WRB. - event PostedRequest(uint256 queryId, address from); - - /// Emitted when a Witnet-solved result is reported to the WRB. - event PostedResult(uint256 queryId, address from); - - /// Emitted when all data related to given query is deleted from the WRB. - event DeletedQuery(uint256 queryId, address from); -} diff --git a/contracts/interfaces/IWitnetRequestBoardRequestor.sol b/contracts/interfaces/IWitnetRequestBoardRequestor.sol deleted file mode 100644 index 2dbb46537..000000000 --- a/contracts/interfaces/IWitnetRequestBoardRequestor.sol +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.7.0 <0.9.0; -pragma experimental ABIEncoderV2; - -import "../libs/WitnetV2.sol"; - -/// @title Witnet Requestor Interface -/// @notice It defines how to interact with the Witnet Request Board in order to: -/// - request the execution of Witnet Radon scripts (data request); -/// - upgrade the resolution reward of any previously posted request, in case gas price raises in mainnet; -/// - read the result of any previously posted request, eventually reported by the Witnet DON. -/// - remove from storage all data related to past and solved data requests, and results. -/// @author The Witnet Foundation. -interface 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) external view returns (Witnet.ResultStatus); - - /// @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 view returns (Witnet.ResultError memory); - - /// @notice Retrieves a copy of all Witnet-provided data related to a previously posted request, removing the whole query from the WRB 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 returns (Witnet.Response memory); - - /// @notice Requests the execution of the given Witnet Data Request in expectation that it will be relayed and solved by the Witnet DON. - /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided - /// @notice result to this request. - /// @dev Fails if: - /// @dev - provided reward is too low. - /// @dev - provided script is zero address. - /// @dev - provided script bytecode is empty. - /// @param addr The address of the IWitnetRequest contract that can provide the actual Data Request bytecode. - /// @return _queryId Unique query identifier. - function postRequest(IWitnetRequest addr) 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 the Witnet DON. - /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided - /// @notice result to this request. - /// @dev Fails if, provided reward is too low. - /// @param radHash The RAD hash of the data request to be solved by Witnet. - /// @param slaHash The SLA hash of the data request to be solved by Witnet. - /// @return _queryId Unique query identifier. - function postRequest(bytes32 radHash, bytes32 slaHash) 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 the Witnet DON. - /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided - /// @notice result to this request. - /// @dev Fails if, provided reward is too low. - /// @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); - - /// @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 - /// @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; -} diff --git a/contracts/interfaces/IWitnetRequestBoardView.sol b/contracts/interfaces/IWitnetRequestBoardView.sol deleted file mode 100644 index d86000ee5..000000000 --- a/contracts/interfaces/IWitnetRequestBoardView.sol +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.7.0 <0.9.0; -pragma experimental ABIEncoderV2; - -import "../libs/Witnet.sol"; - -/// @title Witnet Request Board info interface. -/// @author The Witnet Foundation. -interface IWitnetRequestBoardView { - - /// @notice 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); - - /// @notice Returns next query id to be generated by the Witnet Request Board. - function getNextQueryId() external view returns (uint256); - - /// @notice Gets the whole Query data contents, if any, no matter its current status. - function getQueryData(uint256 _queryId) external view returns (Witnet.Query memory); - - /// @notice Gets current status of given query. - function getQueryStatus(uint256 _queryId) external view returns (Witnet.QueryStatus); - - /// @notice 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) external view returns (Witnet.Request memory); - - /// @notice 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 view returns (bytes memory); - - /// @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 view returns (uint256); - - /// @notice Retrieves the reward currently set for the referred query. - /// @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 view returns (uint256); - - /// @notice Retrieves the whole `Witnet.Response` record referred to a previously posted Witnet Data Request. - /// @dev Fails if the `_queryId` is not in 'Reported' status. - /// @param _queryId The unique query identifier. - function readResponse(uint256 _queryId) external view returns (Witnet.Response memory); - - /// @notice Retrieves error codes of given query. - /// @dev Fails if the `_queryId` is not in 'Reported' status, or if no actual error. - /// @param _queryId The unique query identifier. - function readResponseDrTxHash(uint256 _queryId) external view returns (bytes32); - - /// @notice 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 view returns (address); - - /// @notice 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 view returns (Witnet.Result memory); - - /// @notice 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 view returns (uint256); -} diff --git a/contracts/interfaces/V2/IWitnetBytecodes.sol b/contracts/interfaces/V2/IWitnetBytecodes.sol index 4a0af9d62..938a61d80 100644 --- a/contracts/interfaces/V2/IWitnetBytecodes.sol +++ b/contracts/interfaces/V2/IWitnetBytecodes.sol @@ -6,11 +6,20 @@ import "../../libs/WitnetV2.sol"; interface IWitnetBytecodes { + error UnknownRadonRetrieval(bytes32 hash); + error UnknownRadonReducer(bytes32 hash); + error UnknownRadonRequest(bytes32 hash); + error UnknownRadonSLA(bytes32 hash); + + event NewDataProvider(uint256 index); + event NewRadonRetrievalHash(bytes32 hash); + event NewRadonReducerHash(bytes32 hash); + event NewRadHash(bytes32 hash); + event NewSlaHash(bytes32 hash); + function bytecodeOf(bytes32 radHash) external view returns (bytes memory); function bytecodeOf(bytes32 radHash, bytes32 slahHash) external view returns (bytes memory); - function class() external view returns (bytes4); - function hashOf( bytes32[] calldata sources, bytes32 aggregator, diff --git a/contracts/interfaces/V2/IWitnetBytecodesErrors.sol b/contracts/interfaces/V2/IWitnetBytecodesErrors.sol deleted file mode 100644 index 84d72e671..000000000 --- a/contracts/interfaces/V2/IWitnetBytecodesErrors.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.8.0 <0.9.0; - -interface IWitnetBytecodesErrors { - error UnknownRadonRetrieval(bytes32 hash); - error UnknownRadonReducer(bytes32 hash); - error UnknownRadonRequest(bytes32 hash); - error UnknownRadonSLA(bytes32 hash); -} \ No newline at end of file diff --git a/contracts/interfaces/V2/IWitnetBytecodesEvents.sol b/contracts/interfaces/V2/IWitnetBytecodesEvents.sol deleted file mode 100644 index 35924f6d8..000000000 --- a/contracts/interfaces/V2/IWitnetBytecodesEvents.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.8.0 <0.9.0; - -interface IWitnetBytecodesEvents { - event NewDataProvider(uint256 index); - event NewRadonRetrievalHash(bytes32 hash); - event NewRadonReducerHash(bytes32 hash); - event NewRadHash(bytes32 hash); - event NewSlaHash(bytes32 hash); -} \ No newline at end of file diff --git a/contracts/interfaces/V2/IWitnetRequestBoard.sol b/contracts/interfaces/V2/IWitnetRequestBoard.sol deleted file mode 100644 index 140441018..000000000 --- a/contracts/interfaces/V2/IWitnetRequestBoard.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.7.0 <0.9.0; - -import "../IWitnetRequestBoardDeprecating.sol"; -import "../IWitnetRequestBoardEvents.sol"; -import "../IWitnetRequestBoardReporter.sol"; -import "../IWitnetRequestBoardRequestor.sol"; -import "../IWitnetRequestBoardView.sol"; - -import "./IWitnetRequestFactory.sol"; - -abstract contract IWitnetRequestBoard - is - IWitnetRequestBoardDeprecating, - IWitnetRequestBoardEvents, - IWitnetRequestBoardReporter, - IWitnetRequestBoardRequestor, - IWitnetRequestBoardView -{ - function class() virtual external view returns (bytes4); - function factory() virtual external view returns (IWitnetRequestFactory); - function registry() virtual external view returns (IWitnetBytecodes); -} diff --git a/contracts/interfaces/V2/IWitnetRequestFactory.sol b/contracts/interfaces/V2/IWitnetRequestFactory.sol index 81890a095..6a48ff8e1 100644 --- a/contracts/interfaces/V2/IWitnetRequestFactory.sol +++ b/contracts/interfaces/V2/IWitnetRequestFactory.sol @@ -2,16 +2,15 @@ pragma solidity >=0.7.0 <0.9.0; -import "./IWitnetBytecodes.sol"; - interface IWitnetRequestFactory { + event WitnetRequestTemplateBuilt(address template, bool parameterized); + function buildRequestTemplate( bytes32[] memory sourcesIds, bytes32 aggregatorId, bytes32 tallyId, uint16 resultDataMaxSize ) external returns (address template); - function class() external view returns (bytes4); - function registry() external view returns (IWitnetBytecodes); -} + +} \ No newline at end of file diff --git a/contracts/libs/Create3.sol b/contracts/libs/Create3.sol new file mode 100644 index 000000000..103f02026 --- /dev/null +++ b/contracts/libs/Create3.sol @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +pragma solidity ^0.8.0; + +/// @notice Deploy to deterministic addresses without an initcode factor. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/CREATE3.sol) +/// @author 0xSequence (https://github.com/0xSequence/create3/blob/master/contracts/Create3.sol) + +library Create3 { + + //--------------------------------------------------------------------------------// + // Opcode | Opcode + Arguments | Description | Stack View // + //--------------------------------------------------------------------------------// + // 0x36 | 0x36 | CALLDATASIZE | size // + // 0x3d | 0x3d | RETURNDATASIZE | 0 size // + // 0x3d | 0x3d | RETURNDATASIZE | 0 0 size // + // 0x37 | 0x37 | CALLDATACOPY | // + // 0x36 | 0x36 | CALLDATASIZE | size // + // 0x3d | 0x3d | RETURNDATASIZE | 0 size // + // 0x34 | 0x34 | CALLVALUE | value 0 size // + // 0xf0 | 0xf0 | CREATE | newContract // + //--------------------------------------------------------------------------------// + // Opcode | Opcode + Arguments | Description | Stack View // + //--------------------------------------------------------------------------------// + // 0x67 | 0x67XXXXXXXXXXXXXXXX | PUSH8 bytecode | bytecode // + // 0x3d | 0x3d | RETURNDATASIZE | 0 bytecode // + // 0x52 | 0x52 | MSTORE | // + // 0x60 | 0x6008 | PUSH1 08 | 8 // + // 0x60 | 0x6018 | PUSH1 18 | 24 8 // + // 0xf3 | 0xf3 | RETURN | // + //--------------------------------------------------------------------------------// + + bytes internal constant CREATE3_FACTORY_BYTECODE = hex"67_36_3d_3d_37_36_3d_34_f0_3d_52_60_08_60_18_f3"; + bytes32 internal constant CREATE3_FACTORY_CODEHASH = keccak256(CREATE3_FACTORY_BYTECODE); + + /// @notice Creates a new contract with given `_creationCode` and `_salt` + /// @param _salt Salt of the contract creation, resulting address will be derivated from this value only + /// @param _creationCode Creation code (constructor) of the contract to be deployed, this value doesn't affect the resulting address + /// @return addr of the deployed contract, reverts on error + function deploy(bytes32 _salt, bytes memory _creationCode) + internal + returns (address) + { + return deploy(_salt, _creationCode, 0); + } + + /// @notice Creates a new contract with given `_creationCode`, `_salt` and `_value`. + /// @param _salt Salt of the contract creation, resulting address will be derivated from this value only + /// @param _creationCode Creation code (constructor) of the contract to be deployed, this value doesn't affect the resulting address + /// @param _value In WEI of ETH to be forwarded to child contract + /// @return _deployed The address of the deployed contract. + function deploy(bytes32 _salt, bytes memory _creationCode, uint256 _value) + internal + returns (address _deployed) + { + // Get target final address + _deployed = determineAddr(_salt); + if (_deployed.code.length != 0) revert("Create3: target already exists"); + + // Create factory + address _factory; + bytes memory _factoryBytecode = CREATE3_FACTORY_BYTECODE; + /// @solidity memory-safe-assembly + assembly { + // Deploy a factory contract with our pre-made bytecode via CREATE2. + // We start 32 bytes into the code to avoid copying the byte length. + _factory := create2(0, add(_factoryBytecode, 32), mload(_factoryBytecode), _salt) + } + require(_factory != address(0), "Create3: error creating factory"); + + // Use factory to deploy target + (bool _success, ) = _factory.call{value: _value}(_creationCode); + require(_success && _deployed.code.length != 0, "Create3: error creating target"); + } + + /// @notice Computes the resulting address of a contract deployed using address(this) and the given `_salt` + /// @param _salt Salt of the contract creation, resulting address will be derivated from this value only + /// @return addr of the deployed contract, reverts on error + /// @dev The address creation formula is: keccak256(rlp([keccak256(0xff ++ address(this) ++ _salt ++ keccak256(childBytecode))[12:], 0x01])) + function determineAddr(bytes32 _salt) internal view returns (address) { + address _factory = address( + uint160( + uint256( + keccak256( + abi.encodePacked( + hex'ff', + address(this), + _salt, + CREATE3_FACTORY_CODEHASH + ) + ) + ) + ) + ); + return address( + uint160( + uint256( + keccak256( + abi.encodePacked( + // 0xd6 = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ _factory ++ 0x01) + // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex) + hex"d6_94", + _factory, + // _factory's nonce on which the target is created: 0x1 + hex"01" + ) + ) + ) + ) + ); + } + +} \ No newline at end of file diff --git a/contracts/patterns/Create2Factory.sol b/contracts/patterns/Create2Factory.sol deleted file mode 100644 index 8456e590a..000000000 --- a/contracts/patterns/Create2Factory.sol +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.8.0 <0.9.0; - -/// @title Based on Singleton Factory (EIP-2470), authored by Guilherme Schmidt (Status Research & Development GmbH) -/// @notice Exposes CREATE2 (EIP-1014) to deploy bytecode on deterministic addresses based on initialization code and salt. - -contract Create2Factory { - - /// @notice Deploys `_initCode` using `_salt` for defining the deterministic address. - /// @param _initCode Initialization code. - /// @param _salt Arbitrary value to modify resulting address. - /// @return createdContract Created contract address. - function deploy(bytes memory _initCode, bytes32 _salt) - public - returns (address payable createdContract) - { - assembly { - createdContract := create2(0, add(_initCode, 0x20), mload(_initCode), _salt) - } - } - - /// @notice Determine singleton contract address that might be created from this factory, given its `_initCode` and a `_salt`. - /// @param _initCode Initialization code. - /// @param _salt Arbitrary value to modify resulting address. - /// @return expectedAddr Expected contract address. - function determineAddr(bytes memory _initCode, bytes32 _salt) - public - view - returns (address) - { - return address( - uint160(uint(keccak256( - abi.encodePacked( - bytes1(0xff), - address(this), - _salt, - keccak256(_initCode) - ) - ))) - ); - } - -} \ No newline at end of file diff --git a/contracts/patterns/Destructible.sol b/contracts/patterns/Destructible.sol deleted file mode 100644 index 08b5f0669..000000000 --- a/contracts/patterns/Destructible.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.6.0 <0.9.0; - -interface Destructible { - /// @dev Self-destruct the whole contract. - function destruct() external; -} From 59a163f8ccdd32c70dc89477a6a9c8b65127d8b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 9 Nov 2023 08:10:37 +0100 Subject: [PATCH 09/86] chore: deprecate WPR --- contracts/impls/apps/WitnetPriceRouter.sol | 266 -------------------- contracts/interfaces/IWitnetPriceFeed.sol | 72 ------ contracts/interfaces/IWitnetPriceRouter.sol | 56 ----- 3 files changed, 394 deletions(-) delete mode 100644 contracts/impls/apps/WitnetPriceRouter.sol delete mode 100644 contracts/interfaces/IWitnetPriceFeed.sol delete mode 100644 contracts/interfaces/IWitnetPriceRouter.sol diff --git a/contracts/impls/apps/WitnetPriceRouter.sol b/contracts/impls/apps/WitnetPriceRouter.sol deleted file mode 100644 index 48fd600df..000000000 --- a/contracts/impls/apps/WitnetPriceRouter.sol +++ /dev/null @@ -1,266 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; -pragma experimental ABIEncoderV2; - -import "@openzeppelin/contracts/utils/Strings.sol"; -import "../../interfaces/IWitnetPriceFeed.sol"; - -import "../../impls/WitnetUpgradableBase.sol"; -import "../../interfaces/IWitnetPriceRouter.sol"; - -contract WitnetPriceRouter - is - WitnetUpgradableBase, - IWitnetPriceRouter -{ - using Strings for uint256; - - struct Pair { - IERC165 pricefeed; - uint256 decimals; - string base; - string quote; - } - - struct Storage { - mapping (bytes4 => Pair) pairs; - mapping (address => bytes32) pricefeedId_; - bytes32[] supportedCurrencyPairs; - } - - constructor( - bool _upgradable, - bytes32 _versionTag - ) - WitnetUpgradableBase( - _upgradable, - _versionTag, - "io.witnet.proxiable.router" - ) - {} - - // ================================================================================================================ - // --- 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 - { - address _owner = owner(); - if (_owner == address(0)) { - // set owner if none set yet - _owner = msg.sender; - _transferOwnership(_owner); - } else { - // only owner can initialize: - if (msg.sender != _owner) { - revert WitnetUpgradableBase.OnlyOwner(_owner); - } - } - - if (__proxiable().implementation != address(0)) { - // current implementation cannot be initialized more than once: - if(__proxiable().implementation == base()) { - revert WitnetUpgradableBase.AlreadyUpgraded(base()); - } - } - __proxiable().implementation = 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 = owner(); - return ( - // false if the WRB is intrinsically not upgradable, or `_from` is no owner - isUpgradable() - && _owner == _from - ); - } - - // ======================================================================== - // --- Implementation of 'IERC2362' --------------------------------------- - - /// Returns last valid price value and timestamp, as well as status of - /// the latest update request that got posted to the Witnet Request Board. - /// @dev Fails if the given currency pair is not currently supported. - /// @param _erc2362id Price pair identifier as specified in https://github.com/adoracles/ADOIPs/blob/main/adoip-0010.md - /// @return _lastPrice Last valid price reported back from the Witnet oracle. - /// @return _lastTimestamp EVM-timestamp of the last valid price. - /// @return _latestUpdateStatus Status code of latest update request that got posted to the Witnet Request Board: - /// - 200: latest update request was succesfully solved with no errors - /// - 400: latest update request was solved with errors - /// - 404: latest update request is still pending to be solved - function valueFor(bytes32 _erc2362id) - external view - virtual override - returns ( - int256 _lastPrice, - uint256 _lastTimestamp, - uint256 _latestUpdateStatus - ) - { - IWitnetPriceFeed _pricefeed = IWitnetPriceFeed(address(getPriceFeed(_erc2362id))); - require(address(_pricefeed) != address(0), "WitnetPriceRouter: unsupported currency pair"); - (_lastPrice, _lastTimestamp,, _latestUpdateStatus) = _pricefeed.lastValue(); - } - - - // ======================================================================== - // --- Implementation of 'IWitnetPriceRouter' --------------------------- - - /// Helper pure function: returns hash of the provided ERC2362-compliant currency pair caption (aka ID). - function currencyPairId(string memory _caption) - public pure - virtual override - returns (bytes32) - { - return keccak256(bytes(_caption)); - } - - /// Returns the ERC-165-compliant price feed contract currently serving - /// updates on the given currency pair. - function getPriceFeed(bytes32 _erc2362id) - public view - virtual override - returns (IERC165) - { - return __storage().pairs[bytes4(_erc2362id)].pricefeed; - } - - /// Returns human-readable ERC2362-based caption of the currency pair being - /// served by the given price feed contract address. - /// @dev Fails if the given price feed contract address is not currently - /// @dev registered in the router. - function getPriceFeedCaption(IERC165 _pricefeed) - public view - virtual override - returns (string memory) - { - require(supportsPriceFeed(_pricefeed), "WitnetPriceRouter: unknown"); - return lookupERC2362ID(__storage().pricefeedId_[address(_pricefeed)]); - } - - /// Returns human-readable caption of the ERC2362-based currency pair identifier, if known. - function lookupERC2362ID(bytes32 _erc2362id) - public view - virtual override - returns (string memory _caption) - { - Pair storage _pair = __storage().pairs[bytes4(_erc2362id)]; - if ( - bytes(_pair.base).length > 0 - && bytes(_pair.quote).length > 0 - ) { - _caption = string(abi.encodePacked( - "Price-", - _pair.base, - "/", - _pair.quote, - "-", - _pair.decimals.toString() - )); - } - } - - /// Register a price feed contract that will serve updates for the given currency pair. - /// @dev Setting zero address to a currency pair implies that it will not be served any longer. - /// @dev Otherwise, fails if the price feed contract does not support the `IWitnetPriceFeed` interface, - /// @dev or if given price feed is already serving another currency pair (within this WitnetPriceRouter instance). - function setPriceFeed( - IERC165 _pricefeed, - uint256 _decimals, - string calldata _base, - string calldata _quote - ) - public - virtual override - onlyOwner - { - if (address(_pricefeed) != address(0)) { - require( - _pricefeed.supportsInterface(type(IWitnetPriceFeed).interfaceId), - "WitnetPriceRouter: feed contract is not compliant with IWitnetPriceFeed" - ); - require( - __storage().pricefeedId_[address(_pricefeed)] == bytes32(0), - "WitnetPriceRouter: already serving a currency pair" - ); - } - bytes memory _caption = abi.encodePacked( - "Price-", - bytes(_base), - "/", - bytes(_quote), - "-", - _decimals.toString() - ); - bytes32 _erc2362id = keccak256(_caption); - - Pair storage _record = __storage().pairs[bytes4(_erc2362id)]; - address _currentPriceFeed = address(_record.pricefeed); - if (bytes(_record.base).length == 0) { - _record.base = _base; - _record.quote = _quote; - _record.decimals = _decimals; - __storage().supportedCurrencyPairs.push(_erc2362id); - } - else if (_currentPriceFeed != address(0)) { - __storage().pricefeedId_[_currentPriceFeed] = bytes32(0); - } - if (address(_pricefeed) != _currentPriceFeed) { - __storage().pricefeedId_[address(_pricefeed)] = _erc2362id; - } - _record.pricefeed = _pricefeed; - emit CurrencyPairSet(_erc2362id, _pricefeed); - } - - /// Returns list of known currency pairs IDs. - function supportedCurrencyPairs() - external view - virtual override - returns (bytes32[] memory) - { - return __storage().supportedCurrencyPairs; - } - - /// Returns `true` if given pair is currently being served by a compliant price feed contract. - function supportsCurrencyPair(bytes32 _erc2362id) - public view - virtual override - returns (bool) - { - return address(__storage().pairs[bytes4(_erc2362id)].pricefeed) != address(0); - } - - /// Returns `true` if given price feed contract is currently serving updates to any known currency pair. - function supportsPriceFeed(IERC165 _pricefeed) - public view - virtual override - returns (bool) - { - return __storage().pairs[bytes4(__storage().pricefeedId_[address(_pricefeed)])].pricefeed == _pricefeed; - } - - - /// ======================================================================= - /// --- Internal methods -------------------------------------------------- - - bytes32 internal constant _WITNET_PRICE_ROUTER_SLOTHASH = - /* keccak256("io.witnet.router.data") */ - 0x1ab0a3400242e9b47752f01347893fa91d77046d73895ccd575be9dd5025abd9; - - function __storage() internal pure returns (Storage storage ptr) { - assembly { - ptr.slot := _WITNET_PRICE_ROUTER_SLOTHASH - } - } -} diff --git a/contracts/interfaces/IWitnetPriceFeed.sol b/contracts/interfaces/IWitnetPriceFeed.sol deleted file mode 100644 index d5865f3da..000000000 --- a/contracts/interfaces/IWitnetPriceFeed.sol +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; -pragma experimental ABIEncoderV2; - -/// @title The Witnet Price Feed basic interface. -/// @dev Guides implementation of active price feed polling contracts. -/// @author The Witnet Foundation. - -interface IWitnetPriceFeed { - - /// Signals that a new price update request is being posted to the Witnet Request Board - event PriceFeeding(address indexed from, uint256 queryId, uint256 extraFee); - - /// @notice Estimates minimum fee amount in native currency to be paid when - /// @notice requesting a new price update. - /// @dev Actual fee depends on the gas price of the `requestUpdate()` transaction. - /// @param _gasPrice Gas price expected to be paid when calling `requestUpdate()` - function estimateUpdateFee(uint256 _gasPrice) external view returns (uint256); - - /// @notice Returns result of the last valid price update request successfully solved by the Witnet oracle. - function lastPrice() external view returns (int256); - - /// @notice Returns the EVM-timestamp when last valid price was reported back from the Witnet oracle. - function lastTimestamp() external view returns (uint256); - - /// @notice Returns tuple containing last valid price and timestamp, as well as status code of latest update - /// @notice request that got posted to the Witnet Request Board. - /// @return _lastPrice Last valid price reported back from the Witnet oracle. - /// @return _lastTimestamp EVM-timestamp of the last valid price. - /// @return _lastDrTxHash Hash of the Witnet Data Request that solved the last valid price. - /// @return _latestUpdateStatus Status code of the latest update request. - function lastValue() external view returns ( - int _lastPrice, - uint _lastTimestamp, - bytes32 _lastDrTxHash, - uint _latestUpdateStatus - ); - - /// @notice Returns identifier of the latest update request posted to the Witnet Request Board. - function latestQueryId() external view returns (uint256); - - /// @notice Returns hash of the Witnet Data Request that solved the latest update request. - /// @dev Returning 0 while the latest update request remains unsolved. - function latestUpdateDrTxHash() external view returns (bytes32); - - /// @notice Returns error message of latest update request posted to the Witnet Request Board. - /// @dev Returning empty string if the latest update request remains unsolved, or - /// @dev if it was succesfully solved with no errors. - function latestUpdateErrorMessage() external view returns (string memory); - - /// @notice Returns status code of latest update request posted to the Witnet Request Board: - /// @dev Status codes: - /// @dev - 200: update request was succesfully solved with no errors - /// @dev - 400: update request was solved with errors - /// @dev - 404: update request was not solved yet - function latestUpdateStatus() external view returns (uint256); - - /// @notice Returns `true` if latest update request posted to the Witnet Request Board - /// @notice has not been solved yet by the Witnet oracle. - function pendingUpdate() external view returns (bool); - - /// @notice Posts a new price update request to the Witnet Request Board. Requires payment of a fee - /// @notice that depends on the value of `tx.gasprice`. See `estimateUpdateFee(uint256)`. - /// @dev If previous update request was not solved yet, calling this method again allows - /// @dev upgrading the update fee if called with a higher `tx.gasprice` value. - function requestUpdate() external payable; - - /// @notice Tells whether this contract implements the interface defined by `interfaceId`. - /// @dev See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] - /// @dev to learn more about how these ids are created. - function supportsInterface(bytes4) external view returns (bool); -} diff --git a/contracts/interfaces/IWitnetPriceRouter.sol b/contracts/interfaces/IWitnetPriceRouter.sol deleted file mode 100644 index 23b25cfaa..000000000 --- a/contracts/interfaces/IWitnetPriceRouter.sol +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; -pragma experimental ABIEncoderV2; - -import "ado-contracts/contracts/interfaces/IERC2362.sol"; -import "./IERC165.sol"; - -/// @title The Witnet Price Router basic interface. -/// @dev Guides implementation of price feeds aggregation contracts. -/// @author The Witnet Foundation. -abstract contract IWitnetPriceRouter - is - IERC2362 -{ - /// Emitted everytime a currency pair is attached to a new price feed contract - /// @dev See https://github.com/adoracles/ADOIPs/blob/main/adoip-0010.md - /// @dev to learn how these ids are created. - event CurrencyPairSet(bytes32 indexed erc2362ID, IERC165 pricefeed); - - /// @notice Helper pure function: returns hash of the provided ERC2362-compliant currency pair caption (aka ID). - function currencyPairId(string memory) external pure virtual returns (bytes32); - - /// @notice Returns the ERC-165-compliant price feed contract currently serving - /// @notice updates on the given currency pair. - function getPriceFeed(bytes32 _erc2362id) external view virtual returns (IERC165); - - /// @notice Returns human-readable ERC2362-based caption of the currency pair being - /// @notice served by the given price feed contract address. - /// @dev Should fail if the given price feed contract address is not currently - /// @dev registered in the router. - function getPriceFeedCaption(IERC165) external view virtual returns (string memory); - - /// @notice Returns human-readable caption of the ERC2362-based currency pair identifier, if known. - function lookupERC2362ID(bytes32 _erc2362id) external view virtual returns (string memory); - - /// @notice Register a price feed contract that will serve updates for the given currency pair. - /// @dev Setting zero address to a currency pair implies that it will not be served any longer. - /// @dev Otherwise, should fail if the price feed contract does not support the `IWitnetPriceFeed` interface, - /// @dev or if given price feed is already serving another currency pair (within this WitnetPriceRouter instance). - function setPriceFeed( - IERC165 _pricefeed, - uint256 _decimals, - string calldata _base, - string calldata _quote - ) - external virtual; - - /// @notice Returns list of known currency pairs IDs. - function supportedCurrencyPairs() external view virtual returns (bytes32[] memory); - - /// @notice Returns `true` if given pair is currently being served by a compliant price feed contract. - function supportsCurrencyPair(bytes32 _erc2362id) external view virtual returns (bool); - - /// @notice Returns `true` if given price feed contract is currently serving updates to any known currency pair. - function supportsPriceFeed(IERC165 _priceFeed) external view virtual returns (bool); -} From c9f68cde8b03bb371741697f374b28191878cd7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 9 Nov 2023 08:13:06 +0100 Subject: [PATCH 10/86] chore/feat: refactor contracts folder and impl counter-factual binding --- .../core/customs/WitnetBytecodesNoSha256.sol | 7 +- .../WitnetRequestBoardTrustableBase.sol | 98 +++++++++---------- .../WitnetRequestBoardTrustableBoba.sol | 4 +- .../WitnetRequestBoardTrustableOvm2.sol | 5 +- .../WitnetRequestBoardTrustableReef.sol | 4 +- .../customs/WitnetRequestFactoryCfxCore.sol | 4 +- .../defaults}/WitnetBytecodesDefault.sol | 52 +++------- .../WitnetRequestBoardTrustableDefault.sol | 15 +-- .../defaults}/WitnetRequestFactoryDefault.sol | 58 +++-------- contracts/interfaces/IERC165.sol | 3 - contracts/interfaces/IERC20.sol | 3 - .../mocks/WitnetRandomnessMock.sol | 9 +- contracts/patterns/Payable.sol | 3 +- 13 files changed, 92 insertions(+), 173 deletions(-) rename contracts/{impls => }/core/customs/WitnetBytecodesNoSha256.sol (74%) rename contracts/{impls => }/core/customs/WitnetRequestBoardTrustableBase.sol (93%) rename contracts/{impls => }/core/customs/WitnetRequestBoardTrustableBoba.sol (97%) rename contracts/{impls => }/core/customs/WitnetRequestBoardTrustableOvm2.sol (95%) rename contracts/{impls => }/core/customs/WitnetRequestBoardTrustableReef.sol (94%) rename contracts/{impls => }/core/customs/WitnetRequestFactoryCfxCore.sol (88%) rename contracts/{impls/core => core/defaults}/WitnetBytecodesDefault.sol (93%) rename contracts/{impls/core => core/defaults}/WitnetRequestBoardTrustableDefault.sol (81%) rename contracts/{impls/core => core/defaults}/WitnetRequestFactoryDefault.sol (91%) delete mode 100644 contracts/interfaces/IERC165.sol delete mode 100644 contracts/interfaces/IERC20.sol rename contracts/{impls => }/mocks/WitnetRandomnessMock.sol (97%) diff --git a/contracts/impls/core/customs/WitnetBytecodesNoSha256.sol b/contracts/core/customs/WitnetBytecodesNoSha256.sol similarity index 74% rename from contracts/impls/core/customs/WitnetBytecodesNoSha256.sol rename to contracts/core/customs/WitnetBytecodesNoSha256.sol index 0d50f2621..684f27268 100644 --- a/contracts/impls/core/customs/WitnetBytecodesNoSha256.sol +++ b/contracts/core/customs/WitnetBytecodesNoSha256.sol @@ -3,14 +3,11 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "../WitnetBytecodesDefault.sol"; +import "../defaults/WitnetBytecodesDefault.sol"; contract WitnetBytecodesNoSha256 is WitnetBytecodesDefault { - constructor( - bool _upgradable, - bytes32 _versionTag - ) + constructor(bool _upgradable, bytes32 _versionTag) WitnetBytecodesDefault(_upgradable, _versionTag) {} diff --git a/contracts/impls/core/customs/WitnetRequestBoardTrustableBase.sol b/contracts/core/customs/WitnetRequestBoardTrustableBase.sol similarity index 93% rename from contracts/impls/core/customs/WitnetRequestBoardTrustableBase.sol rename to contracts/core/customs/WitnetRequestBoardTrustableBase.sol index 8fcd213d7..927301e33 100644 --- a/contracts/impls/core/customs/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/customs/WitnetRequestBoardTrustableBase.sol @@ -3,14 +3,15 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "../../WitnetUpgradableBase.sol"; -import "../../../WitnetRequestBoard.sol"; -import "../../../WitnetRequestFactory.sol"; +import "../WitnetUpgradableBase.sol"; +import "../../WitnetRequestBoard.sol"; +import "../../WitnetRequestFactory.sol"; -import "../../../data/WitnetBoardDataACLs.sol"; -import "../../../interfaces/IWitnetRequestBoardAdminACLs.sol"; -import "../../../libs/WitnetErrorsLib.sol"; -import "../../../patterns/Payable.sol"; +import "../../data/WitnetBoardDataACLs.sol"; +import "../../interfaces/IWitnetRequestBoardAdminACLs.sol"; +import "../../interfaces/IWitnetRequestBoardReporter.sol"; +import "../../libs/WitnetErrorsLib.sol"; +import "../../patterns/Payable.sol"; /// @title Witnet Request Board "trustable" base implementation contract. /// @notice Contract to bridge requests to Witnet Decentralized Oracle Network. @@ -22,17 +23,18 @@ abstract contract WitnetRequestBoardTrustableBase WitnetUpgradableBase, WitnetRequestBoard, WitnetBoardDataACLs, + IWitnetRequestBoardReporter, IWitnetRequestBoardAdminACLs, Payable { using Witnet for bytes; using Witnet for Witnet.Result; - bytes4 public immutable override class = type(WitnetRequestBoard).interfaceId; - IWitnetRequestFactory immutable public override factory; + bytes4 public immutable override class = type(IWitnetRequestBoard).interfaceId; + WitnetRequestFactory immutable public override factory; constructor( - IWitnetRequestFactory _factory, + WitnetRequestFactory _factory, bool _upgradable, bytes32 _versionTag, address _currency @@ -44,14 +46,10 @@ abstract contract WitnetRequestBoardTrustableBase "io.witnet.proxiable.board" ) { - require( - _factory.class() == type(WitnetRequestFactory).interfaceId, - "WitnetRequestBoard: uncompliant factory" - ); factory = _factory; } - function registry() public view virtual override returns (IWitnetBytecodes) { + function registry() public view virtual override returns (WitnetBytecodes) { return factory.registry(); } @@ -60,23 +58,23 @@ abstract contract WitnetRequestBoardTrustableBase } /// @dev Provide backwards compatibility for dapps bound to versions <= 0.6.1 - /// @dev (i.e. calling methods in IWitnetRequestBoardDeprecating) + /// @dev (i.e. calling methods in IWitnetRequestBoard) /// @dev (Until 'function ... abi(...)' modifier is allegedly supported in solc versions >= 0.9.1) // solhint-disable-next-line payable-fallback fallback() override external { /* solhint-disable no-complex-fallback */ bytes4 _newSig = msg.sig; if (msg.sig == 0xA8604C1A) { - // IWitnetRequestParser.isOk({bool,CBOR}) --> IWitnetRequestBoardDeprecating.isOk({bool,WitnetCBOR.CBOR}) - _newSig = IWitnetRequestBoardDeprecating.isOk.selector; + // IWitnetRequestParser.isOk({bool,CBOR}) --> IWitnetRequestBoard.isOk({bool,WitnetCBOR.CBOR}) + _newSig = IWitnetRequestBoard.isOk.selector; } else if (msg.sig == 0xCF62D115) { - // IWitnetRequestParser.asBytes32({bool,CBOR}) --> IWitnetRequestBoardDeprecating.asBytes32({bool,WitnetCBOR.CBOR}) - _newSig = IWitnetRequestBoardDeprecating.asBytes32.selector; + // IWitnetRequestParser.asBytes32({bool,CBOR}) --> IWitnetRequestBoard.asBytes32({bool,WitnetCBOR.CBOR}) + _newSig = IWitnetRequestBoard.asBytes32.selector; } else if (msg.sig == 0xBC7E25FF) { - // IWitnetRequestParser.asUint64({bool,CBOR}) --> IWitnetRequestBoardDeprecating.asUint64({bool,WitnetCBOR.CBOR}) - _newSig = IWitnetRequestBoardDeprecating.asUint64.selector; + // IWitnetRequestParser.asUint64({bool,CBOR}) --> IWitnetRequestBoard.asUint64({bool,WitnetCBOR.CBOR}) + _newSig = IWitnetRequestBoard.asUint64.selector; } else if (msg.sig == 0xD74803BE) { - // IWitnetRequestParser.asErrorMessage({bool,CBOR}) --> IWitnetRequestBoardDeprecating.asErrorMessage({bool,WitnetCBOR.CBOR}) - _newSig = IWitnetRequestBoardDeprecating.asErrorMessage.selector; + // IWitnetRequestParser.asErrorMessage({bool,CBOR}) --> IWitnetRequestBoard.asErrorMessage({bool,WitnetCBOR.CBOR}) + _newSig = IWitnetRequestBoard.asErrorMessage.selector; } if (_newSig != msg.sig) { address _self = address(this); @@ -103,21 +101,6 @@ abstract contract WitnetRequestBoardTrustableBase } - // ================================================================================================================ - // --- Overrides IERC165 interface -------------------------------------------------------------------------------- - - /// @dev See {IERC165-supportsInterface}. - function supportsInterface(bytes4 _interfaceId) - public view - virtual override - returns (bool) - { - return _interfaceId == type(WitnetRequestBoard).interfaceId - || _interfaceId == type(IWitnetRequestBoardAdminACLs).interfaceId - || super.supportsInterface(_interfaceId); - } - - // ================================================================================================================ // --- Overrides 'Upgradeable' ------------------------------------------------------------------------------------- @@ -128,16 +111,22 @@ abstract contract WitnetRequestBoardTrustableBase override { address _owner = __storage().owner; + address[] memory _reporters; + if (_owner == address(0)) { - // set owner if none set yet - _owner = msg.sender; + // get owner (and reporters) from _initData + bytes memory _reportersRaw; + (_owner, _reportersRaw) = abi.decode(_initData, (address, bytes)); __storage().owner = _owner; + _reporters = abi.decode(_reportersRaw, (address[])); } else { // only owner can initialize: require( msg.sender == _owner, - "WitnetRequestBoardTrustableBase: only owner" + "WitnetRequestBoardTrustableBase: not the owner" ); + // get reporters from _initData + _reporters = abi.decode(_initData, (address[])); } if (__storage().base != address(0)) { @@ -149,10 +138,13 @@ abstract contract WitnetRequestBoardTrustableBase } __storage().base = base(); - emit Upgraded(msg.sender, base(), codehash(), version()); + require(address(factory).code.length > 0, "WitnetRequestBoardTrustableBase: inexistent factory"); + require(factory.class() == type(IWitnetRequestFactory).interfaceId, "WitnetRequestBoardTrustableBase: uncompliant factory"); - // Do actual base initialization: - setReporters(abi.decode(_initData, (address[]))); + // Set reporters + __setReporters(_reporters); + + emit Upgraded(_owner, base(), codehash(), version()); } /// Tells whether provided address could eventually upgrade the contract. @@ -210,11 +202,7 @@ abstract contract WitnetRequestBoardTrustableBase override onlyOwner { - for (uint ix = 0; ix < _reporters.length; ix ++) { - address _reporter = _reporters[ix]; - _acls().isReporter_[_reporter] = true; - } - emit ReportersSet(_reporters); + __setReporters(_reporters); } /// Removes given addresses from the active reporters control list. @@ -756,7 +744,7 @@ abstract contract WitnetRequestBoardTrustableBase // ================================================================================================================ - // --- Full implementation of 'IWitnetRequestBoardDeprecating' interface ------------------------------------------ + // --- Full implementation of 'IWitnetRequestBoard' interface ------------------------------------------ /// Tell if a Witnet.Result is successful. /// @param _result An instance of Witnet.Result. @@ -847,4 +835,12 @@ abstract contract WitnetRequestBoardTrustableBase // Request data won't be needed anymore, so it can just get deleted right now: delete _query.request; } + + function __setReporters(address[] memory _reporters) internal { + for (uint ix = 0; ix < _reporters.length; ix ++) { + address _reporter = _reporters[ix]; + _acls().isReporter_[_reporter] = true; + } + emit ReportersSet(_reporters); + } } \ No newline at end of file diff --git a/contracts/impls/core/customs/WitnetRequestBoardTrustableBoba.sol b/contracts/core/customs/WitnetRequestBoardTrustableBoba.sol similarity index 97% rename from contracts/impls/core/customs/WitnetRequestBoardTrustableBoba.sol rename to contracts/core/customs/WitnetRequestBoardTrustableBoba.sol index e917dcb7c..372ef5737 100644 --- a/contracts/impls/core/customs/WitnetRequestBoardTrustableBoba.sol +++ b/contracts/core/customs/WitnetRequestBoardTrustableBoba.sol @@ -9,7 +9,7 @@ pragma experimental ABIEncoderV2; import "./WitnetRequestBoardTrustableBase.sol"; // Uses: -import "../../../interfaces/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /// @title Witnet Request Board OVM-compatible (Optimism) "trustable" implementation. /// @notice Contract to bridge requests to Witnet Decentralized Oracle Network. @@ -33,7 +33,7 @@ contract WitnetRequestBoardTrustableBoba } constructor( - IWitnetRequestFactory _factory, + WitnetRequestFactory _factory, bool _upgradable, bytes32 _versionTag, uint256 _layer2ReportResultGasLimit, diff --git a/contracts/impls/core/customs/WitnetRequestBoardTrustableOvm2.sol b/contracts/core/customs/WitnetRequestBoardTrustableOvm2.sol similarity index 95% rename from contracts/impls/core/customs/WitnetRequestBoardTrustableOvm2.sol rename to contracts/core/customs/WitnetRequestBoardTrustableOvm2.sol index e5b1ae03b..34e8cc2a2 100644 --- a/contracts/impls/core/customs/WitnetRequestBoardTrustableOvm2.sol +++ b/contracts/core/customs/WitnetRequestBoardTrustableOvm2.sol @@ -5,7 +5,7 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "../WitnetRequestBoardTrustableDefault.sol"; +import "../defaults/WitnetRequestBoardTrustableDefault.sol"; // solhint-disable-next-line interface OVM_GasPriceOracle { @@ -19,13 +19,12 @@ interface OVM_GasPriceOracle { /// @author The Witnet Foundation contract WitnetRequestBoardTrustableOvm2 is - Destructible, WitnetRequestBoardTrustableDefault { OVM_GasPriceOracle immutable public gasPriceOracleL1; constructor( - IWitnetRequestFactory _factory, + WitnetRequestFactory _factory, bool _upgradable, bytes32 _versionTag, uint256 _reportResultGasLimit diff --git a/contracts/impls/core/customs/WitnetRequestBoardTrustableReef.sol b/contracts/core/customs/WitnetRequestBoardTrustableReef.sol similarity index 94% rename from contracts/impls/core/customs/WitnetRequestBoardTrustableReef.sol rename to contracts/core/customs/WitnetRequestBoardTrustableReef.sol index f3d688928..ed7ea2fde 100644 --- a/contracts/impls/core/customs/WitnetRequestBoardTrustableReef.sol +++ b/contracts/core/customs/WitnetRequestBoardTrustableReef.sol @@ -6,7 +6,7 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; // Inherits from: -import "../WitnetRequestBoardTrustableDefault.sol"; +import "../defaults/WitnetRequestBoardTrustableDefault.sol"; /// @title Witnet Request Board OVM-compatible (Optimism) "trustable" implementation. /// @notice Contract to bridge requests to Witnet Decentralized Oracle Network. @@ -18,7 +18,7 @@ contract WitnetRequestBoardTrustableReef WitnetRequestBoardTrustableDefault { constructor( - IWitnetRequestFactory _factory, + WitnetRequestFactory _factory, bool _upgradable, bytes32 _versionTag, uint256 _reportResultGasLimit diff --git a/contracts/impls/core/customs/WitnetRequestFactoryCfxCore.sol b/contracts/core/customs/WitnetRequestFactoryCfxCore.sol similarity index 88% rename from contracts/impls/core/customs/WitnetRequestFactoryCfxCore.sol rename to contracts/core/customs/WitnetRequestFactoryCfxCore.sol index faa836f73..da2b86498 100644 --- a/contracts/impls/core/customs/WitnetRequestFactoryCfxCore.sol +++ b/contracts/core/customs/WitnetRequestFactoryCfxCore.sol @@ -3,11 +3,11 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "../WitnetRequestFactoryDefault.sol"; +import "../defaults/WitnetRequestFactoryDefault.sol"; contract WitnetRequestFactoryCfxCore is WitnetRequestFactoryDefault { constructor( - IWitnetBytecodes _registry, + WitnetBytecodes _registry, bool _upgradable, bytes32 _versionTag ) diff --git a/contracts/impls/core/WitnetBytecodesDefault.sol b/contracts/core/defaults/WitnetBytecodesDefault.sol similarity index 93% rename from contracts/impls/core/WitnetBytecodesDefault.sol rename to contracts/core/defaults/WitnetBytecodesDefault.sol index 94f6723a4..79f4f7ebb 100644 --- a/contracts/impls/core/WitnetBytecodesDefault.sol +++ b/contracts/core/defaults/WitnetBytecodesDefault.sol @@ -2,12 +2,9 @@ pragma solidity >=0.8.4 <0.9.0; -import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; - import "../WitnetUpgradableBase.sol"; import "../../WitnetBytecodes.sol"; import "../../data/WitnetBytecodesData.sol"; - import "../../libs/WitnetEncodingLib.sol"; /// @title Witnet Request Board EVM-default implementation contract. @@ -20,9 +17,7 @@ contract WitnetBytecodesDefault WitnetBytecodes, WitnetBytecodesData, WitnetUpgradableBase -{ - using ERC165Checker for address; - +{ using Witnet for bytes; using Witnet for string; @@ -33,12 +28,9 @@ contract WitnetBytecodesDefault using WitnetEncodingLib for WitnetV2.RadonSLA; using WitnetEncodingLib for WitnetV2.RadonDataTypes; - bytes4 public immutable override class = type(WitnetBytecodes).interfaceId; + bytes4 public immutable override class = type(IWitnetBytecodes).interfaceId; - constructor( - bool _upgradable, - bytes32 _versionTag - ) + constructor(bool _upgradable, bytes32 _versionTag) WitnetUpgradableBase( _upgradable, _versionTag, @@ -50,20 +42,6 @@ contract WitnetBytecodesDefault revert("WitnetBytecodesDefault: no transfers"); } - - // ================================================================================================================ - // --- Overrides IERC165 interface -------------------------------------------------------------------------------- - - /// @dev See {IERC165-supportsInterface}. - function supportsInterface(bytes4 _interfaceId) - public view - virtual override - returns (bool) - { - return _interfaceId == type(WitnetBytecodes).interfaceId - || super.supportsInterface(_interfaceId); - } - // ================================================================================================================ // --- Overrides 'Ownable2Step' ----------------------------------------------------------------------------------- @@ -117,32 +95,32 @@ contract WitnetBytecodesDefault /// @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) + function initialize(bytes memory _initData) public override { address _owner = __bytecodes().owner; if (_owner == address(0)) { - // set owner if none set yet - _owner = msg.sender; + // set owner from the one specified in _initData + _owner = abi.decode(_initData, (address)); __bytecodes().owner = _owner; } else { // only owner can initialize: if (msg.sender != _owner) { - revert WitnetUpgradableBase.OnlyOwner(_owner); + revert("WitnetBytecodesDefault: not the owner"); } } if (__bytecodes().base != address(0)) { // current implementation cannot be initialized more than once: if(__bytecodes().base == base()) { - revert WitnetUpgradableBase.AlreadyUpgraded(base()); + revert("WitnetBytecodesDefault: already initialized"); } } __bytecodes().base = base(); emit Upgraded( - msg.sender, + _owner, base(), codehash(), version() @@ -177,7 +155,7 @@ contract WitnetBytecodesDefault { WitnetV2.RadonSLA storage __sla = __database().slas[_slaHash]; if (__sla.numWitnesses == 0) { - revert IWitnetBytecodesErrors.UnknownRadonSLA(_slaHash); + revert UnknownRadonSLA(_slaHash); } bytes memory _radBytecode = bytecodeOf(_radHash); return abi.encodePacked( @@ -290,7 +268,7 @@ contract WitnetBytecodesDefault { _source = __database().retrievals[_hash]; if (_source.method == WitnetV2.DataRequestMethods.Unknown) { - revert IWitnetBytecodesErrors.UnknownRadonRetrieval(_hash); + revert UnknownRadonRetrieval(_hash); } } @@ -300,7 +278,7 @@ contract WitnetBytecodesDefault returns (uint8) { if (__database().retrievals[_hash].method == WitnetV2.DataRequestMethods.Unknown) { - revert IWitnetBytecodesErrors.UnknownRadonRetrieval(_hash); + revert UnknownRadonRetrieval(_hash); } return __database().retrievals[_hash].argsCount; } @@ -311,7 +289,7 @@ contract WitnetBytecodesDefault returns (WitnetV2.RadonDataTypes) { if (__database().retrievals[_hash].method == WitnetV2.DataRequestMethods.Unknown) { - revert IWitnetBytecodesErrors.UnknownRadonRetrieval(_hash); + revert UnknownRadonRetrieval(_hash); } return __database().retrievals[_hash].resultDataType; } @@ -323,7 +301,7 @@ contract WitnetBytecodesDefault { _reducer = __database().reducers[_hash]; if (uint8(_reducer.opcode) == 0) { - revert IWitnetBytecodesErrors.UnknownRadonReducer(_hash); + revert UnknownRadonReducer(_hash); } } @@ -386,7 +364,7 @@ contract WitnetBytecodesDefault { sla = __database().slas[_slaHash]; if (sla.numWitnesses == 0) { - revert IWitnetBytecodesErrors.UnknownRadonSLA(_slaHash); + revert UnknownRadonSLA(_slaHash); } } diff --git a/contracts/impls/core/WitnetRequestBoardTrustableDefault.sol b/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol similarity index 81% rename from contracts/impls/core/WitnetRequestBoardTrustableDefault.sol rename to contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol index d51221db4..4cb418ca7 100644 --- a/contracts/impls/core/WitnetRequestBoardTrustableDefault.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol @@ -5,8 +5,7 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "./customs/WitnetRequestBoardTrustableBase.sol"; -import "../../patterns/Destructible.sol"; +import "../customs/WitnetRequestBoardTrustableBase.sol"; /// @title Witnet Request Board "trustable" implementation contract. /// @notice Contract to bridge requests to Witnet Decentralized Oracle Network. @@ -15,13 +14,12 @@ import "../../patterns/Destructible.sol"; /// @author The Witnet Foundation contract WitnetRequestBoardTrustableDefault is - Destructible, WitnetRequestBoardTrustableBase { uint256 internal immutable _ESTIMATED_REPORT_RESULT_GAS; constructor( - IWitnetRequestFactory _factory, + WitnetRequestFactory _factory, bool _upgradable, bytes32 _versionTag, uint256 _reportResultGasLimit @@ -51,15 +49,6 @@ contract WitnetRequestBoardTrustableDefault } - // ================================================================================================================ - // --- Overrides 'Destructible' ----------------------------------------------------------------------------------- - - /// Destroys current instance. Only callable by the owner. - function destruct() external override onlyOwner { - selfdestruct(payable(msg.sender)); - } - - // ================================================================================================================ // --- Overrides 'Payable' ---------------------------------------------------------------------------------------- diff --git a/contracts/impls/core/WitnetRequestFactoryDefault.sol b/contracts/core/defaults/WitnetRequestFactoryDefault.sol similarity index 91% rename from contracts/impls/core/WitnetRequestFactoryDefault.sol rename to contracts/core/defaults/WitnetRequestFactoryDefault.sol index bc95c6f93..9c975deb7 100644 --- a/contracts/impls/core/WitnetRequestFactoryDefault.sol +++ b/contracts/core/defaults/WitnetRequestFactoryDefault.sol @@ -3,12 +3,11 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; +import "../WitnetUpgradableBase.sol"; import "../../WitnetBytecodes.sol"; import "../../WitnetRequestFactory.sol"; import "../../data/WitnetRequestFactoryData.sol"; -import "../../impls/WitnetUpgradableBase.sol"; import "../../patterns/Clonable.sol"; -import "../../requests/WitnetRequest.sol"; contract WitnetRequestFactoryDefault is @@ -19,7 +18,7 @@ contract WitnetRequestFactoryDefault WitnetUpgradableBase { /// @notice Reference to Witnet Data Requests Bytecode Registry - IWitnetBytecodes immutable public override(IWitnetRequestFactory, WitnetRequestTemplate) registry; + WitnetBytecodes immutable public override(WitnetRequestFactory, WitnetRequestTemplate) registry; modifier onlyDelegateCalls override(Clonable, Upgradeable) { require( @@ -47,7 +46,7 @@ contract WitnetRequestFactoryDefault } constructor( - IWitnetBytecodes _registry, + WitnetBytecodes _registry, bool _upgradable, bytes32 _versionTag ) @@ -57,10 +56,6 @@ contract WitnetRequestFactoryDefault "io.witnet.requests.factory" ) { - require( - _registry.class() == type(WitnetBytecodes).interfaceId, - "WitnetRequestFactoryDefault: uncompliant registry" - ); registry = _registry; // let logic contract be used as a factory, while avoiding further initializations: __proxiable().proxy = address(this); @@ -184,7 +179,7 @@ contract WitnetRequestFactoryDefault } function class() - virtual override(IWitnetRequestFactory, WitnetRequestTemplate) + virtual override(WitnetRequestFactory, WitnetRequestTemplate) external view returns (bytes4) { @@ -192,7 +187,7 @@ contract WitnetRequestFactoryDefault address(this) == _SELF || address(this) == __proxy() ) { - return type(WitnetRequestFactory).interfaceId; + return type(IWitnetRequestFactory).interfaceId; } else if (__witnetRequest().radHash != bytes32(0)) { return type(WitnetRequest).interfaceId; } else { @@ -201,34 +196,6 @@ contract WitnetRequestFactoryDefault } - // ================================================================================================================ - // ---Overrides 'IERC165' ----------------------------------------------------------------------------------------- - - /// @dev See {IERC165-supportsInterface}. - function supportsInterface(bytes4 _interfaceId) - public view - virtual override - returns (bool) - { - if (__witnetRequest().radHash != bytes32(0)) { - return ( - _interfaceId == type(IWitnetRequest).interfaceId - || _interfaceId == type(WitnetRequest).interfaceId - || _interfaceId == type(WitnetRequestTemplate).interfaceId - ); - } - else if (__witnetRequestTemplate().retrievals.length > 0) { - return (_interfaceId == type(WitnetRequestTemplate).interfaceId); - } - else { - return ( - _interfaceId == type(WitnetRequestFactory).interfaceId - || super.supportsInterface(_interfaceId) - ); - } - } - - // ================================================================================================================ // --- Overrides 'Ownable2Step' ----------------------------------------------------------------------------------- @@ -281,7 +248,7 @@ contract WitnetRequestFactoryDefault /// @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) + function initialize(bytes memory _initData) virtual override public onlyDelegateCalls @@ -291,13 +258,13 @@ contract WitnetRequestFactoryDefault address _owner = __witnetRequestFactory().owner; if (_owner == address(0)) { - // set owner if none set yet - _owner = msg.sender; + // set owner from the one specified in _initData + _owner = abi.decode(_initData, (address)); __witnetRequestFactory().owner = _owner; } else { // only owner can initialize the proxy if (msg.sender != _owner) { - revert WitnetUpgradableBase.OnlyOwner(_owner); + revert("WitnetRequestFactoryDefault: not the owner"); } } @@ -309,11 +276,14 @@ contract WitnetRequestFactoryDefault if (__proxiable().implementation != address(0)) { // same implementation cannot be initialized more than once: if(__proxiable().implementation == base()) { - revert WitnetUpgradableBase.AlreadyUpgraded(base()); + revert("WitnetRequestFactoryDefault: already initialized"); } } __proxiable().implementation = base(); + require(address(registry).code.length > 0, "WitnetRequestFactoryDefault: inexistent registry"); + require(registry.class() == type(IWitnetBytecodes).interfaceId, "WitnetRequestFactoryDefault: uncompliant registry"); + emit Upgraded(msg.sender, base(), codehash(), version()); } @@ -411,7 +381,7 @@ contract WitnetRequestFactoryDefault override external view onlyDelegateCalls - returns (IWitnetRequestFactory) + returns (WitnetRequestFactory) { WitnetRequestTemplate _template = __witnetRequest().template; if (address(_template) != address(0)) { diff --git a/contracts/interfaces/IERC165.sol b/contracts/interfaces/IERC165.sol deleted file mode 100644 index 27d6b9ff4..000000000 --- a/contracts/interfaces/IERC165.sol +++ /dev/null @@ -1,3 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; -import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; diff --git a/contracts/interfaces/IERC20.sol b/contracts/interfaces/IERC20.sol deleted file mode 100644 index 35ce7b279..000000000 --- a/contracts/interfaces/IERC20.sol +++ /dev/null @@ -1,3 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.9.0; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/contracts/impls/mocks/WitnetRandomnessMock.sol b/contracts/mocks/WitnetRandomnessMock.sol similarity index 97% rename from contracts/impls/mocks/WitnetRandomnessMock.sol rename to contracts/mocks/WitnetRandomnessMock.sol index 3a5232eb9..f13ef281a 100644 --- a/contracts/impls/mocks/WitnetRandomnessMock.sol +++ b/contracts/mocks/WitnetRandomnessMock.sol @@ -3,7 +3,7 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "../apps/WitnetRandomnessProxiable.sol"; +import "../apps/WitnetRandomness.sol"; /// @title WitnetRandomness mock contract implementation. /// @dev TO BE USED ONLY ON DEVELOPMENT ENVIRONMENTS. @@ -13,7 +13,7 @@ import "../apps/WitnetRandomnessProxiable.sol"; /// @author Witnet Foundation. contract WitnetRandomnessMock is - WitnetRandomnessProxiable + WitnetRandomness { uint8 internal __mockRandomizeLatencyBlocks; uint256 internal __mockRandomizeFee; @@ -27,10 +27,7 @@ contract WitnetRandomnessMock uint8 _mockRandomizeLatencyBlocks, uint256 _mockRandomizeFee ) - WitnetRandomnessProxiable( - _wrb, - bytes32("mocked") - ) + WitnetRandomness(msg.sender, _wrb) { __mockRandomizeLatencyBlocks = _mockRandomizeLatencyBlocks; __mockRandomizeFee = _mockRandomizeFee; diff --git a/contracts/patterns/Payable.sol b/contracts/patterns/Payable.sol index 6ff570307..e31a8d1da 100644 --- a/contracts/patterns/Payable.sol +++ b/contracts/patterns/Payable.sol @@ -1,8 +1,7 @@ // SPDX-License-Identifier: MIT - pragma solidity >=0.6.0 <0.9.0; -import "../interfaces/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; abstract contract Payable { IERC20 public immutable currency; From cc601b81e7783ba598cb93292dd9c068dfa6fe49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 9 Nov 2023 08:13:50 +0100 Subject: [PATCH 11/86] chore: refactor app-oracles --- contracts/UsingWitnet.sol | 2 +- contracts/WitnetPriceFeeds.sol | 23 -- contracts/WitnetRandomness.sol | 25 -- contracts/{ => apps}/WitnetFeeds.sol | 12 +- .../WitnetPriceFeeds.sol} | 292 +++++++++--------- .../WitnetRandomness.sol} | 199 +++++------- contracts/interfaces/IWitnetRandomness.sol | 2 +- contracts/interfaces/V2/IWitnetFeeds.sol | 10 +- contracts/interfaces/V2/IWitnetFeedsAdmin.sol | 6 +- .../interfaces/V2/IWitnetFeedsEvents.sol | 12 - contracts/libs/WitnetPriceFeedsLib.sol | 4 +- 11 files changed, 241 insertions(+), 346 deletions(-) delete mode 100644 contracts/WitnetPriceFeeds.sol delete mode 100644 contracts/WitnetRandomness.sol rename contracts/{ => apps}/WitnetFeeds.sol (67%) rename contracts/{impls/apps/WitnetPriceFeedsUpgradable.sol => apps/WitnetPriceFeeds.sol} (82%) rename contracts/{impls/apps/WitnetRandomnessProxiable.sol => apps/WitnetRandomness.sol} (82%) delete mode 100644 contracts/interfaces/V2/IWitnetFeedsEvents.sol diff --git a/contracts/UsingWitnet.sol b/contracts/UsingWitnet.sol index de2ff6ceb..dbd08f8e9 100644 --- a/contracts/UsingWitnet.sol +++ b/contracts/UsingWitnet.sol @@ -16,7 +16,7 @@ abstract contract UsingWitnet { /// @param _wrb The WitnetRequestBoard entry point address. constructor(WitnetRequestBoard _wrb) { - require(address(_wrb) != address(0), "UsingWitnet: no WRB"); + require(address(_wrb) != address(0), "UsingWitnet: no WRB?"); __witnet = _wrb; } diff --git a/contracts/WitnetPriceFeeds.sol b/contracts/WitnetPriceFeeds.sol deleted file mode 100644 index 930dde290..000000000 --- a/contracts/WitnetPriceFeeds.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.8.0 <0.9.0; - -import "ado-contracts/contracts/interfaces/IERC2362.sol"; -import "./interfaces/V2/IWitnetPriceFeeds.sol"; -import "./interfaces/V2/IWitnetPriceSolverDeployer.sol"; -import "./WitnetFeeds.sol"; - -abstract contract WitnetPriceFeeds - is - IERC2362, - IWitnetPriceFeeds, - IWitnetPriceSolverDeployer, - WitnetFeeds -{ - constructor() - WitnetFeeds( - WitnetV2.RadonDataTypes.Integer, - "Price-" - ) - {} -} \ No newline at end of file diff --git a/contracts/WitnetRandomness.sol b/contracts/WitnetRandomness.sol deleted file mode 100644 index 98fc8384b..000000000 --- a/contracts/WitnetRandomness.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.7.0 <0.9.0; -pragma experimental ABIEncoderV2; - -import "./interfaces/IWitnetRandomness.sol"; -import "./interfaces/IWitnetRandomnessAdmin.sol"; - -abstract contract WitnetRandomness - is - IWitnetRandomness, - IWitnetRandomnessAdmin -{ - /// Deploys a minimal-proxy clone in which the `witnetRandomnessRequest` is owned by the cloner, - /// @dev This function should always provide a new address, no matter how many times - /// @dev is actually called from the same `msg.sender`. - function clone() virtual external returns (WitnetRandomness); - - /// Deploys a minimal-proxy clone in which the `witnetRandomnessRequest` is owned by the cloner, - /// and whose address will be determined by the provided salt. - /// @dev This function uses the CREATE2 opcode and a `_salt` to deterministically deploy - /// @dev the clone. Using the same `_salt` multiple time will revert, since - /// @dev no contract can be deployed more than once at the same address. - function cloneDeterministic(bytes32 salt) virtual external returns (WitnetRandomness); -} \ No newline at end of file diff --git a/contracts/WitnetFeeds.sol b/contracts/apps/WitnetFeeds.sol similarity index 67% rename from contracts/WitnetFeeds.sol rename to contracts/apps/WitnetFeeds.sol index 39c4be992..02b5db958 100644 --- a/contracts/WitnetFeeds.sol +++ b/contracts/apps/WitnetFeeds.sol @@ -1,18 +1,16 @@ // SPDX-License-Identifier: MIT -pragma solidity >=0.8.0 <0.9.0; +pragma solidity >=0.7.0 <0.9.0; -import "./interfaces/V2/IFeeds.sol"; -import "./interfaces/V2/IWitnetFeeds.sol"; -import "./interfaces/V2/IWitnetFeedsAdmin.sol"; -import "./interfaces/V2/IWitnetFeedsEvents.sol"; +import "../interfaces/V2/IFeeds.sol"; +import "../interfaces/V2/IWitnetFeeds.sol"; +import "../interfaces/V2/IWitnetFeedsAdmin.sol"; abstract contract WitnetFeeds is IFeeds, IWitnetFeeds, - IWitnetFeedsAdmin, - IWitnetFeedsEvents + IWitnetFeedsAdmin { WitnetV2.RadonDataTypes immutable public override dataType; diff --git a/contracts/impls/apps/WitnetPriceFeedsUpgradable.sol b/contracts/apps/WitnetPriceFeeds.sol similarity index 82% rename from contracts/impls/apps/WitnetPriceFeedsUpgradable.sol rename to contracts/apps/WitnetPriceFeeds.sol index 7647677c0..bcf984ab2 100644 --- a/contracts/impls/apps/WitnetPriceFeedsUpgradable.sol +++ b/contracts/apps/WitnetPriceFeeds.sol @@ -3,47 +3,57 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "../../WitnetPriceFeeds.sol"; -import "../../WitnetRequestBoard.sol"; -import "../../data/WitnetPriceFeedsData.sol"; -import "../../impls/WitnetUpgradableBase.sol"; +import "ado-contracts/contracts/interfaces/IERC2362.sol"; -import "../../interfaces/V2/IWitnetPriceSolver.sol"; -import "../../libs/WitnetPriceFeedsLib.sol"; +import "./WitnetFeeds.sol"; +import "../WitnetRequestBoard.sol"; +import "../data/WitnetPriceFeedsData.sol"; +import "../interfaces/V2/IWitnetPriceFeeds.sol"; +import "../interfaces/V2/IWitnetPriceSolver.sol"; +import "../interfaces/V2/IWitnetPriceSolverDeployer.sol"; +import "../libs/WitnetPriceFeedsLib.sol"; +import "../patterns/Ownable2Step.sol"; -/// @title WitnetPriceFeedsUpgradable: ... -/// @author Witnet Foundation. -contract WitnetPriceFeedsUpgradable +/// @title WitnetPriceFeeds: Price Feeds oracle reliant on the Witnet Solidity Bridge. +/// @author Guillermo Díaz + +contract WitnetPriceFeeds is - WitnetPriceFeeds, - WitnetPriceFeedsData, - WitnetUpgradableBase + IERC2362, + IWitnetPriceFeeds, + IWitnetPriceSolverDeployer, + Ownable2Step, + WitnetFeeds, + WitnetPriceFeedsData { using Witnet for Witnet.Result; using WitnetV2 for WitnetV2.RadonSLA; IWitnetRequestBoard immutable public override witnet; - constructor( - IWitnetRequestBoard _wrb, - bool _upgradable, - bytes32 _version - ) - WitnetUpgradableBase( - _upgradable, - _version, - "io.witnet.proxiable.router" + constructor(address _operator, WitnetRequestBoard _wrb) + WitnetFeeds( + WitnetV2.RadonDataTypes.Integer, + "Price-" ) { + _transferOwnership(_operator); require( - _wrb.class() == type(WitnetRequestBoard).interfaceId, - "WitnetPriceFeedsUpgradable: uncompliant request board" + _wrb.class() == type(IWitnetRequestBoard).interfaceId, + "WitnetPriceFeeds: uncompliant request board" ); witnet = _wrb; + __settleDefaultRadonSLA(WitnetV2.RadonSLA({ + numWitnesses: 5, + witnessCollateral: 15 * 10 ** 9, + witnessReward: 15 * 10 ** 7, + minerCommitRevealFee: 10 ** 7, + minConsensusPercentage: 51 + })); } // solhint-disable-next-line payable-fallback - fallback() override external { + fallback() external { if ( msg.sig == IWitnetPriceSolver.solve.selector && msg.sender == address(this) @@ -51,7 +61,7 @@ contract WitnetPriceFeedsUpgradable address _solver = __records_(bytes4(bytes8(msg.data) << 32)).solver; require( _solver != address(0), - "WitnetPriceFeedsUpgradable: unsettled solver" + "WitnetPriceFeeds: unsettled solver" ); assembly { let ptr := mload(0x40) @@ -64,64 +74,11 @@ contract WitnetPriceFeedsUpgradable default { return(ptr, size) } } } else { - revert("WitnetPriceFeedsUpgradable: not implemented"); + revert("WitnetPriceFeeds: not implemented"); } } - // ================================================================================================================ - // --- 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("WitnetPriceFeedsUpgradable: not the owner"); - } - } - require( - __proxiable().implementation != base(), - "WitnetPriceFeedsUpgradable: already initialized" - ); - if (__storage().defaultSlaHash == 0) { - settleDefaultRadonSLA(WitnetV2.RadonSLA({ - numWitnesses: 5, - witnessCollateral: 15 * 10 ** 9, - witnessReward: 15 * 10 ** 7, - minerCommitRevealFee: 10 ** 7, - minConsensusPercentage: 51 - })); - } - __proxiable().implementation = base(); - emit Upgraded(msg.sender, base(), codehash(), version()); - } - - /// Tells whether provided address could eventually upgrade the contract. - function isUpgradableFrom(address _from) - override - external view - returns (bool) - { - return ( - // false if the contract is set as not upgradable, or `_from` is not the owner - isUpgradable() - && _from == owner() - ); - } - - // ================================================================================================================ // --- Implements 'IFeeds' ---------------------------------------------------------------------------------------- @@ -259,7 +216,7 @@ contract WitnetPriceFeedsUpgradable Record storage __record = __records_(feedId); require( __record.radHash != 0, - "WitnetPriceFeedsUpgradable: no RAD hash" + "WitnetPriceFeeds: no RAD hash" ); return registry().bytecodeOf( __record.radHash, @@ -286,7 +243,7 @@ contract WitnetPriceFeedsUpgradable } function registry() public view virtual override returns (IWitnetBytecodes) { - return witnet.registry(); + return WitnetRequestBoard(address(witnet)).registry(); } function requestUpdate(bytes4 feedId) @@ -294,7 +251,7 @@ contract WitnetPriceFeedsUpgradable virtual override returns (uint256) { - return _requestUpdate(feedId, __storage().defaultSlaHash); + return __requestUpdate(feedId, __storage().defaultSlaHash); } function requestUpdate(bytes4 feedId, bytes32 _slaHash) @@ -304,75 +261,45 @@ contract WitnetPriceFeedsUpgradable { require( registry().lookupRadonSLA(_slaHash).equalOrGreaterThan(defaultRadonSLA()), - "WitnetPriceFeedsUpgradable: unsecure update" + "WitnetPriceFeeds: unsecure update" ); - return _requestUpdate(feedId, _slaHash); + return __requestUpdate(feedId, _slaHash); } - function _requestUpdate(bytes4[] memory _deps, bytes32 slaHash) - virtual internal - returns (uint256 _usedFunds) + + // ================================================================================================================ + // --- Implements 'IWitnetFeedsAdmin' ----------------------------------------------------------------------------- + + function owner() + virtual override (IWitnetFeedsAdmin, Ownable) + public view + returns (address) { - uint _partial = msg.value / _deps.length; - for (uint _ix = 0; _ix < _deps.length; _ix ++) { - _usedFunds += this.requestUpdate{value: _partial}(_deps[_ix], slaHash); - } + return Ownable.owner(); } - - function _requestUpdate(bytes4 feedId, bytes32 _slaHash) - virtual internal - returns (uint256 _usedFunds) + + function acceptOwnership() + virtual override (IWitnetFeedsAdmin, Ownable2Step) + public { - Record storage __feed = __records_(feedId); - if (__feed.radHash != 0) { - _usedFunds = estimateUpdateBaseFee(feedId, tx.gasprice, 0, _slaHash); - require(msg.value>= _usedFunds, "WitnetPriceFeedsUpgradable: reward too low"); - uint _latestId = __feed.latestUpdateQueryId; - Witnet.ResultStatus _latestStatus = _checkQueryResultStatus(_latestId); - if (_latestStatus == Witnet.ResultStatus.Awaiting) { - // latest update is still pending, so just increase the reward - // accordingly to current tx gasprice: - int _deltaReward = int(witnet.readRequestReward(_latestId)) - int(_usedFunds); - if (_deltaReward > 0) { - _usedFunds = uint(_deltaReward); - witnet.upgradeReward{value: _usedFunds}(_latestId); - emit UpdatingFeedReward(msg.sender, feedId, _usedFunds); - } else { - _usedFunds = 0; - } - } else { - // Check if latest update ended successfully: - if (_latestStatus == Witnet.ResultStatus.Ready) { - // If so, remove previous last valid query from the WRB: - if (__feed.latestValidQueryId > 0) { - witnet.deleteQuery(__feed.latestValidQueryId); - } - __feed.latestValidQueryId = _latestId; - } else { - // Otherwise, try to delete latest query, as it was faulty - // and we are about to post a new update request: - try witnet.deleteQuery(_latestId) {} catch {} - } - // Post update request to the WRB: - _latestId = witnet.postRequest{value: _usedFunds}(__feed.radHash, _slaHash); - // Update latest query id: - __feed.latestUpdateQueryId = _latestId; - emit UpdatingFeed(msg.sender, feedId, _slaHash, _usedFunds); - } - } else if (__feed.solver != address(0)) { - _usedFunds = _requestUpdate(_depsOf(feedId), _slaHash); - } else { - revert("WitnetPriceFeedsUpgradable: unknown feed"); - } - if (_usedFunds < msg.value) { - // transfer back unused funds: - payable(msg.sender).transfer(msg.value - _usedFunds); - } + Ownable2Step.acceptOwnership(); } - - // ================================================================================================================ - // --- Implements 'IWitnetFeedsAdmin' ----------------------------------------------------------------------- + function pendingOwner() + virtual override (IWitnetFeedsAdmin, Ownable2Step) + public view + returns (address) + { + return Ownable2Step.pendingOwner(); + } + + function transferOwnership(address _newOwner) + virtual override (IWitnetFeedsAdmin, Ownable2Step) + public + onlyOwner + { + Ownable.transferOwnership(_newOwner); + } function deleteFeed(string calldata caption) virtual override @@ -383,7 +310,7 @@ contract WitnetPriceFeedsUpgradable bytes4[] storage __ids = __storage().ids; Record storage __record = __records_(feedId); uint _index = __record.index; - require(_index != 0, "WitnetPriceFeedsUpgradable: unknown feed"); + require(_index != 0, "WitnetPriceFeeds: unknown feed"); { bytes4 _lastFeedId = __ids[__ids.length - 1]; __ids[_index - 1] = _lastFeedId; @@ -397,7 +324,7 @@ contract WitnetPriceFeedsUpgradable override public onlyOwner { - __storage().defaultSlaHash = registry().verifyRadonSLA(sla); + __settleDefaultRadonSLA(sla); } function settleFeedRequest(string calldata caption, bytes32 radHash) @@ -406,7 +333,7 @@ contract WitnetPriceFeedsUpgradable { require( registry().lookupRadonRequestResultDataType(radHash) == dataType, - "WitnetPriceFeedsUpgradable: bad result data type" + "WitnetPriceFeeds: bad result data type" ); bytes4 feedId = hash(caption); Record storage __record = __records_(feedId); @@ -453,7 +380,7 @@ contract WitnetPriceFeedsUpgradable { require( solver != address(0), - "WitnetPriceFeedsUpgradable: no solver address" + "WitnetPriceFeeds: no solver address" ); bytes4 feedId = hash(caption); Record storage __record = __records_(feedId); @@ -499,7 +426,7 @@ contract WitnetPriceFeedsUpgradable _reason := add(_reason, 4) } revert(string(abi.encodePacked( - "WitnetPriceFeedsUpgradable: smoke-test failed: ", + "WitnetPriceFeeds: smoke-test failed: ", string(abi.decode(_reason,(string))) ))); } @@ -560,7 +487,7 @@ contract WitnetPriceFeedsUpgradable _result := add(_result, 4) } revert(string(abi.encodePacked( - "WitnetPriceFeedsUpgradable: ", + "WitnetPriceFeeds: ", string(abi.decode(_result, (string))) ))); } else { @@ -673,9 +600,74 @@ contract WitnetPriceFeedsUpgradable return _decimals; } catch Error(string memory reason) { revert(string(abi.encodePacked( - "WitnetPriceFeedsUpgradable: ", + "WitnetPriceFeeds: ", reason ))); } } + + function __requestUpdate(bytes4[] memory _deps, bytes32 slaHash) + virtual internal + returns (uint256 _usedFunds) + { + uint _partial = msg.value / _deps.length; + for (uint _ix = 0; _ix < _deps.length; _ix ++) { + _usedFunds += this.requestUpdate{value: _partial}(_deps[_ix], slaHash); + } + } + + function __requestUpdate(bytes4 feedId, bytes32 _slaHash) + virtual internal + returns (uint256 _usedFunds) + { + Record storage __feed = __records_(feedId); + if (__feed.radHash != 0) { + _usedFunds = estimateUpdateBaseFee(feedId, tx.gasprice, 0, _slaHash); + require(msg.value>= _usedFunds, "WitnetPriceFeeds: reward too low"); + uint _latestId = __feed.latestUpdateQueryId; + Witnet.ResultStatus _latestStatus = _checkQueryResultStatus(_latestId); + if (_latestStatus == Witnet.ResultStatus.Awaiting) { + // latest update is still pending, so just increase the reward + // accordingly to current tx gasprice: + int _deltaReward = int(witnet.readRequestReward(_latestId)) - int(_usedFunds); + if (_deltaReward > 0) { + _usedFunds = uint(_deltaReward); + witnet.upgradeReward{value: _usedFunds}(_latestId); + emit UpdatingFeedReward(msg.sender, feedId, _usedFunds); + } else { + _usedFunds = 0; + } + } else { + // Check if latest update ended successfully: + if (_latestStatus == Witnet.ResultStatus.Ready) { + // If so, remove previous last valid query from the WRB: + if (__feed.latestValidQueryId > 0) { + witnet.deleteQuery(__feed.latestValidQueryId); + } + __feed.latestValidQueryId = _latestId; + } else { + // Otherwise, try to delete latest query, as it was faulty + // and we are about to post a new update request: + try witnet.deleteQuery(_latestId) {} catch {} + } + // Post update request to the WRB: + _latestId = witnet.postRequest{value: _usedFunds}(__feed.radHash, _slaHash); + // Update latest query id: + __feed.latestUpdateQueryId = _latestId; + emit UpdatingFeed(msg.sender, feedId, _slaHash, _usedFunds); + } + } else if (__feed.solver != address(0)) { + _usedFunds = __requestUpdate(_depsOf(feedId), _slaHash); + } else { + revert("WitnetPriceFeeds: unknown feed"); + } + if (_usedFunds < msg.value) { + // transfer back unused funds: + payable(msg.sender).transfer(msg.value - _usedFunds); + } + } + + function __settleDefaultRadonSLA(WitnetV2.RadonSLA memory sla) internal { + __storage().defaultSlaHash = registry().verifyRadonSLA(sla); + } } diff --git a/contracts/impls/apps/WitnetRandomnessProxiable.sol b/contracts/apps/WitnetRandomness.sol similarity index 82% rename from contracts/impls/apps/WitnetRandomnessProxiable.sol rename to contracts/apps/WitnetRandomness.sol index 12a11c13b..2fabca8e3 100644 --- a/contracts/impls/apps/WitnetRandomnessProxiable.sol +++ b/contracts/apps/WitnetRandomness.sol @@ -3,25 +3,25 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; - -import "../../UsingWitnet.sol"; -import "../../WitnetRandomness.sol"; -import "../../impls/WitnetUpgradableBase.sol"; -import "../../patterns/Clonable.sol"; - -import "../../requests/WitnetRequest.sol"; - -/// @title WitnetRandomnessProxiable: A trustless randomness generator and registry, using the Witnet oracle. -/// @author Witnet Foundation. -contract WitnetRandomnessProxiable +import "../UsingWitnet.sol"; +import "../WitnetRequest.sol"; +import "../core/WitnetUpgradableBase.sol"; +import "../interfaces/IWitnetRandomness.sol"; +import "../interfaces/IWitnetRandomnessAdmin.sol"; +import "../patterns/Clonable.sol"; +import "../patterns/Ownable2Step.sol"; + +/// @title WitnetRandomness: Randomness oracle reliant on the Witnet Solidity Bridge. +/// @author Guillermo Díaz + +contract WitnetRandomness is + IWitnetRandomness, + IWitnetRandomnessAdmin, Clonable, - UsingWitnet, - WitnetRandomness, - WitnetUpgradableBase + Ownable2Step, + UsingWitnet { - using ERC165Checker for address; using Witnet for Witnet.Result; uint256 public override latestRandomizeBlock; @@ -38,47 +38,19 @@ contract WitnetRandomnessProxiable uint256 witnetQueryId; } - modifier onlyDelegateCalls override(Clonable, Upgradeable) { - require(address(this) != base(), "WitnetRandomnessProxiable: not a delegate call"); - _; - } - - function witnet() - virtual override (IWitnetRandomness, UsingWitnet) - public view returns (WitnetRequestBoard) - { - return UsingWitnet.witnet(); - } - - /// Include an address to specify the immutable WitnetRequestBoard entrypoint address. - /// @param _wrb The WitnetRequestBoard immutable entrypoint address. - constructor( - WitnetRequestBoard _wrb, - bytes32 _version - ) + constructor(address _operator, WitnetRequestBoard _wrb) UsingWitnet(_wrb) - WitnetUpgradableBase( - false, - _version, - "io.witnet.proxiable.randomness" - ) { - require( - address(_wrb) == address(0) - || address(_wrb).supportsInterface(type(WitnetRequestBoard).interfaceId), - "WitnetRandomnessProxiable: uncompliant request board" - ); - IWitnetRequestFactory _factory = witnet().factory(); - IWitnetBytecodes _registry = _factory.registry(); + _transferOwnership(_operator); + assert(_wrb.class() == type(IWitnetRequestBoard).interfaceId); + WitnetRequestFactory _factory = witnet().factory(); + WitnetBytecodes _registry = witnet().registry(); { // Build own Witnet Randomness Request: bytes32[] memory _retrievals = new bytes32[](1); _retrievals[0] = _registry.verifyRadonRetrieval( WitnetV2.DataRequestMethods.Rng, - "", // no schema - "", // no authority - "", // no path - "", // no query + "", // no url "", // no body new string[2][](0), // no headers hex"80" // no retrieval script @@ -106,6 +78,31 @@ contract WitnetRandomnessProxiable __initializeWitnetRandomnessSlaHash(); } + /// Deploys and returns the address of a minimal proxy clone that replicates contract + /// behaviour while using its own EVM storage. + /// @dev This function should always provide a new address, no matter how many times + /// @dev is actually called from the same `msg.sender`. + function clone() + virtual public + wasInitialized + returns (WitnetRandomness) + { + return __afterClone(_clone()); + } + + /// Deploys and returns the address of a minimal proxy clone that replicates contract + /// behaviour while using its own EVM storage. + /// @dev This function uses the CREATE2 opcode and a `_salt` to deterministically deploy + /// @dev the clone. Using the same `_salt` multiple time will revert, since + /// @dev no contract can be deployed more than once at the same address. + function cloneDeterministic(bytes32 _salt) + virtual public + wasInitialized + returns (WitnetRandomness) + { + return __afterClone(_cloneDeterministic(_salt)); + } + /// @notice Initializes a cloned instance. /// @dev Every cloned instance can only get initialized once. function initializeClone(bytes memory _initData) @@ -113,12 +110,12 @@ contract WitnetRandomnessProxiable initializer // => ensure a cloned instance can only be initialized once onlyDelegateCalls // => this method can only be called upon cloned instances { - _initialize(_initData); + __initialize(_initData); } /// =============================================================================================================== - /// --- 'WitnetRandomnessAdmin' implementation ------------------------------------------------------------------------- + /// --- 'IWitnetRandomnessAdmin' implementation ------------------------------------------------------------------- function owner() virtual override (IWitnetRandomnessAdmin, Ownable) @@ -155,41 +152,14 @@ contract WitnetRandomnessProxiable virtual override public onlyOwner - returns (bytes32 _radonSlaHash) + returns (bytes32) { - _radonSlaHash = witnet().registry().verifyRadonSLA(_radonSLA); - __witnetRandomnessSlaHash = _radonSlaHash; + return __settleWitnetRandomnessSLA(_radonSLA); } + /// =============================================================================================================== - /// --- 'WitnetRandomness' implementation ------------------------------------------------------------------------- - - /// Deploys and returns the address of a minimal proxy clone that replicates contract - /// behaviour while using its own EVM storage. - /// @dev This function should always provide a new address, no matter how many times - /// @dev is actually called from the same `msg.sender`. - function clone() - virtual override - public - wasInitialized - returns (WitnetRandomness) - { - return _afterClone(_clone()); - } - - /// Deploys and returns the address of a minimal proxy clone that replicates contract - /// behaviour while using its own EVM storage. - /// @dev This function uses the CREATE2 opcode and a `_salt` to deterministically deploy - /// @dev the clone. Using the same `_salt` multiple time will revert, since - /// @dev no contract can be deployed more than once at the same address. - function cloneDeterministic(bytes32 _salt) - virtual override - public - wasInitialized - returns (WitnetRandomness) - { - return _afterClone(_cloneDeterministic(_salt)); - } + /// --- 'IWitnetRandomness' implementation ------------------------------------------------------------------------- /// Returns amount of wei required to be paid as a fee when requesting randomization with a /// transaction gas price as the one given. @@ -244,16 +214,16 @@ contract WitnetRandomnessProxiable _block = getRandomnessNextBlock(_block); } uint256 _queryId = __randomize_[_block].witnetQueryId; - require(_queryId != 0, "WitnetRandomnessProxiable: not randomized"); + require(_queryId != 0, "WitnetRandomness: not randomized"); Witnet.ResultStatus _resultStatus = witnet().checkResultStatus(_queryId); if (_resultStatus == Witnet.ResultStatus.Ready) { return witnet().readResponseResult(_queryId).asBytes32(); } else if (_resultStatus == Witnet.ResultStatus.Error) { uint256 _nextRandomizeBlock = __randomize_[_block].nextBlock; - require(_nextRandomizeBlock != 0, "WitnetRandomnessProxiable: faulty randomize"); + require(_nextRandomizeBlock != 0, "WitnetRandomness: faulty randomize"); return getRandomnessAfter(_nextRandomizeBlock); } else { - revert("WitnetRandomnessProxiable: pending randomize"); + revert("WitnetRandomness: pending randomize"); } } @@ -407,6 +377,14 @@ contract WitnetRandomnessProxiable } } + /// @notice Result the WitnetRequestBoard address upon which this contract relies on. + function witnet() + virtual override (IWitnetRandomness, UsingWitnet) + public view returns (WitnetRequestBoard) + { + return UsingWitnet.witnet(); + } + /// @notice Returns SLA parameters that are being used every time there's a new randomness request. function witnetRandomnessSLA() virtual override @@ -417,37 +395,6 @@ contract WitnetRandomnessProxiable } - // ================================================================================================================ - // --- 'Upgradeable' extension ------------------------------------------------------------------------------------ - - /// Initialize storage-context when invoked as delegatecall. - /// @dev Must fail when trying to initialize same instance more than once. - function initialize(bytes memory) - public - virtual 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 initilized for the first time ... - __proxiable().proxy = address(this); - _transferOwnership(msg.sender); - __initializeWitnetRandomnessSlaHash(); - } - else if (__proxiable().implementation == base()) { - revert("WitnetRandomnessProxiable: not upgradeable"); - } - __proxiable().implementation = base(); - } - - /// Tells whether provided address could eventually upgrade the contract. - function isUpgradableFrom(address) external pure override returns (bool) { - return false; - } - - // ================================================================================================================ // --- 'Clonable' extension --------------------------------------------------------------------------------------- @@ -465,29 +412,27 @@ contract WitnetRandomnessProxiable // --- INTERNAL FUNCTIONS ----------------------------------------------------------------------------------------- /// @dev Common steps for both deterministic and non-deterministic cloning. - function _afterClone(address _instance) + function __afterClone(address _instance) virtual internal returns (WitnetRandomness) { - WitnetRandomnessProxiable(_instance).initializeClone(hex""); + WitnetRandomness(_instance).initializeClone(hex""); return WitnetRandomness(_instance); } /// @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) + function __initialize(bytes memory) virtual internal { // settle ownership: _transferOwnership(msg.sender); // initialize default Witnet SLA parameters used for every randomness request; __initializeWitnetRandomnessSlaHash(); - // make sure that this clone cannot ever get initialized as a proxy: - __proxiable().implementation = base(); } function __initializeWitnetRandomnessSlaHash() virtual internal { - settleWitnetRandomnessSLA(WitnetV2.RadonSLA({ + __settleWitnetRandomnessSLA(WitnetV2.RadonSLA({ numWitnesses: 5, minConsensusPercentage: 51, witnessReward: 10 ** 8, @@ -496,6 +441,14 @@ contract WitnetRandomnessProxiable })); } + function __settleWitnetRandomnessSLA(WitnetV2.RadonSLA memory _radonSLA) + internal + returns (bytes32 _radonSlaHash) + { + _radonSlaHash = witnet().registry().verifyRadonSLA(_radonSLA); + __witnetRandomnessSlaHash = _radonSlaHash; + } + /// @dev Returns index of the Most Significant Bit of the given number, applying De Bruijn O(1) algorithm. function _msbDeBruijn32(uint32 _v) internal pure diff --git a/contracts/interfaces/IWitnetRandomness.sol b/contracts/interfaces/IWitnetRandomness.sol index f3759b945..c6e561bce 100644 --- a/contracts/interfaces/IWitnetRandomness.sol +++ b/contracts/interfaces/IWitnetRandomness.sol @@ -2,8 +2,8 @@ pragma solidity >=0.7.0 <0.9.0; +import "../WitnetRequest.sol"; import "../WitnetRequestBoard.sol"; -import "../requests/WitnetRequest.sol"; /// @title The Witnet Randomness generator interface. /// @author Witnet Foundation. diff --git a/contracts/interfaces/V2/IWitnetFeeds.sol b/contracts/interfaces/V2/IWitnetFeeds.sol index b1300ff4f..52dc6bcf2 100644 --- a/contracts/interfaces/V2/IWitnetFeeds.sol +++ b/contracts/interfaces/V2/IWitnetFeeds.sol @@ -3,9 +3,17 @@ pragma solidity >=0.8.0 <0.9.0; import "./IWitnetBytecodes.sol"; -import "./IWitnetRequestBoard.sol"; +import "../IWitnetRequestBoard.sol"; interface IWitnetFeeds { + + event DeletedFeed(address indexed from, bytes4 indexed feedId, string caption); + event SettledFeed(address indexed from, bytes4 indexed feedId, string caption, bytes32 radHash); + event SettledFeedSolver(address indexed from, bytes4 indexed feedId, string caption, address solver); + event SettledRadonSLA(address indexed from, bytes32 slaHash); + event UpdatingFeed(address indexed from, bytes4 indexed feedId, bytes32 slaHash, uint256 value); + event UpdatingFeedReward(address indexed from, bytes4 indexed feedId, uint256 value); + function dataType() external view returns (WitnetV2.RadonDataTypes); function prefix() external view returns (string memory); function registry() external view returns (IWitnetBytecodes); diff --git a/contracts/interfaces/V2/IWitnetFeedsAdmin.sol b/contracts/interfaces/V2/IWitnetFeedsAdmin.sol index 92f4694fe..9388cddaa 100644 --- a/contracts/interfaces/V2/IWitnetFeedsAdmin.sol +++ b/contracts/interfaces/V2/IWitnetFeedsAdmin.sol @@ -3,13 +3,17 @@ pragma solidity >=0.8.0 <0.9.0; import "../../libs/WitnetV2.sol"; -import "../../requests/WitnetRequest.sol"; +import "../../WitnetRequest.sol"; interface IWitnetFeedsAdmin { + function acceptOwnership() external; function deleteFeed(string calldata caption) external; + function owner() external view returns (address); + function pendingOwner() external returns (address); function settleDefaultRadonSLA(WitnetV2.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; function settleFeedSolver(string calldata caption, address solver, string[] calldata deps) external; + function transferOwnership(address) external; } \ No newline at end of file diff --git a/contracts/interfaces/V2/IWitnetFeedsEvents.sol b/contracts/interfaces/V2/IWitnetFeedsEvents.sol deleted file mode 100644 index f619e98ca..000000000 --- a/contracts/interfaces/V2/IWitnetFeedsEvents.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.8.0 <0.9.0; - -interface IWitnetFeedsEvents { - event DeletedFeed(address indexed from, bytes4 indexed feedId, string caption); - event SettledFeed(address indexed from, bytes4 indexed feedId, string caption, bytes32 radHash); - event SettledFeedSolver(address indexed from, bytes4 indexed feedId, string caption, address solver); - event SettledRadonSLA(address indexed from, bytes32 slaHash); - event UpdatingFeed(address indexed from, bytes4 indexed feedId, bytes32 slaHash, uint256 value); - event UpdatingFeedReward(address indexed from, bytes4 indexed feedId, uint256 value); -} \ No newline at end of file diff --git a/contracts/libs/WitnetPriceFeedsLib.sol b/contracts/libs/WitnetPriceFeedsLib.sol index 44ed75b09..5d3c0ca62 100644 --- a/contracts/libs/WitnetPriceFeedsLib.sol +++ b/contracts/libs/WitnetPriceFeedsLib.sol @@ -6,9 +6,9 @@ pragma experimental ABIEncoderV2; import "../interfaces/V2/IWitnetPriceSolver.sol"; import "../interfaces/V2/IWitnetPriceSolverDeployer.sol"; -import "./Slices.sol"; +import "../libs/Slices.sol"; -/// @title Ancillary external library for WitnetPriceFeeds implementations. +/// @title Ancillary deployable library for WitnetPriceFeeds. /// @dev Features: /// @dev - deployment of counter-factual IWitnetPriceSolver instances. /// @dev - validation of feed caption strings. From efde9c28136ad4ab7c126ea8990fed0c77aba588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 9 Nov 2023 08:52:20 +0100 Subject: [PATCH 12/86] feat: support counter-factual bindings on migrations --- migrations/scripts/1_Create2Factory.js | 59 ---- migrations/scripts/1_deployer.js | 30 ++ migrations/scripts/2_WitnetLibs.js | 44 --- migrations/scripts/2_libs.js | 61 ++++ migrations/scripts/3_WitnetBytecodes.js | 127 -------- migrations/scripts/3_core.js | 147 ++++++++++ migrations/scripts/4_WitnetRequestFactory.js | 126 -------- migrations/scripts/4_proxies.js | 135 +++++++++ migrations/scripts/5_WitnetRequestBoard.js | 146 --------- migrations/scripts/5_apps.js | 130 ++++++++ migrations/scripts/6_WitnetRandomness.js | 154 ---------- migrations/scripts/7_WitnetPriceFeeds.js | 172 ----------- migrations/scripts/8_WitnetPriceRouter.js | 43 --- migrations/witnet.salts.js | 22 -- migrations/witnet.settings.js | 294 ++++++++++++------- 15 files changed, 698 insertions(+), 992 deletions(-) delete mode 100644 migrations/scripts/1_Create2Factory.js create mode 100644 migrations/scripts/1_deployer.js delete mode 100644 migrations/scripts/2_WitnetLibs.js create mode 100644 migrations/scripts/2_libs.js delete mode 100644 migrations/scripts/3_WitnetBytecodes.js create mode 100644 migrations/scripts/3_core.js delete mode 100644 migrations/scripts/4_WitnetRequestFactory.js create mode 100644 migrations/scripts/4_proxies.js delete mode 100644 migrations/scripts/5_WitnetRequestBoard.js create mode 100644 migrations/scripts/5_apps.js delete mode 100644 migrations/scripts/6_WitnetRandomness.js delete mode 100644 migrations/scripts/7_WitnetPriceFeeds.js delete mode 100644 migrations/scripts/8_WitnetPriceRouter.js delete mode 100644 migrations/witnet.salts.js diff --git a/migrations/scripts/1_Create2Factory.js b/migrations/scripts/1_Create2Factory.js deleted file mode 100644 index 461307ab9..000000000 --- a/migrations/scripts/1_Create2Factory.js +++ /dev/null @@ -1,59 +0,0 @@ -const fs = require("fs") - -const addresses = require("../witnet.addresses") -const utils = require("../../scripts/utils") - -const Create2Factory = artifacts.require("Create2Factory") - -module.exports = async function (deployer, network, [, from,,,,, master]) { - const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" - const ecosystem = utils.getRealmNetworkFromArgs()[0] - network = network.split("-")[0] - - if (!addresses[ecosystem]) addresses[ecosystem] = {} - if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} - - let factory - if (utils.isNullAddress(addresses[ecosystem][network]?.Create2Factory)) { - await deployer.deploy(Create2Factory, { from: master }) - factory = await Create2Factory.deployed() - addresses[ecosystem][network].Create2Factory = factory.address - if (!isDryRun) { - utils.saveAddresses(addresses) - } - } else { - factory = await Create2Factory.at(addresses[ecosystem][network].Create2Factory) - Create2Factory.address = factory.address - utils.traceHeader("Skipping 'Create2Factory'") - console.info(" > Contract address:", factory.address) - console.info() - } - - // Settle WitnetProxy bytecode and source code as to guarantee - // salted addresses remain as expected no matter if the solc version - // is changed in migrations/witnet.settings.js - utils.traceHeader("Defrosting 'WitnetProxy' artifact") - fs.writeFileSync( - `build/${ecosystem}/contracts/WitnetProxy.json`, - fs.readFileSync("migrations/abis/WitnetProxy.json"), - { encoding: "utf8", flag: "w" } - ) - const WitnetProxy = artifacts.require("WitnetProxy") - const metadata = JSON.parse(WitnetProxy.metadata) - console.info(" ", "> compiler: ", metadata.compiler.version) - console.info(" ", "> compilation target:", metadata.settings.compilationTarget) - console.info(" ", "> evmVersion: ", metadata.settings.evmVersion) - console.info(" ", "> optimizer: ", JSON.stringify(metadata.settings.optimizer)) - - if (addresses[ecosystem][network]?.WitnetProxy === "") { - await deployer.deploy(WitnetProxy, { from }) - addresses[ecosystem][network].WitnetProxy = WitnetProxy.address - } else { - if (addresses[ecosystem][network]?.WitnetProxy) { - WitnetProxy.address = addresses[ecosystem][network]?.WitnetProxy - } - } - if (!isDryRun) { - utils.saveAddresses(addresses) - } -} diff --git a/migrations/scripts/1_deployer.js b/migrations/scripts/1_deployer.js new file mode 100644 index 000000000..23ef84805 --- /dev/null +++ b/migrations/scripts/1_deployer.js @@ -0,0 +1,30 @@ +const addresses = require("../witnet.addresses") +const utils = require("../../scripts/utils") + +const WitnetDeployer = artifacts.require("WitnetDeployer") + +module.exports = async function (deployer, network, [, from,, master]) { + const isDryRun = false // network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const ecosystem = utils.getRealmNetworkFromArgs()[0] + network = network.split("-")[0] + + if (!addresses[ecosystem]) addresses[ecosystem] = {} + if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} + + let factory + if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetDeployer)) { + await deployer.deploy(WitnetDeployer, { from: master }) + factory = await WitnetDeployer.deployed() + addresses[ecosystem][network].WitnetDeployer = factory.address + } else { + factory = await WitnetDeployer.at(addresses[ecosystem][network].WitnetDeployer) + WitnetDeployer.address = factory.address + utils.traceHeader("Skipping 'WitnetDeployer'") + console.info(" > Contract address:", factory.address) + console.info() + } + + if (!isDryRun) { + utils.saveAddresses(addresses) + } +} diff --git a/migrations/scripts/2_WitnetLibs.js b/migrations/scripts/2_WitnetLibs.js deleted file mode 100644 index 657a3d09d..000000000 --- a/migrations/scripts/2_WitnetLibs.js +++ /dev/null @@ -1,44 +0,0 @@ -const utils = require("../../scripts/utils") - -const WitnetErrorsLib = artifacts.require("WitnetErrorsLib") -const WitnetEncodingLib = artifacts.require("WitnetEncodingLib") - -module.exports = async function (deployer, network, [, from]) { - const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" - const ecosystem = utils.getRealmNetworkFromArgs()[0] - network = network.split("-")[0] - - const addresses = require("../witnet.addresses") - if (!addresses[ecosystem]) addresses[ecosystem] = {} - if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} - - let lib - if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetErrorsLib)) { - await deployer.deploy(WitnetErrorsLib, { from }) - lib = await WitnetErrorsLib.deployed() - addresses[ecosystem][network].WitnetErrorsLib = lib.address - } else { - lib = await WitnetErrorsLib.at(addresses[ecosystem][network]?.WitnetErrorsLib) - WitnetErrorsLib.address = lib.address - utils.traceHeader("Skipping 'WitnetErrorsLib'") - console.info(" ", "> library address:", lib.address) - console.info() - } - if (!isDryRun) { - utils.saveAddresses(addresses) - } - if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetEncodingLib)) { - await deployer.deploy(WitnetEncodingLib, { from }) - lib = await WitnetEncodingLib.deployed() - addresses[ecosystem][network].WitnetEncodingLib = lib.address - } else { - lib = await WitnetEncodingLib.at(addresses[ecosystem][network]?.WitnetEncodingLib) - WitnetEncodingLib.address = lib.address - utils.traceHeader("Skipping 'WitnetEncodingLib'") - console.info(" ", "> library address:", lib.address) - console.info() - } - if (!isDryRun) { - utils.saveAddresses(addresses) - } -} diff --git a/migrations/scripts/2_libs.js b/migrations/scripts/2_libs.js new file mode 100644 index 000000000..64d0a481a --- /dev/null +++ b/migrations/scripts/2_libs.js @@ -0,0 +1,61 @@ +const { merge } = require("lodash") + +const settings = require("../witnet.settings") +const utils = require("../../scripts/utils") + +const WitnetDeployer = artifacts.require("WitnetDeployer") + +module.exports = async function (_, network, [, from]) { + const isDryRun = false // network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const ecosystem = utils.getRealmNetworkFromArgs()[0] + network = network.split("-")[0] + + const addresses = require("../witnet.addresses") + if (!addresses[ecosystem]) addresses[ecosystem] = {} + if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} + + const targets = merge( + settings.artifacts.default, + settings.artifacts[ecosystem], + settings.artifacts[network] + ) + const libs = [ + targets.WitnetErrorsLib, + targets.WitnetEncodingLib, + targets.WitnetPriceFeedsLib, + ] + + const deployer = await WitnetDeployer.deployed() + for (index in libs) { + const key = libs[index] + const artifact = artifacts.require(key) + if (utils.isNullAddress(addresses[ecosystem][network][key])) { + utils.traceHeader(`Deploying '${key}'...`) + const libInitCode = artifact.toJSON().bytecode + const libAddr = await deployer.determineAddr.call(libInitCode, "0x0", { from }) + console.info(" ", "> account: ", from) + console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), 'ether'), "ETH") + const tx = await deployer.deploy(libInitCode, "0x0", { from }) + console.info(" ", "> transaction hash: ", tx.receipt.transactionHash) + console.info(" ", "> gas used: ", tx.receipt.gasUsed.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")) + console.info(" ", "> gas price: ", tx.receipt.effectiveGasPrice / 10 ** 9, "gwei") + console.info(" ", "> total cost: ", web3.utils.fromWei(BigInt(tx.receipt.gasUsed * tx.receipt.effectiveGasPrice).toString(), 'ether'), "ETH") + if ((await web3.eth.getCode(libAddr)).length > 3) { + addresses[ecosystem][network][key] = libAddr + } else { + console.info(`Library was not deployed on expected address: ${libAddr}`) + process.exit(1) + } + } else { + utils.traceHeader(`Deployed '${key}'`) + } + artifact.address = addresses[ecosystem][network][key] + console.info(" ", "> library address: ", artifact.address) + console.info(" ", "> library codehash: ", web3.utils.soliditySha3(await web3.eth.getCode(artifact.address))) + console.info() + if (!isDryRun) { + utils.saveAddresses(addresses) + } + } + +} diff --git a/migrations/scripts/3_WitnetBytecodes.js b/migrations/scripts/3_WitnetBytecodes.js deleted file mode 100644 index dccaff2a2..000000000 --- a/migrations/scripts/3_WitnetBytecodes.js +++ /dev/null @@ -1,127 +0,0 @@ -const ethUtils = require("ethereumjs-util") -const { merge } = require("lodash") - -const addresses = require("../witnet.addresses") -const settings = require("../witnet.settings") -const singletons = require("../witnet.salts") -const utils = require("../../scripts/utils") -const version = `${ - require("../../package").version -}-${ - require("child_process").execSync("git rev-parse HEAD").toString().trim().substring(0, 7) -}` - -const Create2Factory = artifacts.require("Create2Factory") -const WitnetProxy = artifacts.require("WitnetProxy") -const WitnetBytecodes = artifacts.require("WitnetBytecodes") -const WitnetEncodingLib = artifacts.require("WitnetEncodingLib") - -module.exports = async function (deployer, network, [, from]) { - const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" - const ecosystem = utils.getRealmNetworkFromArgs()[0] - network = network.split("-")[0] - - if (!addresses[ecosystem]) addresses[ecosystem] = {} - if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} - - const artifactNames = merge(settings.artifacts.default, settings.artifacts[ecosystem], settings.artifacts[network]) - const WitnetBytecodesImplementation = artifacts.require(artifactNames.WitnetBytecodes) - - let proxy - if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetBytecodes)) { - const factory = await Create2Factory.deployed() - if ( - factory && !utils.isNullAddress(factory.address) && - singletons?.WitnetBytecodes - ) { - // Deploy the proxy via a singleton factory and a salt... - const bytecode = WitnetProxy.toJSON().bytecode - const salt = singletons.WitnetBytecodes?.salt - ? "0x" + ethUtils.setLengthLeft( - ethUtils.toBuffer( - singletons.WitnetBytecodes.salt - ), 32 - ).toString("hex") - : "0x0" - - const proxyAddr = await factory.determineAddr.call(bytecode, salt, { from }) - if ((await web3.eth.getCode(proxyAddr)).length <= 3) { - // deploy instance only if not found in current network: - utils.traceHeader("Singleton inception of 'WitnetBytecodes':") - const balance = await web3.eth.getBalance(from) - const gas = singletons.WitnetBytecodes.gas - const tx = await factory.deploy(bytecode, salt, { from, gas }) - utils.traceTx( - tx.receipt, - web3.utils.fromWei((balance - await web3.eth.getBalance(from)).toString()) - ) - } else { - utils.traceHeader("Singleton 'WitnetBytecodes':") - } - console.info(" ", "> proxy address: ", proxyAddr) - console.info(" ", "> proxy codehash: ", web3.utils.soliditySha3(await web3.eth.getCode(proxyAddr))) - console.info(" ", "> proxy inception salt:", salt) - proxy = await WitnetProxy.at(proxyAddr) - } else { - // Deploy no singleton proxy ... - proxy = await WitnetProxy.new({ from }) - } - addresses[ecosystem][network].WitnetBytecodes = proxy.address - if (!isDryRun) { - utils.saveAddresses(addresses) - } - } else { - proxy = await WitnetProxy.at(addresses[ecosystem][network].WitnetBytecodes) - console.info(` Skipped: 'WitnetBytecodes' deployed at ${proxy.address}`) - } - WitnetBytecodes.address = proxy.address - - let bytecodes - if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetBytecodesImplementation)) { - await deployer.link(WitnetEncodingLib, [WitnetBytecodesImplementation]) - await deployer.deploy( - WitnetBytecodesImplementation, - /* _isUpgradeable */ true, - /* _versionTag */ utils.fromAscii(version), - { from } - ) - bytecodes = await WitnetBytecodesImplementation.deployed() - addresses[ecosystem][network].WitnetBytecodesImplementation = bytecodes.address - if (!isDryRun) { - utils.saveAddresses(addresses) - } - } else { - bytecodes = await WitnetBytecodesImplementation.at(addresses[ecosystem][network].WitnetBytecodesImplementation) - console.info(` Skipped: '${WitnetBytecodesImplementation.contractName}' deployed at ${bytecodes.address}`) - console.info() - WitnetBytecodesImplementation.address = bytecodes.address - await deployer.link(WitnetEncodingLib, WitnetBytecodesImplementation) - } - - const implementation = await proxy.implementation.call({ from }) - if (implementation.toLowerCase() !== bytecodes.address.toLowerCase()) { - const header = `Upgrading 'WitnetBytecodes' at ${proxy.address}...` - console.info() - console.info(" ", header) - console.info(" ", "-".repeat(header.length)) - console.info() - console.info(" > old implementation:", implementation) - console.info(" > new implementation:", bytecodes.address, `(v${await bytecodes.version.call({ from })})`) - if ( - isDryRun || - ["y", "yes"].includes((await utils.prompt(" > Upgrade the proxy ? [y/N] ")).toLowerCase().trim()) - ) { - try { - const tx = await proxy.upgradeTo(bytecodes.address, "0x", { from }) - console.info(" => transaction hash :", tx.receipt.transactionHash) - console.info(" => transaction gas :", tx.receipt.gasUsed) - console.info(" > Done.") - } catch (ex) { - console.info(" !! Cannot upgrade the proxy:") - console.info(ex) - } - } else { - console.info(" > Not upgraded.") - } - } -} diff --git a/migrations/scripts/3_core.js b/migrations/scripts/3_core.js new file mode 100644 index 000000000..bf1160505 --- /dev/null +++ b/migrations/scripts/3_core.js @@ -0,0 +1,147 @@ +const ethUtils = require("ethereumjs-util") +const { merge } = require("lodash") + +const addresses = require("../witnet.addresses") +const settings = require("../witnet.settings") +const utils = require("../../scripts/utils") +const version = `${ + require("../../package").version + }-${ + require("child_process").execSync("git rev-parse HEAD").toString().trim().substring(0, 7) + }` + +const WitnetDeployer = artifacts.require("WitnetDeployer") + +module.exports = async function (_, network, [, from]) { + const isDryRun = false // network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const ecosystem = utils.getRealmNetworkFromArgs()[0] + network = network.split("-")[0] + + if (!addresses[ecosystem]) addresses[ecosystem] = {} + if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} + + const specs = merge( + settings.specs.default, + settings.specs[ecosystem], + settings.specs[network], + ) + const targets = merge( + settings.artifacts.default, + settings.artifacts[ecosystem], + settings.artifacts[network] + ) + + // Deploy/upgrade WitnetBytecodes target implementation, if required + { + await deploy({ + from, ecosystem, network, targets, + key: targets.WitnetBytecodes, + libs: specs.WitnetBytecodes.libs, + immutables: specs.WitnetBytecodes.immutables, + intrinsics: { types: [ 'bool', 'bytes32' ], values: [ + /* _upgradable */ true, + /* _versionTag */ utils.fromAscii(version) + ]}, + }); + if (!isDryRun) { + utils.saveAddresses(addresses); + } + } + // Deploy/upgrade WitnetRequestFactory target implementation, if required + { + await deploy({ + from, ecosystem, network, targets, + key: targets.WitnetRequestFactory, + libs: specs.WitnetRequestFactory.libs, + immutables: specs.WitnetRequestFactory.immutables, + intrinsics: { types: [ 'address', 'bool', 'bytes32' ], values: [ + /* _registry */ await determineProxyAddr(from, specs.WitnetBytecodes?.vanity || 1), + /* _upgradable */ true, + /* _versionTag */ utils.fromAscii(version), + ]}, + }); + if (!isDryRun) { + utils.saveAddresses(addresses); + } + } + // Deploy/upgrade WitnetRequestBoard target implementation, if required + { + await deploy({ + from, ecosystem, network, targets, + key: targets.WitnetRequestBoard, + libs: specs.WitnetRequestBoard.libs, + immutables: specs.WitnetRequestBoard.immutables, + intrinsics: { types: [ 'address', 'bool', 'bytes32' ], values: [ + /* _registry */ await determineProxyAddr(from, specs.WitnetRequestFactory?.vanity || 2), + /* _upgradable */ true, + /* _versionTag */ utils.fromAscii(version), + ]}, + }); + if (!isDryRun) { + utils.saveAddresses(addresses); + } + } +} + +async function deploy(specs) { + const { from, ecosystem, network, key, libs, intrinsics, immutables, targets } = specs; + const contract = artifacts.require(key) + if (utils.isNullAddress(addresses[ecosystem][network][key])) { + utils.traceHeader(`Deploying '${key}'...`) + console.info(" ", "> account: ", from) + console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), 'ether'), "ETH") + const deployer = await WitnetDeployer.deployed() + let { types, values } = intrinsics + if (immutables?.types) types = [ ...types, ...immutables.types ] + if (immutables?.values) values = [ ...values, ...immutables.values ] + const constructorArgs = web3.eth.abi.encodeParameters(types, values) + if (constructorArgs.length > 2) { + console.info(" ", "> constructor types:", types) + console.info(" ", "> constructor args: ", constructorArgs.slice(2)) + } + const coreBytecode = link(contract.toJSON().bytecode, libs, targets) + if (coreBytecode.indexOf("__") > -1) { + console.info(bytecode) + console.info("Cannot deploy due to some missing libs") + process.exit(1) + } + const coreInitCode = coreBytecode + constructorArgs.slice(2) + const coreAddr = await deployer.determineAddr.call(coreInitCode, "0x0", { from }) + const tx = await deployer.deploy(coreInitCode, "0x0", { from }) + console.info(" ", "> transaction hash: ", tx.receipt.transactionHash) + console.info(" ", "> gas used: ", tx.receipt.gasUsed.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")) + console.info(" ", "> gas price: ", tx.receipt.effectiveGasPrice / 10 ** 9, "gwei") + console.info(" ", "> total cost: ", web3.utils.fromWei(BigInt(tx.receipt.gasUsed * tx.receipt.effectiveGasPrice).toString(), 'ether'), "ETH") + if ((await web3.eth.getCode(coreAddr)).length > 3) { + addresses[ecosystem][network][key] = coreAddr + } else { + console.info(`Contract was not deployed on expected address: ${coreAddr}`) + process.exit(1) + } + } else { + utils.traceHeader(`Deployed '${key}'`) + } + contract.address = addresses[ecosystem][network][key] + console.info(" ", "> contract address: ", contract.address) + console.info(" ", "> contract codehash:", web3.utils.soliditySha3(await web3.eth.getCode(contract.address))) + console.info() + return contract +} + +async function determineProxyAddr(from, nonce) { + const salt = nonce ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(nonce), 32).toString("hex") : "0x0" + const deployer = await WitnetDeployer.deployed() + return await deployer.determineProxyAddr.call(salt, { from }) +} + +function link(bytecode, libs, targets) { + if (libs && Array.isArray(libs) && libs.length > 0) { + for (index in libs) { + const key = targets[libs[index]] + const lib = artifacts.require(key) + bytecode = bytecode.replaceAll(`__${key}${"_".repeat(38-key.length)}`, lib.address.slice(2)) + console.info(" ", `> linked library: ${key} => ${lib.address}`) + } + } + return bytecode +} \ No newline at end of file diff --git a/migrations/scripts/4_WitnetRequestFactory.js b/migrations/scripts/4_WitnetRequestFactory.js deleted file mode 100644 index db5102a15..000000000 --- a/migrations/scripts/4_WitnetRequestFactory.js +++ /dev/null @@ -1,126 +0,0 @@ -const ethUtils = require("ethereumjs-util") -const { merge } = require("lodash") - -const addresses = require("../witnet.addresses") -const settings = require("../witnet.settings") -const singletons = require("../witnet.salts") -const utils = require("../../scripts/utils") -const version = `${ - require("../../package").version -}-${ - require("child_process").execSync("git rev-parse HEAD").toString().trim().substring(0, 7) -}` - -const Create2Factory = artifacts.require("Create2Factory") -const WitnetProxy = artifacts.require("WitnetProxy") - -const WitnetBytecodes = artifacts.require("WitnetBytecodes") -const WitnetRequestFactory = artifacts.require("WitnetRequestFactory") - -module.exports = async function (deployer, network, [, from]) { - const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" - const ecosystem = utils.getRealmNetworkFromArgs()[0] - network = network.split("-")[0] - - if (!addresses[ecosystem]) addresses[ecosystem] = {} - if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} - - const artifactNames = merge(settings.artifacts.default, settings.artifacts[ecosystem], settings.artifacts[network]) - const WitnetRequestFactoryImplementation = artifacts.require(artifactNames.WitnetRequestFactory) - - let proxy - if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetRequestFactory)) { - const create2Factory = await Create2Factory.deployed() - if ( - create2Factory && !utils.isNullAddress(create2Factory.address) && - singletons?.WitnetRequestFactory - ) { - // Deploy the proxy via a singleton factory and a salt... - const bytecode = WitnetProxy.toJSON().bytecode - const salt = singletons.WitnetRequestFactory?.salt - ? "0x" + ethUtils.setLengthLeft( - ethUtils.toBuffer( - singletons.WitnetRequestFactory.salt - ), 32 - ).toString("hex") - : "0x0" - - const proxyAddr = await create2Factory.determineAddr.call(bytecode, salt, { from }) - if ((await web3.eth.getCode(proxyAddr)).length <= 3) { - // deploy instance only if not found in current network: - utils.traceHeader("Singleton inception of 'WitnetRequestFactory':") - const balance = await web3.eth.getBalance(from) - const gas = singletons.WitnetRequestFactory.gas - const tx = await create2Factory.deploy(bytecode, salt, { from, gas }) - utils.traceTx( - tx.receipt, - web3.utils.fromWei((balance - await web3.eth.getBalance(from)).toString()) - ) - } else { - utils.traceHeader("Singleton 'WitnetRequestFactory':") - } - console.info(" ", "> proxy address: ", proxyAddr) - console.info(" ", "> proxy codehash: ", web3.utils.soliditySha3(await web3.eth.getCode(proxyAddr))) - console.info(" ", "> proxy inception salt:", salt) - proxy = await WitnetProxy.at(proxyAddr) - } else { - // Deploy no singleton proxy ... - proxy = await WitnetProxy.new({ from }) - } - addresses[ecosystem][network].WitnetRequestFactory = proxy.address - if (!isDryRun) { - utils.saveAddresses(addresses) - } - } else { - proxy = await WitnetProxy.at(addresses[ecosystem][network].WitnetRequestFactory) - console.info(` Skipped: 'WitnetRequestFactory' deployed at ${proxy.address}`) - } - WitnetRequestFactory.address = proxy.address - - let factory - if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetRequestFactoryImplementation)) { - await deployer.deploy( - WitnetRequestFactoryImplementation, - addresses[ecosystem][network].WitnetBytecodes || WitnetBytecodes.address, - /* _isUpgradeable */ true, - /* _versionTag */ utils.fromAscii(version), - { from } - ) - factory = await WitnetRequestFactoryImplementation.deployed() - addresses[ecosystem][network].WitnetRequestFactoryImplementation = factory.address - if (!isDryRun) { - utils.saveAddresses(addresses) - } - } else { - factory = await WitnetRequestFactoryImplementation.at(addresses[ecosystem][network].WitnetRequestFactoryImplementation) - console.info(` Skipped: '${WitnetRequestFactoryImplementation.contractName}' deployed at ${factory.address}`) - WitnetRequestFactoryImplementation.address = factory.address - } - - const implementation = await proxy.implementation.call({ from }) - if (implementation.toLowerCase() !== factory.address.toLowerCase()) { - const header = `Upgrading 'WitnetRequestFactory' at ${proxy.address}...` - console.info() - console.info(" ", header) - console.info(" ", "-".repeat(header.length)) - console.info() - console.info(" > old implementation:", implementation) - console.info(" > new implementation:", factory.address, `(v${await factory.version.call({ from })})`) - if ( - isDryRun || - ["y", "yes"].includes((await utils.prompt(" > Upgrade the proxy ? [y/N] ")).toLowerCase().trim()) - ) { - try { - const tx = await proxy.upgradeTo(factory.address, "0x", { from }) - console.info(" => transaction hash :", tx.receipt.transactionHash) - console.info(" => transaction gas :", tx.receipt.gasUsed) - console.info(" > Done.") - } catch (ex) { - console.info(" !! Cannot upgrade the proxy:") - console.info(ex) - } - } else { - console.info(" > Not upgraded.") - } - } -} diff --git a/migrations/scripts/4_proxies.js b/migrations/scripts/4_proxies.js new file mode 100644 index 000000000..b10286c31 --- /dev/null +++ b/migrations/scripts/4_proxies.js @@ -0,0 +1,135 @@ +const ethUtils = require("ethereumjs-util") +const { merge } = require("lodash") + +const addresses = require("../witnet.addresses") +const settings = require("../witnet.settings") +const utils = require("../../scripts/utils") + +const WitnetDeployer = artifacts.require("WitnetDeployer") +const WitnetProxy = artifacts.require("WitnetProxy") + +module.exports = async function (_, network, [, from, reporter]) { + const isDryRun = false // network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const ecosystem = utils.getRealmNetworkFromArgs()[0] + network = network.split("-")[0] + + if (!addresses[ecosystem]) addresses[ecosystem] = {} + if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} + + const targets = merge( + settings.artifacts.default, + settings.artifacts[ecosystem], + settings.artifacts[network] + ) + const specs = merge( + settings.specs.default, + settings.specs[ecosystem], + settings.specs[network], + ) + const singletons = [ + "WitnetBytecodes", + "WitnetRequestFactory", + "WitnetRequestBoard", + ] + + specs["WitnetRequestBoard"].mutables = merge({ + types: [ 'address[]', ], + values: [ [ reporter, ], ], + }, specs["WitnetRequestBoard"].mutables + ) + + // Deploy/upgrade singleton proxies, if required + for (index in singletons) { + await deploy({ + from, ecosystem, network, specs, targets, + key: singletons[index], + }); + if (!isDryRun) { + utils.saveAddresses(addresses); + } + } +} + +async function deploy(target) { + const { from, ecosystem, network, key, specs, targets } = target; + + const mutables = specs[key].mutables + const proxy = artifacts.require(key) + const proxy_salt = specs[key].vanity ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(specs[key].vanity), 32).toString("hex") : "0x0" + + if (utils.isNullAddress(addresses[ecosystem][network][key])) { + utils.traceHeader(`Deploying '${key}'...`) + console.info(" ", "> account: ", from) + console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), 'ether'), "ETH") + const deployer = await WitnetDeployer.deployed() + const impl = await artifacts.require(targets[key]).deployed() + const proxyAddr = await deployer.determineProxyAddr.call(proxy_salt, { from }) + if ((await web3.eth.getCode(proxyAddr)).length < 3) { + const initdata = mutables ? web3.eth.abi.encodeParameters(mutables.types, mutables.values) : "0x" + if (initdata.length > 2) { + console.info(" ", "> initialize types: ", mutables.types) + console.info(" ", "> initialize params:", mutables.values) + } + const tx = await deployer.proxify(proxy_salt, impl.address, initdata, { from }) + console.info(" ", "> transaction hash: ", tx.receipt.transactionHash) + console.info(" ", "> gas used: ", tx.receipt.gasUsed.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")) + console.info(" ", "> gas price: ", tx.receipt.effectiveGasPrice / 10 ** 9, "gwei") + console.info(" ", "> total cost: ", web3.utils.fromWei(BigInt(tx.receipt.gasUsed * tx.receipt.effectiveGasPrice).toString(), 'ether'), "ETH") + } else { + console.info(" ", "> already proxified ;-)") + // TODO: check that proxy's class matches impl's class + } + if ((await web3.eth.getCode(proxyAddr)).length > 3) { + addresses[ecosystem][network][key] = proxyAddr + } else { + console.info(`Contract was not deployed on expected address: ${proxyAddr}`) + process.exit(1) + } + } else { + const oldAddr = await getProxyImplementation(from, addresses[ecosystem][network][key]) + const oldImpl = await artifacts.require(targets[key]).at(oldAddr) + const newImpl = await artifacts.require(targets[key]).deployed() + if (oldAddr != newImpl.address) { + utils.traceHeader(`Upgrading '${key}'...`) + const oldVersion = await oldImpl.version.call({ from }) + const newVersion = await newImpl.version.call({ from }) + if( + process.argv.length >= 3 && process.argv[2].includes("--upgrade-all") || ["y", "yes"].includes( + (await utils.prompt(` > From v${oldVersion} to v${newVersion} ? [y / N]`)).toLowerCase().trim() + ) + ) { + const initdata = mutables ? web3.eth.abi.encodeParameters(mutables.types, mutables.values) : "0x" + if (initdata.length > 2) { + console.info(" ", "> initialize types: ", mutables.types) + console.info(" ", "> initialize params:", mutables.values) + } + const tx = await upgradeProxyTo(from, proxy, newImpl.address, initdata) + console.info(" ", "> transaction hash: ", tx.receipt.transactionHash) + console.info(" ", "> gas used: ", tx.receipt.gasUsed.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")) + console.info(" ", "> gas price: ", tx.receipt.effectiveGasPrice / 10 ** 9, "gwei") + console.info(" ", "> total cost: ", web3.utils.fromWei(BigInt(tx.receipt.gasUsed * tx.receipt.effectiveGasPrice).toString(), 'ether'), "ETH") + } + } else { + utils.traceHeader(`Deployed '${key}'`) + } + } + proxy.address = addresses[ecosystem][network][key] + const impl = await artifacts.require(targets[key]).at(proxy.address) + console.info(" ", "> proxy address: ", impl.address) + console.info(" ", "> proxy codehash: ", web3.utils.soliditySha3(await web3.eth.getCode(impl.address))) + console.info(" ", "> proxy operator: ", await impl.owner.call()) + console.info(" ", "> impl. address: ", await getProxyImplementation(from, proxy.address)) + console.info(" ", "> impl. version: ", await impl.version.call()) + console.info() + return proxy +} + +async function getProxyImplementation(from, proxyAddr) { + proxy = await WitnetProxy.at(proxyAddr) + return await proxy.implementation.call({ from }) +} + +async function upgradeProxyTo(from, proxy, implAddr, initData) { + proxy = await WitnetProxy.at(proxy.address) + return await proxy.upgradeTo(implAddr, initData, { from }) +} diff --git a/migrations/scripts/5_WitnetRequestBoard.js b/migrations/scripts/5_WitnetRequestBoard.js deleted file mode 100644 index 9f180baab..000000000 --- a/migrations/scripts/5_WitnetRequestBoard.js +++ /dev/null @@ -1,146 +0,0 @@ -const ethUtils = require("ethereumjs-util") -const { merge } = require("lodash") - -const addresses = require("../witnet.addresses") -const settings = require("../witnet.settings") -const singletons = require("../witnet.salts") -const utils = require("../../scripts/utils") -const version = `${ - require("../../package").version -}-${ - require("child_process").execSync("git rev-parse HEAD").toString().trim().substring(0, 7) -}` - -const Create2Factory = artifacts.require("Create2Factory") -const WitnetProxy = artifacts.require("WitnetProxy") - -const WitnetErrorsLib = artifacts.require("WitnetErrorsLib") -const WitnetRequestFactory = artifacts.require("WitnetRequestFactory") -const WitnetRequestBoard = artifacts.require("WitnetRequestBoard") - -module.exports = async function (deployer, network, [, from, reporter]) { - const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" - const ecosystem = utils.getRealmNetworkFromArgs()[0] - network = network.split("-")[0] - - if (!addresses[ecosystem]) addresses[ecosystem] = {} - 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) - - let proxy - const factory = await Create2Factory.deployed() - if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetRequestBoard)) { - if ( - factory && !utils.isNullAddress(factory.address) && - singletons?.WitnetRequestBoard - ) { - // Deploy the proxy via a singleton factory and a salt... - const bytecode = WitnetProxy.toJSON().bytecode - const salt = singletons.WitnetRequestBoard?.salt - ? "0x" + ethUtils.setLengthLeft( - ethUtils.toBuffer( - singletons.WitnetRequestBoard.salt - ), 32 - ).toString("hex") - : "0x0" - - const proxyAddr = await factory.determineAddr.call(bytecode, salt, { from }) - if ((await web3.eth.getCode(proxyAddr)).length <= 3) { - // deploy instance only if not found in current network: - utils.traceHeader("Singleton inception of 'WitnetRequestBoard':") - const balance = await web3.eth.getBalance(from) - const gas = singletons.WitnetRequestBoard.gas - const tx = await factory.deploy(bytecode, salt, { from, gas }) - utils.traceTx( - tx.receipt, - web3.utils.fromWei((balance - await web3.eth.getBalance(from)).toString()) - ) - } else { - utils.traceHeader("Singleton 'WitnetRequestBoard':") - } - console.info(" ", "> proxy address: ", proxyAddr) - console.info(" ", "> proxy codehash: ", web3.utils.soliditySha3(await web3.eth.getCode(proxyAddr))) - console.info(" ", "> proxy inception salt:", salt) - proxy = await WitnetProxy.at(proxyAddr) - } else { - // Deploy no singleton proxy ... - proxy = await WitnetProxy.new({ from }) - } - // update addresses file - addresses[ecosystem][network].WitnetRequestBoard = proxy.address - if (!isDryRun) { - utils.saveAddresses(addresses) - } - } else { - proxy = await WitnetProxy.at(addresses[ecosystem][network].WitnetRequestBoard) - console.info(` Skipped: 'WitnetRequestBoard' deployed at ${proxy.address}`) - } - WitnetRequestBoard.address = proxy.address - - 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 } - ) - board = await WitnetRequestBoardImplementation.deployed() - addresses[ecosystem][network].WitnetRequestBoardImplementation = board.address - if (!isDryRun) { - utils.saveAddresses(addresses) - } - } else { - board = await WitnetRequestBoardImplementation.at(addresses[ecosystem][network].WitnetRequestBoardImplementation) - console.info(` Skipped: '${WitnetRequestBoardImplementation.contractName}' deployed at ${board.address}`) - console.info() - WitnetRequestBoardImplementation.address = board.address - await deployer.link(WitnetErrorsLib, WitnetRequestBoardImplementation) - } - - const implementation = await proxy.implementation.call({ from }) - if (implementation.toLowerCase() !== board.address.toLowerCase()) { - const header = `Upgrading 'WitnetRequestBoard' at ${proxy.address}...` - console.info() - console.info(" ", header) - console.info(" ", "-".repeat(header.length)) - console.info() - console.info(" > old implementation:", implementation) - console.info(" > new implementation:", board.address, `(v${await board.version.call({ from })})`) - if ( - isDryRun || - ["y", "yes"].includes((await utils.prompt(" > Upgrade the proxy ? [y/N] ")).toLowerCase().trim()) - ) { - try { - const tx = await proxy.upgradeTo( - board.address, - web3.eth.abi.encodeParameter( - "address[]", - [reporter], - ), - { from } - ) - console.info(" => Transaction hash :", tx.receipt.transactionHash) - console.info(" => Transaction gas :", tx.receipt.gasUsed) - console.info(" > Done.") - } catch (ex) { - console.info(" !! Cannot upgrade the proxy:") - console.info(ex) - } - } else { - console.info(" > Not upgraded.") - } - } -} diff --git a/migrations/scripts/5_apps.js b/migrations/scripts/5_apps.js new file mode 100644 index 000000000..b64dd01f2 --- /dev/null +++ b/migrations/scripts/5_apps.js @@ -0,0 +1,130 @@ +const ethUtils = require("ethereumjs-util") +const { merge } = require("lodash") + +const addresses = require("../witnet.addresses") +const settings = require("../witnet.settings") +const utils = require("../../scripts/utils") +const version = `${ + require("../../package").version + }-${ + require("child_process").execSync("git rev-parse HEAD").toString().trim().substring(0, 7) + }` + +const WitnetDeployer = artifacts.require("WitnetDeployer") + +module.exports = async function (_, network, [,,, from]) { + const isDryRun = false // network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const ecosystem = utils.getRealmNetworkFromArgs()[0] + network = network.split("-")[0] + + if (!addresses[ecosystem]) addresses[ecosystem] = {} + if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} + + const specs = merge( + settings.specs.default, + settings.specs[ecosystem], + settings.specs[network], + ) + const targets = merge( + settings.artifacts.default, + settings.artifacts[ecosystem], + settings.artifacts[network] + ) + + // Deploy the WitnetPriceFeeds oracle, if required + { + await deploy({ + from, ecosystem, network, targets, + key: targets.WitnetPriceFeeds, + libs: specs.WitnetPriceFeeds.libs, + vanity: specs.WitnetPriceFeeds?.vanity || 0, + immutables: specs.WitnetPriceFeeds.immutables, + intrinsics: { types: [ 'address', 'address' ], values: [ + /* _operator */ from, + /* _wrb */ await determineProxyAddr(from, specs.WitnetRequestBoard?.vanity || 3), + ]}, + }); + if (!isDryRun) utils.saveAddresses(addresses); + } + // Deploy the WitnetRandomness oracle, if required + { + await deploy({ + from, ecosystem, network, targets, + key: targets.WitnetRandomness, + libs: specs.WitnetRandomness?.libs, + vanity: specs.WitnetRandomness?.vanity || 0, + immutables: specs.WitnetRandomness?.immutables, + intrinsics: { types: [ 'address', 'address' ], values: [ + /* _operator */ from, + /* _wrb */ await determineProxyAddr(from, specs.WitnetRequestBoard?.vanity || 3), + ]}, + }); + if (!isDryRun) utils.saveAddresses(addresses); + } +} + +async function deploy(specs) { + const { from, ecosystem, network, key, libs, intrinsics, immutables, targets, vanity } = specs; + const artifact = artifacts.require(key) + const salt = vanity ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(vanity), 32).toString("hex") : "0x0" + if (utils.isNullAddress(addresses[ecosystem][network][key])) { + utils.traceHeader(`Deploying '${key}'...`) + const deployer = await WitnetDeployer.deployed() + let { types, values } = intrinsics + if (immutables?.types) types = [ ...types, ...immutables.types ] + if (immutables?.values) values = [ ...values, ...immutables.values ] + const constructorArgs = web3.eth.abi.encodeParameters(types, values) + if (constructorArgs.length > 2) { + console.info(" ", "> constructor types:", types) + console.info(" ", "> constructor args: ", constructorArgs.slice(2)) + } + const coreBytecode = link(artifact.toJSON().bytecode, libs, targets) + if (coreBytecode.indexOf("__") > -1) { + console.info(bytecode) + console.info("Cannot deploy due to some missing libs") + process.exit(1) + } + const dappInitCode = coreBytecode + constructorArgs.slice(2) + const dappAddr = await deployer.determineAddr.call(dappInitCode, salt, { from }) + console.info(" ", "> account: ", from) + console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), 'ether'), "ETH") + const tx = await deployer.deploy(dappInitCode, salt, { from }) + console.info(" ", "> transaction hash: ", tx.receipt.transactionHash) + console.info(" ", "> gas used: ", tx.receipt.gasUsed.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")) + console.info(" ", "> gas price: ", tx.receipt.effectiveGasPrice / 10 ** 9, "gwei") + console.info(" ", "> total cost: ", web3.utils.fromWei(BigInt(tx.receipt.gasUsed * tx.receipt.effectiveGasPrice).toString(), 'ether'), "ETH") + if ((await web3.eth.getCode(dappAddr)).length > 3) { + addresses[ecosystem][network][key] = dappAddr + } else { + console.info(`Contract was not deployed on expected address: ${dappAddr}`) + console.log(tx.receipt) + process.exit(1) + } + } else { + utils.traceHeader(`Deployed '${key}'`) + } + artifact.address = addresses[ecosystem][network][key] + console.info(" ", "> contract address: ", artifact.address) + console.info(" ", "> contract codehash:", web3.utils.soliditySha3(await web3.eth.getCode(artifact.address))) + console.info() + return artifact +} + +async function determineProxyAddr(from, nonce) { + const salt = nonce ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(nonce), 32).toString("hex") : "0x0" + const deployer = await WitnetDeployer.deployed() + const addr = await deployer.determineProxyAddr.call(salt, { from }) + return addr +} + +function link(bytecode, libs, targets) { + if (libs && Array.isArray(libs) && libs.length > 0) { + for (index in libs) { + const key = targets[libs[index]] + const lib = artifacts.require(key) + bytecode = bytecode.replaceAll(`__${key}${"_".repeat(38-key.length)}`, lib.address.slice(2)) + console.info(" ", `> linked library: ${key} => ${lib.address}`) + } + } + return bytecode +} \ No newline at end of file diff --git a/migrations/scripts/6_WitnetRandomness.js b/migrations/scripts/6_WitnetRandomness.js deleted file mode 100644 index 2df37b91b..000000000 --- a/migrations/scripts/6_WitnetRandomness.js +++ /dev/null @@ -1,154 +0,0 @@ -const ethUtils = require("ethereumjs-util") -const { merge } = require("lodash") - -const addresses = require("../witnet.addresses") -const settings = require("../witnet.settings") -const singletons = require("../witnet.salts") -const utils = require("../../scripts/utils") -const version = `${ - require("../../package").version -}-${ - require("child_process").execSync("git rev-parse HEAD").toString().trim().substring(0, 7) -}` - -const Create2Factory = artifacts.require("Create2Factory") -const WitnetProxy = artifacts.require("WitnetProxy") - -const WitnetRandomness = artifacts.require("WitnetRandomness") -const WitnetRequestBoard = artifacts.require("WitnetRequestBoard") - -module.exports = async function (deployer, network, [, from]) { - const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" - const ecosystem = utils.getRealmNetworkFromArgs()[0] - network = network.split("-")[0] - - if (!addresses[ecosystem]) addresses[ecosystem] = {} - if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} - - console.info() - if (!isDryRun && addresses[ecosystem][network].WitnetRandomness === undefined) { - console.info(`\n WitnetRandomness: Not to be deployed into '${network}'`) - 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) { - let proxy - if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetRandomness)) { - if ( - create2Factory && !utils.isNullAddress(create2Factory.address) && - singletons?.WitnetRandomness - ) { - // Deploy the proxy via a singleton factory and a salt... - const bytecode = WitnetProxy.toJSON().bytecode - const salt = singletons.WitnetRandomness?.salt - ? "0x" + ethUtils.setLengthLeft( - ethUtils.toBuffer( - singletons.WitnetRandomness.salt - ), 32 - ).toString("hex") - : "0x0" - - const proxyAddr = await create2Factory.determineAddr.call(bytecode, salt, { from }) - if ((await web3.eth.getCode(proxyAddr)).length <= 3) { - // deploy instance only if not found in current network: - utils.traceHeader("Singleton inception of 'WitnetRandomness':") - const balance = await web3.eth.getBalance(from) - const gas = singletons.WitnetRandomness.gas - const tx = await create2Factory.deploy(bytecode, salt, { from, gas }) - utils.traceTx( - tx.receipt, - web3.utils.fromWei((balance - await web3.eth.getBalance(from)).toString()) - ) - } else { - utils.traceHeader("Singleton 'WitnetRandomness':") - } - console.info(" ", "> proxy address: ", proxyAddr) - console.info(" ", "> proxy codehash: ", web3.utils.soliditySha3(await web3.eth.getCode(proxyAddr))) - console.info(" ", "> proxy inception salt:", salt) - proxy = await WitnetProxy.at(proxyAddr) - } else { - // Deploy no singleton proxy ... - proxy = await WitnetProxy.new({ from }) - } - addresses[ecosystem][network].WitnetRandomness = proxy.address - if (!isDryRun) { - utils.saveAddresses(addresses) - } - } else { - proxy = await WitnetProxy.at(addresses[ecosystem][network].WitnetRandomness) - console.info(` Skipped: 'WitnetRandomness' deployed at ${proxy.address}`) - } - WitnetRandomness.address = proxy.address - - let randomness - if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetRandomnessImplementation)) { - await deployer.deploy( - WitnetRandomnessImplementation, - WitnetRequestBoard.address, - /* _versionTag */ utils.fromAscii(version), - { from } - ) - randomness = await WitnetRandomnessImplementation.deployed() - addresses[ecosystem][network].WitnetRandomnessImplementation = randomness.address - if (!isDryRun) { - utils.saveAddresses(addresses) - } - } else { - randomness = await WitnetRandomnessImplementation.at( - addresses[ecosystem][network].WitnetRandomnessImplementation - ) - console.info(` Skipped: '${WitnetRandomnessImplementation.contractName}' deployed at ${randomness.address}`) - WitnetRandomnessImplementation.address = randomness.address - } - - const implementation = await proxy.implementation.call({ from }) - if (implementation.toLowerCase() !== randomness.address.toLowerCase()) { - const header = `Upgrading 'WitnetRandomness' at ${proxy.address}...` - console.info() - console.info(" ", header) - console.info(" ", "-".repeat(header.length)) - console.info() - console.info(" > old implementation:", implementation) - console.info(" > new implementation:", randomness.address, `(v${await randomness.version.call({ from })})`) - if ( - isDryRun || - ["y", "yes"].includes((await utils.prompt(" > Upgrade the proxy ? [y/N] ")).toLowerCase().trim()) - ) { - try { - const tx = await proxy.upgradeTo(randomness.address, "0x", { from }) - console.info(" => transaction hash :", tx.receipt.transactionHash) - console.info(" => transaction gas :", tx.receipt.gasUsed) - console.info(" > Done.") - } catch (ex) { - console.info(" !! Cannot upgrade the proxy:") - console.info(ex) - } - } else { - console.info(" > Not upgraded.") - } - } - } else { - if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetRandomness)) { - // deploy unproxified WitnetRandomness contract - await deployer.deploy( - WitnetRandomnessImplementation, - WitnetRequestBoard.address, - utils.fromAscii(version), - { from } - ) - addresses[ecosystem][network].WitnetRandomness = WitnetRandomnessImplementation.address - if (!isDryRun) { - utils.saveAddresses(addresses) - } - } else { - WitnetRandomnessImplementation.address = addresses[ecosystem][network]?.WitnetRandomness - console.info(` Skipped: unproxied 'WitnetRandomness' deployed at ${WitnetRandomnessImplementation.address}`) - } - WitnetRandomness.address = WitnetRandomnessImplementation.address - } -} diff --git a/migrations/scripts/7_WitnetPriceFeeds.js b/migrations/scripts/7_WitnetPriceFeeds.js deleted file mode 100644 index 3c10eacb7..000000000 --- a/migrations/scripts/7_WitnetPriceFeeds.js +++ /dev/null @@ -1,172 +0,0 @@ -const ethUtils = require("ethereumjs-util") -const { merge } = require("lodash") - -const addresses = require("../witnet.addresses") -const settings = require("../witnet.settings") -const singletons = require("../witnet.salts") -const utils = require("../../scripts/utils") -const version = `${ - require("../../package").version -}-${ - require("child_process").execSync("git rev-parse HEAD").toString().trim().substring(0, 7) -}` - -const Create2Factory = artifacts.require("Create2Factory") -const WitnetProxy = artifacts.require("WitnetProxy") - -const WitnetPriceFeeds = artifacts.require("WitnetPriceFeeds") -const WitnetPriceFeedsLib = artifacts.require("WitnetPriceFeedsLib") -const WitnetRequestBoard = artifacts.require("WitnetRequestBoard") - -module.exports = async function (deployer, network, [, from]) { - const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" - const ecosystem = utils.getRealmNetworkFromArgs()[0] - network = network.split("-")[0] - - if (!addresses[ecosystem]) addresses[ecosystem] = {} - if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} - - console.info() - if (!isDryRun && addresses[ecosystem][network].WitnetPriceFeeds === undefined) { - console.info(`\n WitnetPriceFeeds: Not to be deployed into '${network}'`) - return - } - - const artifactNames = merge(settings.artifacts.default, settings.artifacts[ecosystem], settings.artifacts[network]) - const WitnetPriceFeedsImplementation = artifacts.require(artifactNames.WitnetPriceFeeds) - - if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetPriceFeedsLib)) { - await deployer.deploy(WitnetPriceFeedsLib, { from }) - const lib = await WitnetPriceFeedsLib.deployed() - addresses[ecosystem][network].WitnetPriceFeedsLib = lib.address - if (!isDryRun) { - utils.saveAddresses(addresses) - } - } else { - const lib = await WitnetPriceFeedsLib.at(addresses[ecosystem][network]?.WitnetPriceFeedsLib) - WitnetPriceFeedsLib.address = lib.address - utils.traceHeader("Skipping 'WitnetPriceFeedsLib'") - console.info(" ", "> library address:", lib.address) - console.info() - } - await deployer.link(WitnetPriceFeedsLib, WitnetPriceFeedsImplementation) - - if (addresses[ecosystem][network]?.WitnetPriceFeedsImplementation !== undefined || isDryRun) { - let proxy - if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetPriceFeeds)) { - const create2Factory = await Create2Factory.deployed() - if ( - create2Factory && !utils.isNullAddress(create2Factory.address) && - singletons?.WitnetPriceFeeds - ) { - // Deploy the proxy via a singleton factory and a salt... - const bytecode = WitnetProxy.toJSON().bytecode - const salt = singletons.WitnetPriceFeeds?.salt - ? "0x" + ethUtils.setLengthLeft( - ethUtils.toBuffer( - singletons.WitnetPriceFeeds.salt - ), 32 - ).toString("hex") - : "0x0" - - const proxyAddr = await create2Factory.determineAddr.call(bytecode, salt, { from }) - if ((await web3.eth.getCode(proxyAddr)).length <= 3) { - // deploy instance only if not found in current network: - utils.traceHeader("Singleton inception of 'WitnetPriceFeeds':") - const balance = await web3.eth.getBalance(from) - const gas = singletons.WitnetPriceFeeds.gas - const tx = await create2Factory.deploy(bytecode, salt, { from, gas }) - utils.traceTx( - tx.receipt, - web3.utils.fromWei((balance - await web3.eth.getBalance(from)).toString()) - ) - } else { - utils.traceHeader("Singleton 'WitnetPriceFeeds':") - } - console.info(" ", "> proxy address: ", proxyAddr) - console.info(" ", "> proxy codehash: ", web3.utils.soliditySha3(await web3.eth.getCode(proxyAddr))) - console.info(" ", "> proxy inception salt:", salt) - proxy = await WitnetProxy.at(proxyAddr) - } else { - // Deploy no singleton proxy ... - proxy = await WitnetProxy.new({ from }) - } - addresses[ecosystem][network].WitnetPriceFeeds = proxy.address - if (!isDryRun) { - utils.saveAddresses(addresses) - } - } else { - proxy = await WitnetProxy.at(addresses[ecosystem][network].WitnetPriceFeeds) - console.info(` Skipped: 'WitnetPriceFeeds' deployed at ${proxy.address}`) - } - - let router - if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetPriceFeedsImplementation)) { - await deployer.deploy( - WitnetPriceFeedsImplementation, - WitnetRequestBoard.address, - true, - utils.fromAscii(version), - { from } - ) - router = await WitnetPriceFeedsImplementation.deployed() - addresses[ecosystem][network].WitnetPriceFeedsImplementation = router.address - if (!isDryRun) { - utils.saveAddresses(addresses) - } - } else { - router = await WitnetPriceFeedsImplementation.at( - addresses[ecosystem][network].WitnetPriceFeedsImplementation - ) - console.info(` Skipped: '${WitnetPriceFeedsImplementation.contractName}' deployed at ${router.address}`) - WitnetPriceFeedsImplementation.address = router.address - } - WitnetPriceFeeds.address = proxy.address - - const implementation = await proxy.implementation.call({ from }) - if (implementation.toLowerCase() !== router.address.toLowerCase()) { - const header = `Upgrading 'WitnetPriceFeeds' at ${proxy.address}...` - console.info() - console.info(" ", header) - console.info(" ", "-".repeat(header.length)) - console.info() - console.info(" > old implementation:", implementation) - console.info(" > new implementation:", router.address, `(v${await router.version.call({ from })})`) - if ( - isDryRun || - ["y", "yes"].includes((await utils.prompt(" > Upgrade the proxy ? [y/N] ")).toLowerCase().trim()) - ) { - try { - const tx = await proxy.upgradeTo(router.address, "0x", { from }) - console.info(" => transaction hash :", tx.receipt.transactionHash) - console.info(" => transaction gas :", tx.receipt.gasUsed) - console.info(" > Done.") - } catch (ex) { - console.info(" !! Cannot upgrade the proxy:") - console.info(ex) - } - } else { - console.info(" > Not upgraded.") - } - } - } else { - if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetPriceFeeds)) { - // deploy unproxified WitnetPriceFeeds contract - await deployer.deploy( - WitnetPriceFeedsImplementation, - WitnetRequestBoard.address, - false, - utils.fromAscii(version), - { from } - ) - addresses[ecosystem][network].WitnetPriceFeeds = WitnetPriceFeedsImplementation.address - if (!isDryRun) { - utils.saveAddresses(addresses) - } - } else { - WitnetPriceFeedsImplementation.address = addresses[ecosystem][network]?.WitnetPriceFeeds - console.info(` Skipped: unproxied 'WitnetPriceFeeds' deployed at ${WitnetPriceFeedsImplementation.address}`) - } - WitnetPriceFeeds.address = WitnetPriceFeedsImplementation.address - } -} diff --git a/migrations/scripts/8_WitnetPriceRouter.js b/migrations/scripts/8_WitnetPriceRouter.js deleted file mode 100644 index 16a807697..000000000 --- a/migrations/scripts/8_WitnetPriceRouter.js +++ /dev/null @@ -1,43 +0,0 @@ -const addresses = require("../witnet.addresses") -const utils = require("../../scripts/utils") -const version = `${ - require("../../package").version -}-${ - require("child_process").execSync("git rev-parse HEAD").toString().trim().substring(0, 7) -}` - -const WitnetPriceRouter = artifacts.require("WitnetPriceRouter") - -module.exports = async function (deployer, network, [, from]) { - const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" - const ecosystem = utils.getRealmNetworkFromArgs()[0] - network = network.split("-")[0] - - if (!addresses[ecosystem]) addresses[ecosystem] = {} - if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} - - console.info() - if (!isDryRun && addresses[ecosystem][network].WitnetPriceRouter === undefined) { - console.info(`\n WitnetPriceRouter: Not to be deployed into '${network}'`) - return - } - - if ( - isDryRun || - utils.isNullAddress(addresses[ecosystem][network]?.WitnetPriceRouter) - ) { - await deployer.deploy( - WitnetPriceRouter, - false, - utils.fromAscii(version), - { from } - ) - addresses[ecosystem][network].WitnetPriceRouter = WitnetPriceRouter.address - if (!isDryRun) { - utils.saveAddresses(addresses) - } - } else { - WitnetPriceRouter.address = addresses[ecosystem][network].WitnetPriceRouter - console.info(` Skipped: 'WitnetPriceRouter' deployed at ${WitnetPriceRouter.address}`) - } -} diff --git a/migrations/witnet.salts.js b/migrations/witnet.salts.js deleted file mode 100644 index 5a2cd75f5..000000000 --- a/migrations/witnet.salts.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = { - WitnetBytecodes: { - salt: 61396704, // => solc-0.8.17: 0x0000000e3a3d22d7510B36BdC88994dab11eadc8 - gas: 1000000, - }, - WitnetPriceFeeds: { - salt: 125920098, // => solc-0.8.17: 0x9999999d139bdBFbF25923ba39F63bBFc7593400 - gas: 1000000, - }, - WitnetRandomness: { - salt: 332121398, // => solc-0.8.17: 0x0123456fbBC59E181D76B6Fe8771953d1953B51a - gas: 1000000, - }, - WitnetRequestBoard: { - salt: 198789840, // => solc-0-8.17: 0x777777772C24e6CD34B464D1d71616C444254537 - gas: 1000000, - }, - WitnetRequestFactory: { - salt: 20377356, // => solc-0.8.17: 0x1111111FDE7dC956E3d7922Bc779D9E2349Afb63 - gas: 1000000, - }, -} diff --git a/migrations/witnet.settings.js b/migrations/witnet.settings.js index 8ff8e66cf..0b9bbd7ee 100644 --- a/migrations/witnet.settings.js +++ b/migrations/witnet.settings.js @@ -2,8 +2,11 @@ module.exports = { artifacts: { default: { WitnetBytecodes: "WitnetBytecodesDefault", - WitnetPriceFeeds: "WitnetPriceFeedsUpgradable", - WitnetRandomness: "WitnetRandomnessProxiable", + WitnetEncodingLib: "WitnetEncodingLib", + WitnetErrorsLib: "WitnetErrorsLib", + WitnetPriceFeeds: "WitnetPriceFeeds", + WitnetPriceFeedsLib: "WitnetPriceFeedsLib", + WitnetRandomness: "WitnetRandomness", WitnetRequestBoard: "WitnetRequestBoardTrustableDefault", WitnetRequestFactory: "WitnetRequestFactoryDefault", }, @@ -48,103 +51,6 @@ module.exports = { }, }, }, - constructorParams: { - default: { - WitnetRequestBoard: [ - /* _reportResultGasLimit */ 133000, - ], - }, - avalanche: { - WitnetRequestBoard: [ - /* _reportResultGasLimit */ 155000, - ], - }, - celo: { - WitnetRequestBoard: [ - /* _reportResultGasLimit */ 114000, - ], - }, - conflux: { - WitnetRequestBoard: [ - /* _reportResultGasLimit */ 78500, - ], - }, - "conflux.espace.testnet": { - WitnetRequestBoard: [ - /* _reportResultGasLimit */ 225000, - ], - }, - "conflux.espace.mainnet": { - WitnetRequestBoard: [ - /* _reportResultGasLimit */ 225000, - ], - }, - cronos: { - WitnetRequestBoard: [ - /* _reportResultGasLimit */ 137500, - ], - }, - dogechain: { - WitnetRequestBoard: [ - /* _reportResultGasLimit */ 85000, - ], - }, - harmony: { - WitnetRequestBoard: [ - /* _reportResultGasLimit */ 530000, - ], - }, - hsc: { - WitnetRequestBoard: [ - /* _reportResultGasLimit */ 85000, - ], - }, - kcc: { - WitnetRequestBoard: [ - /* _reportResultGasLimit */ 92500, - ], - }, - klaytn: { - WitnetRequestBoard: [ - /* _reportResultGasLimit */ 105000, - ], - }, - meter: { - WitnetRequestBoard: [ - /* _reportResultGasLimit */ 85000, - ], - }, - metis: { - WitnetRequestBoard: [ - /* _reportResultGasLimit */ 134800, - ], - }, - moonbeam: { - WitnetRequestBoard: [ - /* _reportResultGasLimit */ 115000, - ], - }, - okxchain: { - WitnetRequestBoard: [ - /* _reportResultGasLimit */ 145000, - ], - }, - optimism: { - WitnetRequestBoard: [ - /* _reportResultGasLimit */ 135000, - ], - }, - reef: { - WitnetRequestBoard: [ - /* _reportResultGasLimit */ "0x3100A1CAC7EF19DC", - ], - }, - ultron: { - WitnetRequestBoard: [ - /* _reportResultGasLimit */ 83949, - ], - }, - }, networks: { default: { "ethereum.goerli": { @@ -749,4 +655,194 @@ module.exports = { }, }, }, + specs: { + default: { + WitnetBytecodes: { + libs: [ "WitnetEncodingLib", ], + vanity: 172582, + }, + WitnetRandomness: { + vanity: 4, + }, + WitnetRequestBoard: { + immutables: { + types: [ 'uint256', ], + values: [ + /* _reportResultGasLimit */ 133000, + ] + }, + libs: [ "WitnetErrorsLib", ], + vanity: 83581, + }, + WitnetRequestFactory: { + vanity: 178848, + }, + WitnetPriceFeeds: { + libs: [ "WitnetPriceFeedsLib", ], + vanity: 5, + } + }, + avalanche: { + WitnetRequestBoard: { + immutables: { + values: [ + /* _reportResultGasLimit */ 155000, + ] + }, + }, + }, + celo: { + WitnetRequestBoard: { + immutables: { + values: [ + /* _reportResultGasLimit */ 114000, + ] + }, + }, + }, + conflux: { + WitnetRequestBoard: { + immutables: { + values: [ + /* _reportResultGasLimit */ 78500, + ] + }, + }, + }, + "conflux.espace.testnet": { + WitnetRequestBoard: { + immutables: { + values: [ + /* _reportResultGasLimit */ 225000, + ] + }, + }, + }, + "conflux.espace.mainnet": { + WitnetRequestBoard: { + immutables: { + values: [ + /* _reportResultGasLimit */ 225000, + ] + }, + }, + }, + cronos: { + WitnetRequestBoard: { + immutables: { + values: [ + /* _reportResultGasLimit */ 137500, + ] + }, + }, + }, + dogechain: { + WitnetRequestBoard: { + immutables: { + values: [ + /* _reportResultGasLimit */ 85000, + ] + }, + }, + }, + harmony: { + WitnetRequestBoard: { + immutables: { + values: [ + /* _reportResultGasLimit */ 530000, + ] + }, + }, + }, + hsc: { + WitnetRequestBoard: { + immutables: { + values: [ + /* _reportResultGasLimit */ 85000, + ] + }, + }, + }, + kcc: { + WitnetRequestBoard: { + immutables: { + values: [ + /* _reportResultGasLimit */ 92500, + ] + }, + }, + }, + klaytn: { + WitnetRequestBoard: { + immutables: { + values: [ + /* _reportResultGasLimit */ 105000, + ] + }, + }, + }, + meter: { + WitnetRequestBoard: { + immutables: { + values: [ + /* _reportResultGasLimit */ 85000, + ] + }, + }, + }, + metis: { + WitnetRequestBoard: { + immutables: { + values: [ + /* _reportResultGasLimit */ 134800, + ] + }, + }, + }, + moonbeam: { + WitnetRequestBoard: { + immutables: { + values: [ + /* _reportResultGasLimit */ 115000, + ] + }, + }, + }, + okxchain: { + WitnetRequestBoard: { + immutables: { + values: [ + /* _reportResultGasLimit */ 145000, + ] + }, + }, + }, + optimism: { + WitnetRequestBoard: { + immutables: { + values: [ + /* _reportResultGasLimit */ 135000, + ] + }, + }, + }, + reef: { + WitnetRequestBoard: { + immutables: { + values: [ + /* _reportResultGasLimit */ "0x3100A1CAC7EF19DC", + ] + }, + }, + }, + ultron: { + WitnetRequestBoard: { + immutables: { + values: [ + /* _reportResultGasLimit */ 83949, + ] + }, + }, + }, + }, } From a2918ef00602ca2f02e75d3126c2d1e0d7d7ee16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 9 Nov 2023 08:54:23 +0100 Subject: [PATCH 13/86] feat: implement create2/3 address vanity generators --- package.json | 10 +++-- scripts/eth-create2.js | 37 +++++++++++++++++++ scripts/eth-create3.js | 43 ++++++++++++++++++++++ scripts/vanity2gen.js | 83 ++++++++++++++++++++++++++++++++++++++++++ scripts/vanity3gen.js | 66 +++++++++++++++++++++++++++++++++ 5 files changed, 235 insertions(+), 4 deletions(-) create mode 100644 scripts/eth-create2.js create mode 100644 scripts/eth-create3.js create mode 100644 scripts/vanity2gen.js create mode 100644 scripts/vanity3gen.js diff --git a/package.json b/package.json index 6923e900d..a9f07a1e8 100644 --- a/package.json +++ b/package.json @@ -13,10 +13,10 @@ "coverage": "solidity-coverage", "flatten": "node ./scripts/flatten.js 2>&1", "flatten:all": "npm run clean && npm run flatten:core && npm run flatten:apps && npm run flatten:libs && npm run flatten:proxy", - "flatten:apps": "npm run flatten contracts/impls/apps/", - "flatten:core": "npm run flatten contracts/impls/core/", + "flatten:apps": "npm run flatten contracts/core/apps/", + "flatten:core": "npm run flatten contracts/core/core/", "flatten:libs": "npm run flatten contracts/libs/WitnetErrorsLib.sol && npm run flatten contracts/libs/WitnetEncodingLib.sol && npm run flatten contracts/libs/WitnetPriceFeedsLib.sol", - "flatten:proxy": "npm run flatten contracts/impls/WitnetProxy.sol", + "flatten:proxy": "npm run flatten contracts/core/WitnetProxy.sol", "fmt:js": "eslint \"**/*.js\"", "fmt:sol": "solhint --max-warnings 0 \"contracts/**/*.sol\" && solhint \"test/**/*.sol\" && solhint \"flattened/**/*.sol\"", "fmt!:js": "eslint \"**/*.js\" --fix", @@ -55,9 +55,11 @@ "eslint-plugin-import": "~2.26.0", "eslint-plugin-n": "~15.6.0", "eslint-plugin-promise": "~6.1.1", - "eth-create2": "~1.0.1", + "eth-helpers": "^1.3.0", "eth-gas-reporter": "0.2.25", "js-sha256": "0.9.0", + "nanoassert": "^2.0.0", + "sha3-wasm": "0.0.7", "solhint": "3.3.7", "solidity-coverage": "0.7.16", "truffle": "~5.11.5", diff --git a/scripts/eth-create2.js b/scripts/eth-create2.js new file mode 100644 index 000000000..52a0f84c3 --- /dev/null +++ b/scripts/eth-create2.js @@ -0,0 +1,37 @@ +const assert = require('nanoassert') +const { utils } = require('eth-helpers') +const keccak = require('sha3-wasm').keccak256 + +const prefix = Buffer.from([0xff]) + +/** + * Generate Ethereum CREATE2 address + * + * @param {string|Buffer} address Ethereum address of creator contract as + * string or as a 20 byte `Buffer` + * @param {string|Buffer} salt 256 bit salt as either string or 32 byte `Buffer` + * @param {string|Buffer} initCode init_code as string or Buffer + * @returns {string} result address as hex encoded string. Not + * checksum'ed. This can be done with + * `eth-checksum` or similar modules + */ +module.exports = function create2 (address, salt, initCode) { + if (typeof address === 'string') address = utils.parse.address(address) + if (typeof salt === 'string') salt = utils.parse.uint256(salt) + if (typeof initCode === 'string') initCode = utils.parse.bytes(initCode) + + assert(address.byteLength === 20, 'address must be 20 bytes') + assert(salt.byteLength === 32, 'salt must be 32 bytes') + assert(initCode.byteLength != null, 'initCode must be Buffer') + + const codeHash = keccak().update(initCode).digest() + + return utils.format.address(keccak() + .update(prefix) + .update(address) + .update(salt) + .update(codeHash) + .digest() + .slice(-20)) +} + diff --git a/scripts/eth-create3.js b/scripts/eth-create3.js new file mode 100644 index 000000000..2f5347d48 --- /dev/null +++ b/scripts/eth-create3.js @@ -0,0 +1,43 @@ +const assert = require('nanoassert') +const { utils } = require('eth-helpers') +const keccak = require('sha3-wasm').keccak256 + +const factoryPrefix = Buffer.from([0xff]) + +/** + * Generate Ethereum CREATE3-library address + * + * @param {string|Buffer} address Ethereum address of creator contract as + * string or as a 20 byte `Buffer` + * @param {string|Buffer} salt 256 bit salt as either string or 32 byte `Buffer` + * @returns {string} result address as hex encoded string. Not + * checksum'ed. This can be done with + * `eth-checksum` or similar modules + */ +module.exports = function create3 (address, salt) { + if (typeof address === 'string') address = utils.parse.address(address) + if (typeof salt === 'string') salt = utils.parse.uint256(salt) + + assert(address.byteLength === 20, 'address must be 20 bytes') + assert(salt.byteLength === 32, 'salt must be 32 bytes') + + const factoryHash = utils.parse.uint256("0x21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f") + const factoryAddr = keccak() + .update(factoryPrefix) + .update(address) + .update(salt) + .update(factoryHash) + .digest() + .slice(-20) + ; + assert(factoryAddr.byteLength === 20, 'address must be 20 bytes') + + return utils.format.address(keccak() + .update(Buffer.from([0xd6, 0x94])) + .update(factoryAddr) + .update(Buffer.from([0x01])) + .digest() + .slice(-20) + ) +} + diff --git a/scripts/vanity2gen.js b/scripts/vanity2gen.js new file mode 100644 index 000000000..8a8354137 --- /dev/null +++ b/scripts/vanity2gen.js @@ -0,0 +1,83 @@ +const { assert } = require("chai") +const create2 = require("./eth-create2") +const fs = require("fs") +const utils = require("./utils") + +const addresses = require("../migrations/witnet.addresses") + +module.exports = async function () { + let artifact + let count = 0 + let ecosystem = "default" + let from + let hits = 10 + let offset = 0 + let network = "default" + let prefix = "0x00" + let suffix = "00" + let hexArgs = "" + process.argv.map((argv, index, args) => { + if (argv === "--offset") { + offset = parseInt(args[index + 1]) + } else if (argv === "--artifact") { + artifact = artifacts.require(args[index + 1]) + } else if (argv === "--prefix") { + prefix = args[index + 1].toLowerCase() + assert(web3.utils.isHexStrict(prefix), "--prefix: invalid hex string") + } else if (argv === "--suffix") { + suffix = args[index + 1].toLowerCase() + assert(web3.utils.isHexStrict(suffix), "--suffix: invalid hex string") + } else if (argv === "--hits") { + hits = parseInt(args[index + 1]) + } else if (argv === "--network") { + [ecosystem, network] = utils.getRealmNetworkFromString(args[index + 1].toLowerCase()) + } else if (argv === "--hexArgs") { + hexArgs = args[index + 1].toLowerCase() + if (hexArgs.startsWith("0x")) hexArgs = hexArgs.slice(2) + assert(web3.utils.isHexStrict("0x" + hexArgs), "--hexArgs: invalid hex string") + } else if (argv === "--from") { + from = args[index + 1] + } + return argv + }) + try { + from = from || addresses[ecosystem][network].WitnetDeployer + } catch { + console.error(`WitnetDeployer must have been previously deployed on network '${network}'.\n`) + console.info("Usage:\n") + console.info(" --artifact => Truffle artifact name (mandatory)") + console.info(" --hexArgs => Hexified constructor arguments") + console.info(" --hits => Number of vanity hits to look for (default: 10)") + console.info(" --network => Network name") + console.info(" --offset => Salt starting value minus 1 (default: 0)") + console.info(" --prefix => Prefix hex string to look for (default: 0x00)") + console.info(" --suffix => suffix hex string to look for (default: 0x00)") + process.exit(1) + } + if (!artifact) { + console.error("No --artifact was set!") + process.exit(1) + } + const initCode = artifact.toJSON().bytecode + hexArgs + console.log("Init code: ", initCode) + console.log("Artifact: ", artifact?.contractName) + console.log("From: ", from) + console.log("Hits: ", hits) + console.log("Offset: ", offset) + console.log("Prefix: ", prefix) + console.log("Suffix: ", suffix) + console.log("=".repeat(55)) + suffix = suffix.slice(2) + while (count < hits) { + const salt = "0x" + utils.padLeft(offset.toString(16), "0", 32) + const addr = create2(from, salt, initCode).toLowerCase() + if (addr.startsWith(prefix) && addr.endsWith(suffix)) { + const found = `${offset} => ${web3.utils.toChecksumAddress(addr)}` + console.log(found) + fs.appendFileSync(`./migrations/salts/${artifact?.contractName}$${from.toLowerCase()}.tmp`, found + "\n") + count++ + } + offset++ + } +} + diff --git a/scripts/vanity3gen.js b/scripts/vanity3gen.js new file mode 100644 index 000000000..6452d3b81 --- /dev/null +++ b/scripts/vanity3gen.js @@ -0,0 +1,66 @@ +const { assert } = require("chai") +const create3 = require("./eth-create3") +const fs = require("fs") +const utils = require("./utils") + +const addresses = require("../migrations/witnet.addresses") + +module.exports = async function () { + let count = 0 + let ecosystem = "default" + let from + let hits = 10 + let offset = 0 + let network = "default" + let prefix = "0x00" + let suffix = "0x00" + let hexArgs = "" + process.argv.map((argv, index, args) => { + if (argv === "--offset") { + offset = parseInt(args[index + 1]) + } else if (argv === "--prefix") { + prefix = args[index + 1].toLowerCase() + assert(web3.utils.isHexStrict(prefix), "--prefix: invalid hex string") + } else if (argv === "--suffix") { + suffix = args[index + 1].toLowerCase() + assert(web3.utils.isHexStrict(suffix), "--suffix: invalid hex string") + } else if (argv === "--hits") { + hits = parseInt(args[index + 1]) + } else if (argv === "--network") { + [ecosystem, network] = utils.getRealmNetworkFromString(args[index + 1].toLowerCase()) + } else if (argv === "--from") { + from = args[index + 1] + } + return argv + }) + try { + from = from || addresses[ecosystem][network].WitnetDeployer + } catch { + console.error(`WitnetDeployer must have been previously deployed on network '${network}'.\n`) + console.info("Usage:\n") + console.info(" --hits => Number of vanity hits to look for (default: 10)") + console.info(" --network => Network name") + console.info(" --offset => Salt starting value minus 1 (default: 0)") + console.info(" --prefix => Prefix hex string to look for (default: 0x00)") + console.info(" --suffix => suffix hex string to look for (default: 0x00)") + process.exit(1) + } + console.log("From: ", from) + console.log("Hits: ", hits) + console.log("Offset: ", offset) + console.log("Prefix: ", prefix) + console.log("Suffix: ", suffix) + console.log("=".repeat(55)) + suffix = suffix.slice(2) + while (count < hits) { + const salt = "0x" + utils.padLeft(offset.toString(16), "0", 32) + const addr = create3(from, salt).toLowerCase() + if (addr.startsWith(prefix) && addr.endsWith(suffix)) { + const found = `${offset} => ${web3.utils.toChecksumAddress(addr)}` + console.log(found) + fs.appendFileSync(`./migrations/salts/create3$${from.toLowerCase()}.tmp`, found + "\n") + count++ + } + offset++ + } +} From 1ed8756e4d613b27e730714e26bcdcef1dea78b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 9 Nov 2023 08:54:45 +0100 Subject: [PATCH 14/86] chore: bump package version to 2.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a9f07a1e8..794351cb0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "witnet-solidity-bridge", - "version": "2.0.0", + "version": "2.0.1", "description": "Witnet Solidity Bridge contracts for EVM-compatible chains", "main": "", "scripts": { From d986cc8f6752739f051cfddcdf32f45be5b9b16e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 9 Nov 2023 11:36:43 +0100 Subject: [PATCH 15/86] feat: improve recovery of counter factual proxy addresses --- migrations/scripts/4_proxies.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/migrations/scripts/4_proxies.js b/migrations/scripts/4_proxies.js index b10286c31..bfef92a9d 100644 --- a/migrations/scripts/4_proxies.js +++ b/migrations/scripts/4_proxies.js @@ -76,8 +76,20 @@ async function deploy(target) { console.info(" ", "> gas price: ", tx.receipt.effectiveGasPrice / 10 ** 9, "gwei") console.info(" ", "> total cost: ", web3.utils.fromWei(BigInt(tx.receipt.gasUsed * tx.receipt.effectiveGasPrice).toString(), 'ether'), "ETH") } else { - console.info(" ", "> already proxified ;-)") - // TODO: check that proxy's class matches impl's class + try { + const oldImplAddr = await getProxyImplementation(from, proxyAddr) + const oldImpl = await artifacts.require(targets[key]).at(oldImplAddr) + const oldClass = await oldImpl.class.call({ from }) + const newClass = await impl.class.call({ from }) + if (oldClass !== newClass) { + console.info(`Error: proxy address already taken (\"${oldClass}\" != \"${newClass}\")`) + process.exit(1) + } else { + console.info(" ", `> recovered proxy address on class \"${oldClass}\" ;-)`) + } + } catch (ex) { + console.info("Error: cannot check proxy recoverability:", ex) + } } if ((await web3.eth.getCode(proxyAddr)).length > 3) { addresses[ecosystem][network][key] = proxyAddr From 29a960933ee9fe55eea842eddbb2fc4e6507c253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 9 Nov 2023 11:38:56 +0100 Subject: [PATCH 16/86] feat: auto-save exportable abis when upgraded --- migrations/scripts/4_proxies.js | 12 ++++-------- migrations/scripts/5_apps.js | 2 ++ scripts/utils/index.js | 22 ++++++++++++++++++++++ 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/migrations/scripts/4_proxies.js b/migrations/scripts/4_proxies.js index bfef92a9d..70951c43d 100644 --- a/migrations/scripts/4_proxies.js +++ b/migrations/scripts/4_proxies.js @@ -71,10 +71,8 @@ async function deploy(target) { console.info(" ", "> initialize params:", mutables.values) } const tx = await deployer.proxify(proxy_salt, impl.address, initdata, { from }) - console.info(" ", "> transaction hash: ", tx.receipt.transactionHash) - console.info(" ", "> gas used: ", tx.receipt.gasUsed.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")) - console.info(" ", "> gas price: ", tx.receipt.effectiveGasPrice / 10 ** 9, "gwei") - console.info(" ", "> total cost: ", web3.utils.fromWei(BigInt(tx.receipt.gasUsed * tx.receipt.effectiveGasPrice).toString(), 'ether'), "ETH") + // save/overwrite exportable abi file + utils.saveJsonAbi(key, proxy.abi) } else { try { const oldImplAddr = await getProxyImplementation(from, proxyAddr) @@ -116,10 +114,8 @@ async function deploy(target) { console.info(" ", "> initialize params:", mutables.values) } const tx = await upgradeProxyTo(from, proxy, newImpl.address, initdata) - console.info(" ", "> transaction hash: ", tx.receipt.transactionHash) - console.info(" ", "> gas used: ", tx.receipt.gasUsed.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")) - console.info(" ", "> gas price: ", tx.receipt.effectiveGasPrice / 10 ** 9, "gwei") - console.info(" ", "> total cost: ", web3.utils.fromWei(BigInt(tx.receipt.gasUsed * tx.receipt.effectiveGasPrice).toString(), 'ether'), "ETH") + // save/overwrite exportable abi file + utils.saveJsonAbi(key, proxy.abi) } } else { utils.traceHeader(`Deployed '${key}'`) diff --git a/migrations/scripts/5_apps.js b/migrations/scripts/5_apps.js index b64dd01f2..65a55d627 100644 --- a/migrations/scripts/5_apps.js +++ b/migrations/scripts/5_apps.js @@ -95,6 +95,8 @@ async function deploy(specs) { console.info(" ", "> total cost: ", web3.utils.fromWei(BigInt(tx.receipt.gasUsed * tx.receipt.effectiveGasPrice).toString(), 'ether'), "ETH") if ((await web3.eth.getCode(dappAddr)).length > 3) { addresses[ecosystem][network][key] = dappAddr + // save/overwrite exportable abi file + utils.saveJsonAbi(key, artifact.abi) } else { console.info(`Contract was not deployed on expected address: ${dappAddr}`) console.log(tx.receipt) diff --git a/scripts/utils/index.js b/scripts/utils/index.js index ec39657fd..6d9190a6b 100644 --- a/scripts/utils/index.js +++ b/scripts/utils/index.js @@ -1,5 +1,6 @@ const fs = require("fs") require("dotenv").config() +const { isEqual } = require("lodash") const readline = require("readline") const web3 = require("web3") @@ -14,6 +15,7 @@ module.exports = { padLeft, prompt, saveAddresses, + saveJsonAbi, traceHeader, traceTx, } @@ -116,3 +118,23 @@ function saveAddresses (addrs) { { flag: "w+" } ) } + +function saveJsonAbi (key, abi) { + const version = require("../../package.json").version + const latest_fn = `./migrations/abis/${key}.json`; + const version_fn = `./migrations/abis/${key}-${version}.json` + let latest_abi = [] + if (fs.existsSync(latest_fn)) { + try { + latest_abi = JSON.parse(fs.readFileSync(latest_fn)) + } catch {} + } + if (!isEqual(abi, latest_abi)) { + const json = JSON.stringify(abi, null, 4) + if (fs.existsSync(latest_fn)) { + // avoid creating versioned abi upon first deployment + fs.writeFileSync(version_fn, json, { flag: "w+" }) + } + fs.writeFileSync(latest_fn, json, { flag: "w+" }) + } +} From 5d401ff17d7065fe92dc0fb67ad400d2affe4ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 9 Nov 2023 11:39:35 +0100 Subject: [PATCH 17/86] chore: add exportable abis --- migrations/abis/WitnetBytecodes.json | 954 +++ migrations/abis/WitnetPriceFeeds.json | 1359 ++++ migrations/abis/WitnetProxy.json | 7310 -------------------- migrations/abis/WitnetRandomness.json | 649 ++ migrations/abis/WitnetRequest.json | 400 ++ migrations/abis/WitnetRequestBoard.json | 1088 +++ migrations/abis/WitnetRequestFactory.json | 81 + migrations/abis/WitnetRequestTemplate.json | 348 + 8 files changed, 4879 insertions(+), 7310 deletions(-) create mode 100644 migrations/abis/WitnetBytecodes.json create mode 100644 migrations/abis/WitnetPriceFeeds.json delete mode 100644 migrations/abis/WitnetProxy.json create mode 100644 migrations/abis/WitnetRandomness.json create mode 100644 migrations/abis/WitnetRequest.json create mode 100644 migrations/abis/WitnetRequestBoard.json create mode 100644 migrations/abis/WitnetRequestFactory.json create mode 100644 migrations/abis/WitnetRequestTemplate.json diff --git a/migrations/abis/WitnetBytecodes.json b/migrations/abis/WitnetBytecodes.json new file mode 100644 index 000000000..3641108bd --- /dev/null +++ b/migrations/abis/WitnetBytecodes.json @@ -0,0 +1,954 @@ +[ + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "UnknownRadonReducer", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "UnknownRadonRequest", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "UnknownRadonRetrieval", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "UnknownRadonSLA", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "NewDataProvider", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "NewRadHash", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "NewRadonReducerHash", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "NewRadonRetrievalHash", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "NewSlaHash", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "slahHash", + "type": "bytes32" + } + ], + "name": "bytecodeOf", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + } + ], + "name": "bytecodeOf", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "slaHash", + "type": "bytes32" + } + ], + "name": "hashOf", + "outputs": [ + { + "internalType": "bytes32", + "name": "drQueryHash", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32[]", + "name": "sources", + "type": "bytes32[]" + }, + { + "internalType": "bytes32", + "name": "aggregator", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "tally", + "type": "bytes32" + }, + { + "internalType": "uint16", + "name": "resultMaxSize", + "type": "uint16" + }, + { + "internalType": "string[][]", + "name": "args", + "type": "string[][]" + } + ], + "name": "hashOf", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "slaHash", + "type": "bytes32" + } + ], + "name": "hashWeightWitsOf", + "outputs": [ + { + "internalType": "bytes32", + "name": "drQueryHash", + "type": "bytes32" + }, + { + "internalType": "uint32", + "name": "drQueryWeight", + "type": "uint32" + }, + { + "internalType": "uint256", + "name": "drQueryWits", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "lookupDataProvider", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "authority", + "type": "string" + } + ], + "name": "lookupDataProviderIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "offset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "lookupDataProviderSources", + "outputs": [ + { + "internalType": "bytes32[]", + "name": "", + "type": "bytes32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "lookupRadonReducer", + "outputs": [ + { + "components": [ + { + "internalType": "enum WitnetV2.RadonReducerOpcodes", + "name": "opcode", + "type": "uint8" + }, + { + "components": [ + { + "internalType": "enum WitnetV2.RadonFilterOpcodes", + "name": "opcode", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "args", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonFilter[]", + "name": "filters", + "type": "tuple[]" + }, + { + "internalType": "bytes", + "name": "script", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonReducer", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + } + ], + "name": "lookupRadonRequestAggregator", + "outputs": [ + { + "components": [ + { + "internalType": "enum WitnetV2.RadonReducerOpcodes", + "name": "opcode", + "type": "uint8" + }, + { + "components": [ + { + "internalType": "enum WitnetV2.RadonFilterOpcodes", + "name": "opcode", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "args", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonFilter[]", + "name": "filters", + "type": "tuple[]" + }, + { + "internalType": "bytes", + "name": "script", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonReducer", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + } + ], + "name": "lookupRadonRequestResultDataType", + "outputs": [ + { + "internalType": "enum WitnetV2.RadonDataTypes", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + } + ], + "name": "lookupRadonRequestResultMaxSize", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + } + ], + "name": "lookupRadonRequestSources", + "outputs": [ + { + "internalType": "bytes32[]", + "name": "", + "type": "bytes32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + } + ], + "name": "lookupRadonRequestSourcesCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + } + ], + "name": "lookupRadonRequestTally", + "outputs": [ + { + "components": [ + { + "internalType": "enum WitnetV2.RadonReducerOpcodes", + "name": "opcode", + "type": "uint8" + }, + { + "components": [ + { + "internalType": "enum WitnetV2.RadonFilterOpcodes", + "name": "opcode", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "args", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonFilter[]", + "name": "filters", + "type": "tuple[]" + }, + { + "internalType": "bytes", + "name": "script", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonReducer", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "lookupRadonRetrieval", + "outputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "argsCount", + "type": "uint8" + }, + { + "internalType": "enum WitnetV2.DataRequestMethods", + "name": "method", + "type": "uint8" + }, + { + "internalType": "enum WitnetV2.RadonDataTypes", + "name": "resultDataType", + "type": "uint8" + }, + { + "internalType": "string", + "name": "url", + "type": "string" + }, + { + "internalType": "string", + "name": "body", + "type": "string" + }, + { + "internalType": "string[2][]", + "name": "headers", + "type": "string[2][]" + }, + { + "internalType": "bytes", + "name": "script", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonRetrieval", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "lookupRadonRetrievalArgsCount", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "lookupRadonRetrievalResultDataType", + "outputs": [ + { + "internalType": "enum WitnetV2.RadonDataTypes", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "slaHash", + "type": "bytes32" + } + ], + "name": "lookupRadonSLA", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "numWitnesses", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minConsensusPercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "witnessReward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "witnessCollateral", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minerCommitRevealFee", + "type": "uint256" + } + ], + "internalType": "struct WitnetV2.RadonSLA", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "slaHash", + "type": "bytes32" + } + ], + "name": "lookupRadonSLAReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalDataProviders", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "enum WitnetV2.RadonReducerOpcodes", + "name": "opcode", + "type": "uint8" + }, + { + "components": [ + { + "internalType": "enum WitnetV2.RadonFilterOpcodes", + "name": "opcode", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "args", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonFilter[]", + "name": "filters", + "type": "tuple[]" + }, + { + "internalType": "bytes", + "name": "script", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonReducer", + "name": "reducer", + "type": "tuple" + } + ], + "name": "verifyRadonReducer", + "outputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32[]", + "name": "sources", + "type": "bytes32[]" + }, + { + "internalType": "bytes32", + "name": "aggregator", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "tally", + "type": "bytes32" + }, + { + "internalType": "uint16", + "name": "resultMaxSize", + "type": "uint16" + }, + { + "internalType": "string[][]", + "name": "args", + "type": "string[][]" + } + ], + "name": "verifyRadonRequest", + "outputs": [ + { + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum WitnetV2.DataRequestMethods", + "name": "requestMethod", + "type": "uint8" + }, + { + "internalType": "string", + "name": "requestSchema", + "type": "string" + }, + { + "internalType": "string", + "name": "requestAuthority", + "type": "string" + }, + { + "internalType": "string", + "name": "requestPath", + "type": "string" + }, + { + "internalType": "string", + "name": "requestQuery", + "type": "string" + }, + { + "internalType": "string", + "name": "requestBody", + "type": "string" + }, + { + "internalType": "string[2][]", + "name": "requestHeaders", + "type": "string[2][]" + }, + { + "internalType": "bytes", + "name": "requestRadonScript", + "type": "bytes" + } + ], + "name": "verifyRadonRetrieval", + "outputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum WitnetV2.DataRequestMethods", + "name": "requestMethod", + "type": "uint8" + }, + { + "internalType": "string", + "name": "requestURL", + "type": "string" + }, + { + "internalType": "string", + "name": "requestBody", + "type": "string" + }, + { + "internalType": "string[2][]", + "name": "requestHeaders", + "type": "string[2][]" + }, + { + "internalType": "bytes", + "name": "requestRadonScript", + "type": "bytes" + } + ], + "name": "verifyRadonRetrieval", + "outputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "numWitnesses", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minConsensusPercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "witnessReward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "witnessCollateral", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minerCommitRevealFee", + "type": "uint256" + } + ], + "internalType": "struct WitnetV2.RadonSLA", + "name": "sla", + "type": "tuple" + } + ], + "name": "verifyRadonSLA", + "outputs": [ + { + "internalType": "bytes32", + "name": "slaHash", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "class", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/migrations/abis/WitnetPriceFeeds.json b/migrations/abis/WitnetPriceFeeds.json new file mode 100644 index 000000000..421f539bb --- /dev/null +++ b/migrations/abis/WitnetPriceFeeds.json @@ -0,0 +1,1359 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_operator", + "type": "address" + }, + { + "internalType": "contract WitnetRequestBoard", + "name": "_wrb", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "EmptyBuffer", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "range", + "type": "uint256" + } + ], + "name": "IndexOutOfBounds", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "InvalidLengthEncoding", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "read", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + } + ], + "name": "UnexpectedMajorType", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "unexpected", + "type": "uint256" + } + ], + "name": "UnsupportedMajorType", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + }, + { + "indexed": false, + "internalType": "string", + "name": "caption", + "type": "string" + } + ], + "name": "DeletedFeed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + }, + { + "indexed": false, + "internalType": "string", + "name": "caption", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + } + ], + "name": "SettledFeed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + }, + { + "indexed": false, + "internalType": "string", + "name": "caption", + "type": "string" + }, + { + "indexed": false, + "internalType": "address", + "name": "solver", + "type": "address" + } + ], + "name": "SettledFeedSolver", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "slaHash", + "type": "bytes32" + } + ], + "name": "SettledRadonSLA", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "slaHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "UpdatingFeed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "UpdatingFeedReward", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "solver", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "codehash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "constructorParams", + "type": "bytes" + } + ], + "name": "WitnetPriceSolverDeployed", + "type": "event" + }, + { + "stateMutability": "nonpayable", + "type": "fallback" + }, + { + "inputs": [], + "name": "dataType", + "outputs": [ + { + "internalType": "enum WitnetV2.RadonDataTypes", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "prefix", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "witnet", + "outputs": [ + { + "internalType": "contract IWitnetRequestBoard", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "caption", + "type": "string" + } + ], + "name": "hash", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + } + ], + "name": "lookupCaption", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "supportedFeeds", + "outputs": [ + { + "internalType": "bytes4[]", + "name": "_ids", + "type": "bytes4[]" + }, + { + "internalType": "string[]", + "name": "_captions", + "type": "string[]" + }, + { + "internalType": "bytes32[]", + "name": "_solvers", + "type": "bytes32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "caption", + "type": "string" + } + ], + "name": "supportsCaption", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalFeeds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "defaultRadonSLA", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "numWitnesses", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minConsensusPercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "witnessReward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "witnessCollateral", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minerCommitRevealFee", + "type": "uint256" + } + ], + "internalType": "struct WitnetV2.RadonSLA", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + }, + { + "internalType": "uint256", + "name": "_evmGasPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "estimateUpdateBaseFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + }, + { + "internalType": "uint256", + "name": "_evmGasPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "estimateUpdateBaseFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + } + ], + "name": "latestResponse", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "reporter", + "type": "address" + }, + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "drTxHash", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "cborBytes", + "type": "bytes" + } + ], + "internalType": "struct Witnet.Response", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + } + ], + "name": "latestResult", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "cursor", + "type": "uint256" + } + ], + "internalType": "struct WitnetBuffer.Buffer", + "name": "buffer", + "type": "tuple" + }, + { + "internalType": "uint8", + "name": "initialByte", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "majorType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "additionalInformation", + "type": "uint8" + }, + { + "internalType": "uint64", + "name": "len", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "tag", + "type": "uint64" + } + ], + "internalType": "struct WitnetCBOR.CBOR", + "name": "value", + "type": "tuple" + } + ], + "internalType": "struct Witnet.Result", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + } + ], + "name": "latestUpdateQueryId", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + } + ], + "name": "latestUpdateRequest", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "slaHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "gasprice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + } + ], + "internalType": "struct Witnet.Request", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + } + ], + "name": "latestUpdateResponse", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "reporter", + "type": "address" + }, + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "drTxHash", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "cborBytes", + "type": "bytes" + } + ], + "internalType": "struct Witnet.Response", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + } + ], + "name": "latestUpdateResultError", + "outputs": [ + { + "components": [ + { + "internalType": "enum Witnet.ResultErrorCodes", + "name": "code", + "type": "uint8" + }, + { + "internalType": "string", + "name": "reason", + "type": "string" + } + ], + "internalType": "struct Witnet.ResultError", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + } + ], + "name": "latestUpdateResultStatus", + "outputs": [ + { + "internalType": "enum Witnet.ResultStatus", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + } + ], + "name": "lookupBytecode", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + } + ], + "name": "lookupRadHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + } + ], + "name": "lookupRetrievals", + "outputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "argsCount", + "type": "uint8" + }, + { + "internalType": "enum WitnetV2.DataRequestMethods", + "name": "method", + "type": "uint8" + }, + { + "internalType": "enum WitnetV2.RadonDataTypes", + "name": "resultDataType", + "type": "uint8" + }, + { + "internalType": "string", + "name": "url", + "type": "string" + }, + { + "internalType": "string", + "name": "body", + "type": "string" + }, + { + "internalType": "string[2][]", + "name": "headers", + "type": "string[2][]" + }, + { + "internalType": "bytes", + "name": "script", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonRetrieval[]", + "name": "_retrievals", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "registry", + "outputs": [ + { + "internalType": "contract IWitnetBytecodes", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + }, + { + "internalType": "bytes32", + "name": "_slaHash", + "type": "bytes32" + } + ], + "name": "requestUpdate", + "outputs": [ + { + "internalType": "uint256", + "name": "_usedFunds", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + } + ], + "name": "requestUpdate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "acceptOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "caption", + "type": "string" + } + ], + "name": "deleteFeed", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "numWitnesses", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minConsensusPercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "witnessReward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "witnessCollateral", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minerCommitRevealFee", + "type": "uint256" + } + ], + "internalType": "struct WitnetV2.RadonSLA", + "name": "sla", + "type": "tuple" + } + ], + "name": "settleDefaultRadonSLA", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "caption", + "type": "string" + }, + { + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + } + ], + "name": "settleFeedRequest", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "caption", + "type": "string" + }, + { + "internalType": "contract WitnetRequest", + "name": "request", + "type": "address" + } + ], + "name": "settleFeedRequest", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "caption", + "type": "string" + }, + { + "internalType": "contract WitnetRequestTemplate", + "name": "template", + "type": "address" + }, + { + "internalType": "string[][]", + "name": "args", + "type": "string[][]" + } + ], + "name": "settleFeedRequest", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "caption", + "type": "string" + }, + { + "internalType": "address", + "name": "solver", + "type": "address" + }, + { + "internalType": "string[]", + "name": "deps", + "type": "string[]" + } + ], + "name": "settleFeedSolver", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + } + ], + "name": "lookupDecimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + } + ], + "name": "lookupPriceSolver", + "outputs": [ + { + "internalType": "contract IWitnetPriceSolver", + "name": "_solverAddress", + "type": "address" + }, + { + "internalType": "string[]", + "name": "_solverDeps", + "type": "string[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "feedId", + "type": "bytes4" + } + ], + "name": "latestPrice", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "drTxHash", + "type": "bytes32" + }, + { + "internalType": "enum Witnet.ResultStatus", + "name": "status", + "type": "uint8" + } + ], + "internalType": "struct IWitnetPriceSolver.Price", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4[]", + "name": "feedIds", + "type": "bytes4[]" + } + ], + "name": "latestPrices", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "drTxHash", + "type": "bytes32" + }, + { + "internalType": "enum Witnet.ResultStatus", + "name": "status", + "type": "uint8" + } + ], + "internalType": "struct IWitnetPriceSolver.Price[]", + "name": "_prices", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "initcode", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "constructorParams", + "type": "bytes" + } + ], + "name": "deployPriceSolver", + "outputs": [ + { + "internalType": "address", + "name": "_solver", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "initcode", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "constructorParams", + "type": "bytes" + } + ], + "name": "determinePriceSolverAddress", + "outputs": [ + { + "internalType": "address", + "name": "_address", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "feedId", + "type": "bytes32" + } + ], + "name": "valueFor", + "outputs": [ + { + "internalType": "int256", + "name": "_value", + "type": "int256" + }, + { + "internalType": "uint256", + "name": "_timestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_status", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/migrations/abis/WitnetProxy.json b/migrations/abis/WitnetProxy.json deleted file mode 100644 index 8aa75fc01..000000000 --- a/migrations/abis/WitnetProxy.json +++ /dev/null @@ -1,7310 +0,0 @@ -{ - "contractName": "WitnetProxy", - "abi": [ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "stateMutability": "payable", - "type": "fallback", - "payable": true - }, - { - "stateMutability": "payable", - "type": "receive", - "payable": true - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function", - "constant": true - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "_initData", - "type": "bytes" - } - ], - "name": "upgradeTo", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_initData\",\"type\":\"bytes\"}],\"name\":\"upgradeTo\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"The Witnet Foundation.\",\"kind\":\"dev\",\"methods\":{\"upgradeTo(address,bytes)\":{\"params\":{\"_initData\":\"Raw data with which new implementation will be initialized.\",\"_newImplementation\":\"New implementation address.\"},\"returns\":{\"_0\":\"Returns whether new implementation would be further upgradable, or not.\"}}},\"title\":\"WitnetProxy: upgradable delegate-proxy contract. \",\"version\":1},\"userdoc\":{\"events\":{\"Upgraded(address)\":{\"notice\":\"Event emitted every time the implementation gets updated.\"}},\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructor with no params as to ease eventual support of Singleton pattern (i.e. ERC-2470).\"},\"implementation()\":{\"notice\":\"Returns proxy's current implementation address.\"},\"upgradeTo(address,bytes)\":{\"notice\":\"Upgrades the `implementation` address.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"project:/contracts/impls/WitnetProxy.sol\":\"WitnetProxy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\":{\"keccak256\":\"0xe798cadb41e2da274913e4b3183a80f50fb057a42238fe8467e077268100ec27\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://899f850f7df5a270bccfb765d70069959ca1c20d3a7381c1c3bda8a3ffee1935\",\"dweb:/ipfs/QmVdnAqwyX2L3nX2HDA5WKGtVBFyH1nKE9A1k7fZnPBkhP\"]},\"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\":{\"keccak256\":\"0x2edcb41c121abc510932e8d83ff8b82cf9cdde35e7c297622f5c29ef0af25183\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://72460c66cd1c3b1c11b863e0d8df0a1c56f37743019e468dc312c754f43e3b06\",\"dweb:/ipfs/QmPExYKiNb9PUsgktQBupPaM33kzDHxaYoVeJdLhv8s879\"]},\"project:/contracts/impls/WitnetProxy.sol\":{\"keccak256\":\"0x1c779834ad2643469ffdaa70da075bd4617326663539b018e3a2756873997e3d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://142b32cd3be904194a8b370e6e1e5c961d9e70674903a47c6a3aac6aea770cfa\",\"dweb:/ipfs/Qme3UTCXqJFAdA7MJBKfQc3kUQjAoTuaMoifU8encsJU9P\"]},\"project:/contracts/patterns/Initializable.sol\":{\"keccak256\":\"0xaac470e87f361cf15d68d1618d6eb7d4913885d33ccc39c797841a9591d44296\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ef3760b2039feda8715d4bd9f8de8e3885f25573d12ba92f52d626ba880a08bf\",\"dweb:/ipfs/QmP2mfHPBKkjTAKft95sPDb4PBsjfmAwc47Kdcv3xYSf3g\"]},\"project:/contracts/patterns/Proxiable.sol\":{\"keccak256\":\"0xe1b1bb7ba2e2fc799b33648f6f89a1b0e82a75dd275071215b3fd8c82327a2cb\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a025a64d64d46c7ced3c1c99f4380841ec495a0bb6fbe4426ff9b32e16fa4769\",\"dweb:/ipfs/QmRuUrv285bTD9pPCppUGNMTQkCqqceXSXEJrEnpN2H778\"]},\"project:/contracts/patterns/Upgradeable.sol\":{\"keccak256\":\"0x27ca1e658f13f0128d17ff27e9640670b22afdab6163c0daa14f2ec0853b5954\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://f2eceac1ee77596a31e7ee2f11145ce188eef649e3095b2a26d746a250df2b81\",\"dweb:/ipfs/QmcEh2umA5McbU9VHY319XW8rw4Fs79a7dKGC3F2no8biL\"]}},\"version\":1}", - "bytecode": "0x608060405234801561001057600080fd5b50610912806100206000396000f3fe60806040526004361061002d5760003560e01c80635c60da1b146100655780636fbc15e91461009757610034565b3661003457005b600061003e6100c7565b905060405136600082376000803683855af43d806000843e818015610061578184f35b8184fd5b34801561007157600080fd5b5061007a6100c7565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100a357600080fd5b506100b76100b2366004610757565b6100f5565b604051901515815260200161008e565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b60006001600160a01b0383166101525760405162461bcd60e51b815260206004820181905260248201527f5769746e657450726f78793a206e756c6c20696d706c656d656e746174696f6e60448201526064015b60405180910390fd5b600061015c6100c7565b90506001600160a01b0381161561053857806001600160a01b0316846001600160a01b0316036101ce5760405162461bcd60e51b815260206004820152601f60248201527f5769746e657450726f78793a206e6f7468696e6720746f2075706772616465006044820152606401610149565b806001600160a01b0316635479d9406040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610228575060408051601f3d908101601f1916820190925261022591810190610827565b60015b6102875760405162461bcd60e51b815260206004820152602a60248201527f5769746e657450726f78793a20756e61626c6520746f20636865636b207570676044820152697261646162696c69747960b01b6064820152608401610149565b806102d45760405162461bcd60e51b815260206004820152601b60248201527f5769746e657450726f78793a206e6f742075706772616461626c6500000000006044820152606401610149565b5060405133602482015260009081906001600160a01b0384169060440160408051601f198184030181529181526020820180516001600160e01b03166335ac4b0560e11b179052516103269190610874565b600060405180830381855af49150503d8060008114610361576040519150601f19603f3d011682016040523d82523d6000602084013e610366565b606091505b5091509150816103b85760405162461bcd60e51b815260206004820152601a60248201527f5769746e657450726f78793a206e6f7420636f6d706c69616e740000000000006044820152606401610149565b808060200190518101906103cc9190610827565b6104185760405162461bcd60e51b815260206004820152601b60248201527f5769746e657450726f78793a206e6f7420617574686f72697a656400000000006044820152606401610149565b856001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610456573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061047a9190610890565b836001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104dc9190610890565b146105355760405162461bcd60e51b8152602060048201526024808201527f5769746e657450726f78793a2070726f786961626c655555494473206d69736d6044820152630c2e8c6d60e31b6064820152608401610149565b50505b6000846001600160a01b03168460405160240161055591906108a9565b60408051601f198184030181529181526020820180516001600160e01b031663439fab9160e01b1790525161058a9190610874565b600060405180830381855af49150503d80600081146105c5576040519150601f19603f3d011682016040523d82523d6000602084013e6105ca565b606091505b50509050806106255760405162461bcd60e51b815260206004820152602160248201527f5769746e657450726f78793a20756e61626c6520746f20696e697469616c697a6044820152606560f81b6064820152608401610149565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0387169081179091556040517fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2846001600160a01b0316635479d9406040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156106e5575060408051601f3d908101601f191682019092526106e291810190610827565b60015b6107315760405162461bcd60e51b815260206004820152601a60248201527f5769746e657450726f78793a206e6f7420636f6d706c69616e740000000000006044820152606401610149565b925061073b915050565b92915050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561076a57600080fd5b82356001600160a01b038116811461078157600080fd5b9150602083013567ffffffffffffffff8082111561079e57600080fd5b818501915085601f8301126107b257600080fd5b8135818111156107c4576107c4610741565b604051601f8201601f19908116603f011681019083821181831017156107ec576107ec610741565b8160405282815288602084870101111561080557600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60006020828403121561083957600080fd5b8151801515811461084957600080fd5b9392505050565b60005b8381101561086b578181015183820152602001610853565b50506000910152565b60008251610886818460208701610850565b9190910192915050565b6000602082840312156108a257600080fd5b5051919050565b60208152600082518060208401526108c8816040850160208701610850565b601f01601f1916919091016040019291505056fea26469706673582212200771bc4bad015c089efb2351eb3266c8aad36c8daccf86bbf3421605ef5fc23c64736f6c63430008110033", - "deployedBytecode": "0x60806040526004361061002d5760003560e01c80635c60da1b146100655780636fbc15e91461009757610034565b3661003457005b600061003e6100c7565b905060405136600082376000803683855af43d806000843e818015610061578184f35b8184fd5b34801561007157600080fd5b5061007a6100c7565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100a357600080fd5b506100b76100b2366004610757565b6100f5565b604051901515815260200161008e565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b60006001600160a01b0383166101525760405162461bcd60e51b815260206004820181905260248201527f5769746e657450726f78793a206e756c6c20696d706c656d656e746174696f6e60448201526064015b60405180910390fd5b600061015c6100c7565b90506001600160a01b0381161561053857806001600160a01b0316846001600160a01b0316036101ce5760405162461bcd60e51b815260206004820152601f60248201527f5769746e657450726f78793a206e6f7468696e6720746f2075706772616465006044820152606401610149565b806001600160a01b0316635479d9406040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610228575060408051601f3d908101601f1916820190925261022591810190610827565b60015b6102875760405162461bcd60e51b815260206004820152602a60248201527f5769746e657450726f78793a20756e61626c6520746f20636865636b207570676044820152697261646162696c69747960b01b6064820152608401610149565b806102d45760405162461bcd60e51b815260206004820152601b60248201527f5769746e657450726f78793a206e6f742075706772616461626c6500000000006044820152606401610149565b5060405133602482015260009081906001600160a01b0384169060440160408051601f198184030181529181526020820180516001600160e01b03166335ac4b0560e11b179052516103269190610874565b600060405180830381855af49150503d8060008114610361576040519150601f19603f3d011682016040523d82523d6000602084013e610366565b606091505b5091509150816103b85760405162461bcd60e51b815260206004820152601a60248201527f5769746e657450726f78793a206e6f7420636f6d706c69616e740000000000006044820152606401610149565b808060200190518101906103cc9190610827565b6104185760405162461bcd60e51b815260206004820152601b60248201527f5769746e657450726f78793a206e6f7420617574686f72697a656400000000006044820152606401610149565b856001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610456573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061047a9190610890565b836001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104dc9190610890565b146105355760405162461bcd60e51b8152602060048201526024808201527f5769746e657450726f78793a2070726f786961626c655555494473206d69736d6044820152630c2e8c6d60e31b6064820152608401610149565b50505b6000846001600160a01b03168460405160240161055591906108a9565b60408051601f198184030181529181526020820180516001600160e01b031663439fab9160e01b1790525161058a9190610874565b600060405180830381855af49150503d80600081146105c5576040519150601f19603f3d011682016040523d82523d6000602084013e6105ca565b606091505b50509050806106255760405162461bcd60e51b815260206004820152602160248201527f5769746e657450726f78793a20756e61626c6520746f20696e697469616c697a6044820152606560f81b6064820152608401610149565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0387169081179091556040517fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2846001600160a01b0316635479d9406040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156106e5575060408051601f3d908101601f191682019092526106e291810190610827565b60015b6107315760405162461bcd60e51b815260206004820152601a60248201527f5769746e657450726f78793a206e6f7420636f6d706c69616e740000000000006044820152606401610149565b925061073b915050565b92915050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561076a57600080fd5b82356001600160a01b038116811461078157600080fd5b9150602083013567ffffffffffffffff8082111561079e57600080fd5b818501915085601f8301126107b257600080fd5b8135818111156107c4576107c4610741565b604051601f8201601f19908116603f011681019083821181831017156107ec576107ec610741565b8160405282815288602084870101111561080557600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60006020828403121561083957600080fd5b8151801515811461084957600080fd5b9392505050565b60005b8381101561086b578181015183820152602001610853565b50506000910152565b60008251610886818460208701610850565b9190910192915050565b6000602082840312156108a257600080fd5b5051919050565b60208152600082518060208401526108c8816040850160208701610850565b601f01601f1916919091016040019291505056fea26469706673582212200771bc4bad015c089efb2351eb3266c8aad36c8daccf86bbf3421605ef5fc23c64736f6c63430008110033", - "immutableReferences": {}, - "generatedSources": [], - "deployedGeneratedSources": [ - { - "ast": { - "nodeType": "YulBlock", - "src": "0:6066:84", - "statements": [ - { - "nodeType": "YulBlock", - "src": "6:3:84", - "statements": [] - }, - { - "body": { - "nodeType": "YulBlock", - "src": "115:102:84", - "statements": [ - { - "nodeType": "YulAssignment", - "src": "125:26:84", - "value": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "137:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "148:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "133:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "133:18:84" - }, - "variableNames": [ - { - "name": "tail", - "nodeType": "YulIdentifier", - "src": "125:4:84" - } - ] - }, - { - "expression": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "167:9:84" - }, - { - "arguments": [ - { - "name": "value0", - "nodeType": "YulIdentifier", - "src": "182:6:84" - }, - { - "arguments": [ - { - "arguments": [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "198:3:84", - "type": "", - "value": "160" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "203:1:84", - "type": "", - "value": "1" - } - ], - "functionName": { - "name": "shl", - "nodeType": "YulIdentifier", - "src": "194:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "194:11:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "207:1:84", - "type": "", - "value": "1" - } - ], - "functionName": { - "name": "sub", - "nodeType": "YulIdentifier", - "src": "190:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "190:19:84" - } - ], - "functionName": { - "name": "and", - "nodeType": "YulIdentifier", - "src": "178:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "178:32:84" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "160:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "160:51:84" - }, - "nodeType": "YulExpressionStatement", - "src": "160:51:84" - } - ] - }, - "name": "abi_encode_tuple_t_address__to_t_address__fromStack_reversed", - "nodeType": "YulFunctionDefinition", - "parameters": [ - { - "name": "headStart", - "nodeType": "YulTypedName", - "src": "84:9:84", - "type": "" - }, - { - "name": "value0", - "nodeType": "YulTypedName", - "src": "95:6:84", - "type": "" - } - ], - "returnVariables": [ - { - "name": "tail", - "nodeType": "YulTypedName", - "src": "106:4:84", - "type": "" - } - ], - "src": "14:203:84" - }, - { - "body": { - "nodeType": "YulBlock", - "src": "254:95:84", - "statements": [ - { - "expression": { - "arguments": [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "271:1:84", - "type": "", - "value": "0" - }, - { - "arguments": [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "278:3:84", - "type": "", - "value": "224" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "283:10:84", - "type": "", - "value": "0x4e487b71" - } - ], - "functionName": { - "name": "shl", - "nodeType": "YulIdentifier", - "src": "274:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "274:20:84" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "264:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "264:31:84" - }, - "nodeType": "YulExpressionStatement", - "src": "264:31:84" - }, - { - "expression": { - "arguments": [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "311:1:84", - "type": "", - "value": "4" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "314:4:84", - "type": "", - "value": "0x41" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "304:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "304:15:84" - }, - "nodeType": "YulExpressionStatement", - "src": "304:15:84" - }, - { - "expression": { - "arguments": [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "335:1:84", - "type": "", - "value": "0" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "338:4:84", - "type": "", - "value": "0x24" - } - ], - "functionName": { - "name": "revert", - "nodeType": "YulIdentifier", - "src": "328:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "328:15:84" - }, - "nodeType": "YulExpressionStatement", - "src": "328:15:84" - } - ] - }, - "name": "panic_error_0x41", - "nodeType": "YulFunctionDefinition", - "src": "222:127:84" - }, - { - "body": { - "nodeType": "YulBlock", - "src": "450:999:84", - "statements": [ - { - "body": { - "nodeType": "YulBlock", - "src": "496:16:84", - "statements": [ - { - "expression": { - "arguments": [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "505:1:84", - "type": "", - "value": "0" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "508:1:84", - "type": "", - "value": "0" - } - ], - "functionName": { - "name": "revert", - "nodeType": "YulIdentifier", - "src": "498:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "498:12:84" - }, - "nodeType": "YulExpressionStatement", - "src": "498:12:84" - } - ] - }, - "condition": { - "arguments": [ - { - "arguments": [ - { - "name": "dataEnd", - "nodeType": "YulIdentifier", - "src": "471:7:84" - }, - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "480:9:84" - } - ], - "functionName": { - "name": "sub", - "nodeType": "YulIdentifier", - "src": "467:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "467:23:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "492:2:84", - "type": "", - "value": "64" - } - ], - "functionName": { - "name": "slt", - "nodeType": "YulIdentifier", - "src": "463:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "463:32:84" - }, - "nodeType": "YulIf", - "src": "460:52:84" - }, - { - "nodeType": "YulVariableDeclaration", - "src": "521:36:84", - "value": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "547:9:84" - } - ], - "functionName": { - "name": "calldataload", - "nodeType": "YulIdentifier", - "src": "534:12:84" - }, - "nodeType": "YulFunctionCall", - "src": "534:23:84" - }, - "variables": [ - { - "name": "value", - "nodeType": "YulTypedName", - "src": "525:5:84", - "type": "" - } - ] - }, - { - "body": { - "nodeType": "YulBlock", - "src": "620:16:84", - "statements": [ - { - "expression": { - "arguments": [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "629:1:84", - "type": "", - "value": "0" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "632:1:84", - "type": "", - "value": "0" - } - ], - "functionName": { - "name": "revert", - "nodeType": "YulIdentifier", - "src": "622:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "622:12:84" - }, - "nodeType": "YulExpressionStatement", - "src": "622:12:84" - } - ] - }, - "condition": { - "arguments": [ - { - "arguments": [ - { - "name": "value", - "nodeType": "YulIdentifier", - "src": "579:5:84" - }, - { - "arguments": [ - { - "name": "value", - "nodeType": "YulIdentifier", - "src": "590:5:84" - }, - { - "arguments": [ - { - "arguments": [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "605:3:84", - "type": "", - "value": "160" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "610:1:84", - "type": "", - "value": "1" - } - ], - "functionName": { - "name": "shl", - "nodeType": "YulIdentifier", - "src": "601:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "601:11:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "614:1:84", - "type": "", - "value": "1" - } - ], - "functionName": { - "name": "sub", - "nodeType": "YulIdentifier", - "src": "597:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "597:19:84" - } - ], - "functionName": { - "name": "and", - "nodeType": "YulIdentifier", - "src": "586:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "586:31:84" - } - ], - "functionName": { - "name": "eq", - "nodeType": "YulIdentifier", - "src": "576:2:84" - }, - "nodeType": "YulFunctionCall", - "src": "576:42:84" - } - ], - "functionName": { - "name": "iszero", - "nodeType": "YulIdentifier", - "src": "569:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "569:50:84" - }, - "nodeType": "YulIf", - "src": "566:70:84" - }, - { - "nodeType": "YulAssignment", - "src": "645:15:84", - "value": { - "name": "value", - "nodeType": "YulIdentifier", - "src": "655:5:84" - }, - "variableNames": [ - { - "name": "value0", - "nodeType": "YulIdentifier", - "src": "645:6:84" - } - ] - }, - { - "nodeType": "YulVariableDeclaration", - "src": "669:46:84", - "value": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "700:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "711:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "696:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "696:18:84" - } - ], - "functionName": { - "name": "calldataload", - "nodeType": "YulIdentifier", - "src": "683:12:84" - }, - "nodeType": "YulFunctionCall", - "src": "683:32:84" - }, - "variables": [ - { - "name": "offset", - "nodeType": "YulTypedName", - "src": "673:6:84", - "type": "" - } - ] - }, - { - "nodeType": "YulVariableDeclaration", - "src": "724:28:84", - "value": { - "kind": "number", - "nodeType": "YulLiteral", - "src": "734:18:84", - "type": "", - "value": "0xffffffffffffffff" - }, - "variables": [ - { - "name": "_1", - "nodeType": "YulTypedName", - "src": "728:2:84", - "type": "" - } - ] - }, - { - "body": { - "nodeType": "YulBlock", - "src": "779:16:84", - "statements": [ - { - "expression": { - "arguments": [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "788:1:84", - "type": "", - "value": "0" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "791:1:84", - "type": "", - "value": "0" - } - ], - "functionName": { - "name": "revert", - "nodeType": "YulIdentifier", - "src": "781:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "781:12:84" - }, - "nodeType": "YulExpressionStatement", - "src": "781:12:84" - } - ] - }, - "condition": { - "arguments": [ - { - "name": "offset", - "nodeType": "YulIdentifier", - "src": "767:6:84" - }, - { - "name": "_1", - "nodeType": "YulIdentifier", - "src": "775:2:84" - } - ], - "functionName": { - "name": "gt", - "nodeType": "YulIdentifier", - "src": "764:2:84" - }, - "nodeType": "YulFunctionCall", - "src": "764:14:84" - }, - "nodeType": "YulIf", - "src": "761:34:84" - }, - { - "nodeType": "YulVariableDeclaration", - "src": "804:32:84", - "value": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "818:9:84" - }, - { - "name": "offset", - "nodeType": "YulIdentifier", - "src": "829:6:84" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "814:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "814:22:84" - }, - "variables": [ - { - "name": "_2", - "nodeType": "YulTypedName", - "src": "808:2:84", - "type": "" - } - ] - }, - { - "body": { - "nodeType": "YulBlock", - "src": "884:16:84", - "statements": [ - { - "expression": { - "arguments": [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "893:1:84", - "type": "", - "value": "0" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "896:1:84", - "type": "", - "value": "0" - } - ], - "functionName": { - "name": "revert", - "nodeType": "YulIdentifier", - "src": "886:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "886:12:84" - }, - "nodeType": "YulExpressionStatement", - "src": "886:12:84" - } - ] - }, - "condition": { - "arguments": [ - { - "arguments": [ - { - "arguments": [ - { - "name": "_2", - "nodeType": "YulIdentifier", - "src": "863:2:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "867:4:84", - "type": "", - "value": "0x1f" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "859:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "859:13:84" - }, - { - "name": "dataEnd", - "nodeType": "YulIdentifier", - "src": "874:7:84" - } - ], - "functionName": { - "name": "slt", - "nodeType": "YulIdentifier", - "src": "855:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "855:27:84" - } - ], - "functionName": { - "name": "iszero", - "nodeType": "YulIdentifier", - "src": "848:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "848:35:84" - }, - "nodeType": "YulIf", - "src": "845:55:84" - }, - { - "nodeType": "YulVariableDeclaration", - "src": "909:26:84", - "value": { - "arguments": [ - { - "name": "_2", - "nodeType": "YulIdentifier", - "src": "932:2:84" - } - ], - "functionName": { - "name": "calldataload", - "nodeType": "YulIdentifier", - "src": "919:12:84" - }, - "nodeType": "YulFunctionCall", - "src": "919:16:84" - }, - "variables": [ - { - "name": "_3", - "nodeType": "YulTypedName", - "src": "913:2:84", - "type": "" - } - ] - }, - { - "body": { - "nodeType": "YulBlock", - "src": "958:22:84", - "statements": [ - { - "expression": { - "arguments": [], - "functionName": { - "name": "panic_error_0x41", - "nodeType": "YulIdentifier", - "src": "960:16:84" - }, - "nodeType": "YulFunctionCall", - "src": "960:18:84" - }, - "nodeType": "YulExpressionStatement", - "src": "960:18:84" - } - ] - }, - "condition": { - "arguments": [ - { - "name": "_3", - "nodeType": "YulIdentifier", - "src": "950:2:84" - }, - { - "name": "_1", - "nodeType": "YulIdentifier", - "src": "954:2:84" - } - ], - "functionName": { - "name": "gt", - "nodeType": "YulIdentifier", - "src": "947:2:84" - }, - "nodeType": "YulFunctionCall", - "src": "947:10:84" - }, - "nodeType": "YulIf", - "src": "944:36:84" - }, - { - "nodeType": "YulVariableDeclaration", - "src": "989:17:84", - "value": { - "arguments": [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1003:2:84", - "type": "", - "value": "31" - } - ], - "functionName": { - "name": "not", - "nodeType": "YulIdentifier", - "src": "999:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "999:7:84" - }, - "variables": [ - { - "name": "_4", - "nodeType": "YulTypedName", - "src": "993:2:84", - "type": "" - } - ] - }, - { - "nodeType": "YulVariableDeclaration", - "src": "1015:23:84", - "value": { - "arguments": [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1035:2:84", - "type": "", - "value": "64" - } - ], - "functionName": { - "name": "mload", - "nodeType": "YulIdentifier", - "src": "1029:5:84" - }, - "nodeType": "YulFunctionCall", - "src": "1029:9:84" - }, - "variables": [ - { - "name": "memPtr", - "nodeType": "YulTypedName", - "src": "1019:6:84", - "type": "" - } - ] - }, - { - "nodeType": "YulVariableDeclaration", - "src": "1047:71:84", - "value": { - "arguments": [ - { - "name": "memPtr", - "nodeType": "YulIdentifier", - "src": "1069:6:84" - }, - { - "arguments": [ - { - "arguments": [ - { - "arguments": [ - { - "arguments": [ - { - "name": "_3", - "nodeType": "YulIdentifier", - "src": "1093:2:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1097:4:84", - "type": "", - "value": "0x1f" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "1089:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "1089:13:84" - }, - { - "name": "_4", - "nodeType": "YulIdentifier", - "src": "1104:2:84" - } - ], - "functionName": { - "name": "and", - "nodeType": "YulIdentifier", - "src": "1085:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "1085:22:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1109:2:84", - "type": "", - "value": "63" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "1081:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "1081:31:84" - }, - { - "name": "_4", - "nodeType": "YulIdentifier", - "src": "1114:2:84" - } - ], - "functionName": { - "name": "and", - "nodeType": "YulIdentifier", - "src": "1077:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "1077:40:84" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "1065:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "1065:53:84" - }, - "variables": [ - { - "name": "newFreePtr", - "nodeType": "YulTypedName", - "src": "1051:10:84", - "type": "" - } - ] - }, - { - "body": { - "nodeType": "YulBlock", - "src": "1177:22:84", - "statements": [ - { - "expression": { - "arguments": [], - "functionName": { - "name": "panic_error_0x41", - "nodeType": "YulIdentifier", - "src": "1179:16:84" - }, - "nodeType": "YulFunctionCall", - "src": "1179:18:84" - }, - "nodeType": "YulExpressionStatement", - "src": "1179:18:84" - } - ] - }, - "condition": { - "arguments": [ - { - "arguments": [ - { - "name": "newFreePtr", - "nodeType": "YulIdentifier", - "src": "1136:10:84" - }, - { - "name": "_1", - "nodeType": "YulIdentifier", - "src": "1148:2:84" - } - ], - "functionName": { - "name": "gt", - "nodeType": "YulIdentifier", - "src": "1133:2:84" - }, - "nodeType": "YulFunctionCall", - "src": "1133:18:84" - }, - { - "arguments": [ - { - "name": "newFreePtr", - "nodeType": "YulIdentifier", - "src": "1156:10:84" - }, - { - "name": "memPtr", - "nodeType": "YulIdentifier", - "src": "1168:6:84" - } - ], - "functionName": { - "name": "lt", - "nodeType": "YulIdentifier", - "src": "1153:2:84" - }, - "nodeType": "YulFunctionCall", - "src": "1153:22:84" - } - ], - "functionName": { - "name": "or", - "nodeType": "YulIdentifier", - "src": "1130:2:84" - }, - "nodeType": "YulFunctionCall", - "src": "1130:46:84" - }, - "nodeType": "YulIf", - "src": "1127:72:84" - }, - { - "expression": { - "arguments": [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1215:2:84", - "type": "", - "value": "64" - }, - { - "name": "newFreePtr", - "nodeType": "YulIdentifier", - "src": "1219:10:84" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "1208:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "1208:22:84" - }, - "nodeType": "YulExpressionStatement", - "src": "1208:22:84" - }, - { - "expression": { - "arguments": [ - { - "name": "memPtr", - "nodeType": "YulIdentifier", - "src": "1246:6:84" - }, - { - "name": "_3", - "nodeType": "YulIdentifier", - "src": "1254:2:84" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "1239:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "1239:18:84" - }, - "nodeType": "YulExpressionStatement", - "src": "1239:18:84" - }, - { - "body": { - "nodeType": "YulBlock", - "src": "1303:16:84", - "statements": [ - { - "expression": { - "arguments": [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1312:1:84", - "type": "", - "value": "0" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1315:1:84", - "type": "", - "value": "0" - } - ], - "functionName": { - "name": "revert", - "nodeType": "YulIdentifier", - "src": "1305:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "1305:12:84" - }, - "nodeType": "YulExpressionStatement", - "src": "1305:12:84" - } - ] - }, - "condition": { - "arguments": [ - { - "arguments": [ - { - "arguments": [ - { - "name": "_2", - "nodeType": "YulIdentifier", - "src": "1280:2:84" - }, - { - "name": "_3", - "nodeType": "YulIdentifier", - "src": "1284:2:84" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "1276:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "1276:11:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1289:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "1272:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "1272:20:84" - }, - { - "name": "dataEnd", - "nodeType": "YulIdentifier", - "src": "1294:7:84" - } - ], - "functionName": { - "name": "gt", - "nodeType": "YulIdentifier", - "src": "1269:2:84" - }, - "nodeType": "YulFunctionCall", - "src": "1269:33:84" - }, - "nodeType": "YulIf", - "src": "1266:53:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "memPtr", - "nodeType": "YulIdentifier", - "src": "1345:6:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1353:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "1341:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "1341:15:84" - }, - { - "arguments": [ - { - "name": "_2", - "nodeType": "YulIdentifier", - "src": "1362:2:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1366:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "1358:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "1358:11:84" - }, - { - "name": "_3", - "nodeType": "YulIdentifier", - "src": "1371:2:84" - } - ], - "functionName": { - "name": "calldatacopy", - "nodeType": "YulIdentifier", - "src": "1328:12:84" - }, - "nodeType": "YulFunctionCall", - "src": "1328:46:84" - }, - "nodeType": "YulExpressionStatement", - "src": "1328:46:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "arguments": [ - { - "name": "memPtr", - "nodeType": "YulIdentifier", - "src": "1398:6:84" - }, - { - "name": "_3", - "nodeType": "YulIdentifier", - "src": "1406:2:84" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "1394:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "1394:15:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1411:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "1390:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "1390:24:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1416:1:84", - "type": "", - "value": "0" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "1383:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "1383:35:84" - }, - "nodeType": "YulExpressionStatement", - "src": "1383:35:84" - }, - { - "nodeType": "YulAssignment", - "src": "1427:16:84", - "value": { - "name": "memPtr", - "nodeType": "YulIdentifier", - "src": "1437:6:84" - }, - "variableNames": [ - { - "name": "value1", - "nodeType": "YulIdentifier", - "src": "1427:6:84" - } - ] - } - ] - }, - "name": "abi_decode_tuple_t_addresst_bytes_memory_ptr", - "nodeType": "YulFunctionDefinition", - "parameters": [ - { - "name": "headStart", - "nodeType": "YulTypedName", - "src": "408:9:84", - "type": "" - }, - { - "name": "dataEnd", - "nodeType": "YulTypedName", - "src": "419:7:84", - "type": "" - } - ], - "returnVariables": [ - { - "name": "value0", - "nodeType": "YulTypedName", - "src": "431:6:84", - "type": "" - }, - { - "name": "value1", - "nodeType": "YulTypedName", - "src": "439:6:84", - "type": "" - } - ], - "src": "354:1095:84" - }, - { - "body": { - "nodeType": "YulBlock", - "src": "1549:92:84", - "statements": [ - { - "nodeType": "YulAssignment", - "src": "1559:26:84", - "value": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "1571:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1582:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "1567:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "1567:18:84" - }, - "variableNames": [ - { - "name": "tail", - "nodeType": "YulIdentifier", - "src": "1559:4:84" - } - ] - }, - { - "expression": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "1601:9:84" - }, - { - "arguments": [ - { - "arguments": [ - { - "name": "value0", - "nodeType": "YulIdentifier", - "src": "1626:6:84" - } - ], - "functionName": { - "name": "iszero", - "nodeType": "YulIdentifier", - "src": "1619:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "1619:14:84" - } - ], - "functionName": { - "name": "iszero", - "nodeType": "YulIdentifier", - "src": "1612:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "1612:22:84" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "1594:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "1594:41:84" - }, - "nodeType": "YulExpressionStatement", - "src": "1594:41:84" - } - ] - }, - "name": "abi_encode_tuple_t_bool__to_t_bool__fromStack_reversed", - "nodeType": "YulFunctionDefinition", - "parameters": [ - { - "name": "headStart", - "nodeType": "YulTypedName", - "src": "1518:9:84", - "type": "" - }, - { - "name": "value0", - "nodeType": "YulTypedName", - "src": "1529:6:84", - "type": "" - } - ], - "returnVariables": [ - { - "name": "tail", - "nodeType": "YulTypedName", - "src": "1540:4:84", - "type": "" - } - ], - "src": "1454:187:84" - }, - { - "body": { - "nodeType": "YulBlock", - "src": "1820:182:84", - "statements": [ - { - "expression": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "1837:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1848:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "1830:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "1830:21:84" - }, - "nodeType": "YulExpressionStatement", - "src": "1830:21:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "1871:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1882:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "1867:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "1867:18:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1887:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "1860:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "1860:30:84" - }, - "nodeType": "YulExpressionStatement", - "src": "1860:30:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "1910:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1921:2:84", - "type": "", - "value": "64" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "1906:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "1906:18:84" - }, - { - "hexValue": "5769746e657450726f78793a206e756c6c20696d706c656d656e746174696f6e", - "kind": "string", - "nodeType": "YulLiteral", - "src": "1926:34:84", - "type": "", - "value": "WitnetProxy: null implementation" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "1899:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "1899:62:84" - }, - "nodeType": "YulExpressionStatement", - "src": "1899:62:84" - }, - { - "nodeType": "YulAssignment", - "src": "1970:26:84", - "value": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "1982:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1993:2:84", - "type": "", - "value": "96" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "1978:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "1978:18:84" - }, - "variableNames": [ - { - "name": "tail", - "nodeType": "YulIdentifier", - "src": "1970:4:84" - } - ] - } - ] - }, - "name": "abi_encode_tuple_t_stringliteral_d599eaa5e68d91d75c142446490ab9a15fd0284a41ce949219b5b4d8f267239a__to_t_string_memory_ptr__fromStack_reversed", - "nodeType": "YulFunctionDefinition", - "parameters": [ - { - "name": "headStart", - "nodeType": "YulTypedName", - "src": "1797:9:84", - "type": "" - } - ], - "returnVariables": [ - { - "name": "tail", - "nodeType": "YulTypedName", - "src": "1811:4:84", - "type": "" - } - ], - "src": "1646:356:84" - }, - { - "body": { - "nodeType": "YulBlock", - "src": "2181:181:84", - "statements": [ - { - "expression": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "2198:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "2209:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "2191:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "2191:21:84" - }, - "nodeType": "YulExpressionStatement", - "src": "2191:21:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "2232:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "2243:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "2228:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "2228:18:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "2248:2:84", - "type": "", - "value": "31" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "2221:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "2221:30:84" - }, - "nodeType": "YulExpressionStatement", - "src": "2221:30:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "2271:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "2282:2:84", - "type": "", - "value": "64" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "2267:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "2267:18:84" - }, - { - "hexValue": "5769746e657450726f78793a206e6f7468696e6720746f2075706772616465", - "kind": "string", - "nodeType": "YulLiteral", - "src": "2287:33:84", - "type": "", - "value": "WitnetProxy: nothing to upgrade" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "2260:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "2260:61:84" - }, - "nodeType": "YulExpressionStatement", - "src": "2260:61:84" - }, - { - "nodeType": "YulAssignment", - "src": "2330:26:84", - "value": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "2342:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "2353:2:84", - "type": "", - "value": "96" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "2338:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "2338:18:84" - }, - "variableNames": [ - { - "name": "tail", - "nodeType": "YulIdentifier", - "src": "2330:4:84" - } - ] - } - ] - }, - "name": "abi_encode_tuple_t_stringliteral_e332eab1bae45430d1201a30c0d80d8fcb5570f9e70201a9eb7b229e17fd2084__to_t_string_memory_ptr__fromStack_reversed", - "nodeType": "YulFunctionDefinition", - "parameters": [ - { - "name": "headStart", - "nodeType": "YulTypedName", - "src": "2158:9:84", - "type": "" - } - ], - "returnVariables": [ - { - "name": "tail", - "nodeType": "YulTypedName", - "src": "2172:4:84", - "type": "" - } - ], - "src": "2007:355:84" - }, - { - "body": { - "nodeType": "YulBlock", - "src": "2445:199:84", - "statements": [ - { - "body": { - "nodeType": "YulBlock", - "src": "2491:16:84", - "statements": [ - { - "expression": { - "arguments": [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "2500:1:84", - "type": "", - "value": "0" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "2503:1:84", - "type": "", - "value": "0" - } - ], - "functionName": { - "name": "revert", - "nodeType": "YulIdentifier", - "src": "2493:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "2493:12:84" - }, - "nodeType": "YulExpressionStatement", - "src": "2493:12:84" - } - ] - }, - "condition": { - "arguments": [ - { - "arguments": [ - { - "name": "dataEnd", - "nodeType": "YulIdentifier", - "src": "2466:7:84" - }, - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "2475:9:84" - } - ], - "functionName": { - "name": "sub", - "nodeType": "YulIdentifier", - "src": "2462:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "2462:23:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "2487:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "slt", - "nodeType": "YulIdentifier", - "src": "2458:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "2458:32:84" - }, - "nodeType": "YulIf", - "src": "2455:52:84" - }, - { - "nodeType": "YulVariableDeclaration", - "src": "2516:29:84", - "value": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "2535:9:84" - } - ], - "functionName": { - "name": "mload", - "nodeType": "YulIdentifier", - "src": "2529:5:84" - }, - "nodeType": "YulFunctionCall", - "src": "2529:16:84" - }, - "variables": [ - { - "name": "value", - "nodeType": "YulTypedName", - "src": "2520:5:84", - "type": "" - } - ] - }, - { - "body": { - "nodeType": "YulBlock", - "src": "2598:16:84", - "statements": [ - { - "expression": { - "arguments": [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "2607:1:84", - "type": "", - "value": "0" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "2610:1:84", - "type": "", - "value": "0" - } - ], - "functionName": { - "name": "revert", - "nodeType": "YulIdentifier", - "src": "2600:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "2600:12:84" - }, - "nodeType": "YulExpressionStatement", - "src": "2600:12:84" - } - ] - }, - "condition": { - "arguments": [ - { - "arguments": [ - { - "name": "value", - "nodeType": "YulIdentifier", - "src": "2567:5:84" - }, - { - "arguments": [ - { - "arguments": [ - { - "name": "value", - "nodeType": "YulIdentifier", - "src": "2588:5:84" - } - ], - "functionName": { - "name": "iszero", - "nodeType": "YulIdentifier", - "src": "2581:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "2581:13:84" - } - ], - "functionName": { - "name": "iszero", - "nodeType": "YulIdentifier", - "src": "2574:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "2574:21:84" - } - ], - "functionName": { - "name": "eq", - "nodeType": "YulIdentifier", - "src": "2564:2:84" - }, - "nodeType": "YulFunctionCall", - "src": "2564:32:84" - } - ], - "functionName": { - "name": "iszero", - "nodeType": "YulIdentifier", - "src": "2557:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "2557:40:84" - }, - "nodeType": "YulIf", - "src": "2554:60:84" - }, - { - "nodeType": "YulAssignment", - "src": "2623:15:84", - "value": { - "name": "value", - "nodeType": "YulIdentifier", - "src": "2633:5:84" - }, - "variableNames": [ - { - "name": "value0", - "nodeType": "YulIdentifier", - "src": "2623:6:84" - } - ] - } - ] - }, - "name": "abi_decode_tuple_t_bool_fromMemory", - "nodeType": "YulFunctionDefinition", - "parameters": [ - { - "name": "headStart", - "nodeType": "YulTypedName", - "src": "2411:9:84", - "type": "" - }, - { - "name": "dataEnd", - "nodeType": "YulTypedName", - "src": "2422:7:84", - "type": "" - } - ], - "returnVariables": [ - { - "name": "value0", - "nodeType": "YulTypedName", - "src": "2434:6:84", - "type": "" - } - ], - "src": "2367:277:84" - }, - { - "body": { - "nodeType": "YulBlock", - "src": "2823:232:84", - "statements": [ - { - "expression": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "2840:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "2851:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "2833:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "2833:21:84" - }, - "nodeType": "YulExpressionStatement", - "src": "2833:21:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "2874:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "2885:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "2870:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "2870:18:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "2890:2:84", - "type": "", - "value": "42" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "2863:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "2863:30:84" - }, - "nodeType": "YulExpressionStatement", - "src": "2863:30:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "2913:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "2924:2:84", - "type": "", - "value": "64" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "2909:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "2909:18:84" - }, - { - "hexValue": "5769746e657450726f78793a20756e61626c6520746f20636865636b20757067", - "kind": "string", - "nodeType": "YulLiteral", - "src": "2929:34:84", - "type": "", - "value": "WitnetProxy: unable to check upg" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "2902:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "2902:62:84" - }, - "nodeType": "YulExpressionStatement", - "src": "2902:62:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "2984:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "2995:2:84", - "type": "", - "value": "96" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "2980:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "2980:18:84" - }, - { - "hexValue": "7261646162696c697479", - "kind": "string", - "nodeType": "YulLiteral", - "src": "3000:12:84", - "type": "", - "value": "radability" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "2973:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "2973:40:84" - }, - "nodeType": "YulExpressionStatement", - "src": "2973:40:84" - }, - { - "nodeType": "YulAssignment", - "src": "3022:27:84", - "value": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "3034:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "3045:3:84", - "type": "", - "value": "128" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "3030:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "3030:19:84" - }, - "variableNames": [ - { - "name": "tail", - "nodeType": "YulIdentifier", - "src": "3022:4:84" - } - ] - } - ] - }, - "name": "abi_encode_tuple_t_stringliteral_7f859058ad3ee4e192700ff813ed67dc892a0c7de91510ee584a0ac25fc982fc__to_t_string_memory_ptr__fromStack_reversed", - "nodeType": "YulFunctionDefinition", - "parameters": [ - { - "name": "headStart", - "nodeType": "YulTypedName", - "src": "2800:9:84", - "type": "" - } - ], - "returnVariables": [ - { - "name": "tail", - "nodeType": "YulTypedName", - "src": "2814:4:84", - "type": "" - } - ], - "src": "2649:406:84" - }, - { - "body": { - "nodeType": "YulBlock", - "src": "3234:177:84", - "statements": [ - { - "expression": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "3251:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "3262:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "3244:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "3244:21:84" - }, - "nodeType": "YulExpressionStatement", - "src": "3244:21:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "3285:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "3296:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "3281:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "3281:18:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "3301:2:84", - "type": "", - "value": "27" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "3274:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "3274:30:84" - }, - "nodeType": "YulExpressionStatement", - "src": "3274:30:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "3324:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "3335:2:84", - "type": "", - "value": "64" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "3320:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "3320:18:84" - }, - { - "hexValue": "5769746e657450726f78793a206e6f742075706772616461626c65", - "kind": "string", - "nodeType": "YulLiteral", - "src": "3340:29:84", - "type": "", - "value": "WitnetProxy: not upgradable" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "3313:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "3313:57:84" - }, - "nodeType": "YulExpressionStatement", - "src": "3313:57:84" - }, - { - "nodeType": "YulAssignment", - "src": "3379:26:84", - "value": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "3391:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "3402:2:84", - "type": "", - "value": "96" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "3387:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "3387:18:84" - }, - "variableNames": [ - { - "name": "tail", - "nodeType": "YulIdentifier", - "src": "3379:4:84" - } - ] - } - ] - }, - "name": "abi_encode_tuple_t_stringliteral_d96132834a96bae5cb2f32cb07f13985dcde0f2358055c198eb3065af6c5aa7f__to_t_string_memory_ptr__fromStack_reversed", - "nodeType": "YulFunctionDefinition", - "parameters": [ - { - "name": "headStart", - "nodeType": "YulTypedName", - "src": "3211:9:84", - "type": "" - } - ], - "returnVariables": [ - { - "name": "tail", - "nodeType": "YulTypedName", - "src": "3225:4:84", - "type": "" - } - ], - "src": "3060:351:84" - }, - { - "body": { - "nodeType": "YulBlock", - "src": "3482:184:84", - "statements": [ - { - "nodeType": "YulVariableDeclaration", - "src": "3492:10:84", - "value": { - "kind": "number", - "nodeType": "YulLiteral", - "src": "3501:1:84", - "type": "", - "value": "0" - }, - "variables": [ - { - "name": "i", - "nodeType": "YulTypedName", - "src": "3496:1:84", - "type": "" - } - ] - }, - { - "body": { - "nodeType": "YulBlock", - "src": "3561:63:84", - "statements": [ - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "dst", - "nodeType": "YulIdentifier", - "src": "3586:3:84" - }, - { - "name": "i", - "nodeType": "YulIdentifier", - "src": "3591:1:84" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "3582:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "3582:11:84" - }, - { - "arguments": [ - { - "arguments": [ - { - "name": "src", - "nodeType": "YulIdentifier", - "src": "3605:3:84" - }, - { - "name": "i", - "nodeType": "YulIdentifier", - "src": "3610:1:84" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "3601:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "3601:11:84" - } - ], - "functionName": { - "name": "mload", - "nodeType": "YulIdentifier", - "src": "3595:5:84" - }, - "nodeType": "YulFunctionCall", - "src": "3595:18:84" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "3575:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "3575:39:84" - }, - "nodeType": "YulExpressionStatement", - "src": "3575:39:84" - } - ] - }, - "condition": { - "arguments": [ - { - "name": "i", - "nodeType": "YulIdentifier", - "src": "3522:1:84" - }, - { - "name": "length", - "nodeType": "YulIdentifier", - "src": "3525:6:84" - } - ], - "functionName": { - "name": "lt", - "nodeType": "YulIdentifier", - "src": "3519:2:84" - }, - "nodeType": "YulFunctionCall", - "src": "3519:13:84" - }, - "nodeType": "YulForLoop", - "post": { - "nodeType": "YulBlock", - "src": "3533:19:84", - "statements": [ - { - "nodeType": "YulAssignment", - "src": "3535:15:84", - "value": { - "arguments": [ - { - "name": "i", - "nodeType": "YulIdentifier", - "src": "3544:1:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "3547:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "3540:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "3540:10:84" - }, - "variableNames": [ - { - "name": "i", - "nodeType": "YulIdentifier", - "src": "3535:1:84" - } - ] - } - ] - }, - "pre": { - "nodeType": "YulBlock", - "src": "3515:3:84", - "statements": [] - }, - "src": "3511:113:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "dst", - "nodeType": "YulIdentifier", - "src": "3644:3:84" - }, - { - "name": "length", - "nodeType": "YulIdentifier", - "src": "3649:6:84" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "3640:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "3640:16:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "3658:1:84", - "type": "", - "value": "0" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "3633:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "3633:27:84" - }, - "nodeType": "YulExpressionStatement", - "src": "3633:27:84" - } - ] - }, - "name": "copy_memory_to_memory_with_cleanup", - "nodeType": "YulFunctionDefinition", - "parameters": [ - { - "name": "src", - "nodeType": "YulTypedName", - "src": "3460:3:84", - "type": "" - }, - { - "name": "dst", - "nodeType": "YulTypedName", - "src": "3465:3:84", - "type": "" - }, - { - "name": "length", - "nodeType": "YulTypedName", - "src": "3470:6:84", - "type": "" - } - ], - "src": "3416:250:84" - }, - { - "body": { - "nodeType": "YulBlock", - "src": "3808:150:84", - "statements": [ - { - "nodeType": "YulVariableDeclaration", - "src": "3818:27:84", - "value": { - "arguments": [ - { - "name": "value0", - "nodeType": "YulIdentifier", - "src": "3838:6:84" - } - ], - "functionName": { - "name": "mload", - "nodeType": "YulIdentifier", - "src": "3832:5:84" - }, - "nodeType": "YulFunctionCall", - "src": "3832:13:84" - }, - "variables": [ - { - "name": "length", - "nodeType": "YulTypedName", - "src": "3822:6:84", - "type": "" - } - ] - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "value0", - "nodeType": "YulIdentifier", - "src": "3893:6:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "3901:4:84", - "type": "", - "value": "0x20" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "3889:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "3889:17:84" - }, - { - "name": "pos", - "nodeType": "YulIdentifier", - "src": "3908:3:84" - }, - { - "name": "length", - "nodeType": "YulIdentifier", - "src": "3913:6:84" - } - ], - "functionName": { - "name": "copy_memory_to_memory_with_cleanup", - "nodeType": "YulIdentifier", - "src": "3854:34:84" - }, - "nodeType": "YulFunctionCall", - "src": "3854:66:84" - }, - "nodeType": "YulExpressionStatement", - "src": "3854:66:84" - }, - { - "nodeType": "YulAssignment", - "src": "3929:23:84", - "value": { - "arguments": [ - { - "name": "pos", - "nodeType": "YulIdentifier", - "src": "3940:3:84" - }, - { - "name": "length", - "nodeType": "YulIdentifier", - "src": "3945:6:84" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "3936:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "3936:16:84" - }, - "variableNames": [ - { - "name": "end", - "nodeType": "YulIdentifier", - "src": "3929:3:84" - } - ] - } - ] - }, - "name": "abi_encode_tuple_packed_t_bytes_memory_ptr__to_t_bytes_memory_ptr__nonPadded_inplace_fromStack_reversed", - "nodeType": "YulFunctionDefinition", - "parameters": [ - { - "name": "pos", - "nodeType": "YulTypedName", - "src": "3784:3:84", - "type": "" - }, - { - "name": "value0", - "nodeType": "YulTypedName", - "src": "3789:6:84", - "type": "" - } - ], - "returnVariables": [ - { - "name": "end", - "nodeType": "YulTypedName", - "src": "3800:3:84", - "type": "" - } - ], - "src": "3671:287:84" - }, - { - "body": { - "nodeType": "YulBlock", - "src": "4137:176:84", - "statements": [ - { - "expression": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "4154:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "4165:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "4147:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "4147:21:84" - }, - "nodeType": "YulExpressionStatement", - "src": "4147:21:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "4188:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "4199:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "4184:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "4184:18:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "4204:2:84", - "type": "", - "value": "26" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "4177:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "4177:30:84" - }, - "nodeType": "YulExpressionStatement", - "src": "4177:30:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "4227:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "4238:2:84", - "type": "", - "value": "64" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "4223:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "4223:18:84" - }, - { - "hexValue": "5769746e657450726f78793a206e6f7420636f6d706c69616e74", - "kind": "string", - "nodeType": "YulLiteral", - "src": "4243:28:84", - "type": "", - "value": "WitnetProxy: not compliant" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "4216:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "4216:56:84" - }, - "nodeType": "YulExpressionStatement", - "src": "4216:56:84" - }, - { - "nodeType": "YulAssignment", - "src": "4281:26:84", - "value": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "4293:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "4304:2:84", - "type": "", - "value": "96" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "4289:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "4289:18:84" - }, - "variableNames": [ - { - "name": "tail", - "nodeType": "YulIdentifier", - "src": "4281:4:84" - } - ] - } - ] - }, - "name": "abi_encode_tuple_t_stringliteral_fe0c5d56f2e637bc6ae9d29f1058c00159080f3dd6202013ecdbcca6e4740a65__to_t_string_memory_ptr__fromStack_reversed", - "nodeType": "YulFunctionDefinition", - "parameters": [ - { - "name": "headStart", - "nodeType": "YulTypedName", - "src": "4114:9:84", - "type": "" - } - ], - "returnVariables": [ - { - "name": "tail", - "nodeType": "YulTypedName", - "src": "4128:4:84", - "type": "" - } - ], - "src": "3963:350:84" - }, - { - "body": { - "nodeType": "YulBlock", - "src": "4492:177:84", - "statements": [ - { - "expression": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "4509:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "4520:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "4502:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "4502:21:84" - }, - "nodeType": "YulExpressionStatement", - "src": "4502:21:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "4543:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "4554:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "4539:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "4539:18:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "4559:2:84", - "type": "", - "value": "27" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "4532:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "4532:30:84" - }, - "nodeType": "YulExpressionStatement", - "src": "4532:30:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "4582:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "4593:2:84", - "type": "", - "value": "64" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "4578:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "4578:18:84" - }, - { - "hexValue": "5769746e657450726f78793a206e6f7420617574686f72697a6564", - "kind": "string", - "nodeType": "YulLiteral", - "src": "4598:29:84", - "type": "", - "value": "WitnetProxy: not authorized" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "4571:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "4571:57:84" - }, - "nodeType": "YulExpressionStatement", - "src": "4571:57:84" - }, - { - "nodeType": "YulAssignment", - "src": "4637:26:84", - "value": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "4649:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "4660:2:84", - "type": "", - "value": "96" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "4645:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "4645:18:84" - }, - "variableNames": [ - { - "name": "tail", - "nodeType": "YulIdentifier", - "src": "4637:4:84" - } - ] - } - ] - }, - "name": "abi_encode_tuple_t_stringliteral_ba8d4d661ce88eb2915ba133e6cad533938b754d7b66d8253879ef2c2193ecb2__to_t_string_memory_ptr__fromStack_reversed", - "nodeType": "YulFunctionDefinition", - "parameters": [ - { - "name": "headStart", - "nodeType": "YulTypedName", - "src": "4469:9:84", - "type": "" - } - ], - "returnVariables": [ - { - "name": "tail", - "nodeType": "YulTypedName", - "src": "4483:4:84", - "type": "" - } - ], - "src": "4318:351:84" - }, - { - "body": { - "nodeType": "YulBlock", - "src": "4755:103:84", - "statements": [ - { - "body": { - "nodeType": "YulBlock", - "src": "4801:16:84", - "statements": [ - { - "expression": { - "arguments": [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "4810:1:84", - "type": "", - "value": "0" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "4813:1:84", - "type": "", - "value": "0" - } - ], - "functionName": { - "name": "revert", - "nodeType": "YulIdentifier", - "src": "4803:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "4803:12:84" - }, - "nodeType": "YulExpressionStatement", - "src": "4803:12:84" - } - ] - }, - "condition": { - "arguments": [ - { - "arguments": [ - { - "name": "dataEnd", - "nodeType": "YulIdentifier", - "src": "4776:7:84" - }, - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "4785:9:84" - } - ], - "functionName": { - "name": "sub", - "nodeType": "YulIdentifier", - "src": "4772:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "4772:23:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "4797:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "slt", - "nodeType": "YulIdentifier", - "src": "4768:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "4768:32:84" - }, - "nodeType": "YulIf", - "src": "4765:52:84" - }, - { - "nodeType": "YulAssignment", - "src": "4826:26:84", - "value": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "4842:9:84" - } - ], - "functionName": { - "name": "mload", - "nodeType": "YulIdentifier", - "src": "4836:5:84" - }, - "nodeType": "YulFunctionCall", - "src": "4836:16:84" - }, - "variableNames": [ - { - "name": "value0", - "nodeType": "YulIdentifier", - "src": "4826:6:84" - } - ] - } - ] - }, - "name": "abi_decode_tuple_t_bytes32_fromMemory", - "nodeType": "YulFunctionDefinition", - "parameters": [ - { - "name": "headStart", - "nodeType": "YulTypedName", - "src": "4721:9:84", - "type": "" - }, - { - "name": "dataEnd", - "nodeType": "YulTypedName", - "src": "4732:7:84", - "type": "" - } - ], - "returnVariables": [ - { - "name": "value0", - "nodeType": "YulTypedName", - "src": "4744:6:84", - "type": "" - } - ], - "src": "4674:184:84" - }, - { - "body": { - "nodeType": "YulBlock", - "src": "5037:226:84", - "statements": [ - { - "expression": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "5054:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "5065:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "5047:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "5047:21:84" - }, - "nodeType": "YulExpressionStatement", - "src": "5047:21:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "5088:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "5099:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "5084:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "5084:18:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "5104:2:84", - "type": "", - "value": "36" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "5077:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "5077:30:84" - }, - "nodeType": "YulExpressionStatement", - "src": "5077:30:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "5127:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "5138:2:84", - "type": "", - "value": "64" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "5123:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "5123:18:84" - }, - { - "hexValue": "5769746e657450726f78793a2070726f786961626c655555494473206d69736d", - "kind": "string", - "nodeType": "YulLiteral", - "src": "5143:34:84", - "type": "", - "value": "WitnetProxy: proxiableUUIDs mism" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "5116:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "5116:62:84" - }, - "nodeType": "YulExpressionStatement", - "src": "5116:62:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "5198:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "5209:2:84", - "type": "", - "value": "96" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "5194:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "5194:18:84" - }, - { - "hexValue": "61746368", - "kind": "string", - "nodeType": "YulLiteral", - "src": "5214:6:84", - "type": "", - "value": "atch" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "5187:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "5187:34:84" - }, - "nodeType": "YulExpressionStatement", - "src": "5187:34:84" - }, - { - "nodeType": "YulAssignment", - "src": "5230:27:84", - "value": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "5242:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "5253:3:84", - "type": "", - "value": "128" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "5238:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "5238:19:84" - }, - "variableNames": [ - { - "name": "tail", - "nodeType": "YulIdentifier", - "src": "5230:4:84" - } - ] - } - ] - }, - "name": "abi_encode_tuple_t_stringliteral_f3c1ad1fa1688d47e62cc4dd5b4be101315ef47e38e05aa3a37a4ef2e1cec0a8__to_t_string_memory_ptr__fromStack_reversed", - "nodeType": "YulFunctionDefinition", - "parameters": [ - { - "name": "headStart", - "nodeType": "YulTypedName", - "src": "5014:9:84", - "type": "" - } - ], - "returnVariables": [ - { - "name": "tail", - "nodeType": "YulTypedName", - "src": "5028:4:84", - "type": "" - } - ], - "src": "4863:400:84" - }, - { - "body": { - "nodeType": "YulBlock", - "src": "5387:275:84", - "statements": [ - { - "expression": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "5404:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "5415:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "5397:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "5397:21:84" - }, - "nodeType": "YulExpressionStatement", - "src": "5397:21:84" - }, - { - "nodeType": "YulVariableDeclaration", - "src": "5427:27:84", - "value": { - "arguments": [ - { - "name": "value0", - "nodeType": "YulIdentifier", - "src": "5447:6:84" - } - ], - "functionName": { - "name": "mload", - "nodeType": "YulIdentifier", - "src": "5441:5:84" - }, - "nodeType": "YulFunctionCall", - "src": "5441:13:84" - }, - "variables": [ - { - "name": "length", - "nodeType": "YulTypedName", - "src": "5431:6:84", - "type": "" - } - ] - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "5474:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "5485:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "5470:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "5470:18:84" - }, - { - "name": "length", - "nodeType": "YulIdentifier", - "src": "5490:6:84" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "5463:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "5463:34:84" - }, - "nodeType": "YulExpressionStatement", - "src": "5463:34:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "value0", - "nodeType": "YulIdentifier", - "src": "5545:6:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "5553:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "5541:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "5541:15:84" - }, - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "5562:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "5573:2:84", - "type": "", - "value": "64" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "5558:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "5558:18:84" - }, - { - "name": "length", - "nodeType": "YulIdentifier", - "src": "5578:6:84" - } - ], - "functionName": { - "name": "copy_memory_to_memory_with_cleanup", - "nodeType": "YulIdentifier", - "src": "5506:34:84" - }, - "nodeType": "YulFunctionCall", - "src": "5506:79:84" - }, - "nodeType": "YulExpressionStatement", - "src": "5506:79:84" - }, - { - "nodeType": "YulAssignment", - "src": "5594:62:84", - "value": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "5610:9:84" - }, - { - "arguments": [ - { - "arguments": [ - { - "name": "length", - "nodeType": "YulIdentifier", - "src": "5629:6:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "5637:2:84", - "type": "", - "value": "31" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "5625:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "5625:15:84" - }, - { - "arguments": [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "5646:2:84", - "type": "", - "value": "31" - } - ], - "functionName": { - "name": "not", - "nodeType": "YulIdentifier", - "src": "5642:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "5642:7:84" - } - ], - "functionName": { - "name": "and", - "nodeType": "YulIdentifier", - "src": "5621:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "5621:29:84" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "5606:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "5606:45:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "5653:2:84", - "type": "", - "value": "64" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "5602:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "5602:54:84" - }, - "variableNames": [ - { - "name": "tail", - "nodeType": "YulIdentifier", - "src": "5594:4:84" - } - ] - } - ] - }, - "name": "abi_encode_tuple_t_bytes_memory_ptr__to_t_bytes_memory_ptr__fromStack_reversed", - "nodeType": "YulFunctionDefinition", - "parameters": [ - { - "name": "headStart", - "nodeType": "YulTypedName", - "src": "5356:9:84", - "type": "" - }, - { - "name": "value0", - "nodeType": "YulTypedName", - "src": "5367:6:84", - "type": "" - } - ], - "returnVariables": [ - { - "name": "tail", - "nodeType": "YulTypedName", - "src": "5378:4:84", - "type": "" - } - ], - "src": "5268:394:84" - }, - { - "body": { - "nodeType": "YulBlock", - "src": "5841:223:84", - "statements": [ - { - "expression": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "5858:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "5869:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "5851:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "5851:21:84" - }, - "nodeType": "YulExpressionStatement", - "src": "5851:21:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "5892:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "5903:2:84", - "type": "", - "value": "32" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "5888:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "5888:18:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "5908:2:84", - "type": "", - "value": "33" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "5881:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "5881:30:84" - }, - "nodeType": "YulExpressionStatement", - "src": "5881:30:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "5931:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "5942:2:84", - "type": "", - "value": "64" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "5927:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "5927:18:84" - }, - { - "hexValue": "5769746e657450726f78793a20756e61626c6520746f20696e697469616c697a", - "kind": "string", - "nodeType": "YulLiteral", - "src": "5947:34:84", - "type": "", - "value": "WitnetProxy: unable to initializ" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "5920:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "5920:62:84" - }, - "nodeType": "YulExpressionStatement", - "src": "5920:62:84" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "6002:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "6013:2:84", - "type": "", - "value": "96" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "5998:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "5998:18:84" - }, - { - "hexValue": "65", - "kind": "string", - "nodeType": "YulLiteral", - "src": "6018:3:84", - "type": "", - "value": "e" - } - ], - "functionName": { - "name": "mstore", - "nodeType": "YulIdentifier", - "src": "5991:6:84" - }, - "nodeType": "YulFunctionCall", - "src": "5991:31:84" - }, - "nodeType": "YulExpressionStatement", - "src": "5991:31:84" - }, - { - "nodeType": "YulAssignment", - "src": "6031:27:84", - "value": { - "arguments": [ - { - "name": "headStart", - "nodeType": "YulIdentifier", - "src": "6043:9:84" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "6054:3:84", - "type": "", - "value": "128" - } - ], - "functionName": { - "name": "add", - "nodeType": "YulIdentifier", - "src": "6039:3:84" - }, - "nodeType": "YulFunctionCall", - "src": "6039:19:84" - }, - "variableNames": [ - { - "name": "tail", - "nodeType": "YulIdentifier", - "src": "6031:4:84" - } - ] - } - ] - }, - "name": "abi_encode_tuple_t_stringliteral_55e9f07b665adf0e8c084720fbd831f583a2d75f5997894b64a77e28a0171f3c__to_t_string_memory_ptr__fromStack_reversed", - "nodeType": "YulFunctionDefinition", - "parameters": [ - { - "name": "headStart", - "nodeType": "YulTypedName", - "src": "5818:9:84", - "type": "" - } - ], - "returnVariables": [ - { - "name": "tail", - "nodeType": "YulTypedName", - "src": "5832:4:84", - "type": "" - } - ], - "src": "5667:397:84" - } - ] - }, - "contents": "{\n { }\n function abi_encode_tuple_t_address__to_t_address__fromStack_reversed(headStart, value0) -> tail\n {\n tail := add(headStart, 32)\n mstore(headStart, and(value0, sub(shl(160, 1), 1)))\n }\n function panic_error_0x41()\n {\n mstore(0, shl(224, 0x4e487b71))\n mstore(4, 0x41)\n revert(0, 0x24)\n }\n function abi_decode_tuple_t_addresst_bytes_memory_ptr(headStart, dataEnd) -> value0, value1\n {\n if slt(sub(dataEnd, headStart), 64) { revert(0, 0) }\n let value := calldataload(headStart)\n if iszero(eq(value, and(value, sub(shl(160, 1), 1)))) { revert(0, 0) }\n value0 := value\n let offset := calldataload(add(headStart, 32))\n let _1 := 0xffffffffffffffff\n if gt(offset, _1) { revert(0, 0) }\n let _2 := add(headStart, offset)\n if iszero(slt(add(_2, 0x1f), dataEnd)) { revert(0, 0) }\n let _3 := calldataload(_2)\n if gt(_3, _1) { panic_error_0x41() }\n let _4 := not(31)\n let memPtr := mload(64)\n let newFreePtr := add(memPtr, and(add(and(add(_3, 0x1f), _4), 63), _4))\n if or(gt(newFreePtr, _1), lt(newFreePtr, memPtr)) { panic_error_0x41() }\n mstore(64, newFreePtr)\n mstore(memPtr, _3)\n if gt(add(add(_2, _3), 32), dataEnd) { revert(0, 0) }\n calldatacopy(add(memPtr, 32), add(_2, 32), _3)\n mstore(add(add(memPtr, _3), 32), 0)\n value1 := memPtr\n }\n function abi_encode_tuple_t_bool__to_t_bool__fromStack_reversed(headStart, value0) -> tail\n {\n tail := add(headStart, 32)\n mstore(headStart, iszero(iszero(value0)))\n }\n function abi_encode_tuple_t_stringliteral_d599eaa5e68d91d75c142446490ab9a15fd0284a41ce949219b5b4d8f267239a__to_t_string_memory_ptr__fromStack_reversed(headStart) -> tail\n {\n mstore(headStart, 32)\n mstore(add(headStart, 32), 32)\n mstore(add(headStart, 64), \"WitnetProxy: null implementation\")\n tail := add(headStart, 96)\n }\n function abi_encode_tuple_t_stringliteral_e332eab1bae45430d1201a30c0d80d8fcb5570f9e70201a9eb7b229e17fd2084__to_t_string_memory_ptr__fromStack_reversed(headStart) -> tail\n {\n mstore(headStart, 32)\n mstore(add(headStart, 32), 31)\n mstore(add(headStart, 64), \"WitnetProxy: nothing to upgrade\")\n tail := add(headStart, 96)\n }\n function abi_decode_tuple_t_bool_fromMemory(headStart, dataEnd) -> value0\n {\n if slt(sub(dataEnd, headStart), 32) { revert(0, 0) }\n let value := mload(headStart)\n if iszero(eq(value, iszero(iszero(value)))) { revert(0, 0) }\n value0 := value\n }\n function abi_encode_tuple_t_stringliteral_7f859058ad3ee4e192700ff813ed67dc892a0c7de91510ee584a0ac25fc982fc__to_t_string_memory_ptr__fromStack_reversed(headStart) -> tail\n {\n mstore(headStart, 32)\n mstore(add(headStart, 32), 42)\n mstore(add(headStart, 64), \"WitnetProxy: unable to check upg\")\n mstore(add(headStart, 96), \"radability\")\n tail := add(headStart, 128)\n }\n function abi_encode_tuple_t_stringliteral_d96132834a96bae5cb2f32cb07f13985dcde0f2358055c198eb3065af6c5aa7f__to_t_string_memory_ptr__fromStack_reversed(headStart) -> tail\n {\n mstore(headStart, 32)\n mstore(add(headStart, 32), 27)\n mstore(add(headStart, 64), \"WitnetProxy: not upgradable\")\n tail := add(headStart, 96)\n }\n function copy_memory_to_memory_with_cleanup(src, dst, length)\n {\n let i := 0\n for { } lt(i, length) { i := add(i, 32) }\n {\n mstore(add(dst, i), mload(add(src, i)))\n }\n mstore(add(dst, length), 0)\n }\n function abi_encode_tuple_packed_t_bytes_memory_ptr__to_t_bytes_memory_ptr__nonPadded_inplace_fromStack_reversed(pos, value0) -> end\n {\n let length := mload(value0)\n copy_memory_to_memory_with_cleanup(add(value0, 0x20), pos, length)\n end := add(pos, length)\n }\n function abi_encode_tuple_t_stringliteral_fe0c5d56f2e637bc6ae9d29f1058c00159080f3dd6202013ecdbcca6e4740a65__to_t_string_memory_ptr__fromStack_reversed(headStart) -> tail\n {\n mstore(headStart, 32)\n mstore(add(headStart, 32), 26)\n mstore(add(headStart, 64), \"WitnetProxy: not compliant\")\n tail := add(headStart, 96)\n }\n function abi_encode_tuple_t_stringliteral_ba8d4d661ce88eb2915ba133e6cad533938b754d7b66d8253879ef2c2193ecb2__to_t_string_memory_ptr__fromStack_reversed(headStart) -> tail\n {\n mstore(headStart, 32)\n mstore(add(headStart, 32), 27)\n mstore(add(headStart, 64), \"WitnetProxy: not authorized\")\n tail := add(headStart, 96)\n }\n function abi_decode_tuple_t_bytes32_fromMemory(headStart, dataEnd) -> value0\n {\n if slt(sub(dataEnd, headStart), 32) { revert(0, 0) }\n value0 := mload(headStart)\n }\n function abi_encode_tuple_t_stringliteral_f3c1ad1fa1688d47e62cc4dd5b4be101315ef47e38e05aa3a37a4ef2e1cec0a8__to_t_string_memory_ptr__fromStack_reversed(headStart) -> tail\n {\n mstore(headStart, 32)\n mstore(add(headStart, 32), 36)\n mstore(add(headStart, 64), \"WitnetProxy: proxiableUUIDs mism\")\n mstore(add(headStart, 96), \"atch\")\n tail := add(headStart, 128)\n }\n function abi_encode_tuple_t_bytes_memory_ptr__to_t_bytes_memory_ptr__fromStack_reversed(headStart, value0) -> tail\n {\n mstore(headStart, 32)\n let length := mload(value0)\n mstore(add(headStart, 32), length)\n copy_memory_to_memory_with_cleanup(add(value0, 32), add(headStart, 64), length)\n tail := add(add(headStart, and(add(length, 31), not(31))), 64)\n }\n function abi_encode_tuple_t_stringliteral_55e9f07b665adf0e8c084720fbd831f583a2d75f5997894b64a77e28a0171f3c__to_t_string_memory_ptr__fromStack_reversed(headStart) -> tail\n {\n mstore(headStart, 32)\n mstore(add(headStart, 32), 33)\n mstore(add(headStart, 64), \"WitnetProxy: unable to initializ\")\n mstore(add(headStart, 96), \"e\")\n tail := add(headStart, 128)\n }\n}", - "id": 84, - "language": "Yul", - "name": "#utility.yul" - } - ], - "sourceMap": "244:4800:28:-:0;;;500:17;;;;;;;;;;244:4800;;;;;;", - "deployedSourceMap": "244:4800:28:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;726:23;752:16;:14;:16::i;:::-;726:42;;1116:4;1110:11;1156:14;1153:1;1148:3;1135:36;1260:1;1257;1241:14;1236:3;1219:15;1212:5;1199:63;1288:16;1341:4;1338:1;1333:3;1318:28;1367:6;1391:119;;;;1653:4;1648:3;1641:17;1391:119;1485:4;1480:3;1473:17;1761:110;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;178:32:84;;;160:51;;148:2;133:18;1761:110:28;;;;;;;;2165:2454;;;;;;;;;;-1:-1:-1;2165:2454:28;;;;;:::i;:::-;;:::i;:::-;;;1619:14:84;;1612:22;1594:41;;1582:2;1567:18;2165:2454:28;1454:187:84;1761:110:28;4955:66;1835:28;-1:-1:-1;;;;;1835:28:28;;1761:110::o;2165:2454::-;2261:4;-1:-1:-1;;;;;2338:32:28;;2330:77;;;;-1:-1:-1;;;2330:77:28;;1848:2:84;2330:77:28;;;1830:21:84;;;1867:18;;;1860:30;1926:34;1906:18;;;1899:62;1978:18;;2330:77:28;;;;;;;;;2420:26;2449:16;:14;:16::i;:::-;2420:45;-1:-1:-1;;;;;;2480:32:28;;;2476:1285;;2632:18;-1:-1:-1;;;;;2610:40:28;:18;-1:-1:-1;;;;;2610:40:28;;2602:84;;;;-1:-1:-1;;;2602:84:28;;2209:2:84;2602:84:28;;;2191:21:84;2248:2;2228:18;;;2221:30;2287:33;2267:18;;;2260:61;2338:18;;2602:84:28;2007:355:84;2602:84:28;2802:18;-1:-1:-1;;;;;2790:44:28;;:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2790:46:28;;;;;;;;-1:-1:-1;;2790:46:28;;;;;;;;;;;;:::i;:::-;;;2786:262;;2980:52;;-1:-1:-1;;;2980:52:28;;2851:2:84;2980:52:28;;;2833:21:84;2890:2;2870:18;;;2863:30;2929:34;2909:18;;;2902:62;-1:-1:-1;;;2980:18:84;;;2973:40;3030:19;;2980:52:28;2649:406:84;2786:262:28;2893:13;2885:53;;;;-1:-1:-1;;;2885:53:28;;3262:2:84;2885:53:28;;;3244:21:84;3301:2;3281:18;;;3274:30;3340:29;3320:18;;;3313:57;3387:18;;2885:53:28;3060:351:84;2885:53:28;-1:-1:-1;3252:125:28;;3348:10;3252:125;;;160:51:84;3161:15:28;;;;-1:-1:-1;;;;;3202:31:28;;;133:18:84;;3252:125:28;;;-1:-1:-1;;3252:125:28;;;;;;;;;;;;;;-1:-1:-1;;;;;3252:125:28;-1:-1:-1;;;3252:125:28;;;3202:190;;;3252:125;3202:190;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3160:232;;;;3415:10;3407:49;;;;-1:-1:-1;;;3407:49:28;;4165:2:84;3407:49:28;;;4147:21:84;4204:2;4184:18;;;4177:30;4243:28;4223:18;;;4216:56;4289:18;;3407:49:28;3963:350:84;3407:49:28;3490:7;3479:27;;;;;;;;;;;;:::i;:::-;3471:67;;;;-1:-1:-1;;;3471:67:28;;4520:2:84;3471:67:28;;;4502:21:84;4559:2;4539:18;;;4532:30;4598:29;4578:18;;;4571:57;4645:18;;3471:67:28;4318:351:84;3471:67:28;3642:18;-1:-1:-1;;;;;3630:45:28;;:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3591:18;-1:-1:-1;;;;;3579:45:28;;:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:98;3553:196;;;;-1:-1:-1;;;3553:196:28;;5065:2:84;3553:196:28;;;5047:21:84;5104:2;5084:18;;;5077:30;5143:34;5123:18;;;5116:62;-1:-1:-1;;;5194:18:84;;;5187:34;5238:19;;3553:196:28;4863:400:84;3553:196:28;2514:1247;;2476:1285;3846:20;3871:18;-1:-1:-1;;;;;3871:31:28;3997:9;3917:104;;;;;;;;:::i;:::-;;;;-1:-1:-1;;3917:104:28;;;;;;;;;;;;;;-1:-1:-1;;;;;3917:104:28;-1:-1:-1;;;3917:104:28;;;3871:161;;;3917:104;3871:161;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3845:187;;;4051:15;4043:61;;;;-1:-1:-1;;;4043:61:28;;5869:2:84;4043:61:28;;;5851:21:84;5908:2;5888:18;;;5881:30;5947:34;5927:18;;;5920:62;-1:-1:-1;;;5998:18:84;;;5991:31;6039:19;;4043:61:28;5667:397:84;4043:61:28;4955:66;4199:49;;-1:-1:-1;;;;;;4199:49:28;-1:-1:-1;;;;;4199:49:28;;;;;;;;4264:28;;;;-1:-1:-1;;4264:28:28;4421:18;-1:-1:-1;;;;;4409:44:28;;:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;4409:46:28;;;;;;;;-1:-1:-1;;4409:46:28;;;;;;;;;;;;:::i;:::-;;;4405:207;;4563:37;;-1:-1:-1;;;4563:37:28;;4165:2:84;4563:37:28;;;4147:21:84;4204:2;4184:18;;;4177:30;4243:28;4223:18;;;4216:56;4289:18;;4563:37:28;3963:350:84;4405:207:28;4507:13;-1:-1:-1;4500:20:28;;-1:-1:-1;;4500:20:28;2165:2454;;;;;:::o;222:127:84:-;283:10;278:3;274:20;271:1;264:31;314:4;311:1;304:15;338:4;335:1;328:15;354:1095;431:6;439;492:2;480:9;471:7;467:23;463:32;460:52;;;508:1;505;498:12;460:52;534:23;;-1:-1:-1;;;;;586:31:84;;576:42;;566:70;;632:1;629;622:12;566:70;655:5;-1:-1:-1;711:2:84;696:18;;683:32;734:18;764:14;;;761:34;;;791:1;788;781:12;761:34;829:6;818:9;814:22;804:32;;874:7;867:4;863:2;859:13;855:27;845:55;;896:1;893;886:12;845:55;932:2;919:16;954:2;950;947:10;944:36;;;960:18;;:::i;:::-;1035:2;1029:9;1003:2;1089:13;;-1:-1:-1;;1085:22:84;;;1109:2;1081:31;1077:40;1065:53;;;1133:18;;;1153:22;;;1130:46;1127:72;;;1179:18;;:::i;:::-;1219:10;1215:2;1208:22;1254:2;1246:6;1239:18;1294:7;1289:2;1284;1280;1276:11;1272:20;1269:33;1266:53;;;1315:1;1312;1305:12;1266:53;1371:2;1366;1362;1358:11;1353:2;1345:6;1341:15;1328:46;1416:1;1411:2;1406;1398:6;1394:15;1390:24;1383:35;1437:6;1427:16;;;;;;;354:1095;;;;;:::o;2367:277::-;2434:6;2487:2;2475:9;2466:7;2462:23;2458:32;2455:52;;;2503:1;2500;2493:12;2455:52;2535:9;2529:16;2588:5;2581:13;2574:21;2567:5;2564:32;2554:60;;2610:1;2607;2600:12;2554:60;2633:5;2367:277;-1:-1:-1;;;2367:277:84:o;3416:250::-;3501:1;3511:113;3525:6;3522:1;3519:13;3511:113;;;3601:11;;;3595:18;3582:11;;;3575:39;3547:2;3540:10;3511:113;;;-1:-1:-1;;3658:1:84;3640:16;;3633:27;3416:250::o;3671:287::-;3800:3;3838:6;3832:13;3854:66;3913:6;3908:3;3901:4;3893:6;3889:17;3854:66;:::i;:::-;3936:16;;;;;3671:287;-1:-1:-1;;3671:287:84:o;4674:184::-;4744:6;4797:2;4785:9;4776:7;4772:23;4768:32;4765:52;;;4813:1;4810;4803:12;4765:52;-1:-1:-1;4836:16:84;;4674:184;-1:-1:-1;4674:184:84:o;5268:394::-;5415:2;5404:9;5397:21;5378:4;5447:6;5441:13;5490:6;5485:2;5474:9;5470:18;5463:34;5506:79;5578:6;5573:2;5562:9;5558:18;5553:2;5545:6;5541:15;5506:79;:::i;:::-;5646:2;5625:15;-1:-1:-1;;5621:29:84;5606:45;;;;5653:2;5602:54;;5268:394;-1:-1:-1;;5268:394:84:o", - "source": "// SPDX-License-Identifier: MIT\r\n\r\npragma solidity >=0.7.0 <0.9.0;\r\npragma experimental ABIEncoderV2;\r\n\r\nimport \"../patterns/Upgradeable.sol\";\r\n\r\n/// @title WitnetProxy: upgradable delegate-proxy contract. \r\n/// @author The Witnet Foundation.\r\ncontract WitnetProxy {\r\n\r\n /// Event emitted every time the implementation gets updated.\r\n event Upgraded(address indexed implementation); \r\n\r\n /// Constructor with no params as to ease eventual support of Singleton pattern (i.e. ERC-2470).\r\n constructor () {}\r\n\r\n receive() virtual external payable {}\r\n\r\n /// Payable fallback accepts delegating calls to payable functions. \r\n fallback() external payable { /* solhint-disable no-complex-fallback */\r\n address _implementation = implementation();\r\n assembly { /* solhint-disable avoid-low-level-calls */\r\n // Gas optimized delegate call to 'implementation' contract.\r\n // Note: `msg.data`, `msg.sender` and `msg.value` will be passed over \r\n // to actual implementation of `msg.sig` within `implementation` contract.\r\n let ptr := mload(0x40)\r\n calldatacopy(ptr, 0, calldatasize())\r\n let result := delegatecall(gas(), _implementation, ptr, calldatasize(), 0, 0)\r\n let size := returndatasize()\r\n returndatacopy(ptr, 0, size)\r\n switch result\r\n case 0 { \r\n // pass back revert message:\r\n revert(ptr, size) \r\n }\r\n default {\r\n // pass back same data as returned by 'implementation' contract:\r\n return(ptr, size) \r\n }\r\n }\r\n }\r\n\r\n /// Returns proxy's current implementation address.\r\n function implementation() public view returns (address) {\r\n return __proxySlot().implementation;\r\n }\r\n\r\n /// Upgrades the `implementation` address.\r\n /// @param _newImplementation New implementation address.\r\n /// @param _initData Raw data with which new implementation will be initialized.\r\n /// @return Returns whether new implementation would be further upgradable, or not.\r\n function upgradeTo(address _newImplementation, bytes memory _initData)\r\n public returns (bool)\r\n {\r\n // New implementation cannot be null:\r\n require(_newImplementation != address(0), \"WitnetProxy: null implementation\");\r\n\r\n address _oldImplementation = implementation();\r\n if (_oldImplementation != address(0)) {\r\n // New implementation address must differ from current one:\r\n require(_newImplementation != _oldImplementation, \"WitnetProxy: nothing to upgrade\");\r\n\r\n // Assert whether current implementation is intrinsically upgradable:\r\n try Upgradeable(_oldImplementation).isUpgradable() returns (bool _isUpgradable) {\r\n require(_isUpgradable, \"WitnetProxy: not upgradable\");\r\n } catch {\r\n revert(\"WitnetProxy: unable to check upgradability\");\r\n }\r\n\r\n // Assert whether current implementation allows `msg.sender` to upgrade the proxy:\r\n (bool _wasCalled, bytes memory _result) = _oldImplementation.delegatecall(\r\n abi.encodeWithSignature(\r\n \"isUpgradableFrom(address)\",\r\n msg.sender\r\n )\r\n );\r\n require(_wasCalled, \"WitnetProxy: not compliant\");\r\n require(abi.decode(_result, (bool)), \"WitnetProxy: not authorized\");\r\n require(\r\n Upgradeable(_oldImplementation).proxiableUUID() == Upgradeable(_newImplementation).proxiableUUID(),\r\n \"WitnetProxy: proxiableUUIDs mismatch\"\r\n );\r\n }\r\n\r\n // Initialize new implementation within proxy-context storage:\r\n (bool _wasInitialized,) = _newImplementation.delegatecall(\r\n abi.encodeWithSignature(\r\n \"initialize(bytes)\",\r\n _initData\r\n )\r\n );\r\n require(_wasInitialized, \"WitnetProxy: unable to initialize\");\r\n\r\n // If all checks and initialization pass, update implementation address:\r\n __proxySlot().implementation = _newImplementation;\r\n emit Upgraded(_newImplementation);\r\n\r\n // Asserts new implementation complies w/ minimal implementation of Upgradeable interface:\r\n try Upgradeable(_newImplementation).isUpgradable() returns (bool _isUpgradable) {\r\n return _isUpgradable;\r\n }\r\n catch {\r\n revert (\"WitnetProxy: not compliant\");\r\n }\r\n }\r\n\r\n /// @dev Complying with EIP-1967, retrieves storage struct containing proxy's current implementation address.\r\n function __proxySlot() private pure returns (Proxiable.ProxiableSlot storage _slot) {\r\n assembly {\r\n // bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\r\n _slot.slot := 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc\r\n }\r\n }\r\n\r\n}\r\n", - "sourcePath": "C:\\Users\\guill\\github\\guidiaz\\witnet-solidity-bridge\\contracts\\impls\\WitnetProxy.sol", - "ast": { - "absolutePath": "project:/contracts/impls/WitnetProxy.sol", - "exportedSymbols": { - "AddressUpgradeable": [ - 452 - ], - "Initializable": [ - 168 - ], - "Proxiable": [ - 23471 - ], - "Upgradeable": [ - 23590 - ], - "WitnetProxy": [ - 6719 - ] - }, - "id": 6720, - "license": "MIT", - "nodeType": "SourceUnit", - "nodes": [ - { - "id": 6517, - "literals": [ - "solidity", - ">=", - "0.7", - ".0", - "<", - "0.9", - ".0" - ], - "nodeType": "PragmaDirective", - "src": "35:31:28" - }, - { - "id": 6518, - "literals": [ - "experimental", - "ABIEncoderV2" - ], - "nodeType": "PragmaDirective", - "src": "68:33:28" - }, - { - "absolutePath": "project:/contracts/patterns/Upgradeable.sol", - "file": "../patterns/Upgradeable.sol", - "id": 6519, - "nameLocation": "-1:-1:-1", - "nodeType": "ImportDirective", - "scope": 6720, - "sourceUnit": 23591, - "src": "105:37:28", - "symbolAliases": [], - "unitAlias": "" - }, - { - "abstract": false, - "baseContracts": [], - "canonicalName": "WitnetProxy", - "contractDependencies": [], - "contractKind": "contract", - "documentation": { - "id": 6520, - "nodeType": "StructuredDocumentation", - "src": "146:98:28", - "text": "@title WitnetProxy: upgradable delegate-proxy contract. \n @author The Witnet Foundation." - }, - "fullyImplemented": true, - "id": 6719, - "linearizedBaseContracts": [ - 6719 - ], - "name": "WitnetProxy", - "nameLocation": "253:11:28", - "nodeType": "ContractDefinition", - "nodes": [ - { - "anonymous": false, - "documentation": { - "id": 6521, - "nodeType": "StructuredDocumentation", - "src": "274:61:28", - "text": "Event emitted every time the implementation gets updated." - }, - "eventSelector": "bc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b", - "id": 6525, - "name": "Upgraded", - "nameLocation": "347:8:28", - "nodeType": "EventDefinition", - "parameters": { - "id": 6524, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 6523, - "indexed": true, - "mutability": "mutable", - "name": "implementation", - "nameLocation": "372:14:28", - "nodeType": "VariableDeclaration", - "scope": 6525, - "src": "356:30:28", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 6522, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "356:7:28", - "stateMutability": "nonpayable", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "visibility": "internal" - } - ], - "src": "355:32:28" - }, - "src": "341:47:28" - }, - { - "body": { - "id": 6529, - "nodeType": "Block", - "src": "515:2:28", - "statements": [] - }, - "documentation": { - "id": 6526, - "nodeType": "StructuredDocumentation", - "src": "398:96:28", - "text": "Constructor with no params as to ease eventual support of Singleton pattern (i.e. ERC-2470)." - }, - "id": 6530, - "implemented": true, - "kind": "constructor", - "modifiers": [], - "name": "", - "nameLocation": "-1:-1:-1", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 6527, - "nodeType": "ParameterList", - "parameters": [], - "src": "512:2:28" - }, - "returnParameters": { - "id": 6528, - "nodeType": "ParameterList", - "parameters": [], - "src": "515:0:28" - }, - "scope": 6719, - "src": "500:17:28", - "stateMutability": "nonpayable", - "virtual": false, - "visibility": "public" - }, - { - "body": { - "id": 6533, - "nodeType": "Block", - "src": "560:2:28", - "statements": [] - }, - "id": 6534, - "implemented": true, - "kind": "receive", - "modifiers": [], - "name": "", - "nameLocation": "-1:-1:-1", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 6531, - "nodeType": "ParameterList", - "parameters": [], - "src": "532:2:28" - }, - "returnParameters": { - "id": 6532, - "nodeType": "ParameterList", - "parameters": [], - "src": "560:0:28" - }, - "scope": 6719, - "src": "525:37:28", - "stateMutability": "payable", - "virtual": true, - "visibility": "external" - }, - { - "body": { - "id": 6544, - "nodeType": "Block", - "src": "673:1023:28", - "statements": [ - { - "assignments": [ - 6539 - ], - "declarations": [ - { - "constant": false, - "id": 6539, - "mutability": "mutable", - "name": "_implementation", - "nameLocation": "734:15:28", - "nodeType": "VariableDeclaration", - "scope": 6544, - "src": "726:23:28", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 6538, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "726:7:28", - "stateMutability": "nonpayable", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "visibility": "internal" - } - ], - "id": 6542, - "initialValue": { - "arguments": [], - "expression": { - "argumentTypes": [], - "id": 6540, - "name": "implementation", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6556, - "src": "752:14:28", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_view$__$returns$_t_address_$", - "typeString": "function () view returns (address)" - } - }, - "id": 6541, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "752:16:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "726:42:28" - }, - { - "AST": { - "nodeType": "YulBlock", - "src": "788:901:28", - "statements": [ - { - "nodeType": "YulVariableDeclaration", - "src": "1099:22:28", - "value": { - "arguments": [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1116:4:28", - "type": "", - "value": "0x40" - } - ], - "functionName": { - "name": "mload", - "nodeType": "YulIdentifier", - "src": "1110:5:28" - }, - "nodeType": "YulFunctionCall", - "src": "1110:11:28" - }, - "variables": [ - { - "name": "ptr", - "nodeType": "YulTypedName", - "src": "1103:3:28", - "type": "" - } - ] - }, - { - "expression": { - "arguments": [ - { - "name": "ptr", - "nodeType": "YulIdentifier", - "src": "1148:3:28" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1153:1:28", - "type": "", - "value": "0" - }, - { - "arguments": [], - "functionName": { - "name": "calldatasize", - "nodeType": "YulIdentifier", - "src": "1156:12:28" - }, - "nodeType": "YulFunctionCall", - "src": "1156:14:28" - } - ], - "functionName": { - "name": "calldatacopy", - "nodeType": "YulIdentifier", - "src": "1135:12:28" - }, - "nodeType": "YulFunctionCall", - "src": "1135:36:28" - }, - "nodeType": "YulExpressionStatement", - "src": "1135:36:28" - }, - { - "nodeType": "YulVariableDeclaration", - "src": "1185:77:28", - "value": { - "arguments": [ - { - "arguments": [], - "functionName": { - "name": "gas", - "nodeType": "YulIdentifier", - "src": "1212:3:28" - }, - "nodeType": "YulFunctionCall", - "src": "1212:5:28" - }, - { - "name": "_implementation", - "nodeType": "YulIdentifier", - "src": "1219:15:28" - }, - { - "name": "ptr", - "nodeType": "YulIdentifier", - "src": "1236:3:28" - }, - { - "arguments": [], - "functionName": { - "name": "calldatasize", - "nodeType": "YulIdentifier", - "src": "1241:12:28" - }, - "nodeType": "YulFunctionCall", - "src": "1241:14:28" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1257:1:28", - "type": "", - "value": "0" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1260:1:28", - "type": "", - "value": "0" - } - ], - "functionName": { - "name": "delegatecall", - "nodeType": "YulIdentifier", - "src": "1199:12:28" - }, - "nodeType": "YulFunctionCall", - "src": "1199:63:28" - }, - "variables": [ - { - "name": "result", - "nodeType": "YulTypedName", - "src": "1189:6:28", - "type": "" - } - ] - }, - { - "nodeType": "YulVariableDeclaration", - "src": "1276:28:28", - "value": { - "arguments": [], - "functionName": { - "name": "returndatasize", - "nodeType": "YulIdentifier", - "src": "1288:14:28" - }, - "nodeType": "YulFunctionCall", - "src": "1288:16:28" - }, - "variables": [ - { - "name": "size", - "nodeType": "YulTypedName", - "src": "1280:4:28", - "type": "" - } - ] - }, - { - "expression": { - "arguments": [ - { - "name": "ptr", - "nodeType": "YulIdentifier", - "src": "1333:3:28" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1338:1:28", - "type": "", - "value": "0" - }, - { - "name": "size", - "nodeType": "YulIdentifier", - "src": "1341:4:28" - } - ], - "functionName": { - "name": "returndatacopy", - "nodeType": "YulIdentifier", - "src": "1318:14:28" - }, - "nodeType": "YulFunctionCall", - "src": "1318:28:28" - }, - "nodeType": "YulExpressionStatement", - "src": "1318:28:28" - }, - { - "cases": [ - { - "body": { - "nodeType": "YulBlock", - "src": "1399:111:28", - "statements": [ - { - "expression": { - "arguments": [ - { - "name": "ptr", - "nodeType": "YulIdentifier", - "src": "1480:3:28" - }, - { - "name": "size", - "nodeType": "YulIdentifier", - "src": "1485:4:28" - } - ], - "functionName": { - "name": "revert", - "nodeType": "YulIdentifier", - "src": "1473:6:28" - }, - "nodeType": "YulFunctionCall", - "src": "1473:17:28" - }, - "nodeType": "YulExpressionStatement", - "src": "1473:17:28" - } - ] - }, - "nodeType": "YulCase", - "src": "1391:119:28", - "value": { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1396:1:28", - "type": "", - "value": "0" - } - }, - { - "body": { - "nodeType": "YulBlock", - "src": "1536:142:28", - "statements": [ - { - "expression": { - "arguments": [ - { - "name": "ptr", - "nodeType": "YulIdentifier", - "src": "1648:3:28" - }, - { - "name": "size", - "nodeType": "YulIdentifier", - "src": "1653:4:28" - } - ], - "functionName": { - "name": "return", - "nodeType": "YulIdentifier", - "src": "1641:6:28" - }, - "nodeType": "YulFunctionCall", - "src": "1641:17:28" - }, - "nodeType": "YulExpressionStatement", - "src": "1641:17:28" - } - ] - }, - "nodeType": "YulCase", - "src": "1528:150:28", - "value": "default" - } - ], - "expression": { - "name": "result", - "nodeType": "YulIdentifier", - "src": "1367:6:28" - }, - "nodeType": "YulSwitch", - "src": "1360:318:28" - } - ] - }, - "evmVersion": "london", - "externalReferences": [ - { - "declaration": 6539, - "isOffset": false, - "isSlot": false, - "src": "1219:15:28", - "valueSize": 1 - } - ], - "id": 6543, - "nodeType": "InlineAssembly", - "src": "779:910:28" - } - ] - }, - "documentation": { - "id": 6535, - "nodeType": "StructuredDocumentation", - "src": "570:69:28", - "text": "Payable fallback accepts delegating calls to payable functions. " - }, - "id": 6545, - "implemented": true, - "kind": "fallback", - "modifiers": [], - "name": "", - "nameLocation": "-1:-1:-1", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 6536, - "nodeType": "ParameterList", - "parameters": [], - "src": "653:2:28" - }, - "returnParameters": { - "id": 6537, - "nodeType": "ParameterList", - "parameters": [], - "src": "673:0:28" - }, - "scope": 6719, - "src": "645:1051:28", - "stateMutability": "payable", - "virtual": false, - "visibility": "external" - }, - { - "body": { - "id": 6555, - "nodeType": "Block", - "src": "1817:54:28", - "statements": [ - { - "expression": { - "expression": { - "arguments": [], - "expression": { - "argumentTypes": [], - "id": 6551, - "name": "__proxySlot", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6718, - "src": "1835:11:28", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_pure$__$returns$_t_struct$_ProxiableSlot_$23442_storage_ptr_$", - "typeString": "function () pure returns (struct Proxiable.ProxiableSlot storage pointer)" - } - }, - "id": 6552, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "1835:13:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_struct$_ProxiableSlot_$23442_storage_ptr", - "typeString": "struct Proxiable.ProxiableSlot storage pointer" - } - }, - "id": 6553, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "memberLocation": "1849:14:28", - "memberName": "implementation", - "nodeType": "MemberAccess", - "referencedDeclaration": 23439, - "src": "1835:28:28", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "functionReturnParameters": 6550, - "id": 6554, - "nodeType": "Return", - "src": "1828:35:28" - } - ] - }, - "documentation": { - "id": 6546, - "nodeType": "StructuredDocumentation", - "src": "1704:51:28", - "text": "Returns proxy's current implementation address." - }, - "functionSelector": "5c60da1b", - "id": 6556, - "implemented": true, - "kind": "function", - "modifiers": [], - "name": "implementation", - "nameLocation": "1770:14:28", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 6547, - "nodeType": "ParameterList", - "parameters": [], - "src": "1784:2:28" - }, - "returnParameters": { - "id": 6550, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 6549, - "mutability": "mutable", - "name": "", - "nameLocation": "-1:-1:-1", - "nodeType": "VariableDeclaration", - "scope": 6556, - "src": "1808:7:28", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 6548, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1808:7:28", - "stateMutability": "nonpayable", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "visibility": "internal" - } - ], - "src": "1807:9:28" - }, - "scope": 6719, - "src": "1761:110:28", - "stateMutability": "view", - "virtual": false, - "visibility": "public" - }, - { - "body": { - "id": 6708, - "nodeType": "Block", - "src": "2272:2347:28", - "statements": [ - { - "expression": { - "arguments": [ - { - "commonType": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "id": 6572, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftExpression": { - "id": 6567, - "name": "_newImplementation", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6559, - "src": "2338:18:28", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "BinaryOperation", - "operator": "!=", - "rightExpression": { - "arguments": [ - { - "hexValue": "30", - "id": 6570, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "2368:1:28", - "typeDescriptions": { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - }, - "value": "0" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - } - ], - "id": 6569, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "2360:7:28", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_address_$", - "typeString": "type(address)" - }, - "typeName": { - "id": 6568, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "2360:7:28", - "typeDescriptions": {} - } - }, - "id": 6571, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "2360:10:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "src": "2338:32:28", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - { - "hexValue": "5769746e657450726f78793a206e756c6c20696d706c656d656e746174696f6e", - "id": 6573, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "2372:34:28", - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_d599eaa5e68d91d75c142446490ab9a15fd0284a41ce949219b5b4d8f267239a", - "typeString": "literal_string \"WitnetProxy: null implementation\"" - }, - "value": "WitnetProxy: null implementation" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bool", - "typeString": "bool" - }, - { - "typeIdentifier": "t_stringliteral_d599eaa5e68d91d75c142446490ab9a15fd0284a41ce949219b5b4d8f267239a", - "typeString": "literal_string \"WitnetProxy: null implementation\"" - } - ], - "id": 6566, - "name": "require", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 4294967278, - 4294967278 - ], - "referencedDeclaration": 4294967278, - "src": "2330:7:28", - "typeDescriptions": { - "typeIdentifier": "t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$", - "typeString": "function (bool,string memory) pure" - } - }, - "id": 6574, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "2330:77:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 6575, - "nodeType": "ExpressionStatement", - "src": "2330:77:28" - }, - { - "assignments": [ - 6577 - ], - "declarations": [ - { - "constant": false, - "id": 6577, - "mutability": "mutable", - "name": "_oldImplementation", - "nameLocation": "2428:18:28", - "nodeType": "VariableDeclaration", - "scope": 6708, - "src": "2420:26:28", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 6576, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "2420:7:28", - "stateMutability": "nonpayable", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "visibility": "internal" - } - ], - "id": 6580, - "initialValue": { - "arguments": [], - "expression": { - "argumentTypes": [], - "id": 6578, - "name": "implementation", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6556, - "src": "2449:14:28", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_view$__$returns$_t_address_$", - "typeString": "function () view returns (address)" - } - }, - "id": 6579, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "2449:16:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "2420:45:28" - }, - { - "condition": { - "commonType": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "id": 6586, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftExpression": { - "id": 6581, - "name": "_oldImplementation", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6577, - "src": "2480:18:28", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "BinaryOperation", - "operator": "!=", - "rightExpression": { - "arguments": [ - { - "hexValue": "30", - "id": 6584, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "2510:1:28", - "typeDescriptions": { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - }, - "value": "0" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - } - ], - "id": 6583, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "2502:7:28", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_address_$", - "typeString": "type(address)" - }, - "typeName": { - "id": 6582, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "2502:7:28", - "typeDescriptions": {} - } - }, - "id": 6585, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "2502:10:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "src": "2480:32:28", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - "id": 6662, - "nodeType": "IfStatement", - "src": "2476:1285:28", - "trueBody": { - "id": 6661, - "nodeType": "Block", - "src": "2514:1247:28", - "statements": [ - { - "expression": { - "arguments": [ - { - "commonType": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "id": 6590, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftExpression": { - "id": 6588, - "name": "_newImplementation", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6559, - "src": "2610:18:28", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "BinaryOperation", - "operator": "!=", - "rightExpression": { - "id": 6589, - "name": "_oldImplementation", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6577, - "src": "2632:18:28", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "src": "2610:40:28", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - { - "hexValue": "5769746e657450726f78793a206e6f7468696e6720746f2075706772616465", - "id": 6591, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "2652:33:28", - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_e332eab1bae45430d1201a30c0d80d8fcb5570f9e70201a9eb7b229e17fd2084", - "typeString": "literal_string \"WitnetProxy: nothing to upgrade\"" - }, - "value": "WitnetProxy: nothing to upgrade" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bool", - "typeString": "bool" - }, - { - "typeIdentifier": "t_stringliteral_e332eab1bae45430d1201a30c0d80d8fcb5570f9e70201a9eb7b229e17fd2084", - "typeString": "literal_string \"WitnetProxy: nothing to upgrade\"" - } - ], - "id": 6587, - "name": "require", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 4294967278, - 4294967278 - ], - "referencedDeclaration": 4294967278, - "src": "2602:7:28", - "typeDescriptions": { - "typeIdentifier": "t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$", - "typeString": "function (bool,string memory) pure" - } - }, - "id": 6592, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "2602:84:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 6593, - "nodeType": "ExpressionStatement", - "src": "2602:84:28" - }, - { - "clauses": [ - { - "block": { - "id": 6607, - "nodeType": "Block", - "src": "2866:88:28", - "statements": [ - { - "expression": { - "arguments": [ - { - "id": 6603, - "name": "_isUpgradable", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6600, - "src": "2893:13:28", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - { - "hexValue": "5769746e657450726f78793a206e6f742075706772616461626c65", - "id": 6604, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "2908:29:28", - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_d96132834a96bae5cb2f32cb07f13985dcde0f2358055c198eb3065af6c5aa7f", - "typeString": "literal_string \"WitnetProxy: not upgradable\"" - }, - "value": "WitnetProxy: not upgradable" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bool", - "typeString": "bool" - }, - { - "typeIdentifier": "t_stringliteral_d96132834a96bae5cb2f32cb07f13985dcde0f2358055c198eb3065af6c5aa7f", - "typeString": "literal_string \"WitnetProxy: not upgradable\"" - } - ], - "id": 6602, - "name": "require", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 4294967278, - 4294967278 - ], - "referencedDeclaration": 4294967278, - "src": "2885:7:28", - "typeDescriptions": { - "typeIdentifier": "t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$", - "typeString": "function (bool,string memory) pure" - } - }, - "id": 6605, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "2885:53:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 6606, - "nodeType": "ExpressionStatement", - "src": "2885:53:28" - } - ] - }, - "errorName": "", - "id": 6608, - "nodeType": "TryCatchClause", - "parameters": { - "id": 6601, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 6600, - "mutability": "mutable", - "name": "_isUpgradable", - "nameLocation": "2851:13:28", - "nodeType": "VariableDeclaration", - "scope": 6608, - "src": "2846:18:28", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - }, - "typeName": { - "id": 6599, - "name": "bool", - "nodeType": "ElementaryTypeName", - "src": "2846:4:28", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - "visibility": "internal" - } - ], - "src": "2845:20:28" - }, - "src": "2837:117:28" - }, - { - "block": { - "id": 6613, - "nodeType": "Block", - "src": "2961:87:28", - "statements": [ - { - "expression": { - "arguments": [ - { - "hexValue": "5769746e657450726f78793a20756e61626c6520746f20636865636b207570677261646162696c697479", - "id": 6610, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "2987:44:28", - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_7f859058ad3ee4e192700ff813ed67dc892a0c7de91510ee584a0ac25fc982fc", - "typeString": "literal_string \"WitnetProxy: unable to check upgradability\"" - }, - "value": "WitnetProxy: unable to check upgradability" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_stringliteral_7f859058ad3ee4e192700ff813ed67dc892a0c7de91510ee584a0ac25fc982fc", - "typeString": "literal_string \"WitnetProxy: unable to check upgradability\"" - } - ], - "id": 6609, - "name": "revert", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 4294967277, - 4294967277 - ], - "referencedDeclaration": 4294967277, - "src": "2980:6:28", - "typeDescriptions": { - "typeIdentifier": "t_function_revert_pure$_t_string_memory_ptr_$returns$__$", - "typeString": "function (string memory) pure" - } - }, - "id": 6611, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "2980:52:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 6612, - "nodeType": "ExpressionStatement", - "src": "2980:52:28" - } - ] - }, - "errorName": "", - "id": 6614, - "nodeType": "TryCatchClause", - "src": "2955:93:28" - } - ], - "externalCall": { - "arguments": [], - "expression": { - "argumentTypes": [], - "expression": { - "arguments": [ - { - "id": 6595, - "name": "_oldImplementation", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6577, - "src": "2802:18:28", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 6594, - "name": "Upgradeable", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 23590, - "src": "2790:11:28", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_contract$_Upgradeable_$23590_$", - "typeString": "type(contract Upgradeable)" - } - }, - "id": 6596, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "typeConversion", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "2790:31:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_contract$_Upgradeable_$23590", - "typeString": "contract Upgradeable" - } - }, - "id": 6597, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberLocation": "2822:12:28", - "memberName": "isUpgradable", - "nodeType": "MemberAccess", - "referencedDeclaration": 23569, - "src": "2790:44:28", - "typeDescriptions": { - "typeIdentifier": "t_function_external_view$__$returns$_t_bool_$", - "typeString": "function () view external returns (bool)" - } - }, - "id": 6598, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "2790:46:28", - "tryCall": true, - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - "id": 6615, - "nodeType": "TryStatement", - "src": "2786:262:28" - }, - { - "assignments": [ - 6617, - 6619 - ], - "declarations": [ - { - "constant": false, - "id": 6617, - "mutability": "mutable", - "name": "_wasCalled", - "nameLocation": "3166:10:28", - "nodeType": "VariableDeclaration", - "scope": 6661, - "src": "3161:15:28", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - }, - "typeName": { - "id": 6616, - "name": "bool", - "nodeType": "ElementaryTypeName", - "src": "3161:4:28", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - "visibility": "internal" - }, - { - "constant": false, - "id": 6619, - "mutability": "mutable", - "name": "_result", - "nameLocation": "3191:7:28", - "nodeType": "VariableDeclaration", - "scope": 6661, - "src": "3178:20:28", - "stateVariable": false, - "storageLocation": "memory", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes" - }, - "typeName": { - "id": 6618, - "name": "bytes", - "nodeType": "ElementaryTypeName", - "src": "3178:5:28", - "typeDescriptions": { - "typeIdentifier": "t_bytes_storage_ptr", - "typeString": "bytes" - } - }, - "visibility": "internal" - } - ], - "id": 6629, - "initialValue": { - "arguments": [ - { - "arguments": [ - { - "hexValue": "697355706772616461626c6546726f6d286164647265737329", - "id": 6624, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "3298:27:28", - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_6b58960af5008b519145bb1cb07a67ee0927d8e642573c92f5babc4d0c2721d7", - "typeString": "literal_string \"isUpgradableFrom(address)\"" - }, - "value": "isUpgradableFrom(address)" - }, - { - "expression": { - "id": 6625, - "name": "msg", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 4294967281, - "src": "3348:3:28", - "typeDescriptions": { - "typeIdentifier": "t_magic_message", - "typeString": "msg" - } - }, - "id": 6626, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberLocation": "3352:6:28", - "memberName": "sender", - "nodeType": "MemberAccess", - "src": "3348:10:28", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_stringliteral_6b58960af5008b519145bb1cb07a67ee0927d8e642573c92f5babc4d0c2721d7", - "typeString": "literal_string \"isUpgradableFrom(address)\"" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "expression": { - "id": 6622, - "name": "abi", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 4294967295, - "src": "3252:3:28", - "typeDescriptions": { - "typeIdentifier": "t_magic_abi", - "typeString": "abi" - } - }, - "id": 6623, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "memberLocation": "3256:19:28", - "memberName": "encodeWithSignature", - "nodeType": "MemberAccess", - "src": "3252:23:28", - "typeDescriptions": { - "typeIdentifier": "t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$", - "typeString": "function (string memory) pure returns (bytes memory)" - } - }, - "id": 6627, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "3252:125:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - ], - "expression": { - "id": 6620, - "name": "_oldImplementation", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6577, - "src": "3202:18:28", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "id": 6621, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberLocation": "3221:12:28", - "memberName": "delegatecall", - "nodeType": "MemberAccess", - "src": "3202:31:28", - "typeDescriptions": { - "typeIdentifier": "t_function_baredelegatecall_nonpayable$_t_bytes_memory_ptr_$returns$_t_bool_$_t_bytes_memory_ptr_$", - "typeString": "function (bytes memory) returns (bool,bytes memory)" - } - }, - "id": 6628, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "3202:190:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_tuple$_t_bool_$_t_bytes_memory_ptr_$", - "typeString": "tuple(bool,bytes memory)" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "3160:232:28" - }, - { - "expression": { - "arguments": [ - { - "id": 6631, - "name": "_wasCalled", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6617, - "src": "3415:10:28", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - { - "hexValue": "5769746e657450726f78793a206e6f7420636f6d706c69616e74", - "id": 6632, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "3427:28:28", - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_fe0c5d56f2e637bc6ae9d29f1058c00159080f3dd6202013ecdbcca6e4740a65", - "typeString": "literal_string \"WitnetProxy: not compliant\"" - }, - "value": "WitnetProxy: not compliant" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bool", - "typeString": "bool" - }, - { - "typeIdentifier": "t_stringliteral_fe0c5d56f2e637bc6ae9d29f1058c00159080f3dd6202013ecdbcca6e4740a65", - "typeString": "literal_string \"WitnetProxy: not compliant\"" - } - ], - "id": 6630, - "name": "require", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 4294967278, - 4294967278 - ], - "referencedDeclaration": 4294967278, - "src": "3407:7:28", - "typeDescriptions": { - "typeIdentifier": "t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$", - "typeString": "function (bool,string memory) pure" - } - }, - "id": 6633, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "3407:49:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 6634, - "nodeType": "ExpressionStatement", - "src": "3407:49:28" - }, - { - "expression": { - "arguments": [ - { - "arguments": [ - { - "id": 6638, - "name": "_result", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6619, - "src": "3490:7:28", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - }, - { - "components": [ - { - "id": 6640, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "3500:4:28", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bool_$", - "typeString": "type(bool)" - }, - "typeName": { - "id": 6639, - "name": "bool", - "nodeType": "ElementaryTypeName", - "src": "3500:4:28", - "typeDescriptions": {} - } - } - ], - "id": 6641, - "isConstant": false, - "isInlineArray": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "TupleExpression", - "src": "3499:6:28", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bool_$", - "typeString": "type(bool)" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - }, - { - "typeIdentifier": "t_type$_t_bool_$", - "typeString": "type(bool)" - } - ], - "expression": { - "id": 6636, - "name": "abi", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 4294967295, - "src": "3479:3:28", - "typeDescriptions": { - "typeIdentifier": "t_magic_abi", - "typeString": "abi" - } - }, - "id": 6637, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "memberLocation": "3483:6:28", - "memberName": "decode", - "nodeType": "MemberAccess", - "src": "3479:10:28", - "typeDescriptions": { - "typeIdentifier": "t_function_abidecode_pure$__$returns$__$", - "typeString": "function () pure" - } - }, - "id": 6642, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "3479:27:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - { - "hexValue": "5769746e657450726f78793a206e6f7420617574686f72697a6564", - "id": 6643, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "3508:29:28", - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_ba8d4d661ce88eb2915ba133e6cad533938b754d7b66d8253879ef2c2193ecb2", - "typeString": "literal_string \"WitnetProxy: not authorized\"" - }, - "value": "WitnetProxy: not authorized" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bool", - "typeString": "bool" - }, - { - "typeIdentifier": "t_stringliteral_ba8d4d661ce88eb2915ba133e6cad533938b754d7b66d8253879ef2c2193ecb2", - "typeString": "literal_string \"WitnetProxy: not authorized\"" - } - ], - "id": 6635, - "name": "require", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 4294967278, - 4294967278 - ], - "referencedDeclaration": 4294967278, - "src": "3471:7:28", - "typeDescriptions": { - "typeIdentifier": "t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$", - "typeString": "function (bool,string memory) pure" - } - }, - "id": 6644, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "3471:67:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 6645, - "nodeType": "ExpressionStatement", - "src": "3471:67:28" - }, - { - "expression": { - "arguments": [ - { - "commonType": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "id": 6657, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftExpression": { - "arguments": [], - "expression": { - "argumentTypes": [], - "expression": { - "arguments": [ - { - "id": 6648, - "name": "_oldImplementation", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6577, - "src": "3591:18:28", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 6647, - "name": "Upgradeable", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 23590, - "src": "3579:11:28", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_contract$_Upgradeable_$23590_$", - "typeString": "type(contract Upgradeable)" - } - }, - "id": 6649, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "typeConversion", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "3579:31:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_contract$_Upgradeable_$23590", - "typeString": "contract Upgradeable" - } - }, - "id": 6650, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberLocation": "3611:13:28", - "memberName": "proxiableUUID", - "nodeType": "MemberAccess", - "referencedDeclaration": 23437, - "src": "3579:45:28", - "typeDescriptions": { - "typeIdentifier": "t_function_external_view$__$returns$_t_bytes32_$", - "typeString": "function () view external returns (bytes32)" - } - }, - "id": 6651, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "3579:47:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "nodeType": "BinaryOperation", - "operator": "==", - "rightExpression": { - "arguments": [], - "expression": { - "argumentTypes": [], - "expression": { - "arguments": [ - { - "id": 6653, - "name": "_newImplementation", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6559, - "src": "3642:18:28", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 6652, - "name": "Upgradeable", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 23590, - "src": "3630:11:28", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_contract$_Upgradeable_$23590_$", - "typeString": "type(contract Upgradeable)" - } - }, - "id": 6654, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "typeConversion", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "3630:31:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_contract$_Upgradeable_$23590", - "typeString": "contract Upgradeable" - } - }, - "id": 6655, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberLocation": "3662:13:28", - "memberName": "proxiableUUID", - "nodeType": "MemberAccess", - "referencedDeclaration": 23437, - "src": "3630:45:28", - "typeDescriptions": { - "typeIdentifier": "t_function_external_view$__$returns$_t_bytes32_$", - "typeString": "function () view external returns (bytes32)" - } - }, - "id": 6656, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "3630:47:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "src": "3579:98:28", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - { - "hexValue": "5769746e657450726f78793a2070726f786961626c655555494473206d69736d61746368", - "id": 6658, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "3696:38:28", - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_f3c1ad1fa1688d47e62cc4dd5b4be101315ef47e38e05aa3a37a4ef2e1cec0a8", - "typeString": "literal_string \"WitnetProxy: proxiableUUIDs mismatch\"" - }, - "value": "WitnetProxy: proxiableUUIDs mismatch" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bool", - "typeString": "bool" - }, - { - "typeIdentifier": "t_stringliteral_f3c1ad1fa1688d47e62cc4dd5b4be101315ef47e38e05aa3a37a4ef2e1cec0a8", - "typeString": "literal_string \"WitnetProxy: proxiableUUIDs mismatch\"" - } - ], - "id": 6646, - "name": "require", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 4294967278, - 4294967278 - ], - "referencedDeclaration": 4294967278, - "src": "3553:7:28", - "typeDescriptions": { - "typeIdentifier": "t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$", - "typeString": "function (bool,string memory) pure" - } - }, - "id": 6659, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "3553:196:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 6660, - "nodeType": "ExpressionStatement", - "src": "3553:196:28" - } - ] - } - }, - { - "assignments": [ - 6664, - null - ], - "declarations": [ - { - "constant": false, - "id": 6664, - "mutability": "mutable", - "name": "_wasInitialized", - "nameLocation": "3851:15:28", - "nodeType": "VariableDeclaration", - "scope": 6708, - "src": "3846:20:28", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - }, - "typeName": { - "id": 6663, - "name": "bool", - "nodeType": "ElementaryTypeName", - "src": "3846:4:28", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - "visibility": "internal" - }, - null - ], - "id": 6673, - "initialValue": { - "arguments": [ - { - "arguments": [ - { - "hexValue": "696e697469616c697a6528627974657329", - "id": 6669, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "3959:19:28", - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_439fab91f8ccf5be59586b9cf7bb7786c67a661a95ce1cfc146c1ed62922ae26", - "typeString": "literal_string \"initialize(bytes)\"" - }, - "value": "initialize(bytes)" - }, - { - "id": 6670, - "name": "_initData", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6561, - "src": "3997:9:28", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_stringliteral_439fab91f8ccf5be59586b9cf7bb7786c67a661a95ce1cfc146c1ed62922ae26", - "typeString": "literal_string \"initialize(bytes)\"" - }, - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - ], - "expression": { - "id": 6667, - "name": "abi", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 4294967295, - "src": "3917:3:28", - "typeDescriptions": { - "typeIdentifier": "t_magic_abi", - "typeString": "abi" - } - }, - "id": 6668, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "memberLocation": "3921:19:28", - "memberName": "encodeWithSignature", - "nodeType": "MemberAccess", - "src": "3917:23:28", - "typeDescriptions": { - "typeIdentifier": "t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$", - "typeString": "function (string memory) pure returns (bytes memory)" - } - }, - "id": 6671, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "3917:104:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - ], - "expression": { - "id": 6665, - "name": "_newImplementation", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6559, - "src": "3871:18:28", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "id": 6666, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberLocation": "3890:12:28", - "memberName": "delegatecall", - "nodeType": "MemberAccess", - "src": "3871:31:28", - "typeDescriptions": { - "typeIdentifier": "t_function_baredelegatecall_nonpayable$_t_bytes_memory_ptr_$returns$_t_bool_$_t_bytes_memory_ptr_$", - "typeString": "function (bytes memory) returns (bool,bytes memory)" - } - }, - "id": 6672, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "3871:161:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_tuple$_t_bool_$_t_bytes_memory_ptr_$", - "typeString": "tuple(bool,bytes memory)" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "3845:187:28" - }, - { - "expression": { - "arguments": [ - { - "id": 6675, - "name": "_wasInitialized", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6664, - "src": "4051:15:28", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - { - "hexValue": "5769746e657450726f78793a20756e61626c6520746f20696e697469616c697a65", - "id": 6676, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "4068:35:28", - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_55e9f07b665adf0e8c084720fbd831f583a2d75f5997894b64a77e28a0171f3c", - "typeString": "literal_string \"WitnetProxy: unable to initialize\"" - }, - "value": "WitnetProxy: unable to initialize" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bool", - "typeString": "bool" - }, - { - "typeIdentifier": "t_stringliteral_55e9f07b665adf0e8c084720fbd831f583a2d75f5997894b64a77e28a0171f3c", - "typeString": "literal_string \"WitnetProxy: unable to initialize\"" - } - ], - "id": 6674, - "name": "require", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 4294967278, - 4294967278 - ], - "referencedDeclaration": 4294967278, - "src": "4043:7:28", - "typeDescriptions": { - "typeIdentifier": "t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$", - "typeString": "function (bool,string memory) pure" - } - }, - "id": 6677, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "4043:61:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 6678, - "nodeType": "ExpressionStatement", - "src": "4043:61:28" - }, - { - "expression": { - "id": 6683, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftHandSide": { - "expression": { - "arguments": [], - "expression": { - "argumentTypes": [], - "id": 6679, - "name": "__proxySlot", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6718, - "src": "4199:11:28", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_pure$__$returns$_t_struct$_ProxiableSlot_$23442_storage_ptr_$", - "typeString": "function () pure returns (struct Proxiable.ProxiableSlot storage pointer)" - } - }, - "id": 6680, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "4199:13:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_struct$_ProxiableSlot_$23442_storage_ptr", - "typeString": "struct Proxiable.ProxiableSlot storage pointer" - } - }, - "id": 6681, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": true, - "memberLocation": "4213:14:28", - "memberName": "implementation", - "nodeType": "MemberAccess", - "referencedDeclaration": 23439, - "src": "4199:28:28", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "Assignment", - "operator": "=", - "rightHandSide": { - "id": 6682, - "name": "_newImplementation", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6559, - "src": "4230:18:28", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "src": "4199:49:28", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "id": 6684, - "nodeType": "ExpressionStatement", - "src": "4199:49:28" - }, - { - "eventCall": { - "arguments": [ - { - "id": 6686, - "name": "_newImplementation", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6559, - "src": "4273:18:28", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 6685, - "name": "Upgraded", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6525, - "src": "4264:8:28", - "typeDescriptions": { - "typeIdentifier": "t_function_event_nonpayable$_t_address_$returns$__$", - "typeString": "function (address)" - } - }, - "id": 6687, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "4264:28:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 6688, - "nodeType": "EmitStatement", - "src": "4259:33:28" - }, - { - "clauses": [ - { - "block": { - "id": 6699, - "nodeType": "Block", - "src": "4485:47:28", - "statements": [ - { - "expression": { - "id": 6697, - "name": "_isUpgradable", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6695, - "src": "4507:13:28", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - "functionReturnParameters": 6565, - "id": 6698, - "nodeType": "Return", - "src": "4500:20:28" - } - ] - }, - "errorName": "", - "id": 6700, - "nodeType": "TryCatchClause", - "parameters": { - "id": 6696, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 6695, - "mutability": "mutable", - "name": "_isUpgradable", - "nameLocation": "4470:13:28", - "nodeType": "VariableDeclaration", - "scope": 6700, - "src": "4465:18:28", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - }, - "typeName": { - "id": 6694, - "name": "bool", - "nodeType": "ElementaryTypeName", - "src": "4465:4:28", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - "visibility": "internal" - } - ], - "src": "4464:20:28" - }, - "src": "4456:76:28" - }, - { - "block": { - "id": 6705, - "nodeType": "Block", - "src": "4548:64:28", - "statements": [ - { - "expression": { - "arguments": [ - { - "hexValue": "5769746e657450726f78793a206e6f7420636f6d706c69616e74", - "id": 6702, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "4571:28:28", - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_fe0c5d56f2e637bc6ae9d29f1058c00159080f3dd6202013ecdbcca6e4740a65", - "typeString": "literal_string \"WitnetProxy: not compliant\"" - }, - "value": "WitnetProxy: not compliant" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_stringliteral_fe0c5d56f2e637bc6ae9d29f1058c00159080f3dd6202013ecdbcca6e4740a65", - "typeString": "literal_string \"WitnetProxy: not compliant\"" - } - ], - "id": 6701, - "name": "revert", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 4294967277, - 4294967277 - ], - "referencedDeclaration": 4294967277, - "src": "4563:6:28", - "typeDescriptions": { - "typeIdentifier": "t_function_revert_pure$_t_string_memory_ptr_$returns$__$", - "typeString": "function (string memory) pure" - } - }, - "id": 6703, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "4563:37:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 6704, - "nodeType": "ExpressionStatement", - "src": "4563:37:28" - } - ] - }, - "errorName": "", - "id": 6706, - "nodeType": "TryCatchClause", - "src": "4542:70:28" - } - ], - "externalCall": { - "arguments": [], - "expression": { - "argumentTypes": [], - "expression": { - "arguments": [ - { - "id": 6690, - "name": "_newImplementation", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 6559, - "src": "4421:18:28", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 6689, - "name": "Upgradeable", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 23590, - "src": "4409:11:28", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_contract$_Upgradeable_$23590_$", - "typeString": "type(contract Upgradeable)" - } - }, - "id": 6691, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "typeConversion", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "4409:31:28", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_contract$_Upgradeable_$23590", - "typeString": "contract Upgradeable" - } - }, - "id": 6692, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberLocation": "4441:12:28", - "memberName": "isUpgradable", - "nodeType": "MemberAccess", - "referencedDeclaration": 23569, - "src": "4409:44:28", - "typeDescriptions": { - "typeIdentifier": "t_function_external_view$__$returns$_t_bool_$", - "typeString": "function () view external returns (bool)" - } - }, - "id": 6693, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "4409:46:28", - "tryCall": true, - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - "id": 6707, - "nodeType": "TryStatement", - "src": "4405:207:28" - } - ] - }, - "documentation": { - "id": 6557, - "nodeType": "StructuredDocumentation", - "src": "1879:280:28", - "text": "Upgrades the `implementation` address.\n @param _newImplementation New implementation address.\n @param _initData Raw data with which new implementation will be initialized.\n @return Returns whether new implementation would be further upgradable, or not." - }, - "functionSelector": "6fbc15e9", - "id": 6709, - "implemented": true, - "kind": "function", - "modifiers": [], - "name": "upgradeTo", - "nameLocation": "2174:9:28", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 6562, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 6559, - "mutability": "mutable", - "name": "_newImplementation", - "nameLocation": "2192:18:28", - "nodeType": "VariableDeclaration", - "scope": 6709, - "src": "2184:26:28", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 6558, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "2184:7:28", - "stateMutability": "nonpayable", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "visibility": "internal" - }, - { - "constant": false, - "id": 6561, - "mutability": "mutable", - "name": "_initData", - "nameLocation": "2225:9:28", - "nodeType": "VariableDeclaration", - "scope": 6709, - "src": "2212:22:28", - "stateVariable": false, - "storageLocation": "memory", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes" - }, - "typeName": { - "id": 6560, - "name": "bytes", - "nodeType": "ElementaryTypeName", - "src": "2212:5:28", - "typeDescriptions": { - "typeIdentifier": "t_bytes_storage_ptr", - "typeString": "bytes" - } - }, - "visibility": "internal" - } - ], - "src": "2183:52:28" - }, - "returnParameters": { - "id": 6565, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 6564, - "mutability": "mutable", - "name": "", - "nameLocation": "-1:-1:-1", - "nodeType": "VariableDeclaration", - "scope": 6709, - "src": "2261:4:28", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - }, - "typeName": { - "id": 6563, - "name": "bool", - "nodeType": "ElementaryTypeName", - "src": "2261:4:28", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - "visibility": "internal" - } - ], - "src": "2260:6:28" - }, - "scope": 6719, - "src": "2165:2454:28", - "stateMutability": "nonpayable", - "virtual": false, - "visibility": "public" - }, - { - "body": { - "id": 6717, - "nodeType": "Block", - "src": "4826:213:28", - "statements": [ - { - "AST": { - "nodeType": "YulBlock", - "src": "4846:186:28", - "statements": [ - { - "nodeType": "YulAssignment", - "src": "4941:80:28", - "value": { - "kind": "number", - "nodeType": "YulLiteral", - "src": "4955:66:28", - "type": "", - "value": "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc" - }, - "variableNames": [ - { - "name": "_slot.slot", - "nodeType": "YulIdentifier", - "src": "4941:10:28" - } - ] - } - ] - }, - "evmVersion": "london", - "externalReferences": [ - { - "declaration": 6714, - "isOffset": false, - "isSlot": true, - "src": "4941:10:28", - "suffix": "slot", - "valueSize": 1 - } - ], - "id": 6716, - "nodeType": "InlineAssembly", - "src": "4837:195:28" - } - ] - }, - "documentation": { - "id": 6710, - "nodeType": "StructuredDocumentation", - "src": "4627:109:28", - "text": "@dev Complying with EIP-1967, retrieves storage struct containing proxy's current implementation address." - }, - "id": 6718, - "implemented": true, - "kind": "function", - "modifiers": [], - "name": "__proxySlot", - "nameLocation": "4751:11:28", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 6711, - "nodeType": "ParameterList", - "parameters": [], - "src": "4762:2:28" - }, - "returnParameters": { - "id": 6715, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 6714, - "mutability": "mutable", - "name": "_slot", - "nameLocation": "4819:5:28", - "nodeType": "VariableDeclaration", - "scope": 6718, - "src": "4787:37:28", - "stateVariable": false, - "storageLocation": "storage", - "typeDescriptions": { - "typeIdentifier": "t_struct$_ProxiableSlot_$23442_storage_ptr", - "typeString": "struct Proxiable.ProxiableSlot" - }, - "typeName": { - "id": 6713, - "nodeType": "UserDefinedTypeName", - "pathNode": { - "id": 6712, - "name": "Proxiable.ProxiableSlot", - "nameLocations": [ - "4787:9:28", - "4797:13:28" - ], - "nodeType": "IdentifierPath", - "referencedDeclaration": 23442, - "src": "4787:23:28" - }, - "referencedDeclaration": 23442, - "src": "4787:23:28", - "typeDescriptions": { - "typeIdentifier": "t_struct$_ProxiableSlot_$23442_storage_ptr", - "typeString": "struct Proxiable.ProxiableSlot" - } - }, - "visibility": "internal" - } - ], - "src": "4786:39:28" - }, - "scope": 6719, - "src": "4742:297:28", - "stateMutability": "pure", - "virtual": false, - "visibility": "private" - } - ], - "scope": 6720, - "src": "244:4800:28", - "usedErrors": [] - } - ], - "src": "35:5011:28" - }, - "compiler": { - "name": "solc", - "version": "0.8.17+commit.8df45f5f.Emscripten.clang" - }, - "networks": {}, - "schemaVersion": "3.4.13", - "updatedAt": "2023-04-25T18:38:54.596Z", - "networkType": "ethereum", - "devdoc": { - "author": "The Witnet Foundation.", - "kind": "dev", - "methods": { - "upgradeTo(address,bytes)": { - "params": { - "_initData": "Raw data with which new implementation will be initialized.", - "_newImplementation": "New implementation address." - }, - "returns": { - "_0": "Returns whether new implementation would be further upgradable, or not." - } - } - }, - "title": "WitnetProxy: upgradable delegate-proxy contract. ", - "version": 1 - }, - "userdoc": { - "events": { - "Upgraded(address)": { - "notice": "Event emitted every time the implementation gets updated." - } - }, - "kind": "user", - "methods": { - "constructor": { - "notice": "Constructor with no params as to ease eventual support of Singleton pattern (i.e. ERC-2470)." - }, - "implementation()": { - "notice": "Returns proxy's current implementation address." - }, - "upgradeTo(address,bytes)": { - "notice": "Upgrades the `implementation` address." - } - }, - "version": 1 - } -} \ No newline at end of file diff --git a/migrations/abis/WitnetRandomness.json b/migrations/abis/WitnetRandomness.json new file mode 100644 index 000000000..622be3e19 --- /dev/null +++ b/migrations/abis/WitnetRandomness.json @@ -0,0 +1,649 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_operator", + "type": "address" + }, + { + "internalType": "contract WitnetRequestBoard", + "name": "_wrb", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "range", + "type": "uint256" + } + ], + "name": "IndexOutOfBounds", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "InvalidLengthEncoding", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "read", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + } + ], + "name": "UnexpectedMajorType", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "by", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "self", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "clone", + "type": "address" + } + ], + "name": "Cloned", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "prevBlock", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "witnetQueryId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "witnetRequestHash", + "type": "bytes32" + } + ], + "name": "Randomized", + "type": "event" + }, + { + "inputs": [], + "name": "cloned", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "latestRandomizeBlock", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "self", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "witnetRandomnessRequest", + "outputs": [ + { + "internalType": "contract WitnetRequest", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "clone", + "outputs": [ + { + "internalType": "contract WitnetRandomness", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_salt", + "type": "bytes32" + } + ], + "name": "cloneDeterministic", + "outputs": [ + { + "internalType": "contract WitnetRandomness", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_initData", + "type": "bytes" + } + ], + "name": "initializeClone", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "acceptOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "numWitnesses", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minConsensusPercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "witnessReward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "witnessCollateral", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minerCommitRevealFee", + "type": "uint256" + } + ], + "internalType": "struct WitnetV2.RadonSLA", + "name": "_radonSLA", + "type": "tuple" + } + ], + "name": "settleWitnetRandomnessSLA", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_gasPrice", + "type": "uint256" + } + ], + "name": "estimateRandomizeFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_block", + "type": "uint256" + } + ], + "name": "getRandomizeData", + "outputs": [ + { + "internalType": "address", + "name": "_from", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_prevBlock", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_nextBlock", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_block", + "type": "uint256" + } + ], + "name": "getRandomnessAfter", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_block", + "type": "uint256" + } + ], + "name": "getRandomnessNextBlock", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_block", + "type": "uint256" + } + ], + "name": "getRandomnessPrevBlock", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_block", + "type": "uint256" + } + ], + "name": "isRandomized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "_range", + "type": "uint32" + }, + { + "internalType": "uint256", + "name": "_nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_block", + "type": "uint256" + } + ], + "name": "random", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "_range", + "type": "uint32" + }, + { + "internalType": "uint256", + "name": "_nonce", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "_seed", + "type": "bytes32" + } + ], + "name": "random", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "randomize", + "outputs": [ + { + "internalType": "uint256", + "name": "_usedFunds", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_block", + "type": "uint256" + } + ], + "name": "upgradeRandomizeFee", + "outputs": [ + { + "internalType": "uint256", + "name": "_usedFunds", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "witnet", + "outputs": [ + { + "internalType": "contract WitnetRequestBoard", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "witnetRandomnessSLA", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "numWitnesses", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minConsensusPercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "witnessReward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "witnessCollateral", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minerCommitRevealFee", + "type": "uint256" + } + ], + "internalType": "struct WitnetV2.RadonSLA", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "initialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/migrations/abis/WitnetRequest.json b/migrations/abis/WitnetRequest.json new file mode 100644 index 000000000..153fa6057 --- /dev/null +++ b/migrations/abis/WitnetRequest.json @@ -0,0 +1,400 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "request", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "string[][]", + "name": "args", + "type": "string[][]" + } + ], + "name": "WitnetRequestBuilt", + "type": "event" + }, + { + "inputs": [], + "name": "aggregator", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string[][]", + "name": "args", + "type": "string[][]" + } + ], + "name": "buildRequest", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "class", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "contract WitnetRequestFactory", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRadonAggregator", + "outputs": [ + { + "components": [ + { + "internalType": "enum WitnetV2.RadonReducerOpcodes", + "name": "opcode", + "type": "uint8" + }, + { + "components": [ + { + "internalType": "enum WitnetV2.RadonFilterOpcodes", + "name": "opcode", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "args", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonFilter[]", + "name": "filters", + "type": "tuple[]" + }, + { + "internalType": "bytes", + "name": "script", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonReducer", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "getRadonRetrievalByIndex", + "outputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "argsCount", + "type": "uint8" + }, + { + "internalType": "enum WitnetV2.DataRequestMethods", + "name": "method", + "type": "uint8" + }, + { + "internalType": "enum WitnetV2.RadonDataTypes", + "name": "resultDataType", + "type": "uint8" + }, + { + "internalType": "string", + "name": "url", + "type": "string" + }, + { + "internalType": "string", + "name": "body", + "type": "string" + }, + { + "internalType": "string[2][]", + "name": "headers", + "type": "string[2][]" + }, + { + "internalType": "bytes", + "name": "script", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonRetrieval", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRadonRetrievalsCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRadonTally", + "outputs": [ + { + "components": [ + { + "internalType": "enum WitnetV2.RadonReducerOpcodes", + "name": "opcode", + "type": "uint8" + }, + { + "components": [ + { + "internalType": "enum WitnetV2.RadonFilterOpcodes", + "name": "opcode", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "args", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonFilter[]", + "name": "filters", + "type": "tuple[]" + }, + { + "internalType": "bytes", + "name": "script", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonReducer", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "parameterized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "registry", + "outputs": [ + { + "internalType": "contract WitnetBytecodes", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "resultDataMaxSize", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "resultDataType", + "outputs": [ + { + "internalType": "enum WitnetV2.RadonDataTypes", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "retrievals", + "outputs": [ + { + "internalType": "bytes32[]", + "name": "", + "type": "bytes32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "tally", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string[][]", + "name": "args", + "type": "string[][]" + } + ], + "name": "verifyRadonRequest", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "template", + "outputs": [ + { + "internalType": "contract WitnetRequestTemplate", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "args", + "outputs": [ + { + "internalType": "string[][]", + "name": "", + "type": "string[][]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bytecode", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "radHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + } + ] \ No newline at end of file diff --git a/migrations/abis/WitnetRequestBoard.json b/migrations/abis/WitnetRequestBoard.json new file mode 100644 index 000000000..e01c5649f --- /dev/null +++ b/migrations/abis/WitnetRequestBoard.json @@ -0,0 +1,1088 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "queryId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "from", + "type": "address" + } + ], + "name": "DeletedQuery", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "queryId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "from", + "type": "address" + } + ], + "name": "PostedRequest", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "queryId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "from", + "type": "address" + } + ], + "name": "PostedResult", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "cursor", + "type": "uint256" + } + ], + "internalType": "struct WitnetBuffer.Buffer", + "name": "buffer", + "type": "tuple" + }, + { + "internalType": "uint8", + "name": "initialByte", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "majorType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "additionalInformation", + "type": "uint8" + }, + { + "internalType": "uint64", + "name": "len", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "tag", + "type": "uint64" + } + ], + "internalType": "struct WitnetCBOR.CBOR", + "name": "value", + "type": "tuple" + } + ], + "internalType": "struct Witnet.Result", + "name": "_result", + "type": "tuple" + } + ], + "name": "asBytes32", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "cursor", + "type": "uint256" + } + ], + "internalType": "struct WitnetBuffer.Buffer", + "name": "buffer", + "type": "tuple" + }, + { + "internalType": "uint8", + "name": "initialByte", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "majorType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "additionalInformation", + "type": "uint8" + }, + { + "internalType": "uint64", + "name": "len", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "tag", + "type": "uint64" + } + ], + "internalType": "struct WitnetCBOR.CBOR", + "name": "value", + "type": "tuple" + } + ], + "internalType": "struct Witnet.Result", + "name": "_result", + "type": "tuple" + } + ], + "name": "asErrorMessage", + "outputs": [ + { + "internalType": "enum Witnet.ResultErrorCodes", + "name": "", + "type": "uint8" + }, + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "cursor", + "type": "uint256" + } + ], + "internalType": "struct WitnetBuffer.Buffer", + "name": "buffer", + "type": "tuple" + }, + { + "internalType": "uint8", + "name": "initialByte", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "majorType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "additionalInformation", + "type": "uint8" + }, + { + "internalType": "uint64", + "name": "len", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "tag", + "type": "uint64" + } + ], + "internalType": "struct WitnetCBOR.CBOR", + "name": "value", + "type": "tuple" + } + ], + "internalType": "struct Witnet.Result", + "name": "_result", + "type": "tuple" + } + ], + "name": "asUint64", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_queryId", + "type": "uint256" + } + ], + "name": "checkResultError", + "outputs": [ + { + "components": [ + { + "internalType": "enum Witnet.ResultErrorCodes", + "name": "code", + "type": "uint8" + }, + { + "internalType": "string", + "name": "reason", + "type": "string" + } + ], + "internalType": "struct Witnet.ResultError", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_queryId", + "type": "uint256" + } + ], + "name": "checkResultStatus", + "outputs": [ + { + "internalType": "enum Witnet.ResultStatus", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_queryId", + "type": "uint256" + } + ], + "name": "deleteQuery", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "reporter", + "type": "address" + }, + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "drTxHash", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "cborBytes", + "type": "bytes" + } + ], + "internalType": "struct Witnet.Response", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_gasPrice", + "type": "uint256" + } + ], + "name": "estimateReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getNextQueryId", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_queryId", + "type": "uint256" + } + ], + "name": "getQueryData", + "outputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "slaHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "gasprice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + } + ], + "internalType": "struct Witnet.Request", + "name": "request", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "reporter", + "type": "address" + }, + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "drTxHash", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "cborBytes", + "type": "bytes" + } + ], + "internalType": "struct Witnet.Response", + "name": "response", + "type": "tuple" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + } + ], + "internalType": "struct Witnet.Query", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_queryId", + "type": "uint256" + } + ], + "name": "getQueryStatus", + "outputs": [ + { + "internalType": "enum Witnet.QueryStatus", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "cursor", + "type": "uint256" + } + ], + "internalType": "struct WitnetBuffer.Buffer", + "name": "buffer", + "type": "tuple" + }, + { + "internalType": "uint8", + "name": "initialByte", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "majorType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "additionalInformation", + "type": "uint8" + }, + { + "internalType": "uint64", + "name": "len", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "tag", + "type": "uint64" + } + ], + "internalType": "struct WitnetCBOR.CBOR", + "name": "value", + "type": "tuple" + } + ], + "internalType": "struct Witnet.Result", + "name": "_result", + "type": "tuple" + } + ], + "name": "isOk", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "slaHash", + "type": "bytes32" + } + ], + "name": "postRequest", + "outputs": [ + { + "internalType": "uint256", + "name": "_queryId", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IWitnetRequest", + "name": "addr", + "type": "address" + } + ], + "name": "postRequest", + "outputs": [ + { + "internalType": "uint256", + "name": "_queryId", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "numWitnesses", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minConsensusPercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "witnessReward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "witnessCollateral", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minerCommitRevealFee", + "type": "uint256" + } + ], + "internalType": "struct WitnetV2.RadonSLA", + "name": "slaParams", + "type": "tuple" + } + ], + "name": "postRequest", + "outputs": [ + { + "internalType": "uint256", + "name": "_queryId", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_queryId", + "type": "uint256" + } + ], + "name": "readRequest", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "slaHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "gasprice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + } + ], + "internalType": "struct Witnet.Request", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_queryId", + "type": "uint256" + } + ], + "name": "readRequestBytecode", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_queryId", + "type": "uint256" + } + ], + "name": "readRequestGasPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_queryId", + "type": "uint256" + } + ], + "name": "readRequestReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_queryId", + "type": "uint256" + } + ], + "name": "readResponse", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "reporter", + "type": "address" + }, + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "drTxHash", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "cborBytes", + "type": "bytes" + } + ], + "internalType": "struct Witnet.Response", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_queryId", + "type": "uint256" + } + ], + "name": "readResponseDrTxHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_queryId", + "type": "uint256" + } + ], + "name": "readResponseReporter", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_queryId", + "type": "uint256" + } + ], + "name": "readResponseResult", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "cursor", + "type": "uint256" + } + ], + "internalType": "struct WitnetBuffer.Buffer", + "name": "buffer", + "type": "tuple" + }, + { + "internalType": "uint8", + "name": "initialByte", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "majorType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "additionalInformation", + "type": "uint8" + }, + { + "internalType": "uint64", + "name": "len", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "tag", + "type": "uint64" + } + ], + "internalType": "struct WitnetCBOR.CBOR", + "name": "value", + "type": "tuple" + } + ], + "internalType": "struct Witnet.Result", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_queryId", + "type": "uint256" + } + ], + "name": "readResponseTimestamp", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_cborBytes", + "type": "bytes" + } + ], + "name": "resultFromCborBytes", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "components": [ + { + "components": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "cursor", + "type": "uint256" + } + ], + "internalType": "struct WitnetBuffer.Buffer", + "name": "buffer", + "type": "tuple" + }, + { + "internalType": "uint8", + "name": "initialByte", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "majorType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "additionalInformation", + "type": "uint8" + }, + { + "internalType": "uint64", + "name": "len", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "tag", + "type": "uint64" + } + ], + "internalType": "struct WitnetCBOR.CBOR", + "name": "value", + "type": "tuple" + } + ], + "internalType": "struct Witnet.Result", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_queryId", + "type": "uint256" + } + ], + "name": "upgradeReward", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "class", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "contract WitnetRequestFactory", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "registry", + "outputs": [ + { + "internalType": "contract WitnetBytecodes", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/migrations/abis/WitnetRequestFactory.json b/migrations/abis/WitnetRequestFactory.json new file mode 100644 index 000000000..c603b787f --- /dev/null +++ b/migrations/abis/WitnetRequestFactory.json @@ -0,0 +1,81 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "template", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "parameterized", + "type": "bool" + } + ], + "name": "WitnetRequestTemplateBuilt", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "bytes32[]", + "name": "sourcesIds", + "type": "bytes32[]" + }, + { + "internalType": "bytes32", + "name": "aggregatorId", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "tallyId", + "type": "bytes32" + }, + { + "internalType": "uint16", + "name": "resultDataMaxSize", + "type": "uint16" + } + ], + "name": "buildRequestTemplate", + "outputs": [ + { + "internalType": "address", + "name": "template", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "class", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "registry", + "outputs": [ + { + "internalType": "contract WitnetBytecodes", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/migrations/abis/WitnetRequestTemplate.json b/migrations/abis/WitnetRequestTemplate.json new file mode 100644 index 000000000..45f545f1a --- /dev/null +++ b/migrations/abis/WitnetRequestTemplate.json @@ -0,0 +1,348 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "request", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "radHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "string[][]", + "name": "args", + "type": "string[][]" + } + ], + "name": "WitnetRequestBuilt", + "type": "event" + }, + { + "inputs": [], + "name": "class", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "contract WitnetRequestFactory", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "registry", + "outputs": [ + { + "internalType": "contract WitnetBytecodes", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "aggregator", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "parameterized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "resultDataMaxSize", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "resultDataType", + "outputs": [ + { + "internalType": "enum WitnetV2.RadonDataTypes", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "retrievals", + "outputs": [ + { + "internalType": "bytes32[]", + "name": "", + "type": "bytes32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "tally", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRadonAggregator", + "outputs": [ + { + "components": [ + { + "internalType": "enum WitnetV2.RadonReducerOpcodes", + "name": "opcode", + "type": "uint8" + }, + { + "components": [ + { + "internalType": "enum WitnetV2.RadonFilterOpcodes", + "name": "opcode", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "args", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonFilter[]", + "name": "filters", + "type": "tuple[]" + }, + { + "internalType": "bytes", + "name": "script", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonReducer", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "getRadonRetrievalByIndex", + "outputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "argsCount", + "type": "uint8" + }, + { + "internalType": "enum WitnetV2.DataRequestMethods", + "name": "method", + "type": "uint8" + }, + { + "internalType": "enum WitnetV2.RadonDataTypes", + "name": "resultDataType", + "type": "uint8" + }, + { + "internalType": "string", + "name": "url", + "type": "string" + }, + { + "internalType": "string", + "name": "body", + "type": "string" + }, + { + "internalType": "string[2][]", + "name": "headers", + "type": "string[2][]" + }, + { + "internalType": "bytes", + "name": "script", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonRetrieval", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRadonRetrievalsCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRadonTally", + "outputs": [ + { + "components": [ + { + "internalType": "enum WitnetV2.RadonReducerOpcodes", + "name": "opcode", + "type": "uint8" + }, + { + "components": [ + { + "internalType": "enum WitnetV2.RadonFilterOpcodes", + "name": "opcode", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "args", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonFilter[]", + "name": "filters", + "type": "tuple[]" + }, + { + "internalType": "bytes", + "name": "script", + "type": "bytes" + } + ], + "internalType": "struct WitnetV2.RadonReducer", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string[][]", + "name": "args", + "type": "string[][]" + } + ], + "name": "buildRequest", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string[][]", + "name": "args", + "type": "string[][]" + } + ], + "name": "verifyRadonRequest", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ] \ No newline at end of file From 861848163d256b6b1a8f83cd053572deb512bf43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 9 Nov 2023 11:41:24 +0100 Subject: [PATCH 18/86] chore: improve migrations logs --- migrations/scripts/1_deployer.js | 2 +- migrations/scripts/2_libs.js | 9 ++-- migrations/scripts/3_core.js | 11 ++--- migrations/scripts/4_proxies.js | 6 ++- migrations/scripts/5_apps.js | 7 +--- scripts/utils/traceTx.js | 15 ++++--- scripts/vanitygen.js | 70 -------------------------------- 7 files changed, 21 insertions(+), 99 deletions(-) delete mode 100644 scripts/vanitygen.js diff --git a/migrations/scripts/1_deployer.js b/migrations/scripts/1_deployer.js index 23ef84805..c582c2dd7 100644 --- a/migrations/scripts/1_deployer.js +++ b/migrations/scripts/1_deployer.js @@ -19,7 +19,7 @@ module.exports = async function (deployer, network, [, from,, master]) { } else { factory = await WitnetDeployer.at(addresses[ecosystem][network].WitnetDeployer) WitnetDeployer.address = factory.address - utils.traceHeader("Skipping 'WitnetDeployer'") + utils.traceHeader("Skipped 'WitnetDeployer'") console.info(" > Contract address:", factory.address) console.info() } diff --git a/migrations/scripts/2_libs.js b/migrations/scripts/2_libs.js index 64d0a481a..609092704 100644 --- a/migrations/scripts/2_libs.js +++ b/migrations/scripts/2_libs.js @@ -36,18 +36,15 @@ module.exports = async function (_, network, [, from]) { console.info(" ", "> account: ", from) console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), 'ether'), "ETH") const tx = await deployer.deploy(libInitCode, "0x0", { from }) - console.info(" ", "> transaction hash: ", tx.receipt.transactionHash) - console.info(" ", "> gas used: ", tx.receipt.gasUsed.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")) - console.info(" ", "> gas price: ", tx.receipt.effectiveGasPrice / 10 ** 9, "gwei") - console.info(" ", "> total cost: ", web3.utils.fromWei(BigInt(tx.receipt.gasUsed * tx.receipt.effectiveGasPrice).toString(), 'ether'), "ETH") + utils.traceTx(tx) if ((await web3.eth.getCode(libAddr)).length > 3) { addresses[ecosystem][network][key] = libAddr } else { - console.info(`Library was not deployed on expected address: ${libAddr}`) + console.info(`Error: Library was not deployed on expected address: ${libAddr}`) process.exit(1) } } else { - utils.traceHeader(`Deployed '${key}'`) + utils.traceHeader(`Skipped '${key}'`) } artifact.address = addresses[ecosystem][network][key] console.info(" ", "> library address: ", artifact.address) diff --git a/migrations/scripts/3_core.js b/migrations/scripts/3_core.js index bf1160505..c37902b8a 100644 --- a/migrations/scripts/3_core.js +++ b/migrations/scripts/3_core.js @@ -102,24 +102,21 @@ async function deploy(specs) { const coreBytecode = link(contract.toJSON().bytecode, libs, targets) if (coreBytecode.indexOf("__") > -1) { console.info(bytecode) - console.info("Cannot deploy due to some missing libs") + console.info("Error: Cannot deploy due to some missing libs") process.exit(1) } const coreInitCode = coreBytecode + constructorArgs.slice(2) const coreAddr = await deployer.determineAddr.call(coreInitCode, "0x0", { from }) const tx = await deployer.deploy(coreInitCode, "0x0", { from }) - console.info(" ", "> transaction hash: ", tx.receipt.transactionHash) - console.info(" ", "> gas used: ", tx.receipt.gasUsed.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")) - console.info(" ", "> gas price: ", tx.receipt.effectiveGasPrice / 10 ** 9, "gwei") - console.info(" ", "> total cost: ", web3.utils.fromWei(BigInt(tx.receipt.gasUsed * tx.receipt.effectiveGasPrice).toString(), 'ether'), "ETH") + utils.traceTx(tx) if ((await web3.eth.getCode(coreAddr)).length > 3) { addresses[ecosystem][network][key] = coreAddr } else { - console.info(`Contract was not deployed on expected address: ${coreAddr}`) + console.info(`Error: Contract was not deployed on expected address: ${coreAddr}`) process.exit(1) } } else { - utils.traceHeader(`Deployed '${key}'`) + utils.traceHeader(`Skipped '${key}'`) } contract.address = addresses[ecosystem][network][key] console.info(" ", "> contract address: ", contract.address) diff --git a/migrations/scripts/4_proxies.js b/migrations/scripts/4_proxies.js index 70951c43d..3d4db13ed 100644 --- a/migrations/scripts/4_proxies.js +++ b/migrations/scripts/4_proxies.js @@ -71,6 +71,7 @@ async function deploy(target) { console.info(" ", "> initialize params:", mutables.values) } const tx = await deployer.proxify(proxy_salt, impl.address, initdata, { from }) + utils.traceTx(tx) // save/overwrite exportable abi file utils.saveJsonAbi(key, proxy.abi) } else { @@ -92,7 +93,7 @@ async function deploy(target) { if ((await web3.eth.getCode(proxyAddr)).length > 3) { addresses[ecosystem][network][key] = proxyAddr } else { - console.info(`Contract was not deployed on expected address: ${proxyAddr}`) + console.info(`Error: Contract was not deployed on expected address: ${proxyAddr}`) process.exit(1) } } else { @@ -114,11 +115,12 @@ async function deploy(target) { console.info(" ", "> initialize params:", mutables.values) } const tx = await upgradeProxyTo(from, proxy, newImpl.address, initdata) + utils.traceTx(tx) // save/overwrite exportable abi file utils.saveJsonAbi(key, proxy.abi) } } else { - utils.traceHeader(`Deployed '${key}'`) + utils.traceHeader(`Skipped '${key}'`) } } proxy.address = addresses[ecosystem][network][key] diff --git a/migrations/scripts/5_apps.js b/migrations/scripts/5_apps.js index 65a55d627..4048ae4f4 100644 --- a/migrations/scripts/5_apps.js +++ b/migrations/scripts/5_apps.js @@ -89,10 +89,7 @@ async function deploy(specs) { console.info(" ", "> account: ", from) console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), 'ether'), "ETH") const tx = await deployer.deploy(dappInitCode, salt, { from }) - console.info(" ", "> transaction hash: ", tx.receipt.transactionHash) - console.info(" ", "> gas used: ", tx.receipt.gasUsed.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")) - console.info(" ", "> gas price: ", tx.receipt.effectiveGasPrice / 10 ** 9, "gwei") - console.info(" ", "> total cost: ", web3.utils.fromWei(BigInt(tx.receipt.gasUsed * tx.receipt.effectiveGasPrice).toString(), 'ether'), "ETH") + utils.traceTx(tx) if ((await web3.eth.getCode(dappAddr)).length > 3) { addresses[ecosystem][network][key] = dappAddr // save/overwrite exportable abi file @@ -103,7 +100,7 @@ async function deploy(specs) { process.exit(1) } } else { - utils.traceHeader(`Deployed '${key}'`) + utils.traceHeader(`Skipped '${key}'`) } artifact.address = addresses[ecosystem][network][key] console.info(" ", "> contract address: ", artifact.address) diff --git a/scripts/utils/traceTx.js b/scripts/utils/traceTx.js index 06bdb31ef..4c36b7223 100644 --- a/scripts/utils/traceTx.js +++ b/scripts/utils/traceTx.js @@ -1,9 +1,8 @@ -module.exports = function (receipt, totalCost) { - console.log(" ", "> block number: ", receipt.blockNumber) - console.log(" ", "> transaction hash: ", receipt.transactionHash) - console.log(" ", "> transaction gas: ", receipt.gasUsed) - if (totalCost) { - console.log(" ", "> total cost: ", totalCost, "ETH") - } - console.log() +const web3 = require("web3") + +module.exports = function (tx) { + console.info(" ", "> transaction hash: ", tx.receipt.transactionHash) + console.info(" ", "> gas used: ", tx.receipt.gasUsed.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")) + console.info(" ", "> gas price: ", tx.receipt.effectiveGasPrice / 10 ** 9, "gwei") + console.info(" ", "> total cost: ", web3.utils.fromWei(BigInt(tx.receipt.gasUsed * tx.receipt.effectiveGasPrice).toString(), 'ether'), "ETH") } diff --git a/scripts/vanitygen.js b/scripts/vanitygen.js deleted file mode 100644 index b86638fce..000000000 --- a/scripts/vanitygen.js +++ /dev/null @@ -1,70 +0,0 @@ -const { assert } = require("chai") -const create2 = require("eth-create2") -const fs = require("fs") -const utils = require("./utils") - -const addresses = require("../migrations/witnet.addresses") - -module.exports = async function () { - let artifact - let count = 0 - let ecosystem = "default" - let from - let hits = 10 - let offset = 0 - let network = "default" - let target = "0xfacade" - process.argv.map((argv, index, args) => { - if (argv === "--from") { - from = args[index + 1] - } else if (argv === "--offset") { - offset = parseInt(args[index + 1]) - } else if (argv === "--artifact") { - artifact = artifacts.require(args[index + 1]) - } else if (argv === "--target") { - target = args[index + 1].toLowerCase() - } else if (argv === "--hits") { - hits = parseInt(args[index + 1]) - } else if (argv === "--network") { - [ecosystem, network] = utils.getRealmNetworkFromString(args[index + 1].toLowerCase()) - } - return argv - }) - try { - from = from || addresses[ecosystem][network].Create2Factory - } catch { - console.error(` Create2Factory must have been previously deployed on network '${network}'.\n`) - console.info("Usage:\n") - console.info(" --artifact => Truffle artifact name (default: WitnetProxy)") - console.info(" --hits => Number of vanity hits to look for (default: 10)") - console.info(" --offset => Salt starting value minus 1 (default: 0)") - console.info(" --network => Network name") - console.info(" --target => Prefix hex number to look for (default: 0xc0ffee)") - process.exit(1) - } - const bytecode = artifact - ? artifact.toJSON().bytecode - : `0x3d602d80600a3d3981f3363d3d373d3d3d363d73${from.toLowerCase().slice(2)}5af43d82803e903d91602b57fd5bf3` - const targets = target.split(",") - for (let j = 0; j < targets.length; j++) { - assert(web3.utils.isHexStrict(targets[j]), "--target refers invalid hex string") - } - console.log("Bytecode: ", bytecode) - console.log("Artifact: ", artifact?.contractName || "ERC-1167: Minimal Proxy Contract") - console.log("From: ", from) - console.log("Hits: ", hits) - console.log("Offset: ", offset) - console.log("Target: ", target) - console.log("=".repeat(55)) - while (count < hits) { - const salt = "0x" + utils.padLeft(offset.toString(16), "0", 32) - const addr = create2(from, salt, bytecode) - if (targets.some((word) => addr.toLowerCase().startsWith(word))) { - const found = `${offset} => ${web3.utils.toChecksumAddress(addr)}` - console.log(found) - fs.appendFileSync(`./migrations/salts/${artifact?.contractName || "MinimalProxy"}$${from.toLowerCase()}.tmp`, found + "\n") - count++ - } - offset++ - } -} From 026bbe99247b9caceb0747a111a6efa1a823c8ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 9 Nov 2023 11:43:05 +0100 Subject: [PATCH 19/86] chore: bump solc version to 0.8.22 --- .solhint.json | 1 + migrations/witnet.settings.js | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.solhint.json b/.solhint.json index 7e8130457..0ad4ce74e 100644 --- a/.solhint.json +++ b/.solhint.json @@ -16,6 +16,7 @@ "modifier-name-mixedcase": "warn", "no-empty-blocks": "off", "no-inline-assembly": "off", + "no-global-import": "off", "var-name-mixedcase": "off", "reason-string": [ "warn", diff --git a/migrations/witnet.settings.js b/migrations/witnet.settings.js index 0b9bbd7ee..16bcf2e8f 100644 --- a/migrations/witnet.settings.js +++ b/migrations/witnet.settings.js @@ -41,12 +41,13 @@ module.exports = { compilers: { default: { solc: { - version: "0.8.17", + version: "0.8.22", settings: { optimizer: { enabled: true, runs: 200, }, + evmVersion: "paris", }, }, }, From 83785a0d8687c8f3673840316e425fb36701e830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 9 Nov 2023 19:04:19 +0100 Subject: [PATCH 20/86] fix: avoid addresses to be written on dryruns --- migrations/scripts/1_deployer.js | 2 +- migrations/scripts/2_libs.js | 2 +- migrations/scripts/3_core.js | 2 +- migrations/scripts/4_proxies.js | 2 +- migrations/scripts/5_apps.js | 7 +------ 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/migrations/scripts/1_deployer.js b/migrations/scripts/1_deployer.js index c582c2dd7..66bc77d3c 100644 --- a/migrations/scripts/1_deployer.js +++ b/migrations/scripts/1_deployer.js @@ -4,7 +4,7 @@ const utils = require("../../scripts/utils") const WitnetDeployer = artifacts.require("WitnetDeployer") module.exports = async function (deployer, network, [, from,, master]) { - const isDryRun = false // network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" const ecosystem = utils.getRealmNetworkFromArgs()[0] network = network.split("-")[0] diff --git a/migrations/scripts/2_libs.js b/migrations/scripts/2_libs.js index 609092704..edaf95995 100644 --- a/migrations/scripts/2_libs.js +++ b/migrations/scripts/2_libs.js @@ -6,7 +6,7 @@ const utils = require("../../scripts/utils") const WitnetDeployer = artifacts.require("WitnetDeployer") module.exports = async function (_, network, [, from]) { - const isDryRun = false // network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" const ecosystem = utils.getRealmNetworkFromArgs()[0] network = network.split("-")[0] diff --git a/migrations/scripts/3_core.js b/migrations/scripts/3_core.js index c37902b8a..c8545059b 100644 --- a/migrations/scripts/3_core.js +++ b/migrations/scripts/3_core.js @@ -13,7 +13,7 @@ const version = `${ const WitnetDeployer = artifacts.require("WitnetDeployer") module.exports = async function (_, network, [, from]) { - const isDryRun = false // network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" const ecosystem = utils.getRealmNetworkFromArgs()[0] network = network.split("-")[0] diff --git a/migrations/scripts/4_proxies.js b/migrations/scripts/4_proxies.js index 3d4db13ed..3b4145096 100644 --- a/migrations/scripts/4_proxies.js +++ b/migrations/scripts/4_proxies.js @@ -9,7 +9,7 @@ const WitnetDeployer = artifacts.require("WitnetDeployer") const WitnetProxy = artifacts.require("WitnetProxy") module.exports = async function (_, network, [, from, reporter]) { - const isDryRun = false // network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" const ecosystem = utils.getRealmNetworkFromArgs()[0] network = network.split("-")[0] diff --git a/migrations/scripts/5_apps.js b/migrations/scripts/5_apps.js index 4048ae4f4..3692fa4b5 100644 --- a/migrations/scripts/5_apps.js +++ b/migrations/scripts/5_apps.js @@ -4,16 +4,11 @@ const { merge } = require("lodash") const addresses = require("../witnet.addresses") const settings = require("../witnet.settings") const utils = require("../../scripts/utils") -const version = `${ - require("../../package").version - }-${ - require("child_process").execSync("git rev-parse HEAD").toString().trim().substring(0, 7) - }` const WitnetDeployer = artifacts.require("WitnetDeployer") module.exports = async function (_, network, [,,, from]) { - const isDryRun = false // network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" const ecosystem = utils.getRealmNetworkFromArgs()[0] network = network.split("-")[0] From c7d7506e4b0983110e3f8ace3a7987c1223b19a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Tue, 14 Nov 2023 10:52:17 +0100 Subject: [PATCH 21/86] feat: add support to new radon string operators --- contracts/libs/WitnetEncodingLib.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/libs/WitnetEncodingLib.sol b/contracts/libs/WitnetEncodingLib.sol index 15618f9f3..a033f5ee5 100644 --- a/contracts/libs/WitnetEncodingLib.sol +++ b/contracts/libs/WitnetEncodingLib.sol @@ -13,15 +13,15 @@ library WitnetEncodingLib { using WitnetCBOR for WitnetCBOR.CBOR[]; bytes internal constant WITNET_RADON_OPCODES_RESULT_TYPES = - hex"10ffffffffffffffffffffffffffffff0401ff010203050406071311ff01ffff07ff02ffffffffffffffffffffffffff0703ffffffffffffffffffffffffffff0405070202ff04040404ffffffffffff05070402040205050505ff04ff04ffffff010203050406070101ffffffffffff02ff050404000106060707ffffffffff"; + hex"10ffffffffffffffffffffffffffffff040100010203050406071311ff01ffff07ff02ffffffffffffffffffffffffff0703ffffffffffffffffffffffffffff0405070202ff04040404ffffffffffff05070402040205050505ff04ff04ffffff010203050406070101ffffffffffff02ff050404000106060707070701ffff"; // 10ffffffffffffffffffffffffffffff - // 0401ff000203050406070100ff01ffff + // 040100001203050406070100ff01ffff // 07ff02ffffffffffffffffffffffffff // 0703ffffffffffffffffffffffffffff // 0405070202ff04040404ffffffffffff // 05070402040205050505ff04ff04ffff // ff010203050406070101ffffffffffff - // 02ff050404000106060707ffffffffff + // 02ff050404000106060707070701ffff /// =============================================================================================================== /// --- WitnetLib internal methods -------------------------------------------------------------------------------- From 3c032011bd1e6019e9248d7d9fbdcc0d7166453d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 09:31:23 +0100 Subject: [PATCH 22/86] feat: link WRB back from the WRF --- contracts/WitnetRequestFactory.sol | 2 ++ contracts/WitnetRequestTemplate.sol | 2 ++ .../customs/WitnetRequestBoardTrustableBoba.sol | 2 +- .../core/customs/WitnetRequestFactoryCfxCore.sol | 3 ++- .../WitnetRequestBoardTrustableBase.sol | 7 +++++-- .../WitnetRequestBoardTrustableDefault.sol | 2 +- .../core/defaults/WitnetRequestFactoryDefault.sol | 14 ++++++++++---- contracts/interfaces/V2/IWitnetFeeds.sol | 8 ++++---- migrations/scripts/3_core.js | 5 +++-- 9 files changed, 30 insertions(+), 15 deletions(-) rename contracts/core/{customs => defaults}/WitnetRequestBoardTrustableBase.sol (99%) diff --git a/contracts/WitnetRequestFactory.sol b/contracts/WitnetRequestFactory.sol index 83bcf5a77..1debb0636 100644 --- a/contracts/WitnetRequestFactory.sol +++ b/contracts/WitnetRequestFactory.sol @@ -4,6 +4,7 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; import "./WitnetBytecodes.sol"; +import "./WitnetRequestBoard.sol"; import "./interfaces/V2/IWitnetRequestFactory.sol"; abstract contract WitnetRequestFactory @@ -12,4 +13,5 @@ abstract contract WitnetRequestFactory { function class() virtual external view returns (bytes4); function registry() virtual external view returns (WitnetBytecodes); + function witnet() virtual external view returns (WitnetRequestBoard); } \ No newline at end of file diff --git a/contracts/WitnetRequestTemplate.sol b/contracts/WitnetRequestTemplate.sol index 54a3d9a3a..3a2036da4 100644 --- a/contracts/WitnetRequestTemplate.sol +++ b/contracts/WitnetRequestTemplate.sol @@ -4,6 +4,7 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; import "./WitnetBytecodes.sol"; +import "./WitnetRequestBoard.sol"; import "./WitnetRequestFactory.sol"; abstract contract WitnetRequestTemplate @@ -14,6 +15,7 @@ abstract contract WitnetRequestTemplate function factory() virtual external view returns (WitnetRequestFactory); function registry() virtual external view returns (WitnetBytecodes); function version() virtual external view returns (string memory); + function witnet() virtual external view returns (WitnetRequestBoard); function aggregator() virtual external view returns (bytes32); function parameterized() virtual external view returns (bool); diff --git a/contracts/core/customs/WitnetRequestBoardTrustableBoba.sol b/contracts/core/customs/WitnetRequestBoardTrustableBoba.sol index 372ef5737..d8e471010 100644 --- a/contracts/core/customs/WitnetRequestBoardTrustableBoba.sol +++ b/contracts/core/customs/WitnetRequestBoardTrustableBoba.sol @@ -6,7 +6,7 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; // Inherits from: -import "./WitnetRequestBoardTrustableBase.sol"; +import "../defaults/WitnetRequestBoardTrustableBase.sol"; // Uses: import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/contracts/core/customs/WitnetRequestFactoryCfxCore.sol b/contracts/core/customs/WitnetRequestFactoryCfxCore.sol index da2b86498..fbb8574b1 100644 --- a/contracts/core/customs/WitnetRequestFactoryCfxCore.sol +++ b/contracts/core/customs/WitnetRequestFactoryCfxCore.sol @@ -7,11 +7,12 @@ import "../defaults/WitnetRequestFactoryDefault.sol"; contract WitnetRequestFactoryCfxCore is WitnetRequestFactoryDefault { constructor( + WitnetRequestBoard _witnet, WitnetBytecodes _registry, bool _upgradable, bytes32 _versionTag ) - WitnetRequestFactoryDefault(_registry, _upgradable, _versionTag) + WitnetRequestFactoryDefault(_witnet, _registry, _upgradable, _versionTag) {} function _cloneDeterministic(bytes32 _salt) diff --git a/contracts/core/customs/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol similarity index 99% rename from contracts/core/customs/WitnetRequestBoardTrustableBase.sol rename to contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index 927301e33..3a444ca34 100644 --- a/contracts/core/customs/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -8,6 +8,7 @@ import "../../WitnetRequestBoard.sol"; import "../../WitnetRequestFactory.sol"; import "../../data/WitnetBoardDataACLs.sol"; +import "../../interfaces/IWitnetRequest.sol"; import "../../interfaces/IWitnetRequestBoardAdminACLs.sol"; import "../../interfaces/IWitnetRequestBoardReporter.sol"; import "../../libs/WitnetErrorsLib.sol"; @@ -46,6 +47,7 @@ abstract contract WitnetRequestBoardTrustableBase "io.witnet.proxiable.board" ) { + assert(address(_factory) != address(0)); factory = _factory; } @@ -140,6 +142,7 @@ abstract contract WitnetRequestBoardTrustableBase require(address(factory).code.length > 0, "WitnetRequestBoardTrustableBase: inexistent factory"); require(factory.class() == type(IWitnetRequestFactory).interfaceId, "WitnetRequestBoardTrustableBase: uncompliant factory"); + require(address(factory.witnet()) == address(this), "WitnetRequestBoardTrustableBase: discordant factory"); // Set reporters __setReporters(_reporters); @@ -465,7 +468,7 @@ abstract contract WitnetRequestBoardTrustableBase /// @dev - provided address is zero. /// @param _requestInterface The address of a IWitnetRequest contract, containing the actual Data Request seralized bytecode. /// @return _queryId An unique query identifier. - function postRequest(IWitnetRequest _requestInterface) + function postRequest(address _requestInterface) virtual override public payable returns (uint256 _queryId) @@ -484,7 +487,7 @@ abstract contract WitnetRequestBoardTrustableBase __storage().queries[_queryId].from = msg.sender; Witnet.Request storage _request = __request(_queryId); - _request.addr = address(_requestInterface); + _request.addr = _requestInterface; _request.gasprice = _gasPrice; _request.reward = _value; diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol b/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol index 4cb418ca7..dfbd77f08 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol @@ -5,7 +5,7 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "../customs/WitnetRequestBoardTrustableBase.sol"; +import "./WitnetRequestBoardTrustableBase.sol"; /// @title Witnet Request Board "trustable" implementation contract. /// @notice Contract to bridge requests to Witnet Decentralized Oracle Network. diff --git a/contracts/core/defaults/WitnetRequestFactoryDefault.sol b/contracts/core/defaults/WitnetRequestFactoryDefault.sol index 9c975deb7..6f39014c0 100644 --- a/contracts/core/defaults/WitnetRequestFactoryDefault.sol +++ b/contracts/core/defaults/WitnetRequestFactoryDefault.sol @@ -17,9 +17,12 @@ contract WitnetRequestFactoryDefault WitnetRequestFactoryData, WitnetUpgradableBase { - /// @notice Reference to Witnet Data Requests Bytecode Registry + /// @notice Reference to Witnet Data Requests Bytecode Registry. WitnetBytecodes immutable public override(WitnetRequestFactory, WitnetRequestTemplate) registry; + /// @notice Reference to the Witnet Request Board that all templates built out from this factory will refer to. + WitnetRequestBoard immutable public override(WitnetRequestFactory, WitnetRequestTemplate) witnet; + modifier onlyDelegateCalls override(Clonable, Upgradeable) { require( address(this) != _BASE, @@ -46,6 +49,7 @@ contract WitnetRequestFactoryDefault } constructor( + WitnetRequestBoard _witnet, WitnetBytecodes _registry, bool _upgradable, bytes32 _versionTag @@ -56,6 +60,8 @@ contract WitnetRequestFactoryDefault "io.witnet.requests.factory" ) { + assert(address(_witnet) != address(0) && address(_registry) != address(0)); + witnet = _witnet; registry = _registry; // let logic contract be used as a factory, while avoiding further initializations: __proxiable().proxy = address(this); @@ -281,9 +287,9 @@ contract WitnetRequestFactoryDefault } __proxiable().implementation = base(); - require(address(registry).code.length > 0, "WitnetRequestFactoryDefault: inexistent registry"); - require(registry.class() == type(IWitnetBytecodes).interfaceId, "WitnetRequestFactoryDefault: uncompliant registry"); - + require(address(registry).code.length > 0, "WitnetRequestFactoryDefault: inexistent requests registry"); + require(registry.class() == type(IWitnetBytecodes).interfaceId, "WitnetRequestFactoryDefault: uncompliant requests registry"); + emit Upgraded(msg.sender, base(), codehash(), version()); } diff --git a/contracts/interfaces/V2/IWitnetFeeds.sol b/contracts/interfaces/V2/IWitnetFeeds.sol index 52dc6bcf2..0e2a99667 100644 --- a/contracts/interfaces/V2/IWitnetFeeds.sol +++ b/contracts/interfaces/V2/IWitnetFeeds.sol @@ -2,8 +2,8 @@ pragma solidity >=0.8.0 <0.9.0; -import "./IWitnetBytecodes.sol"; -import "../IWitnetRequestBoard.sol"; +import "../../WitnetBytecodes.sol"; +import "../../WitnetRequestBoard.sol"; interface IWitnetFeeds { @@ -16,8 +16,8 @@ interface IWitnetFeeds { function dataType() external view returns (WitnetV2.RadonDataTypes); function prefix() external view returns (string memory); - function registry() external view returns (IWitnetBytecodes); - function witnet() external view returns (IWitnetRequestBoard); + function registry() external view returns (WitnetBytecodes); + function witnet() external view returns (WitnetRequestBoard); function defaultRadonSLA() external view returns (WitnetV2.RadonSLA memory); diff --git a/migrations/scripts/3_core.js b/migrations/scripts/3_core.js index c8545059b..2248dd485 100644 --- a/migrations/scripts/3_core.js +++ b/migrations/scripts/3_core.js @@ -54,7 +54,8 @@ module.exports = async function (_, network, [, from]) { key: targets.WitnetRequestFactory, libs: specs.WitnetRequestFactory.libs, immutables: specs.WitnetRequestFactory.immutables, - intrinsics: { types: [ 'address', 'bool', 'bytes32' ], values: [ + intrinsics: { types: [ 'address', 'address', 'bool', 'bytes32' ], values: [ + /* _witnet */ await determineProxyAddr(from, specs.WitnetRequestBoard?.vanity || 3), /* _registry */ await determineProxyAddr(from, specs.WitnetBytecodes?.vanity || 1), /* _upgradable */ true, /* _versionTag */ utils.fromAscii(version), @@ -72,7 +73,7 @@ module.exports = async function (_, network, [, from]) { libs: specs.WitnetRequestBoard.libs, immutables: specs.WitnetRequestBoard.immutables, intrinsics: { types: [ 'address', 'bool', 'bytes32' ], values: [ - /* _registry */ await determineProxyAddr(from, specs.WitnetRequestFactory?.vanity || 2), + /* _factory */ await determineProxyAddr(from, specs.WitnetRequestFactory?.vanity || 2), /* _upgradable */ true, /* _versionTag */ utils.fromAscii(version), ]}, From 941a574988c5ee532c7a98d2d93f17ba974af1c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 09:33:02 +0100 Subject: [PATCH 23/86] feat: implement class() on WR and WPF --- contracts/apps/WitnetPriceFeeds.sol | 5 +++-- contracts/apps/WitnetRandomness.sol | 15 +++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/contracts/apps/WitnetPriceFeeds.sol b/contracts/apps/WitnetPriceFeeds.sol index bcf984ab2..76a6cd80b 100644 --- a/contracts/apps/WitnetPriceFeeds.sol +++ b/contracts/apps/WitnetPriceFeeds.sol @@ -29,7 +29,8 @@ contract WitnetPriceFeeds using Witnet for Witnet.Result; using WitnetV2 for WitnetV2.RadonSLA; - IWitnetRequestBoard immutable public override witnet; + bytes4 immutable public class = type(IWitnetPriceFeeds).interfaceId; + WitnetRequestBoard immutable public override witnet; constructor(address _operator, WitnetRequestBoard _wrb) WitnetFeeds( @@ -242,7 +243,7 @@ contract WitnetPriceFeeds } } - function registry() public view virtual override returns (IWitnetBytecodes) { + function registry() public view virtual override returns (WitnetBytecodes) { return WitnetRequestBoard(address(witnet)).registry(); } diff --git a/contracts/apps/WitnetRandomness.sol b/contracts/apps/WitnetRandomness.sol index 2fabca8e3..d558f8830 100644 --- a/contracts/apps/WitnetRandomness.sol +++ b/contracts/apps/WitnetRandomness.sol @@ -24,6 +24,7 @@ contract WitnetRandomness { using Witnet for Witnet.Result; + bytes4 public immutable class = type(IWitnetRandomness).interfaceId; uint256 public override latestRandomizeBlock; WitnetRequest public immutable override witnetRandomnessRequest; @@ -328,10 +329,10 @@ contract WitnetRandomness { if (latestRandomizeBlock < block.number) { // Post the Witnet Randomness request: - uint _queryId; - (_queryId, _usedFunds) = _witnetPostRequest( + _usedFunds = _witnetEstimateBaseFee(tx.gasprice); + uint _queryId = witnet().postRequest{value: _usedFunds}( __witnetRandomnessRadHash, - __witnetRandomnessSlaHash + __witnetRandomnessSlaHash ); // Keep Randomize data in storage: RandomizeData storage _data = __randomize_[block.number]; @@ -366,15 +367,13 @@ contract WitnetRandomness function upgradeRandomizeFee(uint256 _block) public payable virtual override - returns (uint256 _usedFunds) + returns (uint256) { RandomizeData storage _data = __randomize_[_block]; if (_data.witnetQueryId != 0) { - _usedFunds = _witnetUpgradeReward(_data.witnetQueryId); - } - if (_usedFunds < msg.value) { - payable(msg.sender).transfer(msg.value - _usedFunds); + __witnet.upgradeReward{value: msg.value}(_data.witnetQueryId); } + return msg.value; } /// @notice Result the WitnetRequestBoard address upon which this contract relies on. From 8cfe49c0ac24b006b284927bbaac3055f2f7fbd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 09:37:26 +0100 Subject: [PATCH 24/86] chore: refactor+deprecates on IWitnetRequestBoard --- contracts/interfaces/IWitnetRequestBoard.sol | 61 ++++++++++++-------- contracts/libs/Witnet.sol | 1 - 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index a4a61fcbf..d8e81b1ae 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -19,6 +19,10 @@ interface IWitnetRequestBoard { /// =============================================================================================================== /// --- Requestor interface --------------------------------------------------------------------------------------- + /// @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 view returns (Witnet.ResultError 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; @@ -27,7 +31,7 @@ interface IWitnetRequestBoard { /// @param _queryId The unique query identifier. function checkResultStatus(uint256 _queryId) external view returns (Witnet.ResultStatus); - /// @notice Gets error code identifying some possible failure on the resolution of the given query. + function checkResultTraceability(uint256 _queryId) external view returns (uint256, bytes32); /// @param _queryId The unique query identifier. function checkResultError(uint256 _queryId) external view returns (Witnet.ResultError memory); @@ -40,22 +44,12 @@ interface IWitnetRequestBoard { /// @notice Requests the execution of the given Witnet Data Request in expectation that it will be relayed and solved by the Witnet DON. /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided /// @notice result to this request. - /// @dev Fails if: - /// @dev - provided reward is too low. - /// @dev - provided script is zero address. - /// @dev - provided script bytecode is empty. - /// @param addr The address of the IWitnetRequest contract that can provide the actual Data Request bytecode. - /// @return _queryId Unique query identifier. - function postRequest(IWitnetRequest addr) 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 the Witnet DON. - /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided - /// @notice result to this request. - /// @dev Fails if, provided reward is too low. + /// @dev Fails if provided reward is too low. + /// @dev The result to the query will be saved into the WitnetRequestBoard storage. /// @param radHash The RAD hash of the data request to be solved by Witnet. - /// @param slaHash The SLA 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 radHash, bytes32 slaHash) external payable returns (uint256 _queryId); + function postRequest(bytes32 radHash, 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 the Witnet DON. /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided @@ -67,22 +61,14 @@ interface IWitnetRequestBoard { function postRequest(bytes32 radHash, WitnetV2.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 - /// @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; + function upgradeQueryReward(uint256 _queryId) external payable; /// =============================================================================================================== /// --- Reader interface ------------------------------------------------------------------------------------------ - /// @notice 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); + function estimateBaseFee(uint256 _gasPrice, uint256 _resultMaxSize) external view returns (uint256); /// @notice Returns next query id to be generated by the Witnet Request Board. function getNextQueryId() external view returns (uint256); @@ -169,9 +155,34 @@ interface IWitnetRequestBoard { /// @return The `uint` decoded from the Witnet.Result. function asUint64(Witnet.Result memory _result) external pure returns (uint64); + /// @notice Estimate the minimum reward required for posting a data request. + /// @dev Underestimates if the size of returned data is greater than 32 bytes. + /// @param _gasPrice Expected gas price to pay upon posting the data request. + function estimateReward(uint256 _gasPrice) external view returns (uint256); + + /// @notice Requests the execution of the given Witnet Data Request in expectation that it will be relayed and solved by the Witnet DON. + /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided + /// @notice result to this request. + /// @dev Fails if: + /// @dev - provided reward is too low. + /// @dev - provided script is zero address. + /// @dev - provided script bytecode is empty. + /// @param _requestAddr The address of the IWitnetRequest contract that can provide the actual Data Request bytecode. + /// @return _queryId Unique query identifier. + function postRequest(address _requestAddr) external payable returns (uint256 _queryId); + /// Decode raw CBOR 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) external pure returns (Witnet.Result memory); + /// @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 + /// @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; } diff --git a/contracts/libs/Witnet.sol b/contracts/libs/Witnet.sol index 07e50c786..ee4ebfc8a 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 { From bbe087b8868fcb92783f0e736f0adddce255408c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 09:43:26 +0100 Subject: [PATCH 25/86] feat: modeling data request callbacks --- contracts/interfaces/IWitnetRequestBoard.sol | 31 +++++++++++++++++--- contracts/interfaces/V2/IWitnetConsumer.sol | 9 ++++++ 2 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 contracts/interfaces/V2/IWitnetConsumer.sol diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index d8e81b1ae..5b1299fe1 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -32,8 +32,12 @@ interface IWitnetRequestBoard { function checkResultStatus(uint256 _queryId) external view returns (Witnet.ResultStatus); function checkResultTraceability(uint256 _queryId) external view returns (uint256, bytes32); + + /// @notice Delete query without further ado. + /// @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 checkResultError(uint256 _queryId) external view returns (Witnet.ResultError memory); + function burnQuery(uint256 _queryId) external; /// @notice Retrieves a copy of all Witnet-provided data related to a previously posted request, removing the whole query from the WRB storage. /// @dev Fails if the `_queryId` is not in 'Reported' status, or called from an address different to @@ -55,20 +59,30 @@ interface IWitnetRequestBoard { /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided /// @notice result to this request. /// @dev Fails if, provided reward is too low. + /// @dev The caller must be a contract implementing the IWitnetConsumer interface. /// @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. + /// @param querySLA The data query SLA to be fulfilled on the Witnet blockchain. /// @return _queryId Unique query identifier. - function postRequest(bytes32 radHash, WitnetV2.RadonSLA calldata slaParams) external payable returns (uint256 _queryId); + function postRequestWithCallback(bytes32 radHash, WitnetV2.RadonSLA calldata querySLA) 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 upgradeQueryReward(uint256 _queryId) external payable; - + /// =============================================================================================================== /// --- Reader interface ------------------------------------------------------------------------------------------ + /// @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, uint256 _resultMaxSize) 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 _maxCallbackGas Maximum gas to be spent when reporting the data request result. + function estimateBaseFeeWithCallback(uint256 _gasPrice, uint256 _maxCallbackGas) external view returns (uint256); /// @notice Returns next query id to be generated by the Witnet Request Board. function getNextQueryId() external view returns (uint256); @@ -171,6 +185,15 @@ interface IWitnetRequestBoard { /// @return _queryId Unique query identifier. function postRequest(address _requestAddr) 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 the Witnet DON. + /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided + /// @notice result to this request. + /// @dev Fails if, provided reward is too low. + /// @param radHash The RAD hash of the data request to be solved by Witnet. + /// @param slaHash The SLA hash of the data request to be solved by Witnet. + /// @return _queryId Unique query identifier. + function postRequest(bytes32 radHash, bytes32 slaHash) external payable returns (uint256 _queryId); + /// Decode raw CBOR bytes into a Witnet.Result instance. /// @param _cborBytes Raw bytes representing a CBOR-encoded value. /// @return A `Witnet.Result` instance. diff --git a/contracts/interfaces/V2/IWitnetConsumer.sol b/contracts/interfaces/V2/IWitnetConsumer.sol new file mode 100644 index 000000000..0ea6aaa49 --- /dev/null +++ b/contracts/interfaces/V2/IWitnetConsumer.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../../libs/Witnet.sol"; + +interface IWitnetConsumer { + function reportWitnetQueryResult(uint256, WitnetCBOR.CBOR calldata) external; + function reportWitnetQueryError(uint256, Witnet.ResultErrorCodes, uint) external; +} \ No newline at end of file From 020c68291b2db9350ac768f70846be5e126458b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 09:47:52 +0100 Subject: [PATCH 26/86] refactor: UsingWitnet --- contracts/UsingWitnet.sol | 113 +++++++++++++++----------------------- 1 file changed, 44 insertions(+), 69 deletions(-) diff --git a/contracts/UsingWitnet.sol b/contracts/UsingWitnet.sol index dbd08f8e9..fe87158ec 100644 --- a/contracts/UsingWitnet.sol +++ b/contracts/UsingWitnet.sol @@ -10,21 +10,23 @@ import "./WitnetRequestBoard.sol"; /// @author The Witnet Foundation. abstract contract UsingWitnet { - WitnetRequestBoard private immutable __witnet; + WitnetRequestBoard internal immutable __witnet; /// @dev Include an address to specify the WitnetRequestBoard entry point address. /// @param _wrb The WitnetRequestBoard entry point address. - constructor(WitnetRequestBoard _wrb) - { - require(address(_wrb) != address(0), "UsingWitnet: no WRB?"); + constructor(WitnetRequestBoard _wrb) { + require( + _wrb.class() == type(IWitnetRequestBoard).interfaceId, + "UsingWitnet: uncompliant WitnetRequestBoard" + ); __witnet = _wrb; } /// @dev Provides a convenient way for client contracts extending this to block the execution of the main logic of the /// @dev contract until a particular request has been successfully solved and reported by Witnet, /// @dev either with an error or successfully. - modifier witnetQuerySolved(uint256 _id) { - require(_witnetCheckResultAvailability(_id), "UsingWitnet: unsolved query"); + modifier witnetQuerySolved(uint256 _witnetQueryId) { + require(_witnetCheckQueryResultAvailability(_witnetQueryId), "UsingWitnet: unsolved query"); _; } @@ -34,94 +36,67 @@ abstract contract UsingWitnet { /// @notice Check if given query was already reported back from the Witnet oracle. /// @param _id The unique identifier of a previously posted data request. - function _witnetCheckResultAvailability(uint256 _id) + function _witnetCheckQueryResultAvailability(uint256 _id) internal view returns (bool) { return __witnet.getQueryStatus(_id) == Witnet.QueryStatus.Reported; } - /// @notice Estimate the reward amount. - /// @param _gasPrice The gas price for which we want to retrieve the estimation. - /// @return The reward to be included when either posting a new request, or upgrading the reward of a previously posted one. - function _witnetEstimateReward(uint256 _gasPrice) + /// @notice Estimate the minimum reward required for posting a data request, using `tx.gasprice` as a reference. + /// @dev Underestimates if the size of returned data is greater than `_resultMaxSize`. + /// @param _resultMaxSize Maximum expected size of returned data (in bytes). + function _witnetEstimateBaseFee(uint256 _resultMaxSize) internal view returns (uint256) { - return __witnet.estimateReward(_gasPrice); + return __witnet.estimateBaseFee(tx.gasprice, _resultMaxSize); } - /// @notice Estimates the reward amount, considering current transaction gas price. - /// @return The reward to be included when either posting a new request, or upgrading the reward of a previously posted one. - function _witnetEstimateReward() + /// @notice Estimate the minimum reward required for posting a data request, using `tx.gasprice` as a reference. + /// @dev Underestimates if the size of returned data is greater than `_resultMaxSize`. + /// @param _maxCallbackGas Maximum gas to be spent when reporting the data request result. + function _witnetEstimateBaseFeeWithCallback(uint256 _maxCallbackGas) internal view returns (uint256) { - return __witnet.estimateReward(tx.gasprice); + return __witnet.estimateBaseFeeWithCallback(tx.gasprice, _maxCallbackGas); } - /// @notice Post some data request to be eventually solved by the Witnet decentralized oracle network. - /// @notice The EVM -> Witnet bridge will read the Witnet Data Request bytecode from the WitnetBytecodes - /// @notice registry based on given `_radHash` and `_slaHash` values. - /// @dev Enough ETH needs to be provided as to cover for the implicit fee. - /// @param _radHash Unique hash of some pre-validated Witnet Radon Request. - /// @param _slaHash Unique hash of some pre-validated Witnet Radon Service-Level Agreement. - /// @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, bytes32 _slaHash) - virtual internal - returns (uint256 _id, uint256 _reward) + function _witnetCheckQueryResultTraceability(uint256 _witnetQueryId) + internal view + returns ( + uint256 _witnetQueryResponseTimestamp, + bytes32 _witnetQueryResponseDrTxHash + ) { - _reward = _witnetEstimateReward(); - require( - _reward <= msg.value, - "UsingWitnet: reward too low" - ); - _id = __witnet.postRequest{value: _reward}(_radHash, _slaHash); + return __witnet.checkResultTraceability(_witnetQueryId); } - /// @notice Post some data request to be eventually solved by the Witnet decentralized oracle network. - /// @notice The EVM -> Witnet bridge will read the Witnet Data Request bytecode from the WitnetBytecodes - /// @notice registry based on given `_radHash` and `_slaHash` values. - /// @dev Enough ETH needs to be provided as to cover for the implicit fee. - /// @param _radHash Unique hash of some pre-validated Witnet Radon Request. - /// @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) - virtual internal - returns (uint256 _id, uint256 _reward) + function _witnetCheckQueryResultStatus(uint256 _witnetQueryId) + internal view + returns (Witnet.ResultStatus) { - return _witnetPostRequest(_radHash, __witnet.registry().verifyRadonSLA(_slaParams)); + return __witnet.checkResultStatus(_witnetQueryId); } - /// @notice Read the Witnet-provided result to a previously posted request. - /// @dev Reverts if the data request was not yet solved. - /// @param _id The unique identifier of some previously posted data request. - /// @return The result of the request as an instance of `Witnet.Result`. - function _witnetReadResult(uint256 _id) + function _witnetCheckQueryResultError(uint256 _witnetQueryId) internal view - virtual - returns (Witnet.Result memory) + returns (Witnet.ResultError memory) { - return __witnet.readResponseResult(_id); + return __witnet.checkResultError(_witnetQueryId); } - /// @notice Upgrade the reward of some previously posted data request. - /// @dev Reverts if the data request was already solved. - /// @param _id The unique identifier of some previously posted data request. - /// @return Amount in which the reward has been increased. - function _witnetUpgradeReward(uint256 _id) - virtual internal - returns (uint256) + function __witnetRequestData( + uint256 _witnetEvmReward, + WitnetV2.RadonSLA calldata _witnetQuerySLA, + bytes32 _witnetRadHash + ) + virtual internal returns (uint256) { - uint256 _currentReward = __witnet.readRequestReward(_id); - uint256 _newReward = _witnetEstimateReward(); - uint256 _fundsToAdd = 0; - if (_newReward > _currentReward) { - _fundsToAdd = (_newReward - _currentReward); - } - __witnet.upgradeReward{value: _fundsToAdd}(_id); - return _fundsToAdd; + return __witnet.postRequest{value: _witnetEvmReward}( + _witnetRadHash, + _witnetQuerySLA + ); } -} \ No newline at end of file +} From 692db6a75d83ec1526bb27f02cb7da7f2a8f9fd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 09:49:46 +0100 Subject: [PATCH 27/86] chore: move UsingWitnet to contracts/apps --- contracts/{ => apps}/UsingWitnet.sol | 2 +- contracts/apps/WitnetRandomness.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename contracts/{ => apps}/UsingWitnet.sol (99%) diff --git a/contracts/UsingWitnet.sol b/contracts/apps/UsingWitnet.sol similarity index 99% rename from contracts/UsingWitnet.sol rename to contracts/apps/UsingWitnet.sol index fe87158ec..f219138df 100644 --- a/contracts/UsingWitnet.sol +++ b/contracts/apps/UsingWitnet.sol @@ -3,7 +3,7 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "./WitnetRequestBoard.sol"; +import "../WitnetRequestBoard.sol"; /// @title The UsingWitnet contract /// @dev Witnet-aware contracts can inherit from this contract in order to interact with Witnet. diff --git a/contracts/apps/WitnetRandomness.sol b/contracts/apps/WitnetRandomness.sol index d558f8830..bb7ec2597 100644 --- a/contracts/apps/WitnetRandomness.sol +++ b/contracts/apps/WitnetRandomness.sol @@ -3,7 +3,7 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "../UsingWitnet.sol"; +import "./UsingWitnet.sol"; import "../WitnetRequest.sol"; import "../core/WitnetUpgradableBase.sol"; import "../interfaces/IWitnetRandomness.sol"; From 3acfe73ef98aa29f8f93cff508ae01c1f454f759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 09:53:08 +0100 Subject: [PATCH 28/86] feat: extend UsingWitnet use cases --- contracts/apps/UsingWitnetRequest.sol | 50 +++++++++++++++ contracts/apps/UsingWitnetRequestTemplate.sol | 61 +++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 contracts/apps/UsingWitnetRequest.sol create mode 100644 contracts/apps/UsingWitnetRequestTemplate.sol diff --git a/contracts/apps/UsingWitnetRequest.sol b/contracts/apps/UsingWitnetRequest.sol new file mode 100644 index 000000000..8631804df --- /dev/null +++ b/contracts/apps/UsingWitnetRequest.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./UsingWitnet.sol"; +import "../WitnetRequest.sol"; + +abstract contract UsingWitnetRequest + is UsingWitnet +{ + WitnetRequest immutable public dataRequest; + + bytes32 immutable internal __witnetRequestRadHash; + uint256 immutable internal __witnetResultMaxSize; + + constructor (WitnetRequest _witnetRequest) + UsingWitnet(_witnetRequest.witnet()) + { + require( + _witnetRequest.class() == type(WitnetRequest).interfaceId, + "UsingWitnetRequest: uncompliant WitnetRequest" + ); + dataRequest = _witnetRequest; + __witnetResultMaxSize = _witnetRequest.resultDataMaxSize(); + __witnetRequestRadHash = _witnetRequest.radHash(); + } + + function _witnetEstimateBaseFee() + virtual internal view + returns (uint256) + { + return __witnet.estimateBaseFee( + tx.gasprice, + __witnetResultMaxSize + ); + } + + function __witnetRequestData( + uint256 _witnetEvmReward, + WitnetV2.RadonSLA calldata _witnetQuerySLA + ) + virtual internal returns (uint256) + { + return __witnetRequestData( + _witnetEvmReward, + _witnetQuerySLA, + __witnetRequestRadHash + ); + } + +} \ No newline at end of file diff --git a/contracts/apps/UsingWitnetRequestTemplate.sol b/contracts/apps/UsingWitnetRequestTemplate.sol new file mode 100644 index 000000000..0d4ea08ed --- /dev/null +++ b/contracts/apps/UsingWitnetRequestTemplate.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./UsingWitnet.sol"; +import "../WitnetRequest.sol"; + +abstract contract UsingWitnetRequestTemplate + is UsingWitnet +{ + WitnetRequestTemplate immutable public dataRequestTemplate; + + uint256 immutable internal __witnetResultMaxSize; + + constructor (WitnetRequestTemplate _requestTemplate) + UsingWitnet(_requestTemplate.witnet()) + { + require( + _requestTemplate.class() == type(WitnetRequestTemplate).interfaceId, + "UsingWitnetRequestTemplate: uncompliant WitnetRequestTemplate" + ); + dataRequestTemplate = _requestTemplate; + __witnetResultMaxSize = _requestTemplate.resultDataMaxSize(); + } + + function _witnetBuildRadHash(string[][] memory _witnetRequestArgs) + internal returns (bytes32) + { + return dataRequestTemplate.verifyRadonRequest(_witnetRequestArgs); + } + + function _witnetBuildRequest(string[][] memory _witnetRequestArgs) + internal returns (WitnetRequest) + { + return WitnetRequest(dataRequestTemplate.buildRequest(_witnetRequestArgs)); + } + + function _witnetEstimateBaseFee() + internal view + returns (uint256) + { + return __witnet.estimateBaseFee( + tx.gasprice, + __witnetResultMaxSize + ); + } + + function __witnetRequestData( + uint256 _witnetEvmReward, + WitnetV2.RadonSLA calldata _witnetQuerySLA, + string[][] memory _witnetRequestArgs + ) + virtual internal returns (uint256) + { + return __witnetRequestData( + _witnetEvmReward, + _witnetQuerySLA, + _witnetBuildRadHash(_witnetRequestArgs) + ); + } + +} \ No newline at end of file From 129671eab623c53ea92ada0ad61c1acb216392f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 09:53:19 +0100 Subject: [PATCH 29/86] feat: abstract WitnetConsumer use cases Supporting data request callbacks --- contracts/apps/WitnetConsumer.sol | 44 +++++++++++ contracts/apps/WitnetRequestConsumer.sol | 77 +++++++++++++++++++ .../apps/WitnetRequestTemplateConsumer.sol | 77 +++++++++++++++++++ contracts/core/WitnetDeployer.sol | 1 - 4 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 contracts/apps/WitnetConsumer.sol create mode 100644 contracts/apps/WitnetRequestConsumer.sol create mode 100644 contracts/apps/WitnetRequestTemplateConsumer.sol diff --git a/contracts/apps/WitnetConsumer.sol b/contracts/apps/WitnetConsumer.sol new file mode 100644 index 000000000..3704ed996 --- /dev/null +++ b/contracts/apps/WitnetConsumer.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./UsingWitnet.sol"; +import "../interfaces/V2/IWitnetConsumer.sol"; + +abstract contract WitnetConsumer + is + IWitnetConsumer, + UsingWitnet +{ + modifier burnQueryAfterReport(uint256 _witnetQueryId) { + _; + __witnet.burnQuery(_witnetQueryId); + } + + modifier onlyFromWitnet { + require(msg.sender == address(__witnet), "WitnetConsumer: unauthorized"); + _; + } + + function _witnetEstimateBaseFee() + virtual internal view + returns (uint256) + { + return _witnetEstimateBaseFeeWithCallback(_witnetReportCallbackMaxGas()); + } + + function __witnetRequestData( + uint256 _witnetEvmReward, + WitnetV2.RadonSLA calldata _witnetQuerySLA, + bytes32 _witnetRadHash + ) + virtual override internal + returns (uint256) + { + return __witnet.postRequestWithCallback{value: _witnetEvmReward}( + _witnetRadHash, + _witnetQuerySLA + ); + } + + function _witnetReportCallbackMaxGas() virtual internal view returns (uint256); +} diff --git a/contracts/apps/WitnetRequestConsumer.sol b/contracts/apps/WitnetRequestConsumer.sol new file mode 100644 index 000000000..369f054c7 --- /dev/null +++ b/contracts/apps/WitnetRequestConsumer.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./UsingWitnetRequest.sol"; +import "./WitnetConsumer.sol"; + +abstract contract WitnetRequestConsumer + is + UsingWitnetRequest, + WitnetConsumer +{ + using WitnetCBOR for WitnetCBOR.CBOR; + using WitnetCBOR for WitnetCBOR.CBOR[]; + + uint256 private immutable __witnetReportCallbackMaxGas; + + constructor(WitnetRequest _witnetRequest, uint256 _maxCallbackGas) + UsingWitnetRequest(_witnetRequest) + { + require( + _witnetEstimateBaseFeeWithCallback(_maxCallbackGas) > UsingWitnetRequest._witnetEstimateBaseFee(), + "WitnetRequestConsumer: max callback gas too low" + ); + __witnetReportCallbackMaxGas = _maxCallbackGas; + } + + function _witnetEstimateBaseFee() + virtual override(UsingWitnetRequest, WitnetConsumer) + internal view + returns (uint256) + { + return WitnetConsumer._witnetEstimateBaseFee(); + } + + function _witnetReportCallbackMaxGas() virtual override internal view returns (uint256) { + return __witnetReportCallbackMaxGas; + } + + function __witnetRequestData( + uint256 _witnetEvmReward, + WitnetV2.RadonSLA calldata _witnetQuerySLA, + bytes32 _witnetRadHash + ) + virtual override(UsingWitnet, WitnetConsumer) internal + returns (uint256) + { + return WitnetConsumer.__witnetRequestData( + _witnetEvmReward, + _witnetQuerySLA, + _witnetRadHash + ); + } + + function reportWitnetQueryResult( + uint256 _witnetQueryId, + WitnetCBOR.CBOR calldata _value + ) + virtual override + external + onlyFromWitnet + // optional: burnQueryAfterReport(_witnetQueryId) + { + // TODO ... + } + + function reportWitnetQueryError( + uint256 _witnetQueryId, + Witnet.ResultErrorCodes, + uint256 + ) + virtual override external + onlyFromWitnet + // optional: burnQueryAfterReport(_witnetQueryId) + { + // TODO ... + } +} diff --git a/contracts/apps/WitnetRequestTemplateConsumer.sol b/contracts/apps/WitnetRequestTemplateConsumer.sol new file mode 100644 index 000000000..e66fd0041 --- /dev/null +++ b/contracts/apps/WitnetRequestTemplateConsumer.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./UsingWitnetRequestTemplate.sol"; +import "./WitnetConsumer.sol"; + +abstract contract WitnetRequestTemplateConsumer + is + UsingWitnetRequestTemplate, + WitnetConsumer +{ + using WitnetCBOR for WitnetCBOR.CBOR; + using WitnetCBOR for WitnetCBOR.CBOR[]; + + uint256 private immutable __witnetReportCallbackMaxGas; + + constructor(WitnetRequestTemplate _requestTemplate, uint256 _maxCallbackGas) + UsingWitnetRequestTemplate(_requestTemplate) + { + require( + _witnetEstimateBaseFeeWithCallback(_maxCallbackGas) > UsingWitnetRequestTemplate._witnetEstimateBaseFee(), + "WitnetRequestTemplateConsumer: max callback gas too low" + ); + __witnetReportCallbackMaxGas = _maxCallbackGas; + } + + function _witnetEstimateBaseFee() + virtual override(UsingWitnetRequestTemplate, WitnetConsumer) + internal view + returns (uint256) + { + return WitnetConsumer._witnetEstimateBaseFee(); + } + + function _witnetReportCallbackMaxGas() virtual override internal view returns (uint256) { + return __witnetReportCallbackMaxGas; + } + + function __witnetRequestData( + uint256 _witnetEvmReward, + WitnetV2.RadonSLA calldata _witnetQuerySLA, + bytes32 _witnetRadHash + ) + virtual override(UsingWitnet, WitnetConsumer) internal + returns (uint256) + { + return WitnetConsumer.__witnetRequestData( + _witnetEvmReward, + _witnetQuerySLA, + _witnetRadHash + ); + } + + function reportWitnetQueryResult( + uint256 _witnetQueryId, + WitnetCBOR.CBOR calldata _value + ) + virtual override + external + onlyFromWitnet + // optional: burnQueryAfterReport(_witnetQueryId) + { + // TODO ... + } + + function reportWitnetQueryError( + uint256 _witnetQueryId, + Witnet.ResultErrorCodes, + uint256 + ) + virtual override external + onlyFromWitnet + // optional: burnQueryAfterReport(_witnetQueryId) + { + // TODO ... + } +} diff --git a/contracts/core/WitnetDeployer.sol b/contracts/core/WitnetDeployer.sol index 99250caf4..ddcda5a87 100644 --- a/contracts/core/WitnetDeployer.sol +++ b/contracts/core/WitnetDeployer.sol @@ -23,7 +23,6 @@ contract WitnetDeployer { { _deployed = determineAddr(_initCode, _salt); if (_deployed.code.length == 0) { - // address _justDeployed; assembly { _deployed := create2(0, add(_initCode, 0x20), mload(_initCode), _salt) } From 03201dd666b29742f7f5c11bee0baf9885ce806d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 11:37:21 +0100 Subject: [PATCH 30/86] refactor: WitnetBoardData* -> WitnetRequestBoardData* --- contracts/core/defaults/WitnetRequestBoardTrustableBase.sol | 4 ++-- .../{WitnetBoardData.sol => WitnetRequestBoardData.sol} | 6 +++--- ...tnetBoardDataACLs.sol => WitnetRequestBoardDataACLs.sol} | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) rename contracts/data/{WitnetBoardData.sol => WitnetRequestBoardData.sol} (95%) rename contracts/data/{WitnetBoardDataACLs.sol => WitnetRequestBoardDataACLs.sol} (90%) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index 3a444ca34..ee0ef3374 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -7,7 +7,7 @@ import "../WitnetUpgradableBase.sol"; import "../../WitnetRequestBoard.sol"; import "../../WitnetRequestFactory.sol"; -import "../../data/WitnetBoardDataACLs.sol"; +import "../../data/WitnetRequestBoardDataACLs.sol"; import "../../interfaces/IWitnetRequest.sol"; import "../../interfaces/IWitnetRequestBoardAdminACLs.sol"; import "../../interfaces/IWitnetRequestBoardReporter.sol"; @@ -23,7 +23,7 @@ abstract contract WitnetRequestBoardTrustableBase is WitnetUpgradableBase, WitnetRequestBoard, - WitnetBoardDataACLs, + WitnetRequestBoardDataACLs, IWitnetRequestBoardReporter, IWitnetRequestBoardAdminACLs, Payable diff --git a/contracts/data/WitnetBoardData.sol b/contracts/data/WitnetRequestBoardData.sol similarity index 95% rename from contracts/data/WitnetBoardData.sol rename to contracts/data/WitnetRequestBoardData.sol index c24664377..021e5ff30 100644 --- a/contracts/data/WitnetBoardData.sol +++ b/contracts/data/WitnetRequestBoardData.sol @@ -6,9 +6,9 @@ import "../libs/Witnet.sol"; /// @title Witnet Request Board base data model. /// @author The Witnet Foundation. -abstract contract WitnetBoardData { +abstract contract WitnetRequestBoardData { - bytes32 internal constant _WITNET_BOARD_DATA_SLOTHASH = + bytes32 internal constant _WITNET_REQUEST_BOARD_DATA_SLOTHASH = /* keccak256("io.witnet.boards.data") */ 0xf595240b351bc8f951c2f53b26f4e78c32cb62122cf76c19b7fdda7d4968e183; @@ -75,7 +75,7 @@ abstract contract WitnetBoardData { returns (WitnetBoardState storage _ptr) { assembly { - _ptr.slot := _WITNET_BOARD_DATA_SLOTHASH + _ptr.slot := _WITNET_REQUEST_BOARD_DATA_SLOTHASH } } diff --git a/contracts/data/WitnetBoardDataACLs.sol b/contracts/data/WitnetRequestBoardDataACLs.sol similarity index 90% rename from contracts/data/WitnetBoardDataACLs.sol rename to contracts/data/WitnetRequestBoardDataACLs.sol index 989f79068..1652d16f9 100644 --- a/contracts/data/WitnetBoardDataACLs.sol +++ b/contracts/data/WitnetRequestBoardDataACLs.sol @@ -2,13 +2,13 @@ pragma solidity >=0.7.0 <0.9.0; -import "./WitnetBoardData.sol"; +import "./WitnetRequestBoardData.sol"; /// @title Witnet Access Control Lists storage layout, for Witnet-trusted request boards. /// @author The Witnet Foundation. -abstract contract WitnetBoardDataACLs +abstract contract WitnetRequestBoardDataACLs is - WitnetBoardData + WitnetRequestBoardData { bytes32 internal constant _WITNET_BOARD_ACLS_SLOTHASH = /* keccak256("io.witnet.boards.data.acls") */ From 07887336a317152b54b16c1daef360041d08eea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 12:23:11 +0100 Subject: [PATCH 31/86] refactor: WRBD.__* -> WRBD.__seek* --- .../WitnetRequestBoardTrustableBase.sol | 88 +++++++++---------- contracts/data/WitnetRequestBoardData.sol | 36 +++++--- 2 files changed, 65 insertions(+), 59 deletions(-) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index ee0ef3374..d54498c5a 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -389,7 +389,7 @@ abstract contract WitnetRequestBoardTrustableBase { Witnet.QueryStatus _queryStatus = _statusOf(_queryId); if (_queryStatus == Witnet.QueryStatus.Reported) { - bytes storage __cborValues = __response(_queryId).cborBytes; + bytes storage __cborValues = __seekQueryResponse(_queryId).cborBytes; // determine whether reported result is an error by peeking the first byte return (__cborValues[0] == bytes1(0xd8) ? Witnet.ResultStatus.Error @@ -420,7 +420,7 @@ abstract contract WitnetRequestBoardTrustableBase reason: "WitnetRequestBoardTrustableBase: unknown query" }); } else { - try WitnetErrorsLib.resultErrorFromCborBytes(__response(_queryId).cborBytes) + try WitnetErrorsLib.resultErrorFromCborBytes(__seekQueryResponse(_queryId).cborBytes) returns (Witnet.ResultError memory _error) { return _error; @@ -447,17 +447,12 @@ abstract contract WitnetRequestBoardTrustableBase function deleteQuery(uint256 _queryId) public virtual override + onlyRequester(_queryId) inStatus(_queryId, Witnet.QueryStatus.Reported) returns (Witnet.Response memory _response) { - Witnet.Query storage __query = __storage().queries[_queryId]; - require( - msg.sender == __query.from, - "WitnetRequestBoardTrustableBase: only requester" - ); - _response = __query.response; + _response = __seekQuery(_queryId).response; delete __storage().queries[_queryId]; - emit DeletedQuery(_queryId, msg.sender); } /// Requests the execution of the given Witnet Data Request in expectation that it will be relayed and solved by the Witnet DON. @@ -481,15 +476,15 @@ abstract contract WitnetRequestBoardTrustableBase require(_value >= _baseReward, "WitnetRequestBoardTrustableBase: reward too low"); // Validates provided script: - require(_requestInterface.hash() != bytes32(0), "WitnetRequestBoardTrustableBase: no precompiled request"); + require(IWitnetRequest(_requestInterface).hash() != bytes32(0), "WitnetRequestBoardTrustableBase: no precompiled request"); _queryId = ++ __storage().numQueries; __storage().queries[_queryId].from = msg.sender; - Witnet.Request storage _request = __request(_queryId); - _request.addr = _requestInterface; - _request.gasprice = _gasPrice; - _request.reward = _value; + Witnet.Request storage __request = __seekQueryRequest(_queryId); + __request.addr = _requestInterface; + __request.gasprice = _gasPrice; + __request.reward = _value; // Let observers know that a new request has been posted emit PostedRequest(_queryId, msg.sender); @@ -520,11 +515,11 @@ abstract contract WitnetRequestBoardTrustableBase _queryId = ++ __storage().numQueries; __storage().queries[_queryId].from = msg.sender; - Witnet.Request storage _request = __request(_queryId); - _request.radHash = _radHash; - _request.slaHash = _slaHash; - _request.gasprice = _gasPrice; - _request.reward = _value; + Witnet.Request storage __request = __seekQueryRequest(_queryId); + __request.radHash = _radHash; + __request.slaHash = _slaHash; + __request.gasprice = _gasPrice; + __request.reward = _value; // Let observers know that a new request has been posted emit PostedRequest(_queryId, msg.sender); @@ -562,22 +557,22 @@ abstract contract WitnetRequestBoardTrustableBase virtual override inStatus(_queryId, Witnet.QueryStatus.Posted) { - Witnet.Request storage _request = __request(_queryId); + Witnet.Request storage __request = __seekQueryRequest(_queryId); - uint256 _newReward = _request.reward + _getMsgValue(); + uint256 _newReward = __request.reward + _getMsgValue(); uint256 _newGasPrice = _getGasPrice(); // If gas price is increased, then check if new rewards cover gas costs - if (_newGasPrice > _request.gasprice) { + if (_newGasPrice > __request.gasprice) { // Checks the reward is covering gas cost uint256 _minResultReward = estimateReward(_newGasPrice); require( _newReward >= _minResultReward, "WitnetRequestBoardTrustableBase: reward too low" ); - _request.gasprice = _newGasPrice; + __request.gasprice = _newGasPrice; } - _request.reward = _newReward; + __request.reward = _newReward; } @@ -627,9 +622,9 @@ abstract contract WitnetRequestBoardTrustableBase external view override inStatus(_queryId, Witnet.QueryStatus.Posted) - returns (Witnet.Request memory _request) + returns (Witnet.Request memory) { - return __request(_queryId); + return __seekQueryRequest(_queryId); } /// Retrieves the serialized bytecode of a previously posted Witnet Data Request. @@ -646,13 +641,13 @@ abstract contract WitnetRequestBoardTrustableBase _statusOf(_queryId) != Witnet.QueryStatus.Unknown, "WitnetRequestBoardTrustableBase: not yet posted" ); - Witnet.Request storage _request = __request(_queryId); - if (_request.addr != address(0)) { - _bytecode = IWitnetRequest(_request.addr).bytecode(); - } else if (_request.radHash != bytes32(0)) { + Witnet.Request storage __request = __seekQueryRequest(_queryId); + if (__request.addr != address(0)) { + _bytecode = IWitnetRequest(__request.addr).bytecode(); + } else if (__request.radHash != bytes32(0)) { _bytecode = registry().bytecodeOf( - _request.radHash, - _request.slaHash + __request.radHash, + __request.slaHash ); } } @@ -693,7 +688,7 @@ abstract contract WitnetRequestBoardTrustableBase inStatus(_queryId, Witnet.QueryStatus.Reported) returns (Witnet.Response memory _response) { - return __response(_queryId); + return __seekQueryResponse(_queryId); } /// Retrieves the hash of the Witnet transaction that actually solved the referred query. @@ -705,7 +700,7 @@ abstract contract WitnetRequestBoardTrustableBase inStatus(_queryId, Witnet.QueryStatus.Reported) returns (bytes32) { - return __response(_queryId).drTxHash; + return __seekQueryResponse(_queryId).drTxHash; } /// Retrieves the address that reported the result to a previously-posted request. @@ -717,7 +712,7 @@ abstract contract WitnetRequestBoardTrustableBase inStatus(_queryId, Witnet.QueryStatus.Reported) returns (address) { - return __response(_queryId).reporter; + return __seekQueryResponse(_queryId).reporter; } /// Retrieves the Witnet-provided CBOR-bytes result of a previously posted request. @@ -729,7 +724,7 @@ abstract contract WitnetRequestBoardTrustableBase inStatus(_queryId, Witnet.QueryStatus.Reported) returns (Witnet.Result memory) { - Witnet.Response storage _response = __response(_queryId); + Witnet.Response storage _response = __seekQueryResponse(_queryId); return _response.cborBytes.resultFromCborBytes(); } @@ -742,7 +737,7 @@ abstract contract WitnetRequestBoardTrustableBase inStatus(_queryId, Witnet.QueryStatus.Reported) returns (uint256) { - return __response(_queryId).timestamp; + return __seekQueryResponse(_queryId).timestamp; } @@ -822,21 +817,18 @@ abstract contract WitnetRequestBoardTrustableBase internal returns (uint256 _reward) { - Witnet.Query storage _query = __query(_queryId); - Witnet.Request storage _request = _query.request; - Witnet.Response storage _response = _query.response; + Witnet.Query storage __query = __seekQuery(_queryId); + Witnet.Request storage __request = __query.request; + Witnet.Response storage __response = __query.response; // solhint-disable not-rely-on-time - _response.timestamp = _timestamp; - _response.drTxHash = _drTxHash; - _response.reporter = msg.sender; - _response.cborBytes = _cborBytes; + __response.timestamp = _timestamp; + __response.drTxHash = _drTxHash; + __response.reporter = msg.sender; + __response.cborBytes = _cborBytes; // return request latest reward - _reward = _request.reward; - - // Request data won't be needed anymore, so it can just get deleted right now: - delete _query.request; + _reward = __request.reward; } function __setReporters(address[] memory _reporters) internal { diff --git a/contracts/data/WitnetRequestBoardData.sol b/contracts/data/WitnetRequestBoardData.sol index 021e5ff30..677f343d3 100644 --- a/contracts/data/WitnetRequestBoardData.sol +++ b/contracts/data/WitnetRequestBoardData.sol @@ -28,33 +28,47 @@ abstract contract WitnetRequestBoardData { require( _statusOf(_queryId) == _status, _statusOfRevertMessage(_status) - ); - _; + ); _; } /// Asserts the given query was previously posted and that it was not yet deleted. modifier notDeleted(uint256 _queryId) { - require(_queryId > 0 && _queryId <= __storage().numQueries, "WitnetRequestBoard: not yet posted"); - require(__query(_queryId).from != address(0), "WitnetRequestBoard: deleted"); - _; + require( + _queryId > 0 && _queryId <= __storage().numQueries, + "WitnetRequestBoard: not yet posted" + ); + require( + __seekQuery(_queryId).from != address(0), + "WitnetRequestBoard: deleted" + ); _; + } + + /// Asserts the caller actually posted the referred query. + modifier onlyRequester(uint256 _queryId) { + require( + msg.sender == __seekQuery(_queryId).from, + "WitnetRequestBoardBase: not the requester" + ); _; } - /// Asserts the give query was actually posted before calling this method. + /// Asserts the given query was actually posted before calling this method. modifier wasPosted(uint256 _queryId) { - require(_queryId > 0 && _queryId <= __storage().numQueries, "WitnetRequestBoard: not yet posted"); - _; + require( + _queryId > 0 && _queryId <= __storage().numQueries, + "WitnetRequestBoard: not yet posted" + ); _; } // ================================================================================================================ // --- Internal functions ----------------------------------------------------------------------------------------- /// Gets query storage by query id. - function __query(uint256 _queryId) internal view returns (Witnet.Query storage) { + function __seekQuery(uint256 _queryId) internal view returns (Witnet.Query storage) { return __storage().queries[_queryId]; } /// Gets the Witnet.Request part of a given query. - function __request(uint256 _queryId) + function __seekQueryRequest(uint256 _queryId) internal view returns (Witnet.Request storage) { @@ -62,7 +76,7 @@ abstract contract WitnetRequestBoardData { } /// Gets the Witnet.Result part of a given query. - function __response(uint256 _queryId) + function __seekQueryResponse(uint256 _queryId) internal view returns (Witnet.Response storage) { From 420d285d0fd353ae3384d39a934d9e29a2f6f43e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 12:25:56 +0100 Subject: [PATCH 32/86] feat: implement WRB.burnQuery --- .../defaults/WitnetRequestBoardTrustableBase.sol | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index d54498c5a..7638b3b0d 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -439,6 +439,18 @@ abstract contract WitnetRequestBoardTrustableBase } } } + /// @notice Delete query without further ado. + /// @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 burnQuery(uint256 _queryId) + external + virtual override + onlyRequester(_queryId) + inStatus(_queryId, Witnet.QueryStatus.Reported) + { + delete __storage().queries[_queryId]; + } /// 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 From e3f8c259495d66d9868b3e5c2cc41fb1b9416a06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 12:28:37 +0100 Subject: [PATCH 33/86] feat: implement WRB.checkResultTraceability --- .../WitnetRequestBoardTrustableBase.sol | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index 7638b3b0d..7326bc3bc 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -439,6 +439,23 @@ abstract contract WitnetRequestBoardTrustableBase } } } + + /// @notice Returns query's result traceability data + /// @param _queryId The unique query identifier. + /// @return _resultTimestamp Timestamp at which the query was solved by the Witnet blockchain. + /// @return _resultDrTxHash Witnet blockchain hash of the commit/reveal act that solved the query. + function checkResultTraceability(uint256 _queryId) + external view + override + returns (uint256, bytes32) + { + Witnet.Response storage __response = __seekQueryResponse(_queryId); + return ( + __response.timestamp, + __response.drTxHash + ); + } + /// @notice Delete query without further ado. /// @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. From fc9173eb232e6a8c41c064cff9f3231f9003aedc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 12:29:07 +0100 Subject: [PATCH 34/86] chore: deprecate old WitnetRequestBoardTrustableBoba --- .../WitnetRequestBoardTrustableBoba.sol | 132 ------------------ 1 file changed, 132 deletions(-) delete mode 100644 contracts/core/customs/WitnetRequestBoardTrustableBoba.sol diff --git a/contracts/core/customs/WitnetRequestBoardTrustableBoba.sol b/contracts/core/customs/WitnetRequestBoardTrustableBoba.sol deleted file mode 100644 index d8e471010..000000000 --- a/contracts/core/customs/WitnetRequestBoardTrustableBoba.sol +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-License-Identifier: MIT - -/* solhint-disable var-name-mixedcase */ - -pragma solidity >=0.7.0 <0.9.0; -pragma experimental ABIEncoderV2; - -// Inherits from: -import "../defaults/WitnetRequestBoardTrustableBase.sol"; - -// Uses: -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -/// @title Witnet Request Board OVM-compatible (Optimism) "trustable" implementation. -/// @notice Contract to bridge requests to Witnet Decentralized Oracle Network. -/// @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. -/// @author The Witnet Foundation -contract WitnetRequestBoardTrustableBoba - is - Payable, - WitnetRequestBoardTrustableBase -{ - uint256 internal lastBalance; - uint256 internal immutable _OVM_GAS_PRICE; - uint256 internal immutable _OVM_ESTIMATED_REPORT_RESULT_GAS; - - modifier ovmPayable virtual { - _; - // all calls to payable methods, - // MUST update internal 'lastBalance' value at the very end. - lastBalance = _balanceOf(address(this)); - } - - constructor( - WitnetRequestFactory _factory, - bool _upgradable, - bytes32 _versionTag, - uint256 _layer2ReportResultGasLimit, - uint256 _layer2GasPrice, - address _oETH - ) - WitnetRequestBoardTrustableBase(_factory, _upgradable, _versionTag, _oETH) - { - require(address(_oETH) != address(0), "WitnetRequestBoardTrustableBoba: null currency"); - _OVM_GAS_PRICE = _layer2GasPrice; - _OVM_ESTIMATED_REPORT_RESULT_GAS = _layer2ReportResultGasLimit; - } - - /// Gets lastBalance of given address. - function _balanceOf(address _from) - internal view - returns (uint256) - { - return currency.balanceOf(_from); - } - - - // ================================================================================================================ - // --- Overrides 'Payable' ---------------------------------------------------------------------------------------- - - /// Gets current transaction price. - function _getGasPrice() - internal view - override - returns (uint256) - { - return _OVM_GAS_PRICE; - } - - /// Calculates `msg.value` equivalent OVM_ETH value. - /// @dev Based on `lastBalance` value. - function _getMsgValue() - internal view - override - returns (uint256) - { - uint256 _newBalance = _balanceOf(address(this)); - assert(_newBalance >= lastBalance); - return _newBalance - lastBalance; - } - - /// Transfers oETHs to given address. - /// @dev Updates `lastBalance` value. - /// @param _to OVM_ETH recipient account. - /// @param _amount Amount of oETHs to transfer. - function _safeTransferTo(address payable _to, uint256 _amount) - internal - override - { - uint256 _lastBalance = _balanceOf(address(this)); - require(_amount <= _lastBalance, "WitnetRequestBoardTrustableBoba: insufficient funds"); - lastBalance = _lastBalance - _amount; - currency.transfer(_to, _amount); - } - - - // ================================================================================================================ - // --- Overrides implementation of 'IWitnetRequestBoardView' ------------------------------------------------------ - - /// @dev Estimate the minimal amount of reward we need to insert for a given gas price. - /// @return The minimal reward to be included for the given gas price. - function estimateReward(uint256) - public view - virtual override - returns (uint256) - { - return _OVM_GAS_PRICE * _OVM_ESTIMATED_REPORT_RESULT_GAS; - } - - - // ================================================================================================================ - // --- Overrides implementation of 'IWitnetRequestBoardRequestor' ------------------------------------------------- - - function postRequest(IWitnetRequest _request) - public payable - virtual override - ovmPayable - returns (uint256) - { - return WitnetRequestBoardTrustableBase.postRequest(_request); - } - - function upgradeReward(uint256 _queryId) - public payable - virtual override - ovmPayable - inStatus(_queryId, Witnet.QueryStatus.Posted) - { - WitnetRequestBoardTrustableBase.upgradeReward(_queryId); - } -} From 87f112ce5c23ece938d19c5d6922ac02e32996fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 12:43:21 +0100 Subject: [PATCH 35/86] chore: reordering source code --- .../WitnetRequestBoardTrustableBase.sol | 67 +++++++++++-------- contracts/interfaces/IWitnetRequestBoard.sol | 18 +++-- 2 files changed, 50 insertions(+), 35 deletions(-) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index 7326bc3bc..c061cffb3 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -102,9 +102,17 @@ abstract contract WitnetRequestBoardTrustableBase } } + + // ================================================================================================================ + // --- Yet to be implemented virtual methods ---------------------------------------------------------------------- + + /// 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 estimateBaseFee(uint256 _gasPrice) virtual override public view returns (uint256); + // ================================================================================================================ - // --- Overrides 'Upgradeable' ------------------------------------------------------------------------------------- + // --- 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. @@ -226,7 +234,7 @@ abstract contract WitnetRequestBoardTrustableBase // ================================================================================================================ - // --- Full implementation of 'IWitnetRequestBoardReporter' ------------------------------------------------------- + // --- IWitnetRequestBoard Reporter methods ----------------------------------------------------------------------- /// Reports the Witnet-provided result to a previously posted request. /// @dev Will assume `block.timestamp` as the timestamp at which the request was solved. @@ -375,7 +383,20 @@ abstract contract WitnetRequestBoardTrustableBase // ================================================================================================================ - // --- Full implementation of 'IWitnetRequestBoardRequestor' ------------------------------------------------------ + // --- IWitnetRequestBoard Requester methods ---------------------------------------------------------------------- + + /// @notice Delete query without further ado. + /// @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 burnQuery(uint256 _queryId) + external + virtual override + onlyRequester(_queryId) + inStatus(_queryId, Witnet.QueryStatus.Reported) + { + delete __storage().queries[_queryId]; + } /// @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; @@ -456,19 +477,6 @@ abstract contract WitnetRequestBoardTrustableBase ); } - /// @notice Delete query without further ado. - /// @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 burnQuery(uint256 _queryId) - external - virtual override - onlyRequester(_queryId) - inStatus(_queryId, Witnet.QueryStatus.Reported) - { - delete __storage().queries[_queryId]; - } - /// 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. @@ -501,7 +509,7 @@ abstract contract WitnetRequestBoardTrustableBase uint256 _gasPrice = _getGasPrice(); // check base reward - uint256 _baseReward = estimateReward(_gasPrice); + uint256 _baseReward = estimateBaseFee(_gasPrice, 32); require(_value >= _baseReward, "WitnetRequestBoardTrustableBase: reward too low"); // Validates provided script: @@ -535,7 +543,7 @@ abstract contract WitnetRequestBoardTrustableBase uint256 _gasPrice = _getGasPrice(); // check base reward - uint256 _baseReward = estimateReward(_gasPrice); + uint256 _baseReward = estimateBaseFee(_gasPrice, 32); require( _value >= _baseReward, "WitnetRequestBoardTrustableBase: reward too low" @@ -594,7 +602,7 @@ abstract contract WitnetRequestBoardTrustableBase // If gas price is increased, then check if new rewards cover gas costs if (_newGasPrice > __request.gasprice) { // Checks the reward is covering gas cost - uint256 _minResultReward = estimateReward(_newGasPrice); + uint256 _minResultReward = estimateReward(_newGasPrice, 32); require( _newReward >= _minResultReward, "WitnetRequestBoardTrustableBase: reward too low" @@ -606,14 +614,7 @@ abstract contract WitnetRequestBoardTrustableBase // ================================================================================================================ - // --- Full implementation 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) - public view - virtual override - returns (uint256); + // --- 'IWitnetRequestBoard' Viewer methods ----------------------------------------------------------------------- /// Returns next request id to be generated by the Witnet Request Board. function getNextQueryId() @@ -771,7 +772,7 @@ abstract contract WitnetRequestBoardTrustableBase // ================================================================================================================ - // --- Full implementation of 'IWitnetRequestBoard' interface ------------------------------------------ + // --- Deprecating methods from 'IWitnetRequestBoard' ------------------------------------------------------------- /// Tell if a Witnet.Result is successful. /// @param _result An instance of Witnet.Result. @@ -822,6 +823,16 @@ abstract contract WitnetRequestBoardTrustableBase return uint64(_result.asUint()); } + /// 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 + override + returns (uint256) + { + return estimateBaseFee(_gasPrice, 32); + } + /// Decode raw CBOR bytes into a Witnet.Result instance. /// @param _cborBytes Raw bytes representing a CBOR-encoded value. /// @return A `Witnet.Result` instance. diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index 5b1299fe1..643c5ec4b 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -17,8 +17,14 @@ interface IWitnetRequestBoard { /// =============================================================================================================== - /// --- Requestor interface --------------------------------------------------------------------------------------- + /// --- Requester interface --------------------------------------------------------------------------------------- + /// @notice Delete query without further ado. + /// @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 burnQuery(uint256 _queryId) external; + /// @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 view returns (Witnet.ResultError memory); @@ -31,13 +37,11 @@ interface IWitnetRequestBoard { /// @param _queryId The unique query identifier. function checkResultStatus(uint256 _queryId) external view returns (Witnet.ResultStatus); - function checkResultTraceability(uint256 _queryId) external view returns (uint256, bytes32); - - /// @notice Delete query without further ado. - /// @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. + /// @notice Returns query's result traceability data /// @param _queryId The unique query identifier. - function burnQuery(uint256 _queryId) external; + /// @return _resultTimestamp Timestamp at which the query was solved by the Witnet blockchain. + /// @return _resultDrTxHash Witnet blockchain hash of the commit/reveal act that solved the query. + function checkResultTraceability(uint256 _queryId) external view returns (uint256 _resultTimestamp, bytes32 _resultDrTxHash); /// @notice Retrieves a copy of all Witnet-provided data related to a previously posted request, removing the whole query from the WRB storage. /// @dev Fails if the `_queryId` is not in 'Reported' status, or called from an address different to From b9413ee2fcebe7919baabd7fd267f1d329c678c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 12:44:52 +0100 Subject: [PATCH 36/86] chore: deprecate IWRB.DeletedQuery --- contracts/interfaces/IWitnetRequestBoard.sol | 3 --- 1 file changed, 3 deletions(-) diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index 643c5ec4b..bbb192ce3 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -12,9 +12,6 @@ interface IWitnetRequestBoard { /// Emitted when a Witnet-solved result is reported to the WRB. event PostedResult(uint256 queryId, address from); - /// Emitted when all data related to given query is deleted from the WRB. - event DeletedQuery(uint256 queryId, address from); - /// =============================================================================================================== /// --- Requester interface --------------------------------------------------------------------------------------- From c820012cbfbc56cc6cd8b714a6ed42188e5af810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 13:42:04 +0100 Subject: [PATCH 37/86] feat: implement WRB.estimateBaseFee(uint,uint) --- .../WitnetRequestBoardTrustableOvm2.sol | 26 ++++++++++++------- .../WitnetRequestBoardTrustableReef.sol | 19 +++++++++----- .../WitnetRequestBoardTrustableBase.sol | 10 ++++--- .../WitnetRequestBoardTrustableDefault.sol | 26 +++++++++++++------ 4 files changed, 52 insertions(+), 29 deletions(-) diff --git a/contracts/core/customs/WitnetRequestBoardTrustableOvm2.sol b/contracts/core/customs/WitnetRequestBoardTrustableOvm2.sol index 34e8cc2a2..eac97c4f6 100644 --- a/contracts/core/customs/WitnetRequestBoardTrustableOvm2.sol +++ b/contracts/core/customs/WitnetRequestBoardTrustableOvm2.sol @@ -27,13 +27,15 @@ contract WitnetRequestBoardTrustableOvm2 WitnetRequestFactory _factory, bool _upgradable, bytes32 _versionTag, - uint256 _reportResultGasLimit + uint256 _reportResultGasBase, + uint256 _sstoreFromZeroGas ) WitnetRequestBoardTrustableDefault( _factory, _upgradable, _versionTag, - _reportResultGasLimit + _reportResultGasBase, + _sstoreFromZeroGas ) { gasPriceOracleL1 = OVM_GasPriceOracle(0x420000000000000000000000000000000000000F); @@ -41,17 +43,21 @@ contract WitnetRequestBoardTrustableOvm2 // ================================================================================================================ - // --- Overrides implementation 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) - public view + // --- Overrides 'IWitnetRequestBoard' ---------------------------------------------------------------------------- + + /// @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, uint256 _resultMaxSize) + public view virtual override returns (uint256) { - return _gasPrice * _ESTIMATED_REPORT_RESULT_GAS + gasPriceOracleL1.getL1Fee( - hex"c8f5cdd500000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000225820ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + return WitnetRequestBoardTrustableDefault.estimateBaseFee(_gasPrice, _resultMaxSize) + ( + _gasPrice * gasPriceOracleL1.getL1Fee( + hex"c8f5cdd500000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000225820ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + ) ); } } diff --git a/contracts/core/customs/WitnetRequestBoardTrustableReef.sol b/contracts/core/customs/WitnetRequestBoardTrustableReef.sol index ed7ea2fde..9094c62a6 100644 --- a/contracts/core/customs/WitnetRequestBoardTrustableReef.sol +++ b/contracts/core/customs/WitnetRequestBoardTrustableReef.sol @@ -21,29 +21,34 @@ contract WitnetRequestBoardTrustableReef WitnetRequestFactory _factory, bool _upgradable, bytes32 _versionTag, - uint256 _reportResultGasLimit + uint256 _reportResultGasBase, + uint256 _sstoreFromZeroGas ) WitnetRequestBoardTrustableDefault( _factory, _upgradable, _versionTag, - _reportResultGasLimit + _reportResultGasBase, + _sstoreFromZeroGas ) {} // ================================================================================================================ - // --- Overrides implementation of 'IWitnetRequestBoardView' ------------------------------------------------------ + // --- Overrides 'IWitnetRequestBoard' ---------------------------------------------------------------------------- - /// @dev Estimate the minimal amount of reward we need to insert for a given gas price. - /// @return The minimal reward to be included for the given gas price. - function estimateReward(uint256) + /// @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, uint256 _resultMaxSize) public view virtual override returns (uint256) { - return _ESTIMATED_REPORT_RESULT_GAS; + return WitnetRequestBoardTrustableDefault.estimateBaseFee(1, _resultMaxSize); } + // ================================================================================================================ // --- Overrides 'Payable' ---------------------------------------------------------------------------------------- diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index c061cffb3..5ecaca577 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -106,9 +106,11 @@ abstract contract WitnetRequestBoardTrustableBase // ================================================================================================================ // --- Yet to be implemented virtual methods ---------------------------------------------------------------------- - /// 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 estimateBaseFee(uint256 _gasPrice) virtual override public view returns (uint256); + /// @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, uint256 _resultMaxSize) virtual public view returns (uint256); // ================================================================================================================ @@ -602,7 +604,7 @@ abstract contract WitnetRequestBoardTrustableBase // If gas price is increased, then check if new rewards cover gas costs if (_newGasPrice > __request.gasprice) { // Checks the reward is covering gas cost - uint256 _minResultReward = estimateReward(_newGasPrice, 32); + uint256 _minResultReward = estimateBaseFee(_newGasPrice, 32); require( _newReward >= _minResultReward, "WitnetRequestBoardTrustableBase: reward too low" diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol b/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol index dfbd77f08..ef7829193 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol @@ -16,13 +16,15 @@ contract WitnetRequestBoardTrustableDefault is WitnetRequestBoardTrustableBase { - uint256 internal immutable _ESTIMATED_REPORT_RESULT_GAS; + uint256 internal immutable __reportResultGasBase; + uint256 internal immutable __sstoreFromZeroGas; constructor( WitnetRequestFactory _factory, bool _upgradable, bytes32 _versionTag, - uint256 _reportResultGasLimit + uint256 _reportResultGasBase, + uint256 _sstoreFromZeroGas ) WitnetRequestBoardTrustableBase( _factory, @@ -31,21 +33,29 @@ contract WitnetRequestBoardTrustableDefault address(0) ) { - _ESTIMATED_REPORT_RESULT_GAS = _reportResultGasLimit; + __reportResultGasBase = _reportResultGasBase; + __sstoreFromZeroGas = _sstoreFromZeroGas; } // ================================================================================================================ - // --- Overrides implementation of 'IWitnetRequestBoardView' ------------------------------------------------------ + // --- Overrides 'IWitnetRequestBoard' ---------------------------------------------------------------------------- - /// 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) + /// @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, uint256 _resultMaxSize) public view virtual override returns (uint256) { - return _gasPrice * _ESTIMATED_REPORT_RESULT_GAS; + return _gasPrice * ( + __reportResultGasBase + + __sstoreFromZeroGas * ( + 3 + _resultMaxSize / 32 + ) + ); } From c9286a8d72f50b4673b0263cbedf02fcd43ee388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 14:07:50 +0100 Subject: [PATCH 38/86] feat: implement WRB.estimateBaseFeeWithCallback --- .../customs/WitnetRequestBoardTrustableOvm2.sol | 15 +++++++++++++++ .../customs/WitnetRequestBoardTrustableReef.sol | 11 +++++++++++ .../WitnetRequestBoardTrustableDefault.sol | 15 +++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/contracts/core/customs/WitnetRequestBoardTrustableOvm2.sol b/contracts/core/customs/WitnetRequestBoardTrustableOvm2.sol index eac97c4f6..e00075c36 100644 --- a/contracts/core/customs/WitnetRequestBoardTrustableOvm2.sol +++ b/contracts/core/customs/WitnetRequestBoardTrustableOvm2.sol @@ -60,4 +60,19 @@ contract WitnetRequestBoardTrustableOvm2 ) ); } + + /// @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 _maxCallbackGas Maximum gas to be spent when reporting the data request result. + function estimateBaseFeeWithCallback(uint256 _gasPrice, uint256 _maxCallbackGas) + public view + virtual override + returns (uint256) + { + return WitnetRequestBoardTrustableDefault.estimateBaseFeeWithCallback(_gasPrice, _maxCallbackGas) + ( + _gasPrice * gasPriceOracleL1.getL1Fee( + hex"c8f5cdd500000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000225820ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + ) + ); + } } diff --git a/contracts/core/customs/WitnetRequestBoardTrustableReef.sol b/contracts/core/customs/WitnetRequestBoardTrustableReef.sol index 9094c62a6..ed1872cdb 100644 --- a/contracts/core/customs/WitnetRequestBoardTrustableReef.sol +++ b/contracts/core/customs/WitnetRequestBoardTrustableReef.sol @@ -48,6 +48,17 @@ contract WitnetRequestBoardTrustableReef return WitnetRequestBoardTrustableDefault.estimateBaseFee(1, _resultMaxSize); } + /// @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 _maxCallbackGas Maximum gas to be spent when reporting the data request result. + function estimateBaseFeeWithCallback(uint256 _gasPrice, uint256 _maxCallbackGas) + public view + virtual override + returns (uint256) + { + return WitnetRequestBoardTrustableDefault.estimateBaseFeeWithCallback(1, _maxCallbackGas); + } + // ================================================================================================================ // --- Overrides 'Payable' ---------------------------------------------------------------------------------------- diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol b/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol index ef7829193..d3bf30358 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol @@ -58,6 +58,21 @@ contract WitnetRequestBoardTrustableDefault ); } + /// @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 _maxCallbackGas Maximum gas to be spent when reporting the data request result. + function estimateBaseFeeWithCallback(uint256 _gasPrice, uint256 _maxCallbackGas) + public view + virtual override + returns (uint256) + { + return _gasPrice * ( + __reportResultGasBase + + 3 * __sstoreFromZeroGas + + _maxCallbackGas + ); + } + // ================================================================================================================ // --- Overrides 'Payable' ---------------------------------------------------------------------------------------- From 6ad43c7ef6f75eb795a758ecaa2e5bc880f77750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 14:10:21 +0100 Subject: [PATCH 39/86] feat: implement WRB.upgradeQueryReward --- .../WitnetRequestBoardTrustableBase.sol | 51 ++++++++++++------- contracts/interfaces/IWitnetRequestBoard.sol | 7 ++- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index 5ecaca577..5339cafec 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -591,27 +591,13 @@ abstract contract WitnetRequestBoardTrustableBase /// @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) + function upgradeQueryReward(uint256 _queryId) public payable virtual override inStatus(_queryId, Witnet.QueryStatus.Posted) { - Witnet.Request storage __request = __seekQueryRequest(_queryId); - - uint256 _newReward = __request.reward + _getMsgValue(); - uint256 _newGasPrice = _getGasPrice(); - - // If gas price is increased, then check if new rewards cover gas costs - if (_newGasPrice > __request.gasprice) { - // Checks the reward is covering gas cost - uint256 _minResultReward = estimateBaseFee(_newGasPrice, 32); - require( - _newReward >= _minResultReward, - "WitnetRequestBoardTrustableBase: reward too low" - ); - __request.gasprice = _newGasPrice; - } - __request.reward = _newReward; + __seekQueryRequest(_queryId).reward += _getMsgValue(); + emit UpgradedReward(_queryId); } @@ -846,6 +832,37 @@ abstract contract WitnetRequestBoardTrustableBase return Witnet.resultFromCborBytes(_cborBytes); } + /// 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) + public payable + virtual override + inStatus(_queryId, Witnet.QueryStatus.Posted) + { + Witnet.Request storage __request = __seekQueryRequest(_queryId); + + uint256 _newReward = __request.reward + _getMsgValue(); + uint256 _newGasPrice = _getGasPrice(); + + // If gas price is increased, then check if new rewards cover gas costs + if (_newGasPrice > __request.gasprice) { + // Checks the reward is covering gas cost + uint256 _minResultReward = estimateBaseFee(_newGasPrice, 32); + require( + _newReward >= _minResultReward, + "WitnetRequestBoardTrustableBase: reward too low" + ); + __request.gasprice = _newGasPrice; + } + __request.reward = _newReward; + } + // ================================================================================================================ // --- Internal functions ----------------------------------------------------------------------------------------- diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index bbb192ce3..68b86ca00 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -7,10 +7,13 @@ import "../libs/WitnetV2.sol"; interface IWitnetRequestBoard { /// Emitted when a Witnet Data Request is posted to the WRB. - event PostedRequest(uint256 queryId, address from); + event PostedRequest(uint256 indexed queryId, address from); /// Emitted when a Witnet-solved result is reported to the WRB. - event PostedResult(uint256 queryId, address from); + event PostedResult(uint256 indexed queryId, address from); + + /// Emitted when the reward of some not-yet reported query is upgraded. + event UpgradedReward(uint256 indexed queryId); /// =============================================================================================================== From c4cb486a5e02b7381f38b4dee0640ac8ba08d8d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 14:18:56 +0100 Subject: [PATCH 40/86] chore: deprecating WRB.postRequest(address) --- .../WitnetRequestBoardTrustableBase.sol | 67 +++++++++---------- contracts/libs/Witnet.sol | 2 +- 2 files changed, 33 insertions(+), 36 deletions(-) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index 5339cafec..86d7b3488 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -494,41 +494,6 @@ abstract contract WitnetRequestBoardTrustableBase 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 _requestInterface The address of a IWitnetRequest contract, containing the actual Data Request seralized bytecode. - /// @return _queryId An unique query identifier. - function postRequest(address _requestInterface) - virtual override - public payable - returns (uint256 _queryId) - { - uint256 _value = _getMsgValue(); - uint256 _gasPrice = _getGasPrice(); - - // check base reward - uint256 _baseReward = estimateBaseFee(_gasPrice, 32); - require(_value >= _baseReward, "WitnetRequestBoardTrustableBase: reward too low"); - - // Validates provided script: - require(IWitnetRequest(_requestInterface).hash() != bytes32(0), "WitnetRequestBoardTrustableBase: no precompiled request"); - - _queryId = ++ __storage().numQueries; - __storage().queries[_queryId].from = msg.sender; - - Witnet.Request storage __request = __seekQueryRequest(_queryId); - __request.addr = _requestInterface; - __request.gasprice = _gasPrice; - __request.reward = _value; - - // Let observers know that a new request has been posted - emit PostedRequest(_queryId, msg.sender); - } - /// 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. @@ -821,6 +786,38 @@ abstract contract WitnetRequestBoardTrustableBase return estimateBaseFee(_gasPrice, 32); } + /// 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 _requestInterface The address of a IWitnetRequest contract, containing the actual Data Request seralized bytecode. + /// @return _queryId An unique query identifier. + function postRequest(address _requestInterface) + virtual override + public payable + returns (uint256 _queryId) + { + uint256 _value = _getMsgValue(); + uint256 _gasPrice = _getGasPrice(); + + // check base reward + uint256 _baseFee = estimateBaseFee(_gasPrice, 32); + require(_value >= _baseFee, "WitnetRequestBoardTrustableBase: reward too low"); + + _queryId = ++ __storage().numQueries; + __storage().queries[_queryId].from = msg.sender; + + Witnet.Request storage __request = __seekQueryRequest(_queryId); + __request._addr = _requestInterface; + __request.gasprice = _gasPrice; + __request.reward = _value; + + // Let observers know that a new request has been posted + emit PostedRequest(_queryId, msg.sender); + } + /// Decode raw CBOR bytes into a Witnet.Result instance. /// @param _cborBytes Raw bytes representing a CBOR-encoded value. /// @return A `Witnet.Result` instance. diff --git a/contracts/libs/Witnet.sol b/contracts/libs/Witnet.sol index ee4ebfc8a..7ab1ffcfe 100644 --- a/contracts/libs/Witnet.sol +++ b/contracts/libs/Witnet.sol @@ -28,7 +28,7 @@ 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; // Deprecating: Address of the 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. From d98e5b87bfc99ca355f30e6daf41f192ce2d238c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 17 Nov 2023 14:23:44 +0100 Subject: [PATCH 41/86] feat: deprecate Witnet.Request.gasprice --- .../WitnetRequestBoardTrustableReef.sol | 6 +- .../WitnetRequestBoardTrustableBase.sol | 56 +++++++++++-------- contracts/interfaces/IWitnetRequestBoard.sol | 14 ++--- contracts/libs/Witnet.sol | 8 +-- 4 files changed, 47 insertions(+), 37 deletions(-) diff --git a/contracts/core/customs/WitnetRequestBoardTrustableReef.sol b/contracts/core/customs/WitnetRequestBoardTrustableReef.sol index ed1872cdb..9d7feaeab 100644 --- a/contracts/core/customs/WitnetRequestBoardTrustableReef.sol +++ b/contracts/core/customs/WitnetRequestBoardTrustableReef.sol @@ -38,9 +38,8 @@ contract WitnetRequestBoardTrustableReef /// @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, uint256 _resultMaxSize) + function estimateBaseFee(uint256, uint256 _resultMaxSize) public view virtual override returns (uint256) @@ -49,9 +48,8 @@ contract WitnetRequestBoardTrustableReef } /// @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 _maxCallbackGas Maximum gas to be spent when reporting the data request result. - function estimateBaseFeeWithCallback(uint256 _gasPrice, uint256 _maxCallbackGas) + function estimateBaseFeeWithCallback(uint256, uint256 _maxCallbackGas) public view virtual override returns (uint256) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index 86d7b3488..26de78298 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -510,9 +510,9 @@ abstract contract WitnetRequestBoardTrustableBase uint256 _gasPrice = _getGasPrice(); // check base reward - uint256 _baseReward = estimateBaseFee(_gasPrice, 32); + uint256 _baseFee = estimateBaseFee(_gasPrice, 32); require( - _value >= _baseReward, + _value >= _baseFee, "WitnetRequestBoardTrustableBase: reward too low" ); @@ -522,7 +522,6 @@ abstract contract WitnetRequestBoardTrustableBase Witnet.Request storage __request = __seekQueryRequest(_queryId); __request.radHash = _radHash; __request.slaHash = _slaHash; - __request.gasprice = _gasPrice; __request.reward = _value; // Let observers know that a new request has been posted @@ -546,6 +545,19 @@ abstract contract WitnetRequestBoardTrustableBase registry().verifyRadonSLA(_slaParams) ); } + + /// @notice Requests the execution of the given Witnet Data Request in expectation that it will be relayed and solved by the Witnet DON. + /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided + /// @notice result to this request. + /// @dev Fails if, provided reward is too low. + /// @dev The caller must be a contract implementing the IWitnetConsumer interface. + function postRequestWithCallback(bytes32, WitnetV2.RadonSLA calldata) + virtual override + external payable + returns (uint256) + { + revert("WitnetRequestBoardTrustableBase: not implemented"); + } /// Increments the reward of a previously posted request by adding the transaction value to it. @@ -625,8 +637,8 @@ abstract contract WitnetRequestBoardTrustableBase "WitnetRequestBoardTrustableBase: not yet posted" ); Witnet.Request storage __request = __seekQueryRequest(_queryId); - if (__request.addr != address(0)) { - _bytecode = IWitnetRequest(__request.addr).bytecode(); + if (__request._addr != address(0)) { + _bytecode = IWitnetRequest(__request._addr).bytecode(); } else if (__request.radHash != bytes32(0)) { _bytecode = registry().bytecodeOf( __request.radHash, @@ -635,20 +647,6 @@ abstract contract WitnetRequestBoardTrustableBase } } - /// 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 identifier - function readRequestGasPrice(uint256 _queryId) - external view - override - inStatus(_queryId, Witnet.QueryStatus.Posted) - returns (uint256) - { - return __storage().queries[_queryId].request.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. @@ -811,13 +809,27 @@ abstract contract WitnetRequestBoardTrustableBase Witnet.Request storage __request = __seekQueryRequest(_queryId); __request._addr = _requestInterface; - __request.gasprice = _gasPrice; + __request._gasprice = _gasPrice; __request.reward = _value; // Let observers know that a new request has been posted emit PostedRequest(_queryId, msg.sender); } + /// 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 identifier + function readRequestGasPrice(uint256 _queryId) + external view + override + inStatus(_queryId, Witnet.QueryStatus.Posted) + returns (uint256) + { + return __storage().queries[_queryId].request._gasprice; + } + /// Decode raw CBOR bytes into a Witnet.Result instance. /// @param _cborBytes Raw bytes representing a CBOR-encoded value. /// @return A `Witnet.Result` instance. @@ -848,14 +860,14 @@ abstract contract WitnetRequestBoardTrustableBase uint256 _newGasPrice = _getGasPrice(); // If gas price is increased, then check if new rewards cover gas costs - if (_newGasPrice > __request.gasprice) { + if (_newGasPrice > __request._gasprice) { // Checks the reward is covering gas cost uint256 _minResultReward = estimateBaseFee(_newGasPrice, 32); require( _newReward >= _minResultReward, "WitnetRequestBoardTrustableBase: reward too low" ); - __request.gasprice = _newGasPrice; + __request._gasprice = _newGasPrice; } __request.reward = _newReward; } diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index 68b86ca00..5026d0b65 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -110,13 +110,6 @@ interface IWitnetRequestBoard { /// @param _queryId The unique query identifier. function readRequestBytecode(uint256 _queryId) external view returns (bytes memory); - /// @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 view returns (uint256); - /// @notice Retrieves the reward currently set for the referred query. /// @dev Fails if the `_queryId` is not valid or, if it has already been /// @dev reported, or deleted. @@ -198,6 +191,13 @@ interface IWitnetRequestBoard { /// @return _queryId Unique query identifier. function postRequest(bytes32 radHash, bytes32 slaHash) external payable returns (uint256 _queryId); + /// @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 view returns (uint256); + /// Decode raw CBOR bytes into a Witnet.Result instance. /// @param _cborBytes Raw bytes representing a CBOR-encoded value. /// @return A `Witnet.Result` instance. diff --git a/contracts/libs/Witnet.sol b/contracts/libs/Witnet.sol index 7ab1ffcfe..cc7ad91d1 100644 --- a/contracts/libs/Witnet.sol +++ b/contracts/libs/Witnet.sol @@ -29,10 +29,10 @@ library Witnet { /// Data kept in EVM-storage for every Request posted to the Witnet Request Board. struct Request { address _addr; // Deprecating: Address of the 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. + bytes32 slaHash; // Radon SLA hash of the Witnet data request. + bytes32 radHash; // Radon radHash of the Witnet data request. + uint256 _gasprice; // Deprecating: 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. From 3c41a2514132e2c06f7989fa2ed0f2db2ffce596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 23 Nov 2023 12:47:03 +0100 Subject: [PATCH 42/86] refactor: WitnetV2.* -> Witnet.* --- contracts/WitnetRequestTemplate.sol | 8 +- contracts/apps/WitnetFeeds.sol | 4 +- contracts/apps/WitnetPriceFeeds.sol | 32 +-- contracts/apps/WitnetRandomness.sol | 32 +-- .../core/defaults/WitnetBytecodesDefault.sol | 272 +++++++++--------- .../defaults/WitnetRequestFactoryDefault.sol | 10 +- contracts/data/WitnetBytecodesData.sol | 26 +- contracts/data/WitnetRequestFactoryData.sol | 2 +- contracts/interfaces/IWitnetRandomness.sol | 2 +- .../interfaces/IWitnetRandomnessAdmin.sol | 2 +- contracts/interfaces/IWitnetRequestBoard.sol | 4 +- contracts/interfaces/V2/IWitnetBytecodes.sol | 44 +-- contracts/interfaces/V2/IWitnetFeeds.sol | 6 +- contracts/interfaces/V2/IWitnetFeedsAdmin.sol | 2 +- contracts/libs/Witnet.sol | 125 ++++++++ contracts/libs/WitnetEncodingLib.sol | 259 +++++++++-------- contracts/libs/WitnetV2.sol | 132 --------- 17 files changed, 489 insertions(+), 473 deletions(-) diff --git a/contracts/WitnetRequestTemplate.sol b/contracts/WitnetRequestTemplate.sol index 3a2036da4..1593ef7d6 100644 --- a/contracts/WitnetRequestTemplate.sol +++ b/contracts/WitnetRequestTemplate.sol @@ -20,14 +20,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/contracts/apps/WitnetFeeds.sol b/contracts/apps/WitnetFeeds.sol index 02b5db958..0eb7ef337 100644 --- a/contracts/apps/WitnetFeeds.sol +++ b/contracts/apps/WitnetFeeds.sol @@ -12,12 +12,12 @@ abstract contract WitnetFeeds IWitnetFeeds, IWitnetFeedsAdmin { - WitnetV2.RadonDataTypes immutable public override dataType; + Witnet.RadonDataTypes immutable public override dataType; bytes32 immutable internal __prefix; constructor( - WitnetV2.RadonDataTypes _dataType, + Witnet.RadonDataTypes _dataType, string memory _prefix ) { diff --git a/contracts/apps/WitnetPriceFeeds.sol b/contracts/apps/WitnetPriceFeeds.sol index 76a6cd80b..83eee104d 100644 --- a/contracts/apps/WitnetPriceFeeds.sol +++ b/contracts/apps/WitnetPriceFeeds.sol @@ -27,14 +27,14 @@ contract WitnetPriceFeeds WitnetPriceFeedsData { using Witnet for Witnet.Result; - using WitnetV2 for WitnetV2.RadonSLA; + using Witnet for Witnet.RadonSLA; bytes4 immutable public class = type(IWitnetPriceFeeds).interfaceId; WitnetRequestBoard immutable public override witnet; constructor(address _operator, WitnetRequestBoard _wrb) WitnetFeeds( - WitnetV2.RadonDataTypes.Integer, + Witnet.RadonDataTypes.Integer, "Price-" ) { @@ -44,7 +44,7 @@ contract WitnetPriceFeeds "WitnetPriceFeeds: uncompliant request board" ); witnet = _wrb; - __settleDefaultRadonSLA(WitnetV2.RadonSLA({ + __settleDefaultRadonSLA(Witnet.RadonSLA({ numWitnesses: 5, witnessCollateral: 15 * 10 ** 9, witnessReward: 15 * 10 ** 7, @@ -138,7 +138,7 @@ contract WitnetPriceFeeds function defaultRadonSLA() override public view - returns (WitnetV2.RadonSLA memory) + returns (Witnet.RadonSLA memory) { return registry().lookupRadonSLA(__storage().defaultSlaHash); } @@ -149,7 +149,7 @@ contract WitnetPriceFeeds returns (uint) { // TODO: refactor when WRB.estimateBaseFee(bytes32,bytes32,uint256,uint256) is implemented. - return witnet.estimateReward(_evmGasPrice); + return witnet.estimateBaseFee(_evmGasPrice, 32); } function estimateUpdateBaseFee(bytes4, uint256 _evmGasPrice, uint256, bytes32) @@ -158,21 +158,21 @@ contract WitnetPriceFeeds returns (uint) { // TODO: refactor when WRB.estimateBaseFee(bytes32,bytes32,uint256,uint256) is implemented. - return witnet.estimateReward(_evmGasPrice); + return witnet.estimateBaseFee(_evmGasPrice, 32); } function latestResponse(bytes4 feedId) override public view returns (Witnet.Response memory) { - return witnet.readResponse(_latestValidQueryId(feedId)); + return witnet.getQueryResponse(_latestValidQueryId(feedId)); } function latestResult(bytes4 feedId) override external view returns (Witnet.Result memory) { - return witnet.readResponseResult(_latestValidQueryId(feedId)); + return witnet.getQueryResponseResult(_latestValidQueryId(feedId)); } function latestUpdateQueryId(bytes4 feedId) @@ -186,14 +186,14 @@ contract WitnetPriceFeeds override external view returns (Witnet.Request memory) { - return witnet.readRequest(latestUpdateQueryId(feedId)); + return witnet.getQueryRequest(latestUpdateQueryId(feedId)); } function latestUpdateResponse(bytes4 feedId) override external view returns (Witnet.Response memory) { - return witnet.readResponse(latestUpdateQueryId(feedId)); + return witnet.getQueryResponse(latestUpdateQueryId(feedId)); } function latestUpdateResultError(bytes4 feedId) @@ -234,10 +234,10 @@ contract WitnetPriceFeeds 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]); } @@ -321,7 +321,7 @@ contract WitnetPriceFeeds emit DeletedFeed(msg.sender, feedId, caption); } - function settleDefaultRadonSLA(WitnetV2.RadonSLA memory sla) + function settleDefaultRadonSLA(Witnet.RadonSLA memory sla) override public onlyOwner { @@ -630,10 +630,10 @@ contract WitnetPriceFeeds if (_latestStatus == Witnet.ResultStatus.Awaiting) { // latest update is still pending, so just increase the reward // accordingly to current tx gasprice: - int _deltaReward = int(witnet.readRequestReward(_latestId)) - int(_usedFunds); + int _deltaReward = int(witnet.getQueryReward(_latestId)) - int(_usedFunds); if (_deltaReward > 0) { _usedFunds = uint(_deltaReward); - witnet.upgradeReward{value: _usedFunds}(_latestId); + witnet.upgradeQueryReward{value: _usedFunds}(_latestId); emit UpdatingFeedReward(msg.sender, feedId, _usedFunds); } else { _usedFunds = 0; @@ -668,7 +668,7 @@ contract WitnetPriceFeeds } } - function __settleDefaultRadonSLA(WitnetV2.RadonSLA memory sla) internal { + function __settleDefaultRadonSLA(Witnet.RadonSLA memory sla) internal { __storage().defaultSlaHash = registry().verifyRadonSLA(sla); } } diff --git a/contracts/apps/WitnetRandomness.sol b/contracts/apps/WitnetRandomness.sol index bb7ec2597..5d6d4d93c 100644 --- a/contracts/apps/WitnetRandomness.sol +++ b/contracts/apps/WitnetRandomness.sol @@ -50,22 +50,20 @@ contract WitnetRandomness // Build own Witnet Randomness Request: bytes32[] memory _retrievals = new bytes32[](1); _retrievals[0] = _registry.verifyRadonRetrieval( - WitnetV2.DataRequestMethods.Rng, + Witnet.RadonDataRequestMethods.Rng, "", // no url "", // no body 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, - filters: _filters, // no filters - script: hex"" // no aggregation script + Witnet.RadonFilter[] memory _filters; + bytes32 _aggregator = _registry.verifyRadonReducer(Witnet.RadonReducer({ + opcode: Witnet.RadonReducerOpcodes.Mode, + filters: _filters // no filters })); - bytes32 _tally = _registry.verifyRadonReducer(WitnetV2.RadonReducer({ - opcode: WitnetV2.RadonReducerOpcodes.ConcatenateAndHash, - filters: _filters, // no filters - script: hex"" // no aggregation script + bytes32 _tally = _registry.verifyRadonReducer(Witnet.RadonReducer({ + opcode: Witnet.RadonReducerOpcodes.ConcatenateAndHash, + filters: _filters // no filters })); WitnetRequestTemplate _template = WitnetRequestTemplate(_factory.buildRequestTemplate( _retrievals, @@ -149,7 +147,7 @@ contract WitnetRandomness Ownable.transferOwnership(_newOwner); } - function settleWitnetRandomnessSLA(WitnetV2.RadonSLA memory _radonSLA) + function settleWitnetRandomnessSLA(Witnet.RadonSLA memory _radonSLA) virtual override public onlyOwner @@ -169,7 +167,7 @@ contract WitnetRandomness virtual override returns (uint256) { - return witnet().estimateReward(_gasPrice); + return witnet().estimateBaseFee(_gasPrice, 32); } /// Retrieves data of a randomization request that got successfully posted to the WRB within a given block. @@ -218,7 +216,7 @@ contract WitnetRandomness require(_queryId != 0, "WitnetRandomness: not randomized"); Witnet.ResultStatus _resultStatus = witnet().checkResultStatus(_queryId); if (_resultStatus == Witnet.ResultStatus.Ready) { - return witnet().readResponseResult(_queryId).asBytes32(); + return witnet().getQueryResponseResult(_queryId).asBytes32(); } else if (_resultStatus == Witnet.ResultStatus.Error) { uint256 _nextRandomizeBlock = __randomize_[_block].nextBlock; require(_nextRandomizeBlock != 0, "WitnetRandomness: faulty randomize"); @@ -371,7 +369,7 @@ contract WitnetRandomness { RandomizeData storage _data = __randomize_[_block]; if (_data.witnetQueryId != 0) { - __witnet.upgradeReward{value: msg.value}(_data.witnetQueryId); + __witnet.upgradeQueryReward{value: msg.value}(_data.witnetQueryId); } return msg.value; } @@ -388,7 +386,7 @@ contract WitnetRandomness function witnetRandomnessSLA() virtual override external view - returns (WitnetV2.RadonSLA memory) + returns (Witnet.RadonSLA memory) { return witnet().registry().lookupRadonSLA(__witnetRandomnessSlaHash); } @@ -431,7 +429,7 @@ contract WitnetRandomness } function __initializeWitnetRandomnessSlaHash() virtual internal { - __settleWitnetRandomnessSLA(WitnetV2.RadonSLA({ + __settleWitnetRandomnessSLA(Witnet.RadonSLA({ numWitnesses: 5, minConsensusPercentage: 51, witnessReward: 10 ** 8, @@ -440,7 +438,7 @@ contract WitnetRandomness })); } - function __settleWitnetRandomnessSLA(WitnetV2.RadonSLA memory _radonSLA) + function __settleWitnetRandomnessSLA(Witnet.RadonSLA memory _radonSLA) internal returns (bytes32 _radonSlaHash) { diff --git a/contracts/core/defaults/WitnetBytecodesDefault.sol b/contracts/core/defaults/WitnetBytecodesDefault.sol index 79f4f7ebb..37a578e94 100644 --- a/contracts/core/defaults/WitnetBytecodesDefault.sol +++ b/contracts/core/defaults/WitnetBytecodesDefault.sol @@ -21,12 +21,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; bytes4 public immutable override class = type(IWitnetBytecodes).interfaceId; @@ -153,9 +153,9 @@ 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 UnknownRadonSLA(_slaHash); + revert("WitnetBytecodesDefault: unknown Radon SLA"); } bytes memory _radBytecode = bytecodeOf(_radHash); return abi.encodePacked( @@ -204,7 +204,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; @@ -248,7 +248,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) { @@ -264,10 +264,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 UnknownRadonRetrieval(_hash); } } @@ -277,7 +277,7 @@ contract WitnetBytecodesDefault override returns (uint8) { - if (__database().retrievals[_hash].method == WitnetV2.DataRequestMethods.Unknown) { + if (__database().retrievals[_hash].method == Witnet.RadonDataRequestMethods.Unknown) { revert UnknownRadonRetrieval(_hash); } return __database().retrievals[_hash].argsCount; @@ -286,9 +286,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 UnknownRadonRetrieval(_hash); } return __database().retrievals[_hash].resultDataType; @@ -297,7 +297,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) { @@ -308,7 +308,7 @@ contract WitnetBytecodesDefault function lookupRadonRequestAggregator(bytes32 _radHash) external view override - returns (WitnetV2.RadonReducer memory) + returns (Witnet.RadonReducer memory) { return __database().reducers[ __requests(_radHash).aggregator @@ -318,7 +318,7 @@ contract WitnetBytecodesDefault function lookupRadonRequestResultDataType(bytes32 _radHash) external view override - returns (WitnetV2.RadonDataTypes) + returns (Witnet.RadonDataTypes) { return __requests(_radHash).resultDataType; } @@ -350,17 +350,31 @@ contract WitnetBytecodesDefault function lookupRadonRequestTally(bytes32 _radHash) external view override - returns (WitnetV2.RadonReducer memory) + returns (Witnet.RadonReducer memory) { return __database().reducers[ __requests(_radHash).tally ]; } + function lookupRadonRAD(bytes32 _radHash) + external view + override + returns (Witnet.RadonRAD memory rad) + { + DataRequest storage __request = __requests(_radHash); + rad.retrieve = new Witnet.RadonRetrieval[](__request.retrievals.length); + for (uint _ix = 0; _ix < rad.retrieve.length; _ix ++) { + rad.retrieve[_ix] = __database().retrievals[__request.retrievals[_ix]]; + } + rad.aggregate = __database().reducers[__request.aggregator]; + rad.tally = __database().reducers[__request.tally]; + } + 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) { @@ -373,12 +387,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, @@ -387,85 +401,25 @@ contract WitnetBytecodesDefault public virtual override returns (bytes32 hash) - { - // validate data source params - hash = _requestMethod.validate(_requestURL, _requestBody, _requestHeaders, _requestRadonScript); - - // should it be a new data source: - if ( - __database().retrievals[hash].method == WitnetV2.DataRequestMethods.Unknown - ) { - // compose data source and save it in storage: - __database().retrievals[hash] = WitnetV2.RadonRetrieval({ - argsCount: - WitnetBuffer.argsCountOf( - abi.encode( - _requestURL, bytes(" "), - _requestBody, bytes(" "), - _requestHeaders, bytes(" "), - _requestRadonScript - ) - ), - - method: - _requestMethod, - - resultDataType: - WitnetEncodingLib.verifyRadonScriptResultDataType(_requestRadonScript), - - url: - _requestURL, - - body: - _requestBody, - - headers: - _requestHeaders, - - script: - _requestRadonScript - }); - emit NewRadonRetrievalHash(hash); - } - } - - function verifyRadonRetrieval( - WitnetV2.DataRequestMethods _requestMethod, - string memory _requestSchema, - string memory _requestAuthority, - string memory _requestPath, - string memory _requestQuery, - string memory _requestBody, - string[2][] memory _requestHeaders, - bytes calldata _requestRadonScript - ) - external - virtual override - returns (bytes32 hash) { // validate data source params hash = _requestMethod.validate( - _requestSchema, - _requestAuthority, - _requestPath, - _requestQuery, - _requestBody, - _requestHeaders, + _requestURL, + _requestBody, + _requestHeaders, _requestRadonScript ); // 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( - _requestAuthority, bytes(" "), - _requestPath, bytes(" "), - _requestQuery, bytes(" "), + _requestURL, bytes(" "), _requestBody, bytes(" "), _requestHeaders, bytes(" "), _requestRadonScript @@ -479,16 +433,7 @@ contract WitnetBytecodesDefault WitnetEncodingLib.verifyRadonScriptResultDataType(_requestRadonScript), url: - string(abi.encodePacked( - _requestSchema, - _requestAuthority, - bytes(_requestPath).length > 0 - ? abi.encodePacked(bytes("/"), _requestPath) - : bytes(""), - bytes(_requestQuery).length > 0 - ? abi.encodePacked("?", _requestQuery) - : bytes("") - )), + _requestURL, body: _requestBody, @@ -499,16 +444,90 @@ contract WitnetBytecodesDefault script: _requestRadonScript }); - __pushDataProviderSource(_requestAuthority, hash); emit NewRadonRetrievalHash(hash); } } - function verifyRadonReducer(WitnetV2.RadonReducer memory _reducer) + // function verifyRadonRetrieval( + // Witnet.RadonDataRequestMethods _requestMethod, + // string memory _requestSchema, + // string memory _requestAuthority, + // string memory _requestPath, + // string memory _requestQuery, + // string memory _requestBody, + // string[2][] memory _requestHeaders, + // bytes calldata _requestRadonScript + // ) + // external + // virtual override + // returns (bytes32 hash) + // { + // // validate data source params + // hash = _requestMethod.validate( + // _requestSchema, + // _requestAuthority, + // _requestPath, + // _requestQuery, + // _requestBody, + // _requestHeaders, + // _requestRadonScript + // ); + + // // should it be a new data source: + // if ( + // __database().retrievals[hash].method == Witnet.RadonDataRequestMethods.Unknown + // ) { + // // compose data source and save it in storage: + // __database().retrievals[hash] = Witnet.RadonRetrieval({ + // argsCount: + // WitnetBuffer.argsCountOf( + // abi.encode( + // _requestAuthority, bytes(" "), + // _requestPath, bytes(" "), + // _requestQuery, bytes(" "), + // _requestBody, bytes(" "), + // _requestHeaders, bytes(" "), + // _requestRadonScript + // ) + // ), + + // method: + // _requestMethod, + + // resultDataType: + // WitnetEncodingLib.verifyRadonScriptResultDataType(_requestRadonScript), + + // url: + // string(abi.encodePacked( + // _requestSchema, + // _requestAuthority, + // bytes(_requestPath).length > 0 + // ? abi.encodePacked(bytes("/"), _requestPath) + // : bytes(""), + // bytes(_requestQuery).length > 0 + // ? abi.encodePacked("?", _requestQuery) + // : bytes("") + // )), + + // body: + // _requestBody, + + // headers: + // _requestHeaders, + + // script: + // _requestRadonScript + // }); + // __pushDataProviderSource(_requestAuthority, hash); + // emit NewRadonRetrievalHash(hash); + // } + // } + + 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 @@ -545,46 +564,32 @@ contract WitnetBytecodesDefault // Check that at least one source is provided; if (_retrievalsIds.length == 0) { - revert WitnetV2.RadonRequestNoSources(); + revert("WitnetBytecodesDefault: no retrievals"); } // Check that number of args arrays matches the number of sources: if ( _retrievalsIds.length != _args.length) { - revert WitnetV2.RadonRequestSourcesArgsMismatch( - _retrievalsIds.length, - _args.length - ); + revert("WitnetBytecodesDefault: args mismatch"); } // Check sources and tally reducers: - WitnetV2.RadonReducer memory _aggregator = __database().reducers[_aggregatorId]; - WitnetV2.RadonReducer memory _tally = __database().reducers[_tallyId]; - if (_tally.script.length > 0) { - revert WitnetV2.UnsupportedRadonTallyScript(_tallyId); - } + Witnet.RadonReducer memory _aggregator = __database().reducers[_aggregatorId]; + Witnet.RadonReducer memory _tally = __database().reducers[_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: if (_ix == 0) { _resultDataType = _retrievals[0].resultDataType; } else if (_retrievals[_ix].resultDataType != _resultDataType) { - revert WitnetV2.RadonRequestResultsMismatch( - _ix, - uint8(_retrievals[_ix].resultDataType), - uint8(_resultDataType) - ); + revert("WitnetBytecodesDefault: mismatching retrievals"); } // check enough args are provided for each source if (_args[_ix].length < uint(_retrievals[_ix].argsCount)) { - revert WitnetV2.RadonRequestMissingArgs( - _ix, - _retrievals[_ix].argsCount, - _args[_ix].length - ); + revert("WitnetBytecodesDefault: missing args"); } } @@ -599,14 +604,14 @@ contract WitnetBytecodesDefault _resultMaxSize ); if (_bytecode.length > 65535) { - revert WitnetV2.RadonRequestTooHeavy(_bytecode, _bytecode.length); + revert("WitnetBytecodesDefault: too heavy request"); } // Calculate radhash and add request metadata and rad bytecode to storage: _radHash = _witnetHash(_bytecode); __database().rads[hash] = _radHash; __database().radsBytecode[_radHash] = _bytecode; - __database().requests[_radHash] = RadonRequest({ + __database().requests[_radHash] = DataRequest({ aggregator: _aggregatorId, args: _args, radHash: _radHash, @@ -619,22 +624,23 @@ contract WitnetBytecodesDefault } } - function verifyRadonSLA(WitnetV2.RadonSLA calldata _sla) + function verifyRadonSLA(Witnet.RadonSLA calldata _sla) external virtual override returns (bytes32 _slaHash) - { - // Validate SLA params: - _sla.validate(); - + { // Build RadonSLA bytecode: bytes memory _bytecode = _sla.encode(); - // Calculate hash and add to storage if new: + // Add it to storage if not verified yet: _slaHash = _witnetHash(_bytecode); if (__database().slas[_slaHash].numWitnesses == 0) { + // validate SLA params: + _sla.validate(); + // save parameters and encoded bytecode in storage: __database().slas[_slaHash] = _sla; __database().slasBytecode[_slaHash] = _bytecode; + // emit event emit NewSlaHash(_slaHash); } } @@ -677,8 +683,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/core/defaults/WitnetRequestFactoryDefault.sol b/contracts/core/defaults/WitnetRequestFactoryDefault.sol index 6f39014c0..2367b46a3 100644 --- a/contracts/core/defaults/WitnetRequestFactoryDefault.sol +++ b/contracts/core/defaults/WitnetRequestFactoryDefault.sol @@ -80,7 +80,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?" @@ -443,7 +443,7 @@ contract WitnetRequestFactoryDefault override external view onlyDelegateCalls - returns (WitnetV2.RadonDataTypes) + returns (Witnet.RadonDataTypes) { WitnetRequestTemplate _template = __witnetRequest().template; if (address(_template) != address(0)) { @@ -486,7 +486,7 @@ contract WitnetRequestFactoryDefault override external view onlyDelegateCalls - returns (WitnetV2.RadonReducer memory) + returns (Witnet.RadonReducer memory) { WitnetRequestTemplate _template = __witnetRequest().template; if (address(_template) != address(0)) { @@ -502,7 +502,7 @@ contract WitnetRequestFactoryDefault override external view onlyDelegateCalls - returns (WitnetV2.RadonRetrieval memory) + returns (Witnet.RadonRetrieval memory) { WitnetRequestTemplate _template = __witnetRequest().template; if (address(_template) != address(0)) { @@ -536,7 +536,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/data/WitnetBytecodesData.sol b/contracts/data/WitnetBytecodesData.sol index adb92052f..8d7da1371 100644 --- a/contracts/data/WitnetBytecodesData.sol +++ b/contracts/data/WitnetBytecodesData.sol @@ -22,25 +22,31 @@ abstract contract WitnetBytecodesData { // ... } - struct RadonRequest { + struct DataProvider { + string authority; + uint256 totalEndpoints; + mapping (uint256 => bytes32) endpoints; + } + + struct DataRequest { string[][] args; bytes32 aggregator; bytes32 radHash; - WitnetV2.RadonDataTypes resultDataType; + Witnet.RadonDataTypes resultDataType; uint16 resultMaxSize; bytes32[] retrievals; bytes32 tally; } 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 => DataRequest) requests; mapping (bytes32 => bytes32) rads; mapping (bytes32 => bytes) radsBytecode; @@ -74,10 +80,10 @@ abstract contract WitnetBytecodesData { return __bytecodes().db; } - function __requests(bytes32 _drRetrievalHash) + function __requests(bytes32 _radHash) internal view - returns (RadonRequest storage _ptr) + returns (DataRequest storage _ptr) { - return __database().requests[_drRetrievalHash]; + return __database().requests[_radHash]; } } \ No newline at end of file diff --git a/contracts/data/WitnetRequestFactoryData.sol b/contracts/data/WitnetRequestFactoryData.sol index c2111fd30..6679dfd64 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/interfaces/IWitnetRandomness.sol b/contracts/interfaces/IWitnetRandomness.sol index c6e561bce..c4d209b63 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/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index 5026d0b65..3492e08b1 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -57,7 +57,7 @@ interface IWitnetRequestBoard { /// @param radHash 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 radHash, WitnetV2.RadonSLA calldata querySLA) external payable returns (uint256 _queryId); + function postRequest(bytes32 radHash, Witnet.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 the Witnet DON. /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided @@ -67,7 +67,7 @@ interface IWitnetRequestBoard { /// @param radHash 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 postRequestWithCallback(bytes32 radHash, WitnetV2.RadonSLA calldata querySLA) external payable returns (uint256 _queryId); + function postRequestWithCallback(bytes32 radHash, Witnet.RadonSLA calldata querySLA, uint256 maxCallbackGas) 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. diff --git a/contracts/interfaces/V2/IWitnetBytecodes.sol b/contracts/interfaces/V2/IWitnetBytecodes.sol index 938a61d80..6b3f76070 100644 --- a/contracts/interfaces/V2/IWitnetBytecodes.sol +++ b/contracts/interfaces/V2/IWitnetBytecodes.sol @@ -1,8 +1,7 @@ // SPDX-License-Identifier: MIT - pragma solidity >=0.8.0 <0.9.0; -import "../../libs/WitnetV2.sol"; +import "../../libs/Witnet.sol"; interface IWitnetBytecodes { @@ -38,42 +37,43 @@ 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 lookupRadonRAD(bytes32 radHash) external view returns (Witnet.RadonRAD memory); + function lookupRadonSLA(bytes32 slaHash) external view returns (Witnet.RadonSLA memory); function lookupRadonSLAReward(bytes32 slaHash) external view returns (uint); - function verifyRadonRetrieval( - WitnetV2.DataRequestMethods requestMethod, - string calldata requestSchema, - string calldata requestAuthority, - string calldata requestPath, - string calldata requestQuery, - string calldata requestBody, - string[2][] calldata requestHeaders, - bytes calldata requestRadonScript - ) external returns (bytes32 hash); + // function verifyRadonRetrieval( + // Witnet.RadonDataRequestMethods requestMethod, + // string calldata requestSchema, + // string calldata requestAuthority, + // string calldata requestPath, + // string calldata requestQuery, + // string calldata requestBody, + // string[2][] calldata requestHeaders, + // bytes calldata requestRadonScript + // ) 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( @@ -84,7 +84,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/IWitnetFeeds.sol b/contracts/interfaces/V2/IWitnetFeeds.sol index 0e2a99667..09ae8df0b 100644 --- a/contracts/interfaces/V2/IWitnetFeeds.sol +++ b/contracts/interfaces/V2/IWitnetFeeds.sol @@ -14,12 +14,12 @@ interface IWitnetFeeds { event UpdatingFeed(address indexed from, bytes4 indexed feedId, bytes32 slaHash, uint256 value); event UpdatingFeedReward(address indexed from, bytes4 indexed feedId, uint256 value); - 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); @@ -35,7 +35,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 9388cddaa..39e55b4cb 100644 --- a/contracts/interfaces/V2/IWitnetFeedsAdmin.sol +++ b/contracts/interfaces/V2/IWitnetFeedsAdmin.sol @@ -10,7 +10,7 @@ interface IWitnetFeedsAdmin { function deleteFeed(string calldata caption) external; function owner() external view returns (address); function pendingOwner() external returns (address); - 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/libs/Witnet.sol b/contracts/libs/Witnet.sol index cc7ad91d1..7f64b1be4 100644 --- a/contracts/libs/Witnet.sol +++ b/contracts/libs/Witnet.sol @@ -176,6 +176,131 @@ library Witnet { UnhandledIntercept } + /// 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; + } + + + /// @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 + ); + } + + function isValid(Witnet.RadonSLA memory sla) + internal pure returns (bool) + { + return ( + sla.witnessReward > 0 + && sla.numWitnesses > 0 && sla.numWitnesses <= 127 + && sla.minConsensusPercentage > 50 && sla.minConsensusPercentage < 100 + && sla.witnessCollateral > 0 + && sla.witnessCollateral / sla.witnessReward <= 127 + ); + } /// =============================================================================================================== /// --- 'Witnet.Result' helper methods ---------------------------------------------------------------------------- diff --git a/contracts/libs/WitnetEncodingLib.sol b/contracts/libs/WitnetEncodingLib.sol index a033f5ee5..5f76550ad 100644 --- a/contracts/libs/WitnetEncodingLib.sol +++ b/contracts/libs/WitnetEncodingLib.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.0 <0.9.0; -import "./WitnetV2.sol"; +import "./Witnet.sol"; /// @title A library for encoding Witnet Data Requests. /// @author The Witnet Foundation. @@ -23,15 +23,25 @@ library WitnetEncodingLib { // ff010203050406070101ffffffffffff // 02ff050404000106060707070701ffff + 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); + /// =============================================================================================================== /// --- 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 @@ -131,7 +141,7 @@ library WitnetEncodingLib { } } - function encode(WitnetV2.RadonRetrieval memory source) + function encode(Witnet.RadonRetrieval memory source) public pure returns (bytes memory) { @@ -191,7 +201,7 @@ library WitnetEncodingLib { } function encode( - WitnetV2.RadonRetrieval[] memory sources, + Witnet.RadonRetrieval[] memory sources, string[][] memory args, bytes memory aggregatorInnerBytecode, bytes memory tallyInnerBytecode, @@ -218,11 +228,11 @@ 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) { + // if (reducer.script.length == 0) { for (uint ix = 0; ix < reducer.filters.length; ix ++) { bytecode = abi.encodePacked( bytecode, @@ -233,15 +243,15 @@ library WitnetEncodingLib { bytecode, encode(reducer.opcode) ); - } else { - return abi.encodePacked( - encode(uint64(reducer.script.length), bytes1(0x18)), - reducer.script - ); - } + // } else { + // return abi.encodePacked( + // encode(uint64(reducer.script.length), bytes1(0x18)), + // reducer.script + // ); + // } } - function encode(WitnetV2.RadonFilter memory filter) + function encode(Witnet.RadonFilter memory filter) public pure returns (bytes memory bytecode) { @@ -259,7 +269,7 @@ library WitnetEncodingLib { ); } - function encode(WitnetV2.RadonReducerOpcodes opcode) + function encode(Witnet.RadonReducerOpcodes opcode) public pure returns (bytes memory) { @@ -267,7 +277,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,7 +309,7 @@ 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); @@ -311,7 +321,7 @@ library WitnetEncodingLib { } function validate( - WitnetV2.DataRequestMethods method, + Witnet.RadonDataRequestMethods method, string memory url, string memory body, string[2][] memory headers, @@ -323,16 +333,16 @@ 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 )) { - revert WitnetV2.UnsupportedDataRequestMethod( + revert UnsupportedDataRequestMethod( uint8(method), url, body, @@ -342,168 +352,171 @@ library WitnetEncodingLib { return keccak256(abi.encode(method, url, body, headers, script)); } - function validate( - WitnetV2.DataRequestMethods method, - string memory schema, - string memory authority, - string memory path, - string memory query, - string memory body, - string[2][] memory headers, - bytes memory script - ) - public pure - returns (bytes32) - { - if (!( - (method == WitnetV2.DataRequestMethods.HttpGet - || method == WitnetV2.DataRequestMethods.HttpPost - || method == WitnetV2.DataRequestMethods.HttpHead - ) - && bytes(authority).length > 0 - && ( - bytes(schema).length == 0 - || keccak256(bytes(schema)) == keccak256(bytes("https://")) - || keccak256(bytes(schema)) == keccak256(bytes("http://")) - ) - || method == WitnetV2.DataRequestMethods.Rng - && bytes(schema).length == 0 - && bytes(authority).length == 0 - && bytes(path).length == 0 - && bytes(query).length == 0 - && bytes(body).length == 0 - && headers.length == 0 - && script.length >= 1 - )) { - revert WitnetV2.UnsupportedDataRequestMethod( - uint8(method), - schema, - body, - headers - ); - } - return keccak256(abi.encode( - method, - schema, - authority, - path, - query, - body, - headers, - script - )); - } + // function validate( + // Witnet.RadonDataRequestMethods method, + // string memory schema, + // string memory authority, + // string memory path, + // string memory query, + // string memory body, + // string[2][] memory headers, + // bytes memory script + // ) + // public pure + // returns (bytes32) + // { + // if (!( + // (method == Witnet.RadonDataRequestMethods.HttpGet + // || method == Witnet.RadonDataRequestMethods.HttpPost + // || method == Witnet.RadonDataRequestMethods.HttpHead + // ) + // && bytes(authority).length > 0 + // && ( + // bytes(schema).length == 0 + // || keccak256(bytes(schema)) == keccak256(bytes("https://")) + // || keccak256(bytes(schema)) == keccak256(bytes("http://")) + // ) + // || method == Witnet.RadonDataRequestMethods.Rng + // && bytes(schema).length == 0 + // && bytes(authority).length == 0 + // && bytes(path).length == 0 + // && bytes(query).length == 0 + // && bytes(body).length == 0 + // && headers.length == 0 + // && script.length >= 1 + // )) { + // revert UnsupportedDataRequestMethod( + // uint8(method), + // schema, + // body, + // headers + // ); + // } + // return keccak256(abi.encode( + // method, + // schema, + // authority, + // path, + // query, + // body, + // headers, + // script + // )); + // } 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( + revert UnsupportedRadonDataType( uint8(dataType), maxDataSize ); } 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 { - revert WitnetV2.UnsupportedRadonDataType( + revert UnsupportedRadonDataType( uint8(dataType), size(dataType) ); } } - 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)); + revert UnsupportedRadonFilterArgs(uint8(filter.opcode), filter.args); } } 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) { - revert WitnetV2.UnsupportedRadonFilterArgs(uint8(filter.opcode), filter.args); + revert UnsupportedRadonFilterArgs(uint8(filter.opcode), filter.args); } } else { // reject unsupported opcodes - revert WitnetV2.UnsupportedRadonFilterOpcode(uint8(filter.opcode)); + revert UnsupportedRadonFilterOpcode(uint8(filter.opcode)); } } - function validate(WitnetV2.RadonReducer memory reducer) + function validate(Witnet.RadonReducer memory reducer) public pure { - if (reducer.script.length == 0) { + // 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)); + revert UnsupportedRadonReducerOpcode(uint8(reducer.opcode)); } for (uint ix = 0; ix < reducer.filters.length; ix ++) { validate(reducer.filters[ix]); } - } else { - if (uint8(reducer.opcode) != 0xff || reducer.filters.length > 0) { - revert WitnetV2.UnsupportedRadonReducerScript( - uint8(reducer.opcode), - reducer.script, - 0 - ); - } - } + // } else { + // if (uint8(reducer.opcode) != 0xff || reducer.filters.length > 0) { + // revert UnsupportedRadonReducerScript( + // uint8(reducer.opcode), + // reducer.script, + // 0 + // ); + // } + // } } - function validate(WitnetV2.RadonSLA memory sla) + function validate(Witnet.RadonSLA memory sla) public pure { if (sla.witnessReward == 0) { - revert WitnetV2.RadonSlaNoReward(); + revert("WitnetEncodingLib: invalid SLA: no reward"); } if (sla.numWitnesses == 0) { - revert WitnetV2.RadonSlaNoWitnesses(); + revert("WitnetEncodingLib: invalid SLA: no witnesses"); } else if (sla.numWitnesses > 127) { - revert WitnetV2.RadonSlaTooManyWitnesses(sla.numWitnesses); + revert("WitnetEncodingLib: invalid SLA: too many witnesses (>127)"); } if ( sla.minConsensusPercentage < 51 || sla.minConsensusPercentage > 99 ) { - revert WitnetV2.RadonSlaConsensusOutOfRange(sla.minConsensusPercentage); + revert("WitnetEncodingLib: invalid SLA: consensus percentage out of range"); + } + if (sla.witnessCollateral > 0) { + revert("WitnetEncodingLib: invalid SLA: no collateral"); } - if (sla.witnessCollateral < 10 ** 9) { - revert WitnetV2.RadonSlaLowCollateral(sla.witnessCollateral); + if (sla.witnessCollateral / sla.witnessReward > 127) { + revert("WitnetEncodingLib: invalid SLA: collateral/reward ratio too high (>127)"); } } function verifyRadonScriptResultDataType(bytes memory script) public pure - returns (WitnetV2.RadonDataTypes) + returns (Witnet.RadonDataTypes) { return _verifyRadonScriptResultDataType( WitnetCBOR.fromBytes(script), @@ -538,7 +551,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,7 +561,7 @@ 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; @@ -557,14 +570,14 @@ library WitnetEncodingLib { ? 0xff : uint8(WITNET_RADON_OPCODES_RESULT_TYPES[opcode]) ); - if (dataType > uint8(type(WitnetV2.RadonDataTypes).max)) { - revert WitnetV2.UnsupportedRadonScriptOpcode( + if (dataType > uint8(type(Witnet.RadonDataTypes).max)) { + revert 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/WitnetV2.sol b/contracts/libs/WitnetV2.sol index 4b9c0912c..ecfff6046 100644 --- a/contracts/libs/WitnetV2.sol +++ b/contracts/libs/WitnetV2.sol @@ -6,34 +6,6 @@ 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; @@ -106,108 +78,4 @@ library WitnetV2 { Accepted, Rejected } - - struct DataProvider { - string authority; - uint256 totalEndpoints; - mapping (uint256 => bytes32) endpoints; - } - - 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 - } - - struct RadonFilter { - RadonFilterOpcodes opcode; - bytes args; - } - - 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; - } - - 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 - } - - struct RadonRetrieval { - uint8 argsCount; - DataRequestMethods method; - RadonDataTypes resultDataType; - string url; - string body; - string[2][] headers; - bytes script; - } - - struct RadonSLA { - uint numWitnesses; - uint minConsensusPercentage; - uint witnessReward; - uint witnessCollateral; - uint minerCommitRevealFee; - } - - /// @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 - ); - } - } \ No newline at end of file From f502d965d0e0ea368fa9b2ab3e1e93ae105e5af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 23 Nov 2023 12:50:02 +0100 Subject: [PATCH 43/86] refactor: deprecate ballast on WitnetBytecodes --- .../core/defaults/WitnetBytecodesDefault.sol | 75 ------------------- contracts/interfaces/V2/IWitnetBytecodes.sol | 11 --- contracts/libs/WitnetEncodingLib.sol | 54 +------------ 3 files changed, 1 insertion(+), 139 deletions(-) diff --git a/contracts/core/defaults/WitnetBytecodesDefault.sol b/contracts/core/defaults/WitnetBytecodesDefault.sol index 37a578e94..3f0704fcc 100644 --- a/contracts/core/defaults/WitnetBytecodesDefault.sol +++ b/contracts/core/defaults/WitnetBytecodesDefault.sol @@ -448,81 +448,6 @@ contract WitnetBytecodesDefault } } - // function verifyRadonRetrieval( - // Witnet.RadonDataRequestMethods _requestMethod, - // string memory _requestSchema, - // string memory _requestAuthority, - // string memory _requestPath, - // string memory _requestQuery, - // string memory _requestBody, - // string[2][] memory _requestHeaders, - // bytes calldata _requestRadonScript - // ) - // external - // virtual override - // returns (bytes32 hash) - // { - // // validate data source params - // hash = _requestMethod.validate( - // _requestSchema, - // _requestAuthority, - // _requestPath, - // _requestQuery, - // _requestBody, - // _requestHeaders, - // _requestRadonScript - // ); - - // // should it be a new data source: - // if ( - // __database().retrievals[hash].method == Witnet.RadonDataRequestMethods.Unknown - // ) { - // // compose data source and save it in storage: - // __database().retrievals[hash] = Witnet.RadonRetrieval({ - // argsCount: - // WitnetBuffer.argsCountOf( - // abi.encode( - // _requestAuthority, bytes(" "), - // _requestPath, bytes(" "), - // _requestQuery, bytes(" "), - // _requestBody, bytes(" "), - // _requestHeaders, bytes(" "), - // _requestRadonScript - // ) - // ), - - // method: - // _requestMethod, - - // resultDataType: - // WitnetEncodingLib.verifyRadonScriptResultDataType(_requestRadonScript), - - // url: - // string(abi.encodePacked( - // _requestSchema, - // _requestAuthority, - // bytes(_requestPath).length > 0 - // ? abi.encodePacked(bytes("/"), _requestPath) - // : bytes(""), - // bytes(_requestQuery).length > 0 - // ? abi.encodePacked("?", _requestQuery) - // : bytes("") - // )), - - // body: - // _requestBody, - - // headers: - // _requestHeaders, - - // script: - // _requestRadonScript - // }); - // __pushDataProviderSource(_requestAuthority, hash); - // emit NewRadonRetrievalHash(hash); - // } - // } - function verifyRadonReducer(Witnet.RadonReducer memory _reducer) external returns (bytes32 hash) { diff --git a/contracts/interfaces/V2/IWitnetBytecodes.sol b/contracts/interfaces/V2/IWitnetBytecodes.sol index 6b3f76070..685735b40 100644 --- a/contracts/interfaces/V2/IWitnetBytecodes.sol +++ b/contracts/interfaces/V2/IWitnetBytecodes.sol @@ -54,17 +54,6 @@ interface IWitnetBytecodes { function lookupRadonSLA(bytes32 slaHash) external view returns (Witnet.RadonSLA memory); function lookupRadonSLAReward(bytes32 slaHash) external view returns (uint); - // function verifyRadonRetrieval( - // Witnet.RadonDataRequestMethods requestMethod, - // string calldata requestSchema, - // string calldata requestAuthority, - // string calldata requestPath, - // string calldata requestQuery, - // string calldata requestBody, - // string[2][] calldata requestHeaders, - // bytes calldata requestRadonScript - // ) external returns (bytes32 hash); - function verifyRadonRetrieval( Witnet.RadonDataRequestMethods requestMethod, string calldata requestURL, diff --git a/contracts/libs/WitnetEncodingLib.sol b/contracts/libs/WitnetEncodingLib.sol index 5f76550ad..654e6f4ac 100644 --- a/contracts/libs/WitnetEncodingLib.sol +++ b/contracts/libs/WitnetEncodingLib.sol @@ -350,59 +350,7 @@ library WitnetEncodingLib { ); } return keccak256(abi.encode(method, url, body, headers, script)); - } - - // function validate( - // Witnet.RadonDataRequestMethods method, - // string memory schema, - // string memory authority, - // string memory path, - // string memory query, - // string memory body, - // string[2][] memory headers, - // bytes memory script - // ) - // public pure - // returns (bytes32) - // { - // if (!( - // (method == Witnet.RadonDataRequestMethods.HttpGet - // || method == Witnet.RadonDataRequestMethods.HttpPost - // || method == Witnet.RadonDataRequestMethods.HttpHead - // ) - // && bytes(authority).length > 0 - // && ( - // bytes(schema).length == 0 - // || keccak256(bytes(schema)) == keccak256(bytes("https://")) - // || keccak256(bytes(schema)) == keccak256(bytes("http://")) - // ) - // || method == Witnet.RadonDataRequestMethods.Rng - // && bytes(schema).length == 0 - // && bytes(authority).length == 0 - // && bytes(path).length == 0 - // && bytes(query).length == 0 - // && bytes(body).length == 0 - // && headers.length == 0 - // && script.length >= 1 - // )) { - // revert UnsupportedDataRequestMethod( - // uint8(method), - // schema, - // body, - // headers - // ); - // } - // return keccak256(abi.encode( - // method, - // schema, - // authority, - // path, - // query, - // body, - // headers, - // script - // )); - // } + } function validate( Witnet.RadonDataTypes dataType, From f91d4d03ecffc987174eb8d2972083f60a2bb18a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 23 Nov 2023 12:51:45 +0100 Subject: [PATCH 44/86] refactor: IWRB.read* -> IWRB.getQuery* --- .../WitnetRequestBoardTrustableBase.sol | 35 ++++++------------- contracts/interfaces/IWitnetRequestBoard.sol | 23 +++++------- 2 files changed, 20 insertions(+), 38 deletions(-) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index 26de78298..b2130cf1d 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -613,7 +613,7 @@ abstract contract WitnetRequestBoardTrustableBase /// @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) + function getQueryRequest(uint256 _queryId) external view override inStatus(_queryId, Witnet.QueryStatus.Posted) @@ -627,7 +627,7 @@ abstract contract WitnetRequestBoardTrustableBase /// @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) + function getQueryRequestBytecode(uint256 _queryId) external view virtual override returns (bytes memory _bytecode) @@ -647,23 +647,10 @@ abstract contract WitnetRequestBoardTrustableBase } } - /// 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 view - override - inStatus(_queryId, Witnet.QueryStatus.Posted) - returns (uint256) - { - return __storage().queries[_queryId].request.reward; - } - /// 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) + function getQueryResponse(uint256 _queryId) external view override inStatus(_queryId, Witnet.QueryStatus.Reported) @@ -699,7 +686,7 @@ abstract contract WitnetRequestBoardTrustableBase /// 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) + function getQueryResponseResult(uint256 _queryId) external view override inStatus(_queryId, Witnet.QueryStatus.Reported) @@ -709,19 +696,19 @@ abstract contract WitnetRequestBoardTrustableBase return _response.cborBytes.resultFromCborBytes(); } - /// 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) + /// 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 getQueryReward(uint256 _queryId) external view override - inStatus(_queryId, Witnet.QueryStatus.Reported) + inStatus(_queryId, Witnet.QueryStatus.Posted) returns (uint256) { - return __seekQueryResponse(_queryId).timestamp; + return __storage().queries[_queryId].request.reward; } - // ================================================================================================================ // --- Deprecating methods from 'IWitnetRequestBoard' ------------------------------------------------------------- diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index 3492e08b1..9997f59ec 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -101,30 +101,25 @@ interface IWitnetRequestBoard { /// @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) external view returns (Witnet.Request memory); + function getQueryRequest(uint256 _queryId) external view returns (Witnet.Request memory); /// @notice 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 view returns (bytes memory); - - /// @notice Retrieves the reward currently set for the referred query. - /// @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 view returns (uint256); - + function getQueryRequestBytecode(uint256 _queryId) external view returns (bytes memory); + /// @notice Retrieves the whole `Witnet.Response` record referred to a previously posted Witnet Data Request. /// @dev Fails if the `_queryId` is not in 'Reported' status. /// @param _queryId The unique query identifier. - function readResponse(uint256 _queryId) external view returns (Witnet.Response memory); + function getQueryResponse(uint256 _queryId) external view returns (Witnet.Response memory); - /// @notice Retrieves error codes of given query. - /// @dev Fails if the `_queryId` is not in 'Reported' status, or if no actual error. + /// @notice Retrieves the reward currently set for the referred query. + /// @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 readResponseDrTxHash(uint256 _queryId) external view returns (bytes32); + function getQueryReward(uint256 _queryId) external view returns (uint256); /// @notice Retrieves the address that reported the result to a previously-posted request. /// @dev Fails if the `_queryId` is not in 'Reported' status. @@ -134,7 +129,7 @@ interface IWitnetRequestBoard { /// @notice 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 view returns (Witnet.Result memory); + function getQueryResponseResult(uint256 _queryId) external view returns (Witnet.Result memory); /// @notice 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. From 9827c1476bc7774ebd3dcee5d73895253e2bff8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 23 Nov 2023 13:02:53 +0100 Subject: [PATCH 45/86] refactor: deprecate ballast on WitnetRequestBoard --- .../WitnetRequestBoardTrustableBase.sol | 104 ++++-------------- contracts/interfaces/IWitnetRequestBoard.sol | 80 -------------- contracts/libs/WitnetErrorsLib.sol | 19 ++++ 3 files changed, 39 insertions(+), 164 deletions(-) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index b2130cf1d..c9856d930 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -62,44 +62,16 @@ abstract contract WitnetRequestBoardTrustableBase /// @dev Provide backwards compatibility for dapps bound to versions <= 0.6.1 /// @dev (i.e. calling methods in IWitnetRequestBoard) /// @dev (Until 'function ... abi(...)' modifier is allegedly supported in solc versions >= 0.9.1) - // solhint-disable-next-line payable-fallback - fallback() override external { /* solhint-disable no-complex-fallback */ - bytes4 _newSig = msg.sig; - if (msg.sig == 0xA8604C1A) { - // IWitnetRequestParser.isOk({bool,CBOR}) --> IWitnetRequestBoard.isOk({bool,WitnetCBOR.CBOR}) - _newSig = IWitnetRequestBoard.isOk.selector; - } else if (msg.sig == 0xCF62D115) { - // IWitnetRequestParser.asBytes32({bool,CBOR}) --> IWitnetRequestBoard.asBytes32({bool,WitnetCBOR.CBOR}) - _newSig = IWitnetRequestBoard.asBytes32.selector; - } else if (msg.sig == 0xBC7E25FF) { - // IWitnetRequestParser.asUint64({bool,CBOR}) --> IWitnetRequestBoard.asUint64({bool,WitnetCBOR.CBOR}) - _newSig = IWitnetRequestBoard.asUint64.selector; - } else if (msg.sig == 0xD74803BE) { - // IWitnetRequestParser.asErrorMessage({bool,CBOR}) --> IWitnetRequestBoard.asErrorMessage({bool,WitnetCBOR.CBOR}) - _newSig = IWitnetRequestBoard.asErrorMessage.selector; - } - if (_newSig != msg.sig) { - address _self = address(this); - assembly { - let ptr := mload(0x40) - calldatacopy(ptr, 0, calldatasize()) - mstore(ptr, or(and(mload(ptr), 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff), _newSig)) - let result := delegatecall(gas(), _self, ptr, calldatasize(), 0, 0) - let size := returndatasize() - returndatacopy(ptr, 0, size) - switch result - case 0 { revert(ptr, size) } - default { return(ptr, size) } - } - } else { - revert(string(abi.encodePacked( - "WitnetRequestBoardTrustableBase: not implemented: 0x", - Witnet.toHexString(uint8(bytes1(msg.sig))), - Witnet.toHexString(uint8(bytes1(msg.sig << 8))), - Witnet.toHexString(uint8(bytes1(msg.sig << 16))), - Witnet.toHexString(uint8(bytes1(msg.sig << 24))) - ))); - } + /* solhint-disable payable-fallback */ + /* solhint-disable no-complex-fallback */ + fallback() override external { + revert(string(abi.encodePacked( + "WitnetRequestBoardTrustableBase: not implemented: 0x", + Witnet.toHexString(uint8(bytes1(msg.sig))), + Witnet.toHexString(uint8(bytes1(msg.sig << 8))), + Witnet.toHexString(uint8(bytes1(msg.sig << 16))), + Witnet.toHexString(uint8(bytes1(msg.sig << 24))) + ))); } @@ -432,34 +404,22 @@ abstract contract WitnetRequestBoardTrustableBase returns (Witnet.ResultError memory) { Witnet.ResultStatus _status = checkResultStatus(_queryId); - if (_status == Witnet.ResultStatus.Awaiting) { + try WitnetErrorsLib.asResultError(_status, __seekQueryResponse(_queryId).cborBytes) + returns (Witnet.ResultError memory _resultError) + { + return _resultError; + } + catch Error(string memory _reason) { return Witnet.ResultError({ code: Witnet.ResultErrorCodes.Unknown, - reason: "WitnetRequestBoardTrustableBase: not yet solved" + reason: string(abi.encodePacked("WitnetErrorsLib: ", _reason)) }); - } else if (_status == Witnet.ResultStatus.Void) { + } + catch (bytes memory) { return Witnet.ResultError({ code: Witnet.ResultErrorCodes.Unknown, - reason: "WitnetRequestBoardTrustableBase: unknown query" + reason: "WitnetErrorsLib: assertion failed" }); - } else { - try WitnetErrorsLib.resultErrorFromCborBytes(__seekQueryResponse(_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" - }); - } } } @@ -659,30 +619,6 @@ abstract contract WitnetRequestBoardTrustableBase return __seekQueryResponse(_queryId); } - /// 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 view - override - inStatus(_queryId, Witnet.QueryStatus.Reported) - returns (bytes32) - { - return __seekQueryResponse(_queryId).drTxHash; - } - - /// 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 view - override - inStatus(_queryId, Witnet.QueryStatus.Reported) - returns (address) - { - return __seekQueryResponse(_queryId).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 diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index 9997f59ec..3985c6cd4 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -121,90 +121,10 @@ interface IWitnetRequestBoard { /// @param _queryId The unique query identifier. function getQueryReward(uint256 _queryId) external view returns (uint256); - /// @notice 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 view returns (address); - /// @notice 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 getQueryResponseResult(uint256 _queryId) external view returns (Witnet.Result memory); - /// @notice 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 view returns (uint256); - - - /// =============================================================================================================== - /// --- Deprecating funcionality v0.5 ----------------------------------------------------------------------------- - - /// Tell if a Witnet.Result is successful. - /// @param _result An instance of Witnet.Result. - /// @return `true` if successful, `false` if errored. - function isOk(Witnet.Result memory _result) external pure returns (bool); - - /// Decode a bytes value from a Witnet.Result as a `bytes32` value. - /// @param _result An instance of Witnet.Result. - /// @return The `bytes32` decoded from the Witnet.Result. - function asBytes32(Witnet.Result memory _result) external pure returns (bytes32); - - /// Generate a suitable error message for a member of `Witnet.ResultErrorCodes` and its corresponding arguments. - /// @dev WARN: Note that client contracts should wrap this function into a try-catch foreseing potential errors generated in this function - /// @param _result An instance of `Witnet.Result`. - /// @return A tuple containing the `CBORValue.Error memory` decoded from the `Witnet.Result`, plus a loggable error message. - function asErrorMessage(Witnet.Result memory _result) external pure returns (Witnet.ResultErrorCodes, string memory); - - /// Decode a natural numeric value from a Witnet.Result as a `uint` value. - /// @param _result An instance of Witnet.Result. - /// @return The `uint` decoded from the Witnet.Result. - function asUint64(Witnet.Result memory _result) external pure returns (uint64); - - /// @notice Estimate the minimum reward required for posting a data request. - /// @dev Underestimates if the size of returned data is greater than 32 bytes. - /// @param _gasPrice Expected gas price to pay upon posting the data request. - function estimateReward(uint256 _gasPrice) external view returns (uint256); - - /// @notice Requests the execution of the given Witnet Data Request in expectation that it will be relayed and solved by the Witnet DON. - /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided - /// @notice result to this request. - /// @dev Fails if: - /// @dev - provided reward is too low. - /// @dev - provided script is zero address. - /// @dev - provided script bytecode is empty. - /// @param _requestAddr The address of the IWitnetRequest contract that can provide the actual Data Request bytecode. - /// @return _queryId Unique query identifier. - function postRequest(address _requestAddr) 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 the Witnet DON. - /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided - /// @notice result to this request. - /// @dev Fails if, provided reward is too low. - /// @param radHash The RAD hash of the data request to be solved by Witnet. - /// @param slaHash The SLA hash of the data request to be solved by Witnet. - /// @return _queryId Unique query identifier. - function postRequest(bytes32 radHash, bytes32 slaHash) external payable returns (uint256 _queryId); - - /// @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 view returns (uint256); - /// Decode raw CBOR 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) external pure returns (Witnet.Result memory); - - /// @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 - /// @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; } diff --git a/contracts/libs/WitnetErrorsLib.sol b/contracts/libs/WitnetErrorsLib.sol index 54c017569..ae1f38ec6 100644 --- a/contracts/libs/WitnetErrorsLib.sol +++ b/contracts/libs/WitnetErrorsLib.sol @@ -28,6 +28,25 @@ library WitnetErrorsLib { ); } + function asResultError(Witnet.ResultStatus _status, bytes memory _cborBytes) + public pure + returns (Witnet.ResultError memory) + { + if (_status == Witnet.ResultStatus.Awaiting) { + return Witnet.ResultError({ + code: Witnet.ResultErrorCodes.Unknown, + reason: "WitnetRequestBoard: not yet solved" + }); + } else if (_status == Witnet.ResultStatus.Void) { + return Witnet.ResultError({ + code: Witnet.ResultErrorCodes.Unknown, + reason: "WitnetRequestBoard: unknown query" + }); + } else { + return resultErrorFromCborBytes(_cborBytes); + } + } + /// @notice Extract error code and description string from given CBOR-encoded value. /// @dev Client contracts should wrap this function into a try-catch foreseeing potential parsing errors. /// @return _error Witnet.ResultError data struct containing error code and description. From 879bfc48dd9733d9d7df0b8445e5038f05928218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 23 Nov 2023 13:29:30 +0100 Subject: [PATCH 46/86] refactor: IWRB events --- .../WitnetRequestBoardTrustableBase.sol | 100 ++++++++++-------- contracts/interfaces/IWitnetRequestBoard.sol | 12 ++- 2 files changed, 60 insertions(+), 52 deletions(-) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index c9856d930..b271f4c27 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -33,6 +33,14 @@ abstract contract WitnetRequestBoardTrustableBase bytes4 public immutable override class = type(IWitnetRequestBoard).interfaceId; WitnetRequestFactory immutable public override factory; + + modifier checkReward(uint256 _baseFee) { + require( + _getMsgValue() >= _baseFee, + "WitnetRequestBoardTrustableBase: reward too low" + ); _; + } + constructor( WitnetRequestFactory _factory, @@ -229,10 +237,16 @@ abstract contract WitnetRequestBoardTrustableBase onlyReporters inStatus(_queryId, Witnet.QueryStatus.Posted) { - require(_drTxHash != 0, "WitnetRequestBoardTrustableDefault: Witnet drTxHash cannot be zero"); + require( + _drTxHash != 0, + "WitnetRequestBoardTrustableDefault: Witnet drTxHash cannot be zero" + ); // Ensures the result bytes do not have zero length // This would not be a valid encoding with CBOR and could trigger a reentrancy attack - require(_cborBytes.length != 0, "WitnetRequestBoardTrustableDefault: result cannot be empty"); + require( + _cborBytes.length != 0, + "WitnetRequestBoardTrustableDefault: result cannot be empty" + ); // solhint-disable not-rely-on-time _safeTransferTo( payable(msg.sender), @@ -243,7 +257,6 @@ abstract contract WitnetRequestBoardTrustableBase _cborBytes ) ); - emit PostedResult(_queryId, msg.sender); } /// Reports the Witnet-provided result to a previously posted request. @@ -267,21 +280,27 @@ abstract contract WitnetRequestBoardTrustableBase onlyReporters inStatus(_queryId, Witnet.QueryStatus.Posted) { - require(_timestamp <= block.timestamp, "WitnetRequestBoardTrustableDefault: bad timestamp"); - require(_drTxHash != 0, "WitnetRequestBoardTrustableDefault: Witnet drTxHash cannot be zero"); - // Ensures the result bytes do not have zero length - // This would not be a valid encoding with CBOR and could trigger a reentrancy attack - require(_cborBytes.length != 0, "WitnetRequestBoardTrustableDefault: result cannot be empty"); - _safeTransferTo( - payable(msg.sender), - __reportResult( - _queryId, - _timestamp, - _drTxHash, - _cborBytes - ) + require( + _timestamp <= block.timestamp, + "WitnetRequestBoardTrustableDefault: bad timestamp" + ); + require( + _drTxHash != 0, + "WitnetRequestBoardTrustableDefault: Witnet drTxHash cannot be zero" + ); + // Ensures the result bytes do not have zero length (this would not be a valid CBOR encoding + // and could trigger a reentrancy attack) + require( + _cborBytes.length != 0, + "WitnetRequestBoardTrustableDefault: result cannot be empty" ); - emit PostedResult(_queryId, msg.sender); + // Transfer query's reward to the reporter: + _safeTransferTo(payable(msg.sender), __reportResult( + _queryId, + _timestamp, + _drTxHash, + _cborBytes + )); } /// Reports Witnet-provided results to multiple requests within a single EVM tx. @@ -340,10 +359,6 @@ abstract contract WitnetRequestBoardTrustableBase _result.drTxHash, _result.cborBytes ); - emit PostedResult( - _result.queryId, - msg.sender - ); } } // Transfer all successful rewards in one single shot to the authorized reporter, if any: @@ -464,28 +479,12 @@ abstract contract WitnetRequestBoardTrustableBase function postRequest(bytes32 _radHash, bytes32 _slaHash) virtual override public payable + checkReward(estimateBaseFee(_getGasPrice(), 32)) returns (uint256 _queryId) { - uint256 _value = _getMsgValue(); - uint256 _gasPrice = _getGasPrice(); - - // check base reward - uint256 _baseFee = estimateBaseFee(_gasPrice, 32); - require( - _value >= _baseFee, - "WitnetRequestBoardTrustableBase: reward too low" - ); - - _queryId = ++ __storage().numQueries; - __storage().queries[_queryId].from = msg.sender; - - Witnet.Request storage __request = __seekQueryRequest(_queryId); - __request.radHash = _radHash; - __request.slaHash = _slaHash; - __request.reward = _value; - + _queryId = __postRequest(_radHash, _slaHash); // Let observers know that a new request has been posted - emit PostedRequest(_queryId, msg.sender); + emit NewQuery(_queryId, _getMsgValue()); } /// Requests the execution of the given Witnet Data Request in expectation that it will be relayed and solved by the Witnet DON. @@ -494,18 +493,25 @@ abstract contract WitnetRequestBoardTrustableBase /// @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, WitnetV2.RadonSLA calldata _slaParams) + /// @param _querySLA The SLA param of the data request to be solved by Witnet. + function postRequest( + bytes32 _radHash, + Witnet.RadonSLA calldata _querySLA + ) virtual override public payable + checkReward(estimateBaseFee(_getGasPrice(), 32)) returns (uint256 _queryId) { - return postRequest( - _radHash, - registry().verifyRadonSLA(_slaParams) + _queryId = __postRequest( + _radHash, + registry().verifyRadonSLA(_querySLA) ); + // Let observers know that a new request has been posted + emit NewQuery(_queryId, _getMsgValue()); } - + } + /// @notice Requests the execution of the given Witnet Data Request in expectation that it will be relayed and solved by the Witnet DON. /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided /// @notice result to this request. @@ -534,7 +540,7 @@ abstract contract WitnetRequestBoardTrustableBase inStatus(_queryId, Witnet.QueryStatus.Posted) { __seekQueryRequest(_queryId).reward += _getMsgValue(); - emit UpgradedReward(_queryId); + emit QueryRewardUpgraded(_queryId, __seekQueryRequest(_queryId).reward); } diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index 3985c6cd4..41dec51d7 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -2,19 +2,21 @@ pragma solidity >=0.7.0 <0.9.0; -import "../libs/WitnetV2.sol"; +import "../libs/Witnet.sol"; interface IWitnetRequestBoard { - - /// Emitted when a Witnet Data Request is posted to the WRB. - event PostedRequest(uint256 indexed queryId, address from); + + /// Emitted every time a new query containing some verified data request is posted to the WRB. + event NewQuery(uint256 indexed id, uint256 evmReward); /// Emitted when a Witnet-solved result is reported to the WRB. event PostedResult(uint256 indexed queryId, address from); /// Emitted when the reward of some not-yet reported query is upgraded. - event UpgradedReward(uint256 indexed queryId); + event QueryRewardUpgraded(uint256 indexed id, uint256 evmReward); + /// Emitted when a query with no callback gets reported into the WRB. + event QueryReport(uint256 indexed id, uint256 evmGasPrice); /// =============================================================================================================== /// --- Requester interface --------------------------------------------------------------------------------------- From 30fd3f47b07522371ce752df438c74b973c8f107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 23 Nov 2023 13:52:23 +0100 Subject: [PATCH 47/86] feat: implement query callbacks from the WRB --- .../WitnetRequestBoardTrustableBase.sol | 281 ++++++++---------- contracts/interfaces/IWitnetRequestBoard.sol | 38 ++- contracts/interfaces/V2/IWitnetConsumer.sol | 41 ++- 3 files changed, 195 insertions(+), 165 deletions(-) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index b271f4c27..9348e8ab0 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -11,6 +11,7 @@ import "../../data/WitnetRequestBoardDataACLs.sol"; import "../../interfaces/IWitnetRequest.sol"; import "../../interfaces/IWitnetRequestBoardAdminACLs.sol"; import "../../interfaces/IWitnetRequestBoardReporter.sol"; +import "../../interfaces/V2/IWitnetConsumer.sol"; import "../../libs/WitnetErrorsLib.sol"; import "../../patterns/Payable.sol"; @@ -30,6 +31,7 @@ abstract contract WitnetRequestBoardTrustableBase { using Witnet for bytes; using Witnet for Witnet.Result; + using WitnetCBOR for WitnetCBOR.CBOR; bytes4 public immutable override class = type(IWitnetRequestBoard).interfaceId; WitnetRequestFactory immutable public override factory; @@ -41,6 +43,12 @@ abstract contract WitnetRequestBoardTrustableBase ); _; } + modifier checkCallbackRecipient(address _addr) { + require( + _addr.code.length > 0 && IWitnetConsumer(_addr).reportableFrom(address(this)), + "WitnetRequestBoardTrustableBase: invalid callback recipient" + ); _; + } constructor( WitnetRequestFactory _factory, @@ -92,6 +100,11 @@ abstract contract WitnetRequestBoardTrustableBase /// @param _resultMaxSize Maximum expected size of returned data (in bytes). function estimateBaseFee(uint256 _gasPrice, uint256 _resultMaxSize) virtual public 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 _maxCallbackGas Maximum gas to be spent when reporting the data request result. + function estimateBaseFeeWithCallback(uint256 _gasPrice, uint256 _maxCallbackGas) virtual public view returns (uint256); + // ================================================================================================================ // --- Overrides 'Upgradeable' ------------------------------------------------------------------------------------ @@ -517,15 +530,25 @@ abstract contract WitnetRequestBoardTrustableBase /// @notice result to this request. /// @dev Fails if, provided reward is too low. /// @dev The caller must be a contract implementing the IWitnetConsumer interface. - function postRequestWithCallback(bytes32, WitnetV2.RadonSLA calldata) + function postRequestWithCallback( + bytes32 _radHash, + Witnet.RadonSLA calldata _querySLA, + uint256 _queryMaxCallbackGas + ) virtual override external payable - returns (uint256) + checkCallbackRecipient(msg.sender) + checkReward(estimateBaseFeeWithCallback(_getGasPrice(), _queryMaxCallbackGas)) + returns (uint256 _queryId) { - revert("WitnetRequestBoardTrustableBase: not implemented"); + _queryId = __postRequest( + _radHash, + registry().verifyRadonSLA(_querySLA) + ); + __seekQueryRequest(_queryId).maxCallbackGas = _queryMaxCallbackGas; + emit NewQuery(_queryId, _getMsgValue()); } - /// 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 @@ -651,160 +674,29 @@ abstract contract WitnetRequestBoardTrustableBase return __storage().queries[_queryId].request.reward; } - // ================================================================================================================ - // --- Deprecating methods from 'IWitnetRequestBoard' ------------------------------------------------------------- - /// Tell if a Witnet.Result is successful. - /// @param _result An instance of Witnet.Result. - /// @return `true` if successful, `false` if errored. - function isOk(Witnet.Result memory _result) - external pure - override - returns (bool) - { - return _result.success; - } - - /// Decode a bytes value from a Witnet.Result as a `bytes32` value. - /// @param _result An instance of Witnet.Result. - /// @return The `bytes32` decoded from the Witnet.Result. - function asBytes32(Witnet.Result memory _result) - external pure - override - returns (bytes32) - { - return _result.asBytes32(); - } - - /// Generate a suitable error message for a member of `Witnet.ResultErrorCodes` and its corresponding arguments. - /// @dev WARN: Note that client contracts should wrap this function into a try-catch foreseing potential errors generated in this function - /// @param _result An instance of `Witnet.Result`. - /// @return A tuple containing the `CBORValue.Error memory` decoded from the `Witnet.Result`, plus a loggable error message. - function asErrorMessage(Witnet.Result memory _result) - external pure - override - returns (Witnet.ResultErrorCodes, string memory) - { - Witnet.ResultError memory _resultError = WitnetErrorsLib.asError(_result); - return ( - _resultError.code, - _resultError.reason - ); - } - - /// Decode a natural numeric value from a Witnet.Result as a `uint` value. - /// @param _result An instance of Witnet.Result. - /// @return The `uint` decoded from the Witnet.Result. - function asUint64(Witnet.Result memory _result) - external pure - override - returns (uint64) - { - return uint64(_result.asUint()); - } + // ================================================================================================================ + // --- Internal functions ----------------------------------------------------------------------------------------- - /// 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 - override - returns (uint256) + function __newQuery() + virtual internal returns (uint256) { - return estimateBaseFee(_gasPrice, 32); + return ++ __storage().numQueries; } - /// 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 _requestInterface The address of a IWitnetRequest contract, containing the actual Data Request seralized bytecode. - /// @return _queryId An unique query identifier. - function postRequest(address _requestInterface) - virtual override - public payable + function __postRequest(bytes32 _radHash, bytes32 _slaHash) + virtual internal returns (uint256 _queryId) { - uint256 _value = _getMsgValue(); - uint256 _gasPrice = _getGasPrice(); - - // check base reward - uint256 _baseFee = estimateBaseFee(_gasPrice, 32); - require(_value >= _baseFee, "WitnetRequestBoardTrustableBase: reward too low"); - - _queryId = ++ __storage().numQueries; - __storage().queries[_queryId].from = msg.sender; - + _queryId = __newQuery(); Witnet.Request storage __request = __seekQueryRequest(_queryId); - __request._addr = _requestInterface; - __request._gasprice = _gasPrice; - __request.reward = _value; - - // Let observers know that a new request has been posted - emit PostedRequest(_queryId, msg.sender); - } - - /// 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 identifier - function readRequestGasPrice(uint256 _queryId) - external view - override - inStatus(_queryId, Witnet.QueryStatus.Posted) - returns (uint256) - { - return __storage().queries[_queryId].request._gasprice; - } - - /// Decode raw CBOR 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) - external pure - override - returns (Witnet.Result memory) - { - return Witnet.resultFromCborBytes(_cborBytes); - } - - /// 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) - public payable - virtual override - inStatus(_queryId, Witnet.QueryStatus.Posted) - { - Witnet.Request storage __request = __seekQueryRequest(_queryId); - - uint256 _newReward = __request.reward + _getMsgValue(); - uint256 _newGasPrice = _getGasPrice(); - - // If gas price is increased, then check if new rewards cover gas costs - if (_newGasPrice > __request._gasprice) { - // Checks the reward is covering gas cost - uint256 _minResultReward = estimateBaseFee(_newGasPrice, 32); - require( - _newReward >= _minResultReward, - "WitnetRequestBoardTrustableBase: reward too low" - ); - __request._gasprice = _newGasPrice; + { + __request.radHash = _radHash; + __request.slaHash = _slaHash; + __request.reward = _getMsgValue(); } - __request.reward = _newReward; } - - // ================================================================================================================ - // --- Internal functions ----------------------------------------------------------------------------------------- - function __reportResult( uint256 _queryId, uint256 _timestamp, @@ -812,20 +704,105 @@ abstract contract WitnetRequestBoardTrustableBase bytes memory _cborBytes ) internal - returns (uint256 _reward) + returns (uint256 _evmReward) { Witnet.Query storage __query = __seekQuery(_queryId); + + // read and erase query report reward Witnet.Request storage __request = __query.request; - Witnet.Response storage __response = __query.response; + _evmReward = __request.reward; + __request.reward = 0; + // write report traceability data in storage + // (could potentially be deleted from a callback method within same transaction) + Witnet.Response storage __response = __query.response; // solhint-disable not-rely-on-time __response.timestamp = _timestamp; __response.drTxHash = _drTxHash; __response.reporter = msg.sender; - __response.cborBytes = _cborBytes; - // return request latest reward - _reward = __request.reward; + // determine whether a callback is required + if (__request.maxCallbackGas > 0) { + uint _evmCallbackGas = gasleft(); + bool _evmCallbackSuccess; + bytes memory _evmCallbackRevertBytes; + // if callback is required, select which callback method to call + // depending on whether the query was solved with or without errors: + if (_cborBytes[0] == bytes1(0xd8)) { + WitnetCBOR.CBOR[] memory _errors = WitnetCBOR.fromBytes(_cborBytes).readArray(); + if (_errors.length < 2) { + // result with unknown error: + (_evmCallbackSuccess, _evmCallbackRevertBytes) = __query.from.call{gas: __request.maxCallbackGas}( + abi.encodeWithSelector(IWitnetConsumer.reportWitnetQueryError.selector, + _queryId, + Witnet.ResultErrorCodes.Unknown, + WitnetCBOR.CBOR({ + buffer: WitnetBuffer.Buffer({ data: hex"", cursor: 0}), + initialByte: 0, + majorType: 0, + additionalInformation: 0, + len: 0, + tag: 0 + }) + ) + ); + } else { + // result with parsable error: + (_evmCallbackSuccess, _evmCallbackRevertBytes) = __query.from.call{gas: __request.maxCallbackGas}( + abi.encodeWithSelector(IWitnetConsumer.reportWitnetQueryError.selector, + _queryId, + Witnet.ResultErrorCodes(_errors[0].readUint()), + _errors[0] + ) + ); + } + } else { + // result with no error + (_evmCallbackSuccess, _evmCallbackRevertBytes) = __query.from.call{gas: __request.maxCallbackGas}( + abi.encodeWithSelector(IWitnetConsumer.reportWitnetQueryResult.selector, + _queryId, + WitnetCBOR.fromBytes(_cborBytes) + ) + ); + } + _evmCallbackGas -= gasleft(); + if (_evmCallbackSuccess) { + emit QueryCallback( + _queryId, + _getGasPrice(), + _evmCallbackGas + ); + } else { + if (_evmCallbackRevertBytes.length < 68) { + emit QueryCallbackRevert( + _queryId, + _getGasPrice(), + _evmCallbackGas, + "WitnetRequestBoardTrustableDefault: unhandled callback revert" + ); + } else { + assembly { + _evmCallbackRevertBytes := add(_evmCallbackRevertBytes, 0x04) + } + emit QueryCallbackRevert( + _queryId, + _getGasPrice(), + _evmCallbackGas, + string(abi.encodePacked( + "WitnetRequestBoardTrustableDefault: callback revert: ", + _evmCallbackRevertBytes + )) + ); + } + } + } else { + // no callback is involved, so just keep the cbor-encoded result in storage: + __response.cborBytes = _cborBytes; + emit QueryReport( + _queryId, + _getGasPrice() + ); + } } function __setReporters(address[] memory _reporters) internal { diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index 41dec51d7..70446cc96 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -17,6 +17,12 @@ interface IWitnetRequestBoard { /// Emitted when a query with no callback gets reported into the WRB. event QueryReport(uint256 indexed id, uint256 evmGasPrice); + + /// Emitted when a query with a callback gets successfully reported into the WRB. + event QueryCallback(uint256 indexed id, uint256 evmGasPrice, uint256 evmCallbackGas); + + /// Emitted when a query with a callback cannot get reported into the WRB. + event QueryCallbackRevert(uint256 indexed id, uint256 evmGasPrice, uint256 evmCallbackGas, string evmReason); /// =============================================================================================================== /// --- Requester interface --------------------------------------------------------------------------------------- @@ -51,6 +57,26 @@ interface IWitnetRequestBoard { /// @param _queryId The unique query identifier. function deleteQuery(uint256 _queryId) external returns (Witnet.Response memory); + /// @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, uint256 _resultMaxSize) 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 _maxCallbackGas Maximum gas to be spent when reporting the data request result. + function estimateBaseFeeWithCallback(uint256 _gasPrice, uint256 _maxCallbackGas) external view returns (uint256); + + /// @notice Requests the execution of the given Witnet Data Request in expectation that it will be relayed and solved by the Witnet DON. + /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided + /// @notice result to this request. + /// @dev Fails if, provided reward is too low. + /// @param radHash The RAD hash of the data request to be solved by Witnet. + /// @param slaHash The SLA hash of the data request to be solved by Witnet. + /// @return _queryId Unique query identifier. + function postRequest(bytes32 radHash, bytes32 slaHash) 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 the Witnet DON. /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided /// @notice result to this request. @@ -68,6 +94,7 @@ interface IWitnetRequestBoard { /// @dev The caller must be a contract implementing the IWitnetConsumer interface. /// @param radHash 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 maxCallbackGas Maximum gas to be spent when reporting the data request result. /// @return _queryId Unique query identifier. function postRequestWithCallback(bytes32 radHash, Witnet.RadonSLA calldata querySLA, uint256 maxCallbackGas) external payable returns (uint256 _queryId); @@ -79,17 +106,6 @@ interface IWitnetRequestBoard { /// =============================================================================================================== /// --- Reader interface ------------------------------------------------------------------------------------------ - /// @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, uint256 _resultMaxSize) 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 _maxCallbackGas Maximum gas to be spent when reporting the data request result. - function estimateBaseFeeWithCallback(uint256 _gasPrice, uint256 _maxCallbackGas) external view returns (uint256); - /// @notice Returns next query id to be generated by the Witnet Request Board. function getNextQueryId() external view returns (uint256); diff --git a/contracts/interfaces/V2/IWitnetConsumer.sol b/contracts/interfaces/V2/IWitnetConsumer.sol index 0ea6aaa49..af065fec3 100644 --- a/contracts/interfaces/V2/IWitnetConsumer.sol +++ b/contracts/interfaces/V2/IWitnetConsumer.sol @@ -4,6 +4,43 @@ pragma solidity ^0.8.0; import "../../libs/Witnet.sol"; interface IWitnetConsumer { - function reportWitnetQueryResult(uint256, WitnetCBOR.CBOR calldata) external; - function reportWitnetQueryError(uint256, Witnet.ResultErrorCodes, uint) external; + + /// @notice Method to be called from the WitnetRequestBoard 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 WitnetRequestBoard being used + /// @dev by the WitnetConsumer contract. Within the implementation of this method, the WitnetConsumer + /// @dev can call to the WRB as to retrieve the Witnet tracking information (i.e. the `witnetDrTxHash` + /// @dev and `witnetDrCommitTimestamp`), or the finality status, of the result being reported. + /// @param queryId The unique identifier of the Witnet query being reported. + /// @param cborValue The CBOR-encoded resulting value of the Witnet query being reported. + function reportWitnetQueryResult( + uint256 queryId, + WitnetCBOR.CBOR calldata cborValue + ) external; + + /// @notice Method to be called from the WitnetRequestBoard 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 WitnetRequestBoard being used + /// @dev by the WitnetConsumer contract. Within the implementation of this method, the WitnetConsumer + /// @dev can call to the WRB as to retrieve the Witnet tracking information (i.e. the `witnetDrTxHash` + /// @dev and `witnetDrCommitTimestamp`), or the finality status, of the result being reported. + /// @param queryId The unique identifier of the Witnet query being reported. + /// @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 queryId, + Witnet.ResultErrorCodes errorCode, + WitnetCBOR.CBOR calldata errorArgs + ) external; + + /// @notice Method to be called from the WitnetRequestBoard contract as soon as some dispute + /// @notice arises concerning the given Witnet `queryId`. + /// @param queryId The unique identifier of the Witnet query being disputed. + /// @param resolutionBlock The EVM block number at which the query resolution is expected to be final. + function reportWitnetQueryDispute(uint256 queryId, uint256 resolutionBlock) external; + + /// @notice Determines if Witnet queries can be reported from given address. + /// @dev In practice, must only be true on the WitnetRequestBoard 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 From 87e8f2936f7673f8236dcb75fec3f67f59ae18d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 23 Nov 2023 19:50:25 +0100 Subject: [PATCH 48/86] feat: 5-param Witnet.RadonSLA -> 2-param WitnetV2.RadonSLA --- contracts/apps/UsingWitnet.sol | 4 +- contracts/apps/UsingWitnetRequest.sol | 4 +- contracts/apps/UsingWitnetRequestTemplate.sol | 6 +- contracts/apps/WitnetPriceFeeds.sol | 79 ++++++------ contracts/apps/WitnetRandomness.sol | 90 ++++++------- .../core/defaults/WitnetBytecodesDefault.sol | 122 ++---------------- .../WitnetRequestBoardTrustableBase.sol | 69 +++++++--- contracts/data/WitnetBytecodesData.sol | 4 +- contracts/data/WitnetPriceFeedsData.sol | 2 +- contracts/interfaces/IWitnetRandomness.sol | 2 +- .../interfaces/IWitnetRandomnessAdmin.sol | 2 +- contracts/interfaces/IWitnetRequestBoard.sol | 35 ++--- contracts/interfaces/V2/IWitnetBytecodes.sol | 27 +--- contracts/interfaces/V2/IWitnetFeeds.sol | 8 +- contracts/interfaces/V2/IWitnetFeedsAdmin.sol | 2 +- contracts/libs/Witnet.sol | 37 +++++- contracts/libs/WitnetV2.sol | 117 ++++++++--------- 17 files changed, 277 insertions(+), 333 deletions(-) diff --git a/contracts/apps/UsingWitnet.sol b/contracts/apps/UsingWitnet.sol index f219138df..d5b3d28dd 100644 --- a/contracts/apps/UsingWitnet.sol +++ b/contracts/apps/UsingWitnet.sol @@ -89,8 +89,8 @@ abstract contract UsingWitnet { function __witnetRequestData( uint256 _witnetEvmReward, - WitnetV2.RadonSLA calldata _witnetQuerySLA, - bytes32 _witnetRadHash + bytes32 _witnetRadHash, + WitnetV2.RadonSLA calldata _witnetQuerySLA ) virtual internal returns (uint256) { diff --git a/contracts/apps/UsingWitnetRequest.sol b/contracts/apps/UsingWitnetRequest.sol index 8631804df..d7103c3b7 100644 --- a/contracts/apps/UsingWitnetRequest.sol +++ b/contracts/apps/UsingWitnetRequest.sol @@ -42,8 +42,8 @@ abstract contract UsingWitnetRequest { return __witnetRequestData( _witnetEvmReward, - _witnetQuerySLA, - __witnetRequestRadHash + __witnetRequestRadHash, + _witnetQuerySLA ); } diff --git a/contracts/apps/UsingWitnetRequestTemplate.sol b/contracts/apps/UsingWitnetRequestTemplate.sol index 0d4ea08ed..dfeaf2573 100644 --- a/contracts/apps/UsingWitnetRequestTemplate.sol +++ b/contracts/apps/UsingWitnetRequestTemplate.sol @@ -35,7 +35,7 @@ abstract contract UsingWitnetRequestTemplate } function _witnetEstimateBaseFee() - internal view + virtual internal view returns (uint256) { return __witnet.estimateBaseFee( @@ -53,8 +53,8 @@ abstract contract UsingWitnetRequestTemplate { return __witnetRequestData( _witnetEvmReward, - _witnetQuerySLA, - _witnetBuildRadHash(_witnetRequestArgs) + _witnetBuildRadHash(_witnetRequestArgs), + _witnetQuerySLA ); } diff --git a/contracts/apps/WitnetPriceFeeds.sol b/contracts/apps/WitnetPriceFeeds.sol index 83eee104d..182a6a1a0 100644 --- a/contracts/apps/WitnetPriceFeeds.sol +++ b/contracts/apps/WitnetPriceFeeds.sol @@ -27,7 +27,7 @@ contract WitnetPriceFeeds WitnetPriceFeedsData { using Witnet for Witnet.Result; - using Witnet for Witnet.RadonSLA; + using WitnetV2 for WitnetV2.RadonSLA; bytes4 immutable public class = type(IWitnetPriceFeeds).interfaceId; WitnetRequestBoard immutable public override witnet; @@ -44,12 +44,9 @@ contract WitnetPriceFeeds "WitnetPriceFeeds: uncompliant request board" ); witnet = _wrb; - __settleDefaultRadonSLA(Witnet.RadonSLA({ + __settleDefaultRadonSLA(WitnetV2.RadonSLA({ numWitnesses: 5, - witnessCollateral: 15 * 10 ** 9, - witnessReward: 15 * 10 ** 7, - minerCommitRevealFee: 10 ** 7, - minConsensusPercentage: 51 + witnessingCollateralRatio: 10 })); } @@ -138,26 +135,16 @@ contract WitnetPriceFeeds function defaultRadonSLA() override public view - returns (Witnet.RadonSLA memory) + returns (WitnetV2.RadonSLA memory) { - return registry().lookupRadonSLA(__storage().defaultSlaHash); + return WitnetV2.toRadonSLA(__storage().packedDefaultSLA); } - function estimateUpdateBaseFee(bytes4, uint256 _evmGasPrice, uint256) + function estimateUpdateBaseFee(uint256 _evmGasPrice) virtual override public view returns (uint) { - // TODO: refactor when WRB.estimateBaseFee(bytes32,bytes32,uint256,uint256) is implemented. - return witnet.estimateBaseFee(_evmGasPrice, 32); - } - - function estimateUpdateBaseFee(bytes4, uint256 _evmGasPrice, uint256, bytes32) - virtual override - public view - returns (uint) - { - // TODO: refactor when WRB.estimateBaseFee(bytes32,bytes32,uint256,uint256) is implemented. return witnet.estimateBaseFee(_evmGasPrice, 32); } @@ -219,10 +206,7 @@ contract WitnetPriceFeeds __record.radHash != 0, "WitnetPriceFeeds: no RAD hash" ); - return registry().bytecodeOf( - __record.radHash, - __storage().defaultSlaHash - ); + return registry().bytecodeOf(__record.radHash); } function lookupRadHash(bytes4 feedId) @@ -252,19 +236,22 @@ contract WitnetPriceFeeds virtual override returns (uint256) { - return __requestUpdate(feedId, __storage().defaultSlaHash); + return __requestUpdate( + feedId, + WitnetV2.toRadonSLA(__storage().packedDefaultSLA) + ); } - function requestUpdate(bytes4 feedId, bytes32 _slaHash) + function requestUpdate(bytes4 feedId, WitnetV2.RadonSLA calldata updateSLA) public payable virtual override returns (uint256 _usedFunds) { require( - registry().lookupRadonSLA(_slaHash).equalOrGreaterThan(defaultRadonSLA()), + updateSLA.equalOrGreaterThan(defaultRadonSLA()), "WitnetPriceFeeds: unsecure update" ); - return __requestUpdate(feedId, _slaHash); + return __requestUpdate(feedId, updateSLA); } @@ -321,11 +308,11 @@ contract WitnetPriceFeeds emit DeletedFeed(msg.sender, feedId, caption); } - function settleDefaultRadonSLA(Witnet.RadonSLA memory sla) + function settleDefaultRadonSLA(WitnetV2.RadonSLA memory defaultSLA) override public onlyOwner { - __settleDefaultRadonSLA(sla); + __settleDefaultRadonSLA(defaultSLA); } function settleFeedRequest(string calldata caption, bytes32 radHash) @@ -607,24 +594,27 @@ contract WitnetPriceFeeds } } - function __requestUpdate(bytes4[] memory _deps, bytes32 slaHash) + function __requestUpdate(bytes4[] memory _deps, WitnetV2.RadonSLA memory sla) virtual internal returns (uint256 _usedFunds) { uint _partial = msg.value / _deps.length; for (uint _ix = 0; _ix < _deps.length; _ix ++) { - _usedFunds += this.requestUpdate{value: _partial}(_deps[_ix], slaHash); + _usedFunds += this.requestUpdate{value: _partial}(_deps[_ix], sla); } } - function __requestUpdate(bytes4 feedId, bytes32 _slaHash) + function __requestUpdate(bytes4 feedId, WitnetV2.RadonSLA memory querySLA) virtual internal returns (uint256 _usedFunds) { Record storage __feed = __records_(feedId); if (__feed.radHash != 0) { - _usedFunds = estimateUpdateBaseFee(feedId, tx.gasprice, 0, _slaHash); - require(msg.value>= _usedFunds, "WitnetPriceFeeds: reward too low"); + _usedFunds = estimateUpdateBaseFee(tx.gasprice); + require( + msg.value >= _usedFunds, + "WitnetPriceFeeds: reward too low" + ); uint _latestId = __feed.latestUpdateQueryId; Witnet.ResultStatus _latestStatus = _checkQueryResultStatus(_latestId); if (_latestStatus == Witnet.ResultStatus.Awaiting) { @@ -652,13 +642,24 @@ contract WitnetPriceFeeds try witnet.deleteQuery(_latestId) {} catch {} } // Post update request to the WRB: - _latestId = witnet.postRequest{value: _usedFunds}(__feed.radHash, _slaHash); + _latestId = witnet.postRequest{value: _usedFunds}( + __feed.radHash, + querySLA + ); // Update latest query id: __feed.latestUpdateQueryId = _latestId; - emit UpdatingFeed(msg.sender, feedId, _slaHash, _usedFunds); + emit UpdatingFeed( + msg.sender, + feedId, + querySLA.packed(), + _usedFunds + ); } } else if (__feed.solver != address(0)) { - _usedFunds = __requestUpdate(_depsOf(feedId), _slaHash); + _usedFunds = __requestUpdate( + _depsOf(feedId), + querySLA + ); } else { revert("WitnetPriceFeeds: unknown feed"); } @@ -668,7 +669,7 @@ contract WitnetPriceFeeds } } - function __settleDefaultRadonSLA(Witnet.RadonSLA memory sla) internal { - __storage().defaultSlaHash = registry().verifyRadonSLA(sla); + function __settleDefaultRadonSLA(WitnetV2.RadonSLA memory sla) internal { + __storage().packedDefaultSLA = WitnetV2.packed(sla); } } diff --git a/contracts/apps/WitnetRandomness.sol b/contracts/apps/WitnetRandomness.sol index 5d6d4d93c..14de02640 100644 --- a/contracts/apps/WitnetRandomness.sol +++ b/contracts/apps/WitnetRandomness.sol @@ -23,13 +23,15 @@ contract WitnetRandomness UsingWitnet { using Witnet for Witnet.Result; + using WitnetV2 for bytes32; + using WitnetV2 for WitnetV2.RadonSLA; bytes4 public immutable class = type(IWitnetRandomness).interfaceId; uint256 public override latestRandomizeBlock; WitnetRequest public immutable override witnetRandomnessRequest; bytes32 internal immutable __witnetRandomnessRadHash; - bytes32 internal __witnetRandomnessSlaHash; + bytes32 internal __witnetRandomnessPackedSLA; mapping (uint256 => RandomizeData) internal __randomize_; struct RandomizeData { @@ -74,7 +76,7 @@ contract WitnetRandomness witnetRandomnessRequest = WitnetRequest(_template.buildRequest(new string[][](_retrievals.length))); __witnetRandomnessRadHash = witnetRandomnessRequest.radHash(); } - __initializeWitnetRandomnessSlaHash(); + __initializeWitnetRandomnessSLA(); } /// Deploys and returns the address of a minimal proxy clone that replicates contract @@ -147,13 +149,14 @@ contract WitnetRandomness Ownable.transferOwnership(_newOwner); } - function settleWitnetRandomnessSLA(Witnet.RadonSLA memory _radonSLA) + function settleWitnetRandomnessSLA(WitnetV2.RadonSLA calldata sla) virtual override public onlyOwner returns (bytes32) { - return __settleWitnetRandomnessSLA(_radonSLA); + require(sla.isValid(), "WitnetRandomness: invalid SLA"); + return __settleWitnetRandomnessSLA(sla); } @@ -330,7 +333,7 @@ contract WitnetRandomness _usedFunds = _witnetEstimateBaseFee(tx.gasprice); uint _queryId = witnet().postRequest{value: _usedFunds}( __witnetRandomnessRadHash, - __witnetRandomnessSlaHash + __witnetRandomnessPackedSLA.toRadonSLA() ); // Keep Randomize data in storage: RandomizeData storage _data = __randomize_[block.number]; @@ -386,9 +389,9 @@ contract WitnetRandomness function witnetRandomnessSLA() virtual override external view - returns (Witnet.RadonSLA memory) + returns (WitnetV2.RadonSLA memory) { - return witnet().registry().lookupRadonSLA(__witnetRandomnessSlaHash); + return __witnetRandomnessPackedSLA.toRadonSLA(); } @@ -408,44 +411,6 @@ contract WitnetRandomness // ================================================================================================================ // --- INTERNAL FUNCTIONS ----------------------------------------------------------------------------------------- - /// @dev Common steps for both deterministic and non-deterministic cloning. - function __afterClone(address _instance) - virtual internal - returns (WitnetRandomness) - { - WitnetRandomness(_instance).initializeClone(hex""); - return WitnetRandomness(_instance); - } - - /// @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) - virtual internal - { - // settle ownership: - _transferOwnership(msg.sender); - // initialize default Witnet SLA parameters used for every randomness request; - __initializeWitnetRandomnessSlaHash(); - } - - function __initializeWitnetRandomnessSlaHash() virtual internal { - __settleWitnetRandomnessSLA(Witnet.RadonSLA({ - numWitnesses: 5, - minConsensusPercentage: 51, - witnessReward: 10 ** 8, - witnessCollateral: 10 ** 9, - minerCommitRevealFee: 10 ** 7 - })); - } - - function __settleWitnetRandomnessSLA(Witnet.RadonSLA memory _radonSLA) - internal - returns (bytes32 _radonSlaHash) - { - _radonSlaHash = witnet().registry().verifyRadonSLA(_radonSLA); - __witnetRandomnessSlaHash = _radonSlaHash; - } - /// @dev Returns index of the Most Significant Bit of the given number, applying De Bruijn O(1) algorithm. function _msbDeBruijn32(uint32 _v) internal pure @@ -486,4 +451,39 @@ contract WitnetRandomness ); } + /// @dev Common steps for both deterministic and non-deterministic cloning. + function __afterClone(address _instance) + virtual internal + returns (WitnetRandomness) + { + WitnetRandomness(_instance).initializeClone(hex""); + return WitnetRandomness(_instance); + } + + /// @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) + virtual internal + { + // settle ownership: + _transferOwnership(msg.sender); + // initialize default Witnet SLA parameters used for every randomness request; + __initializeWitnetRandomnessSLA(); + } + + function __initializeWitnetRandomnessSLA() virtual internal { + __settleWitnetRandomnessSLA(WitnetV2.RadonSLA({ + numWitnesses: 5, + witnessingCollateralRatio: 10 + })); + } + + function __settleWitnetRandomnessSLA(WitnetV2.RadonSLA memory sla) + internal + returns (bytes32 _packed) + { + _packed = sla.packed(); + __witnetRandomnessPackedSLA = _packed; + } + } diff --git a/contracts/core/defaults/WitnetBytecodesDefault.sol b/contracts/core/defaults/WitnetBytecodesDefault.sol index 3f0704fcc..e456f60ac 100644 --- a/contracts/core/defaults/WitnetBytecodesDefault.sol +++ b/contracts/core/defaults/WitnetBytecodesDefault.sol @@ -149,78 +149,6 @@ contract WitnetBytecodesDefault return __database().radsBytecode[_radHash]; } - function bytecodeOf(bytes32 _radHash, bytes32 _slaHash) - external view - returns (bytes memory) - { - Witnet.RadonSLA storage __sla = __database().slas[_slaHash]; - if (__sla.numWitnesses == 0) { - revert("WitnetBytecodesDefault: unknown Radon SLA"); - } - bytes memory _radBytecode = bytecodeOf(_radHash); - return abi.encodePacked( - WitnetEncodingLib.encode(uint64(_radBytecode.length), 0x0a), - _radBytecode, - __database().slasBytecode[_slaHash] - ); - } - - function hashOf( - bytes32[] calldata _retrievalsIds, - bytes32 _aggregatorId, - bytes32 _tallyId, - uint16 _resultMaxSize, - string[][] calldata _args - ) - external pure - virtual override - returns (bytes32) - { - return keccak256(abi.encode( - _retrievalsIds, - _aggregatorId, - _tallyId, - _resultMaxSize, - _args - )); - } - - function hashOf(bytes32 _radHash, bytes32 _slaHash) - public pure - virtual override - returns (bytes32) - { - return sha256(abi.encode( - _radHash, - _slaHash - )); - } - - function hashWeightWitsOf( - bytes32 _radHash, - bytes32 _slaHash - ) - external view - virtual override - returns (bytes32, uint32, uint256) - { - Witnet.RadonSLA storage __sla = __database().slas[_slaHash]; - { - uint _numWitnesses = __sla.numWitnesses; - uint _weight = __database().radsBytecode[_radHash].length; - uint _witnessWits = __sla.witnessReward + 2 * __sla.minerCommitRevealFee; - return ( - hashOf(_radHash, _slaHash), - uint32(_weight - + _numWitnesses * 636 - // + (8 + 2 + 8 + 4 + 8) - + 100 - ), - _numWitnesses * _witnessWits - ); - } - } - function lookupDataProvider(uint256 _index) external view override @@ -371,25 +299,16 @@ contract WitnetBytecodesDefault rad.tally = __database().reducers[__request.tally]; } - function lookupRadonSLA(bytes32 _slaHash) - external view - override - returns (Witnet.RadonSLA memory sla) - { - sla = __database().slas[_slaHash]; - if (sla.numWitnesses == 0) { - revert UnknownRadonSLA(_slaHash); - } - } - - function lookupRadonSLAReward(bytes32 _slaHash) - public view - override - returns (uint) - { - Witnet.RadonSLA storage __sla = __database().slas[_slaHash]; - return __sla.numWitnesses * __sla.witnessReward; - } + // function lookupRadonSLA(bytes32 _slaHash) + // external view + // override + // returns (Witnet.RadonSLA memory sla) + // { + // sla = __database().slas[_slaHash]; + // if (sla.numWitnesses == 0) { + // revert UnknownRadonSLA(_slaHash); + // } + // } function verifyRadonRetrieval( Witnet.RadonDataRequestMethods _requestMethod, @@ -549,27 +468,6 @@ contract WitnetBytecodesDefault } } - function verifyRadonSLA(Witnet.RadonSLA calldata _sla) - external - virtual override - returns (bytes32 _slaHash) - { - // Build RadonSLA bytecode: - bytes memory _bytecode = _sla.encode(); - - // Add it to storage if not verified yet: - _slaHash = _witnetHash(_bytecode); - if (__database().slas[_slaHash].numWitnesses == 0) { - // validate SLA params: - _sla.validate(); - // save parameters and encoded bytecode in storage: - __database().slas[_slaHash] = _sla; - __database().slasBytecode[_slaHash] = _bytecode; - // emit event - emit NewSlaHash(_slaHash); - } - } - function totalDataProviders() external view override diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index 9348e8ab0..ff43a3eef 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -32,10 +32,18 @@ abstract contract WitnetRequestBoardTrustableBase using Witnet for bytes; using Witnet for Witnet.Result; using WitnetCBOR for WitnetCBOR.CBOR; + using WitnetV2 for WitnetV2.RadonSLA; bytes4 public immutable override class = type(IWitnetRequestBoard).interfaceId; WitnetRequestFactory immutable public override factory; + modifier checkCallbackRecipient(address _addr) { + require( + _addr.code.length > 0 && IWitnetConsumer(_addr).reportableFrom(address(this)), + "WitnetRequestBoardTrustableBase: invalid callback recipient" + ); _; + } + modifier checkReward(uint256 _baseFee) { require( _getMsgValue() >= _baseFee, @@ -43,10 +51,10 @@ abstract contract WitnetRequestBoardTrustableBase ); _; } - modifier checkCallbackRecipient(address _addr) { + modifier checkSLA(WitnetV2.RadonSLA calldata sla) { require( - _addr.code.length > 0 && IWitnetConsumer(_addr).reportableFrom(address(this)), - "WitnetRequestBoardTrustableBase: invalid callback recipient" + WitnetV2.isValid(sla), + "WitnetRequestBoardTrustableBase: invalid SLA" ); _; } @@ -482,6 +490,29 @@ abstract contract WitnetRequestBoardTrustableBase delete __storage().queries[_queryId]; } + /// @notice Estimates the actual earnings (or loss), in WEI, that a reporter would get by reporting result to given query, + /// @notice based on the gas price of the calling transaction. + /// @dev Data requesters should consider upgrading the reward on queries providing no actual earnings. + function estimateQueryEarnings(uint256 _queryId) + virtual override + external view + returns (int256 _earnings) + { + Witnet.Request storage __request = __seekQueryRequest(_queryId); + _earnings = int(__request.evmReward); + if (__request.maxCallbackGas > 0) { + _earnings -= int(estimateBaseFeeWithCallback( + _getGasPrice(), + __request.maxCallbackGas + )); + } else { + _earnings -= int(estimateBaseFee( + _getGasPrice(), + registry().lookupRadonRequestResultMaxSize(__request.radHash) + )); + } + } + /// 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. @@ -509,16 +540,17 @@ abstract contract WitnetRequestBoardTrustableBase /// @param _querySLA The SLA param of the data request to be solved by Witnet. function postRequest( bytes32 _radHash, - Witnet.RadonSLA calldata _querySLA + WitnetV2.RadonSLA calldata _querySLA ) virtual override public payable checkReward(estimateBaseFee(_getGasPrice(), 32)) + checkSLA(_querySLA) returns (uint256 _queryId) { _queryId = __postRequest( _radHash, - registry().verifyRadonSLA(_querySLA) + _querySLA.packed() ); // Let observers know that a new request has been posted emit NewQuery(_queryId, _getMsgValue()); @@ -532,18 +564,19 @@ abstract contract WitnetRequestBoardTrustableBase /// @dev The caller must be a contract implementing the IWitnetConsumer interface. function postRequestWithCallback( bytes32 _radHash, - Witnet.RadonSLA calldata _querySLA, + WitnetV2.RadonSLA calldata _querySLA, uint256 _queryMaxCallbackGas ) virtual override external payable checkCallbackRecipient(msg.sender) checkReward(estimateBaseFeeWithCallback(_getGasPrice(), _queryMaxCallbackGas)) + checkSLA(_querySLA) returns (uint256 _queryId) { _queryId = __postRequest( _radHash, - registry().verifyRadonSLA(_querySLA) + _querySLA.packed() ); __seekQueryRequest(_queryId).maxCallbackGas = _queryMaxCallbackGas; emit NewQuery(_queryId, _getMsgValue()); @@ -562,8 +595,9 @@ abstract contract WitnetRequestBoardTrustableBase virtual override inStatus(_queryId, Witnet.QueryStatus.Posted) { - __seekQueryRequest(_queryId).reward += _getMsgValue(); - emit QueryRewardUpgraded(_queryId, __seekQueryRequest(_queryId).reward); + Witnet.Request storage __request = __seekQueryRequest(_queryId); + __request.evmReward += _getMsgValue(); + emit QueryRewardUpgraded(_queryId, __request.evmReward); } @@ -629,10 +663,7 @@ abstract contract WitnetRequestBoardTrustableBase if (__request._addr != address(0)) { _bytecode = IWitnetRequest(__request._addr).bytecode(); } else if (__request.radHash != bytes32(0)) { - _bytecode = registry().bytecodeOf( - __request.radHash, - __request.slaHash - ); + _bytecode = registry().bytecodeOf(__request.radHash); } } @@ -671,7 +702,7 @@ abstract contract WitnetRequestBoardTrustableBase inStatus(_queryId, Witnet.QueryStatus.Posted) returns (uint256) { - return __storage().queries[_queryId].request.reward; + return __seekQueryRequest(_queryId).evmReward; } @@ -684,7 +715,7 @@ abstract contract WitnetRequestBoardTrustableBase return ++ __storage().numQueries; } - function __postRequest(bytes32 _radHash, bytes32 _slaHash) + function __postRequest(bytes32 _radHash, bytes32 _slaPacked) virtual internal returns (uint256 _queryId) { @@ -692,8 +723,8 @@ abstract contract WitnetRequestBoardTrustableBase Witnet.Request storage __request = __seekQueryRequest(_queryId); { __request.radHash = _radHash; - __request.slaHash = _slaHash; - __request.reward = _getMsgValue(); + __request.slaPacked = _slaPacked; + __request.evmReward = _getMsgValue(); } } @@ -710,8 +741,8 @@ abstract contract WitnetRequestBoardTrustableBase // read and erase query report reward Witnet.Request storage __request = __query.request; - _evmReward = __request.reward; - __request.reward = 0; + _evmReward = __request.evmReward; + __request.evmReward = 0; // write report traceability data in storage // (could potentially be deleted from a callback method within same transaction) diff --git a/contracts/data/WitnetBytecodesData.sol b/contracts/data/WitnetBytecodesData.sol index 8d7da1371..624f5f4e3 100644 --- a/contracts/data/WitnetBytecodesData.sol +++ b/contracts/data/WitnetBytecodesData.sol @@ -44,13 +44,13 @@ abstract contract WitnetBytecodesData { mapping (bytes32 => Witnet.RadonReducer) reducers; mapping (bytes32 => Witnet.RadonRetrieval) retrievals; - mapping (bytes32 => Witnet.RadonSLA) slas; + mapping (bytes32 => Witnet.RadonSLA) _slas; mapping (bytes32 => DataRequest) requests; mapping (bytes32 => bytes32) rads; mapping (bytes32 => bytes) radsBytecode; - mapping (bytes32 => bytes) slasBytecode; + mapping (bytes32 => bytes) _slasBytecode; } constructor() { diff --git a/contracts/data/WitnetPriceFeedsData.sol b/contracts/data/WitnetPriceFeedsData.sol index 94e486d97..e1fc4b4ed 100644 --- a/contracts/data/WitnetPriceFeedsData.sol +++ b/contracts/data/WitnetPriceFeedsData.sol @@ -11,7 +11,7 @@ abstract contract WitnetPriceFeedsData { 0xe36ea87c48340f2c23c9e1c9f72f5c5165184e75683a4d2a19148e5964c1d1ff; struct Storage { - bytes32 defaultSlaHash; + bytes32 packedDefaultSLA; bytes4[] ids; mapping (bytes4 => Record) records; } diff --git a/contracts/interfaces/IWitnetRandomness.sol b/contracts/interfaces/IWitnetRandomness.sol index c4d209b63..c6e561bce 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 (Witnet.RadonSLA memory); + function witnetRandomnessSLA() external view returns (WitnetV2.RadonSLA memory); } \ No newline at end of file diff --git a/contracts/interfaces/IWitnetRandomnessAdmin.sol b/contracts/interfaces/IWitnetRandomnessAdmin.sol index 2dd7dd1b9..741eb6648 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(Witnet.RadonSLA calldata) external returns (bytes32); + function settleWitnetRandomnessSLA(WitnetV2.RadonSLA calldata) external returns (bytes32); } \ No newline at end of file diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index 70446cc96..164c9c1c2 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -1,8 +1,7 @@ // SPDX-License-Identifier: MIT - pragma solidity >=0.7.0 <0.9.0; -import "../libs/Witnet.sol"; +import "../libs/WitnetV2.sol"; interface IWitnetRequestBoard { @@ -84,8 +83,8 @@ interface IWitnetRequestBoard { /// @dev The result to the query will be saved into the WitnetRequestBoard storage. /// @param radHash 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 radHash, Witnet.RadonSLA calldata querySLA) external payable returns (uint256 _queryId); + /// @return queryId Unique query identifier. + function postRequest(bytes32 radHash, 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 the Witnet DON. /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided @@ -95,12 +94,12 @@ interface IWitnetRequestBoard { /// @param radHash 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 maxCallbackGas Maximum gas to be spent when reporting the data request result. - /// @return _queryId Unique query identifier. - function postRequestWithCallback(bytes32 radHash, Witnet.RadonSLA calldata querySLA, uint256 maxCallbackGas) external payable returns (uint256 _queryId); + /// @return queryId Unique query identifier. + function postRequestWithCallback(bytes32 radHash, WitnetV2.RadonSLA calldata querySLA, uint256 maxCallbackGas) 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 upgradeQueryReward(uint256 _queryId) external payable; + /// @param queryId The unique query identifier. + function upgradeQueryReward(uint256 queryId) external payable; /// =============================================================================================================== @@ -134,15 +133,21 @@ interface IWitnetRequestBoard { function getQueryResponse(uint256 _queryId) external view returns (Witnet.Response memory); /// @notice Retrieves the reward currently set for the referred query. - /// @dev Fails if the `_queryId` is not valid or, if it has already been + /// @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 getQueryReward(uint256 _queryId) external view returns (uint256); + /// @param queryId The unique query identifier. + function getQueryReward(uint256 queryId) external view returns (uint256); - /// @notice 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 getQueryResponseResult(uint256 _queryId) external view returns (Witnet.Result memory); + /// =============================================================================================================== + /// --- Deprecating methods --------------------------------------------------------------------------------------- + /// @notice Requests the execution of the given Witnet Data Request in expectation that it will be relayed and solved by the Witnet DON. + /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided + /// @notice result to this request. + /// @dev Fails if, provided reward is too low. + /// @param radHash The RAD hash of the data request to be solved by Witnet. + /// @param slaHash The SLA hash of the data request to be solved by Witnet. + /// @return queryId Unique query identifier. + function postRequest(bytes32 radHash, bytes32 slaHash) external payable returns (uint256 queryId); } diff --git a/contracts/interfaces/V2/IWitnetBytecodes.sol b/contracts/interfaces/V2/IWitnetBytecodes.sol index 685735b40..06527664c 100644 --- a/contracts/interfaces/V2/IWitnetBytecodes.sol +++ b/contracts/interfaces/V2/IWitnetBytecodes.sol @@ -8,30 +8,13 @@ interface IWitnetBytecodes { error UnknownRadonRetrieval(bytes32 hash); error UnknownRadonReducer(bytes32 hash); error UnknownRadonRequest(bytes32 hash); - error UnknownRadonSLA(bytes32 hash); event NewDataProvider(uint256 index); event NewRadonRetrievalHash(bytes32 hash); event NewRadonReducerHash(bytes32 hash); event NewRadHash(bytes32 hash); - event NewSlaHash(bytes32 hash); function bytecodeOf(bytes32 radHash) external view returns (bytes memory); - function bytecodeOf(bytes32 radHash, bytes32 slahHash) external view returns (bytes memory); - - function hashOf( - bytes32[] calldata sources, - bytes32 aggregator, - bytes32 tally, - uint16 resultMaxSize, - string[][] calldata args - ) external pure returns (bytes32); - function hashOf(bytes32 radHash, bytes32 slaHash) external pure returns (bytes32 drQueryHash); - function hashWeightWitsOf(bytes32 radHash, bytes32 slaHash) external view returns ( - bytes32 drQueryHash, - uint32 drQueryWeight, - uint256 drQueryWits - ); function lookupDataProvider(uint256 index) external view returns (string memory, uint); function lookupDataProviderIndex(string calldata authority) external view returns (uint); @@ -51,8 +34,6 @@ interface IWitnetBytecodes { function lookupRadonRequestTally(bytes32 radHash) external view returns (Witnet.RadonReducer memory); function lookupRadonRAD(bytes32 radHash) external view returns (Witnet.RadonRAD memory); - function lookupRadonSLA(bytes32 slaHash) external view returns (Witnet.RadonSLA memory); - function lookupRadonSLAReward(bytes32 slaHash) external view returns (uint); function verifyRadonRetrieval( Witnet.RadonDataRequestMethods requestMethod, @@ -72,10 +53,12 @@ interface IWitnetBytecodes { uint16 resultMaxSize, string[][] calldata args ) external returns (bytes32 radHash); - - function verifyRadonSLA(Witnet.RadonSLA calldata sla) - external returns (bytes32 slaHash); function totalDataProviders() external view returns (uint); + + /// =============================================================================================================== + /// --- Deprecating methods --------------------------------------------------------------------------------------- + + // function lookupRadonSLA(bytes32 slaHash) external view returns (Witnet.RadonSLA memory); } \ No newline at end of file diff --git a/contracts/interfaces/V2/IWitnetFeeds.sol b/contracts/interfaces/V2/IWitnetFeeds.sol index 09ae8df0b..59807c4b8 100644 --- a/contracts/interfaces/V2/IWitnetFeeds.sol +++ b/contracts/interfaces/V2/IWitnetFeeds.sol @@ -19,10 +19,8 @@ interface IWitnetFeeds { function registry() external view returns (WitnetBytecodes); function witnet() external view returns (WitnetRequestBoard); - 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); + function defaultRadonSLA() external view returns (WitnetV2.RadonSLA memory); + function estimateUpdateBaseFee(uint256 evmGasPrice) external view returns (uint); function latestResponse(bytes4 feedId) external view returns (Witnet.Response memory); function latestResult(bytes4 feedId) external view returns (Witnet.Result memory); @@ -38,5 +36,5 @@ interface IWitnetFeeds { 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); + function requestUpdate(bytes4 feedId, WitnetV2.RadonSLA calldata updateSLA) external payable returns (uint256 usedFunds); } \ No newline at end of file diff --git a/contracts/interfaces/V2/IWitnetFeedsAdmin.sol b/contracts/interfaces/V2/IWitnetFeedsAdmin.sol index 39e55b4cb..9388cddaa 100644 --- a/contracts/interfaces/V2/IWitnetFeedsAdmin.sol +++ b/contracts/interfaces/V2/IWitnetFeedsAdmin.sol @@ -10,7 +10,7 @@ interface IWitnetFeedsAdmin { function deleteFeed(string calldata caption) external; function owner() external view returns (address); function pendingOwner() external returns (address); - function settleDefaultRadonSLA(Witnet.RadonSLA calldata) external; + function settleDefaultRadonSLA(WitnetV2.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/libs/Witnet.sol b/contracts/libs/Witnet.sol index 7f64b1be4..6758615b5 100644 --- a/contracts/libs/Witnet.sol +++ b/contracts/libs/Witnet.sol @@ -28,11 +28,12 @@ library Witnet { /// Data kept in EVM-storage for every Request posted to the Witnet Request Board. struct Request { - address _addr; // Deprecating: Address of the IWitnetRequest contract containing Witnet data request raw bytecode. - bytes32 slaHash; // Radon SLA hash of the Witnet data request. + address _addr; // Deprecating: Formerly used as address of the (deprecated) IWitnetRequest contract. + bytes32 slaPacked; // Radon SLA of the Witnet data request (packed). bytes32 radHash; // Radon radHash of the Witnet data request. - uint256 _gasprice; // Deprecating: Minimum gas price the DR resolver should pay on the solving tx. - uint256 reward; // Escrowed reward to be paid to the DR resolver. + uint256 _gasprice; // Deprecating: Formerly used as minimum gas price the DR resolver should pay on the solving tx. + uint256 evmReward; // Escrowed reward to be paid to the DR resolver. + uint256 maxCallbackGas; // Maximum gas to be spent when reporting the data request result. } /// Data kept in EVM-storage containing Witnet-provided response metadata and result. @@ -275,7 +276,6 @@ library Witnet { uint64 minerCommitRevealFee; } - /// @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) @@ -302,6 +302,33 @@ library Witnet { ); } + function packed(RadonSLA memory sla) internal pure returns (bytes32) { + return bytes32( + uint(sla.witnessReward) + | sla.witnessCollateral << 64 + | sla.minerCommitRevealFee << 128 + | sla.numWitnesses << 248 + | sla.minConsensusPercentage << 232 + ); + } + + function toRadonSLA(bytes32 _packed) internal pure returns (RadonSLA memory) { + return RadonSLA({ + numWitnesses: uint8(uint(_packed >> 248)), + minConsensusPercentage: uint8(uint(_packed >> 232) & 0xff), + witnessReward: uint64(uint(_packed) & 0xffffffffffffffff), + witnessCollateral: uint64(uint(_packed >> 64) & 0xffffffffffffffff), + minerCommitRevealFee: uint64(uint(_packed >> 128) & 0xffffffffffffffff) + }); + } + + function totalWitnessingReward(Witnet.RadonSLA memory sla) + internal pure returns (uint64) + { + return sla.witnessReward * sla.numWitnesses; + } + + /// =============================================================================================================== /// --- 'Witnet.Result' helper methods ---------------------------------------------------------------------------- diff --git a/contracts/libs/WitnetV2.sol b/contracts/libs/WitnetV2.sol index ecfff6046..20a692bd2 100644 --- a/contracts/libs/WitnetV2.sol +++ b/contracts/libs/WitnetV2.sol @@ -6,76 +6,77 @@ import "./Witnet.sol"; library WitnetV2 { + uint256 internal constant _WITNET_GENESIS_TIMESTAMP = 1602666045; + uint256 internal constant _WITNET_GENESIS_EPOCH_SECONDS = 45; - function toEpoch(uint _timestamp) internal pure returns (uint) { - return 1 + (_timestamp - 11111) / 15; - } + uint256 internal constant _WITNET_2_0_EPOCH = 1234567; + uint256 internal constant _WITNET_2_0_EPOCH_SECONDS = 30; + uint256 internal constant _WITNET_2_0_TIMESTAMP = _WITNET_GENESIS_TIMESTAMP + _WITNET_2_0_EPOCH * _WITNET_GENESIS_EPOCH_SECONDS; - function toTimestamp(uint _epoch) internal pure returns (uint) { - return 111111+ _epoch * 15; + struct RadonSLA { + uint8 numWitnesses; + uint8 witnessingCollateralRatio; } - struct Beacon { - uint256 escrow; - uint256 evmBlock; - uint256 gasprice; - address relayer; - address slasher; - uint256 superblockIndex; - uint256 superblockRoot; + function equalOrGreaterThan(RadonSLA memory a, RadonSLA memory b) + internal pure returns (bool) + { + return ( + a.numWitnesses * a.witnessingCollateralRatio + >= b.numWitnesses * b.witnessingCollateralRatio + ); } - - enum BeaconStatus { - Idle + + function isValid(RadonSLA calldata sla) internal pure returns (bool) { + return ( + sla.numWitnesses > 0 && sla.numWitnesses <= 127 + && sla.witnessingCollateralRatio > 0 && sla.witnessingCollateralRatio <= 127 + ); } - struct Block { - bytes32 blockHash; - bytes32 drTxsRoot; - bytes32 drTallyTxsRoot; - } - - enum BlockStatus { - Idle + function packed(RadonSLA memory sla) internal pure returns (bytes32) { + return bytes32( + uint(sla.numWitnesses) << 248 + | uint(sla.witnessingCollateralRatio) << 240 + ); } - 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 toRadonSLA(bytes32 _packed) + internal pure returns (RadonSLA memory) + { + return RadonSLA({ + numWitnesses: uint8(uint(_packed >> 248)), + witnessingCollateralRatio: uint8(uint(_packed >> 240)) + }); } - /// 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 timestampToWitnetEpoch(uint _timestamp) internal pure returns (uint) { + if (_timestamp > _WITNET_2_0_TIMESTAMP ) { + return ( + _WITNET_2_0_EPOCH + ( + _timestamp - _WITNET_2_0_TIMESTAMP + ) / _WITNET_2_0_EPOCH_SECONDS + ); + } else if (_timestamp > _WITNET_GENESIS_TIMESTAMP) { + return ( + 1 + ( + _timestamp - _WITNET_GENESIS_TIMESTAMP + ) / _WITNET_GENESIS_EPOCH_SECONDS + ); + } else { + return 0; + } } - enum DrPostStatus { - Void, - Deleted, - Expired, - Posted, - Disputed, - Reported, - Finalized, - Accepted, - Rejected + function witnetEpochToTimestamp(uint _epoch) internal pure returns (uint) { + if (_epoch >= _WITNET_2_0_EPOCH) { + return ( + _WITNET_2_0_TIMESTAMP + ( + _epoch - _WITNET_2_0_EPOCH + ) * _WITNET_2_0_EPOCH_SECONDS + ); + } else { + return (_WITNET_GENESIS_TIMESTAMP + _epoch * _WITNET_GENESIS_EPOCH_SECONDS); + } } } \ No newline at end of file From dc79d526c8d88574355dc2c07474f2ebb08e1346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 23 Nov 2023 20:16:40 +0100 Subject: [PATCH 49/86] feat: implement posting of RAD raw bytecodes --- .../core/defaults/WitnetBytecodesDefault.sol | 5 + .../WitnetRequestBoardTrustableBase.sol | 80 ++++++++-- contracts/interfaces/IWitnetRequestBoard.sol | 142 +++++++++++------- contracts/interfaces/V2/IWitnetBytecodes.sol | 1 + 4 files changed, 165 insertions(+), 63 deletions(-) diff --git a/contracts/core/defaults/WitnetBytecodesDefault.sol b/contracts/core/defaults/WitnetBytecodesDefault.sol index e456f60ac..3a9ec6e4e 100644 --- a/contracts/core/defaults/WitnetBytecodesDefault.sol +++ b/contracts/core/defaults/WitnetBytecodesDefault.sol @@ -149,6 +149,11 @@ contract WitnetBytecodesDefault return __database().radsBytecode[_radHash]; } + function hashOf(bytes calldata _radBytecode) external pure override returns (bytes32) { + // todo: validate correctness of _radBytecode + return _witnetHash(_radBytecode); + } + function lookupDataProvider(uint256 _index) external view override diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index ff43a3eef..c215c19b0 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -531,13 +531,14 @@ abstract contract WitnetRequestBoardTrustableBase emit NewQuery(_queryId, _getMsgValue()); } - /// 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 _querySLA The SLA param of the data request to be solved by Witnet. + /// @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-provided result to this request. + /// @dev Fails if provided reward is too low. + /// @dev The result to the query will be saved into the WitnetRequestBoard storage. + /// @param _radHash 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 _radHash, WitnetV2.RadonSLA calldata _querySLA @@ -555,13 +556,42 @@ abstract contract WitnetRequestBoardTrustableBase // Let observers know that a new request has been posted emit NewQuery(_queryId, _getMsgValue()); } + + /// @notice Requests the execution of the given Witnet Data Request bytecode, 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-provided result to this request. + /// @dev Fails if provided reward is too low. + /// @dev The result to the query will be saved into the WitnetRequestBoard storage. + /// @param _radBytecode The raw bytecode of the Witnet Data Request to be solved by Witnet. + /// @param _querySLA The data query SLA to be fulfilled by the Witnet blockchain. + /// @return _queryId A unique query identifier. + function postRequest( + bytes calldata _radBytecode, + WitnetV2.RadonSLA calldata _querySLA + ) + virtual override + public payable + checkReward(estimateBaseFee(_getGasPrice(), 32)) + checkSLA(_querySLA) + returns (uint256 _queryId) + { + _queryId = __postRequest( + registry().hashOf(_radBytecode), + _querySLA.packed() + ); + // Let observers know that a new request has been posted + emit NewQueryWithBytecode(_queryId, _getMsgValue(), _radBytecode); } - /// @notice Requests the execution of the given Witnet Data Request in expectation that it will be relayed and solved by the Witnet DON. - /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided - /// @notice result to this request. + /// @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-provided result to this request. /// @dev Fails if, provided reward is too low. /// @dev The caller must be a contract implementing the IWitnetConsumer interface. + /// @param _radHash 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 _queryMaxCallbackGas Maximum gas to be spent when reporting the data request result. + /// @return _queryId Unique query identifier. function postRequestWithCallback( bytes32 _radHash, WitnetV2.RadonSLA calldata _querySLA, @@ -581,6 +611,35 @@ abstract contract WitnetRequestBoardTrustableBase __seekQueryRequest(_queryId).maxCallbackGas = _queryMaxCallbackGas; emit NewQuery(_queryId, _getMsgValue()); } + + /// @notice Requests the execution of the given Witnet Data Request bytecode, in expectation that it will be + /// @notice relayed and solved by the Witnet blockchain. A reward amount is escrowed by the Witnet Request Board + /// @notice that will be transferred to the reporter who relays back the Witnet-provided result to this request. + /// @dev Fails if, provided reward is too low. + /// @dev The caller must be a contract implementing the IWitnetConsumer interface. + /// @param _radBytecode 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 _queryMaxCallbackGas Maximum gas to be spent when reporting the data request result. + /// @return _queryId A unique query identifier. + function postRequestWithCallback( + bytes calldata _radBytecode, + WitnetV2.RadonSLA calldata _querySLA, + uint256 _queryMaxCallbackGas + ) + virtual override + external payable + checkCallbackRecipient(msg.sender) + checkReward(estimateBaseFeeWithCallback(_getGasPrice(), _queryMaxCallbackGas)) + checkSLA(_querySLA) + returns (uint256 _queryId) + { + _queryId = __postRequest( + registry().hashOf(_radBytecode), + _querySLA.packed() + ); + __seekQueryRequest(_queryId).maxCallbackGas = _queryMaxCallbackGas; + emit NewQueryWithBytecode(_queryId, _getMsgValue(), _radBytecode); + } /// 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 @@ -843,4 +902,5 @@ abstract contract WitnetRequestBoardTrustableBase } emit ReportersSet(_reporters); } + } \ No newline at end of file diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index 164c9c1c2..c06aa1972 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -8,9 +8,9 @@ interface IWitnetRequestBoard { /// Emitted every time a new query containing some verified data request is posted to the WRB. event NewQuery(uint256 indexed id, uint256 evmReward); - /// Emitted when a Witnet-solved result is reported to the WRB. - event PostedResult(uint256 indexed queryId, address from); - + /// Emitted every time a new query containing non-verified data request is posted to the WRB. + event NewQueryWithBytecode(uint256 indexed id, uint256 evmReward, bytes radBytecode); + /// Emitted when the reward of some not-yet reported query is upgraded. event QueryRewardUpgraded(uint256 indexed id, uint256 evmReward); @@ -27,75 +27,106 @@ interface IWitnetRequestBoard { /// --- Requester interface --------------------------------------------------------------------------------------- /// @notice Delete query without further ado. - /// @dev Fails if the `_queryId` is not in 'Reported' status, or called from an address different to + /// @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 burnQuery(uint256 _queryId) external; + /// @param queryId The unique query identifier. + function burnQuery(uint256 queryId) external; /// @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 view returns (Witnet.ResultError memory); + /// @param queryId The unique query identifier. + function checkResultError(uint256 queryId) external view returns (Witnet.ResultError 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 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) external view returns (Witnet.ResultStatus); + /// @param queryId The unique query identifier. + function checkResultStatus(uint256 queryId) external view returns (Witnet.ResultStatus); /// @notice Returns query's result traceability data - /// @param _queryId The unique query identifier. + /// @param queryId The unique query identifier. /// @return _resultTimestamp Timestamp at which the query was solved by the Witnet blockchain. /// @return _resultDrTxHash Witnet blockchain hash of the commit/reveal act that solved the query. - function checkResultTraceability(uint256 _queryId) external view returns (uint256 _resultTimestamp, bytes32 _resultDrTxHash); + function checkResultTraceability(uint256 queryId) external view returns (uint256 _resultTimestamp, bytes32 _resultDrTxHash); /// @notice Retrieves a copy of all Witnet-provided data related to a previously posted request, removing the whole query from the WRB storage. - /// @dev Fails if the `_queryId` is not in 'Reported' status, or called from an address different to + /// @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 returns (Witnet.Response memory); + /// @param queryId The unique query identifier. + function deleteQuery(uint256 queryId) external returns (Witnet.Response memory); /// @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, uint256 _resultMaxSize) external view returns (uint256); + /// @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, uint256 resultMaxSize) 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 _maxCallbackGas Maximum gas to be spent when reporting the data request result. - function estimateBaseFeeWithCallback(uint256 _gasPrice, uint256 _maxCallbackGas) external view returns (uint256); - - /// @notice Requests the execution of the given Witnet Data Request in expectation that it will be relayed and solved by the Witnet DON. - /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided - /// @notice result to this request. - /// @dev Fails if, provided reward is too low. - /// @param radHash The RAD hash of the data request to be solved by Witnet. - /// @param slaHash The SLA hash of the data request to be solved by Witnet. - /// @return _queryId Unique query identifier. - function postRequest(bytes32 radHash, bytes32 slaHash) 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 the Witnet DON. - /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided - /// @notice result to this request. + /// @param gasPrice Expected gas price to pay upon posting the data request. + /// @param maxCallbackGas Maximum gas to be spent when reporting the data request result. + function estimateBaseFeeWithCallback(uint256 gasPrice, uint256 maxCallbackGas) external view returns (uint256); + + /// @notice Estimates the actual earnings (or loss), in WEI, that a reporter would get by reporting result to given query, + /// @notice based on the gas price of the calling transaction. + /// @dev Data requesters should consider upgrading the reward on queries providing no actual earnings. + function estimateQueryEarnings(uint256 queryId) external view returns (int256); + + /// @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-provided result to this request. /// @dev Fails if provided reward is too low. /// @dev The result to the query will be saved into the WitnetRequestBoard storage. /// @param radHash 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 radHash, 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 the Witnet DON. - /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided - /// @notice result to this request. + function postRequest( + bytes32 radHash, + WitnetV2.RadonSLA calldata querySLA + ) external payable returns (uint256 queryId); + + /// @notice Requests the execution of the given Witnet Data Request bytecode, 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-provided result to this request. + /// @dev Fails if provided reward is too low. + /// @dev The result to the query will be saved into the WitnetRequestBoard storage. + /// @param radBytecode The raw bytecode of the Witnet Data Request to be solved by Witnet. + /// @param querySLA The data query SLA to be fulfilled by the Witnet blockchain. + /// @return A unique query identifier. + function postRequest( + bytes calldata radBytecode, + WitnetV2.RadonSLA calldata querySLA + ) external payable returns (uint256); + + /// @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-provided result to this request. /// @dev Fails if, provided reward is too low. /// @dev The caller must be a contract implementing the IWitnetConsumer interface. /// @param radHash 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 maxCallbackGas Maximum gas to be spent when reporting the data request result. /// @return queryId Unique query identifier. - function postRequestWithCallback(bytes32 radHash, WitnetV2.RadonSLA calldata querySLA, uint256 maxCallbackGas) external payable returns (uint256 queryId); + function postRequestWithCallback( + bytes32 radHash, + WitnetV2.RadonSLA calldata querySLA, + uint256 maxCallbackGas + ) external payable returns (uint256 queryId); + + /// @notice Requests the execution of the given Witnet Data Request bytecode, in expectation that it will be + /// @notice relayed and solved by the Witnet blockchain. A reward amount is escrowed by the Witnet Request Board + /// @notice that will be transferred to the reporter who relays back the Witnet-provided result to this request. + /// @dev Fails if, provided reward is too low. + /// @dev The caller must be a contract implementing the IWitnetConsumer interface. + /// @param radBytecode 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 maxCallbackGas Maximum gas to be spent when reporting the data request result. + /// @return A unique query identifier. + function postRequestWithCallback( + bytes calldata radBytecode, + WitnetV2.RadonSLA calldata querySLA, + uint256 maxCallbackGas + ) external payable returns (uint256); /// @notice Increments the reward of a previously posted request by adding the transaction value to it. /// @param queryId The unique query identifier. @@ -109,28 +140,33 @@ interface IWitnetRequestBoard { function getNextQueryId() external view returns (uint256); /// @notice Gets the whole Query data contents, if any, no matter its current status. - function getQueryData(uint256 _queryId) external view returns (Witnet.Query memory); + function getQueryData(uint256 queryId) external view returns (Witnet.Query memory); /// @notice Gets current status of given query. - function getQueryStatus(uint256 _queryId) external view returns (Witnet.QueryStatus); + function getQueryStatus(uint256 queryId) external view returns (Witnet.QueryStatus); /// @notice 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 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 getQueryRequest(uint256 _queryId) external view returns (Witnet.Request memory); + /// @param queryId The unique identifier of a previously posted query. + function getQueryRequest(uint256 queryId) external view returns (Witnet.Request memory); /// @notice 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 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 getQueryRequestBytecode(uint256 _queryId) external view returns (bytes memory); + /// @param queryId The unique query identifier. + function getQueryRequestBytecode(uint256 queryId) external view returns (bytes memory); /// @notice Retrieves the whole `Witnet.Response` record referred to a previously posted Witnet Data Request. - /// @dev Fails if the `_queryId` is not in 'Reported' status. - /// @param _queryId The unique query identifier. - function getQueryResponse(uint256 _queryId) external view returns (Witnet.Response memory); + /// @dev Fails if the `queryId` is not in 'Reported' status. + /// @param queryId The unique query identifier. + function getQueryResponse(uint256 queryId) external view returns (Witnet.Response memory); + + /// @notice 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 getQueryResponseResult(uint256 queryId) external view returns (Witnet.Result memory); /// @notice Retrieves the reward currently set for the referred query. /// @dev Fails if the `queryId` is not valid or, if it has already been @@ -141,7 +177,7 @@ interface IWitnetRequestBoard { /// =============================================================================================================== /// --- Deprecating methods --------------------------------------------------------------------------------------- - /// @notice Requests the execution of the given Witnet Data Request in expectation that it will be relayed and solved by the Witnet DON. + /// @notice Requests the execution of the given Witnet Data Request in expectation that it will be relayed and solved by the Witnet blockchain. /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided /// @notice result to this request. /// @dev Fails if, provided reward is too low. diff --git a/contracts/interfaces/V2/IWitnetBytecodes.sol b/contracts/interfaces/V2/IWitnetBytecodes.sol index 06527664c..d33c22b98 100644 --- a/contracts/interfaces/V2/IWitnetBytecodes.sol +++ b/contracts/interfaces/V2/IWitnetBytecodes.sol @@ -15,6 +15,7 @@ interface IWitnetBytecodes { event NewRadHash(bytes32 hash); function bytecodeOf(bytes32 radHash) external view returns (bytes memory); + function hashOf(bytes calldata) external view returns (bytes32); function lookupDataProvider(uint256 index) external view returns (string memory, uint); function lookupDataProviderIndex(string calldata authority) external view returns (uint); From e7370028705c04e63c3cbaa1ff2f4e8f088cf16d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 23 Nov 2023 20:29:23 +0100 Subject: [PATCH 50/86] refactor: postpone dispute of queries to v2.1+ --- contracts/interfaces/V2/IWitnetConsumer.sol | 6 ------ 1 file changed, 6 deletions(-) diff --git a/contracts/interfaces/V2/IWitnetConsumer.sol b/contracts/interfaces/V2/IWitnetConsumer.sol index af065fec3..dc60dd49e 100644 --- a/contracts/interfaces/V2/IWitnetConsumer.sol +++ b/contracts/interfaces/V2/IWitnetConsumer.sol @@ -33,12 +33,6 @@ interface IWitnetConsumer { WitnetCBOR.CBOR calldata errorArgs ) external; - /// @notice Method to be called from the WitnetRequestBoard contract as soon as some dispute - /// @notice arises concerning the given Witnet `queryId`. - /// @param queryId The unique identifier of the Witnet query being disputed. - /// @param resolutionBlock The EVM block number at which the query resolution is expected to be final. - function reportWitnetQueryDispute(uint256 queryId, uint256 resolutionBlock) external; - /// @notice Determines if Witnet queries can be reported from given address. /// @dev In practice, must only be true on the WitnetRequestBoard address that's being used by /// @dev the WitnetConsumer to post queries. From f83f37f748be712153f4e741ff8ebf362f47d1e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 23 Nov 2023 20:30:09 +0100 Subject: [PATCH 51/86] chore: polish contract/apps --- contracts/apps/UsingWitnet.sol | 13 +++++ contracts/apps/WitnetConsumer.sol | 52 ++++++++++++++++--- contracts/apps/WitnetRequestConsumer.sol | 47 ++++++----------- .../apps/WitnetRequestTemplateConsumer.sol | 48 ++++++----------- contracts/interfaces/V2/IWitnetConsumer.sol | 4 +- 5 files changed, 94 insertions(+), 70 deletions(-) diff --git a/contracts/apps/UsingWitnet.sol b/contracts/apps/UsingWitnet.sol index d5b3d28dd..f6c08980f 100644 --- a/contracts/apps/UsingWitnet.sol +++ b/contracts/apps/UsingWitnet.sol @@ -99,4 +99,17 @@ abstract contract UsingWitnet { _witnetQuerySLA ); } + + function __witnetRequestData( + uint256 _witnetEvmReward, + bytes calldata _witnetRadBytecode, + WitnetV2.RadonSLA calldata _witnetQuerySLA + ) + virtual internal returns (uint256) + { + return __witnet.postRequest{value: _witnetEvmReward}( + _witnetRadBytecode, + _witnetQuerySLA + ); + } } diff --git a/contracts/apps/WitnetConsumer.sol b/contracts/apps/WitnetConsumer.sol index 3704ed996..862394752 100644 --- a/contracts/apps/WitnetConsumer.sol +++ b/contracts/apps/WitnetConsumer.sol @@ -8,7 +8,9 @@ abstract contract WitnetConsumer is IWitnetConsumer, UsingWitnet -{ +{ + uint256 private immutable __witnetReportCallbackMaxGas; + modifier burnQueryAfterReport(uint256 _witnetQueryId) { _; __witnet.burnQuery(_witnetQueryId); @@ -19,26 +21,64 @@ abstract contract WitnetConsumer _; } + constructor (uint256 _maxCallbackGas) { + __witnetReportCallbackMaxGas = _maxCallbackGas; + } + + + /// =============================================================================================================== + /// --- Base implementation of IWitnetConsumer -------------------------------------------------------------------- + + function reportableFrom(address _from) virtual override external view returns (bool) { + return _from == address(__witnet); + } + + + /// =============================================================================================================== + /// --- WitnetConsumer virtual methods ---------------------------------------------------------------------------- + function _witnetEstimateBaseFee() - virtual internal view + virtual internal view returns (uint256) { return _witnetEstimateBaseFeeWithCallback(_witnetReportCallbackMaxGas()); } + function _witnetReportCallbackMaxGas() + virtual internal view + returns (uint256) + { + return __witnetReportCallbackMaxGas; + } + function __witnetRequestData( uint256 _witnetEvmReward, - WitnetV2.RadonSLA calldata _witnetQuerySLA, - bytes32 _witnetRadHash + bytes32 _witnetRadHash, + WitnetV2.RadonSLA calldata _witnetQuerySLA ) virtual override internal returns (uint256) { return __witnet.postRequestWithCallback{value: _witnetEvmReward}( _witnetRadHash, - _witnetQuerySLA + _witnetQuerySLA, + __witnetReportCallbackMaxGas + ); + } + + function __witnetRequestData( + uint256 _witnetEvmReward, + bytes calldata _witnetRadBytecode, + WitnetV2.RadonSLA calldata _witnetQuerySLA + ) + virtual override internal + returns (uint256) + { + return __witnet.postRequestWithCallback{value: _witnetEvmReward}( + _witnetRadBytecode, + _witnetQuerySLA, + __witnetReportCallbackMaxGas ); } - function _witnetReportCallbackMaxGas() virtual internal view returns (uint256); } diff --git a/contracts/apps/WitnetRequestConsumer.sol b/contracts/apps/WitnetRequestConsumer.sol index 369f054c7..ca7b3431b 100644 --- a/contracts/apps/WitnetRequestConsumer.sol +++ b/contracts/apps/WitnetRequestConsumer.sol @@ -11,17 +11,15 @@ abstract contract WitnetRequestConsumer { using WitnetCBOR for WitnetCBOR.CBOR; using WitnetCBOR for WitnetCBOR.CBOR[]; - - uint256 private immutable __witnetReportCallbackMaxGas; constructor(WitnetRequest _witnetRequest, uint256 _maxCallbackGas) UsingWitnetRequest(_witnetRequest) + WitnetConsumer(_maxCallbackGas) { require( _witnetEstimateBaseFeeWithCallback(_maxCallbackGas) > UsingWitnetRequest._witnetEstimateBaseFee(), "WitnetRequestConsumer: max callback gas too low" ); - __witnetReportCallbackMaxGas = _maxCallbackGas; } function _witnetEstimateBaseFee() @@ -32,46 +30,33 @@ abstract contract WitnetRequestConsumer return WitnetConsumer._witnetEstimateBaseFee(); } - function _witnetReportCallbackMaxGas() virtual override internal view returns (uint256) { - return __witnetReportCallbackMaxGas; - } - function __witnetRequestData( uint256 _witnetEvmReward, - WitnetV2.RadonSLA calldata _witnetQuerySLA, - bytes32 _witnetRadHash + bytes32 _witnetRadHash, + WitnetV2.RadonSLA calldata _witnetQuerySLA ) virtual override(UsingWitnet, WitnetConsumer) internal returns (uint256) { return WitnetConsumer.__witnetRequestData( _witnetEvmReward, - _witnetQuerySLA, - _witnetRadHash + _witnetRadHash, + _witnetQuerySLA ); } - function reportWitnetQueryResult( - uint256 _witnetQueryId, - WitnetCBOR.CBOR calldata _value - ) - virtual override - external - onlyFromWitnet - // optional: burnQueryAfterReport(_witnetQueryId) - { - // TODO ... - } - - function reportWitnetQueryError( - uint256 _witnetQueryId, - Witnet.ResultErrorCodes, - uint256 + function __witnetRequestData( + uint256 _witnetEvmReward, + bytes calldata _witnetRadBytecode, + WitnetV2.RadonSLA calldata _witnetQuerySLA ) - virtual override external - onlyFromWitnet - // optional: burnQueryAfterReport(_witnetQueryId) + virtual override(UsingWitnet, WitnetConsumer) internal + returns (uint256) { - // TODO ... + return WitnetConsumer.__witnetRequestData( + _witnetEvmReward, + _witnetRadBytecode, + _witnetQuerySLA + ); } } diff --git a/contracts/apps/WitnetRequestTemplateConsumer.sol b/contracts/apps/WitnetRequestTemplateConsumer.sol index e66fd0041..b08b1cc1f 100644 --- a/contracts/apps/WitnetRequestTemplateConsumer.sol +++ b/contracts/apps/WitnetRequestTemplateConsumer.sol @@ -11,17 +11,16 @@ abstract contract WitnetRequestTemplateConsumer { using WitnetCBOR for WitnetCBOR.CBOR; using WitnetCBOR for WitnetCBOR.CBOR[]; - - uint256 private immutable __witnetReportCallbackMaxGas; constructor(WitnetRequestTemplate _requestTemplate, uint256 _maxCallbackGas) UsingWitnetRequestTemplate(_requestTemplate) + WitnetConsumer(_maxCallbackGas) { require( _witnetEstimateBaseFeeWithCallback(_maxCallbackGas) > UsingWitnetRequestTemplate._witnetEstimateBaseFee(), "WitnetRequestTemplateConsumer: max callback gas too low" ); - __witnetReportCallbackMaxGas = _maxCallbackGas; + } function _witnetEstimateBaseFee() @@ -32,46 +31,33 @@ abstract contract WitnetRequestTemplateConsumer return WitnetConsumer._witnetEstimateBaseFee(); } - function _witnetReportCallbackMaxGas() virtual override internal view returns (uint256) { - return __witnetReportCallbackMaxGas; - } - function __witnetRequestData( uint256 _witnetEvmReward, - WitnetV2.RadonSLA calldata _witnetQuerySLA, - bytes32 _witnetRadHash + bytes32 _witnetRadHash, + WitnetV2.RadonSLA calldata _witnetQuerySLA ) virtual override(UsingWitnet, WitnetConsumer) internal returns (uint256) { return WitnetConsumer.__witnetRequestData( _witnetEvmReward, - _witnetQuerySLA, - _witnetRadHash + _witnetRadHash, + _witnetQuerySLA ); } - function reportWitnetQueryResult( - uint256 _witnetQueryId, - WitnetCBOR.CBOR calldata _value - ) - virtual override - external - onlyFromWitnet - // optional: burnQueryAfterReport(_witnetQueryId) - { - // TODO ... - } - - function reportWitnetQueryError( - uint256 _witnetQueryId, - Witnet.ResultErrorCodes, - uint256 + function __witnetRequestData( + uint256 _witnetEvmReward, + bytes calldata _witnetRadBytecode, + WitnetV2.RadonSLA calldata _witnetQuerySLA ) - virtual override external - onlyFromWitnet - // optional: burnQueryAfterReport(_witnetQueryId) + virtual override(UsingWitnet, WitnetConsumer) internal + returns (uint256) { - // TODO ... + return WitnetConsumer.__witnetRequestData( + _witnetEvmReward, + _witnetRadBytecode, + _witnetQuerySLA + ); } } diff --git a/contracts/interfaces/V2/IWitnetConsumer.sol b/contracts/interfaces/V2/IWitnetConsumer.sol index dc60dd49e..c1b314c58 100644 --- a/contracts/interfaces/V2/IWitnetConsumer.sol +++ b/contracts/interfaces/V2/IWitnetConsumer.sol @@ -10,7 +10,7 @@ interface IWitnetConsumer { /// @dev It should revert if called from any other address different to the WitnetRequestBoard being used /// @dev by the WitnetConsumer contract. Within the implementation of this method, the WitnetConsumer /// @dev can call to the WRB as to retrieve the Witnet tracking information (i.e. the `witnetDrTxHash` - /// @dev and `witnetDrCommitTimestamp`), or the finality status, of the result being reported. + /// @dev and `witnetDrCommitTxTimestamp`), or the finality status, of the result being reported. /// @param queryId The unique identifier of the Witnet query being reported. /// @param cborValue The CBOR-encoded resulting value of the Witnet query being reported. function reportWitnetQueryResult( @@ -23,7 +23,7 @@ interface IWitnetConsumer { /// @dev It should revert if called from any other address different to the WitnetRequestBoard being used /// @dev by the WitnetConsumer contract. Within the implementation of this method, the WitnetConsumer /// @dev can call to the WRB as to retrieve the Witnet tracking information (i.e. the `witnetDrTxHash` - /// @dev and `witnetDrCommitTimestamp`), or the finality status, of the result being reported. + /// @dev and `witnetDrCommitTxTimestamp`), or the finality status, of the result being reported. /// @param queryId The unique identifier of the Witnet query being reported. /// @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. From 77bee1d0bef24133f5a6f6de4239c14133ebf685 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 23 Nov 2023 20:39:19 +0100 Subject: [PATCH 52/86] refactor: Witnet*.class() -> Witnet*.specs() --- contracts/WitnetBytecodes.sol | 2 +- contracts/WitnetRequestBoard.sol | 2 +- contracts/WitnetRequestFactory.sol | 2 +- contracts/WitnetRequestTemplate.sol | 2 +- contracts/apps/UsingWitnet.sol | 2 +- contracts/apps/UsingWitnetRequest.sol | 2 +- contracts/apps/UsingWitnetRequestTemplate.sol | 2 +- contracts/apps/WitnetPriceFeeds.sol | 4 ++-- contracts/apps/WitnetRandomness.sol | 4 ++-- contracts/core/defaults/WitnetBytecodesDefault.sol | 2 +- contracts/core/defaults/WitnetRequestBoardTrustableBase.sol | 4 ++-- contracts/core/defaults/WitnetRequestFactoryDefault.sol | 4 ++-- contracts/interfaces/V2/IWitnetPriceSolver.sol | 2 +- contracts/libs/WitnetPriceFeedsLib.sol | 2 +- 14 files changed, 18 insertions(+), 18 deletions(-) diff --git a/contracts/WitnetBytecodes.sol b/contracts/WitnetBytecodes.sol index f96fc4c10..0a79a6271 100644 --- a/contracts/WitnetBytecodes.sol +++ b/contracts/WitnetBytecodes.sol @@ -9,5 +9,5 @@ abstract contract WitnetBytecodes is IWitnetBytecodes { - function class() virtual external view returns (bytes4); + function specs() virtual external view returns (bytes4); } \ No newline at end of file diff --git a/contracts/WitnetRequestBoard.sol b/contracts/WitnetRequestBoard.sol index 8f47e1ba5..85953ad18 100644 --- a/contracts/WitnetRequestBoard.sol +++ b/contracts/WitnetRequestBoard.sol @@ -12,7 +12,7 @@ abstract contract WitnetRequestBoard is IWitnetRequestBoard { - function class() virtual external view returns (bytes4); function factory() virtual external view returns (WitnetRequestFactory); function registry() virtual external view returns (WitnetBytecodes); + function specs() virtual external view returns (bytes4); } \ No newline at end of file diff --git a/contracts/WitnetRequestFactory.sol b/contracts/WitnetRequestFactory.sol index 1debb0636..7fb997b5e 100644 --- a/contracts/WitnetRequestFactory.sol +++ b/contracts/WitnetRequestFactory.sol @@ -11,7 +11,7 @@ abstract contract WitnetRequestFactory is IWitnetRequestFactory { - function class() virtual external view returns (bytes4); function registry() virtual external view returns (WitnetBytecodes); + function specs() virtual external view returns (bytes4); function witnet() virtual external view returns (WitnetRequestBoard); } \ No newline at end of file diff --git a/contracts/WitnetRequestTemplate.sol b/contracts/WitnetRequestTemplate.sol index 1593ef7d6..9ad8835e6 100644 --- a/contracts/WitnetRequestTemplate.sol +++ b/contracts/WitnetRequestTemplate.sol @@ -11,9 +11,9 @@ abstract contract WitnetRequestTemplate { event WitnetRequestBuilt(address indexed request, bytes32 indexed radHash, string[][] args); - function class() virtual external view returns (bytes4); function factory() virtual external view returns (WitnetRequestFactory); function registry() virtual external view returns (WitnetBytecodes); + function specs() virtual external view returns (bytes4); function version() virtual external view returns (string memory); function witnet() virtual external view returns (WitnetRequestBoard); diff --git a/contracts/apps/UsingWitnet.sol b/contracts/apps/UsingWitnet.sol index f6c08980f..0d7dda68e 100644 --- a/contracts/apps/UsingWitnet.sol +++ b/contracts/apps/UsingWitnet.sol @@ -16,7 +16,7 @@ abstract contract UsingWitnet { /// @param _wrb The WitnetRequestBoard entry point address. constructor(WitnetRequestBoard _wrb) { require( - _wrb.class() == type(IWitnetRequestBoard).interfaceId, + _wrb.specs() == type(IWitnetRequestBoard).interfaceId, "UsingWitnet: uncompliant WitnetRequestBoard" ); __witnet = _wrb; diff --git a/contracts/apps/UsingWitnetRequest.sol b/contracts/apps/UsingWitnetRequest.sol index d7103c3b7..13412c5fb 100644 --- a/contracts/apps/UsingWitnetRequest.sol +++ b/contracts/apps/UsingWitnetRequest.sol @@ -16,7 +16,7 @@ abstract contract UsingWitnetRequest UsingWitnet(_witnetRequest.witnet()) { require( - _witnetRequest.class() == type(WitnetRequest).interfaceId, + _witnetRequest.specs() == type(WitnetRequest).interfaceId, "UsingWitnetRequest: uncompliant WitnetRequest" ); dataRequest = _witnetRequest; diff --git a/contracts/apps/UsingWitnetRequestTemplate.sol b/contracts/apps/UsingWitnetRequestTemplate.sol index dfeaf2573..dcb0bd772 100644 --- a/contracts/apps/UsingWitnetRequestTemplate.sol +++ b/contracts/apps/UsingWitnetRequestTemplate.sol @@ -15,7 +15,7 @@ abstract contract UsingWitnetRequestTemplate UsingWitnet(_requestTemplate.witnet()) { require( - _requestTemplate.class() == type(WitnetRequestTemplate).interfaceId, + _requestTemplate.specs() == type(WitnetRequestTemplate).interfaceId, "UsingWitnetRequestTemplate: uncompliant WitnetRequestTemplate" ); dataRequestTemplate = _requestTemplate; diff --git a/contracts/apps/WitnetPriceFeeds.sol b/contracts/apps/WitnetPriceFeeds.sol index 182a6a1a0..c8fee5d8e 100644 --- a/contracts/apps/WitnetPriceFeeds.sol +++ b/contracts/apps/WitnetPriceFeeds.sol @@ -29,7 +29,7 @@ contract WitnetPriceFeeds using Witnet for Witnet.Result; using WitnetV2 for WitnetV2.RadonSLA; - bytes4 immutable public class = type(IWitnetPriceFeeds).interfaceId; + bytes4 immutable public specs = type(IWitnetPriceFeeds).interfaceId; WitnetRequestBoard immutable public override witnet; constructor(address _operator, WitnetRequestBoard _wrb) @@ -40,7 +40,7 @@ contract WitnetPriceFeeds { _transferOwnership(_operator); require( - _wrb.class() == type(IWitnetRequestBoard).interfaceId, + _wrb.specs() == type(IWitnetRequestBoard).interfaceId, "WitnetPriceFeeds: uncompliant request board" ); witnet = _wrb; diff --git a/contracts/apps/WitnetRandomness.sol b/contracts/apps/WitnetRandomness.sol index 14de02640..0803a1790 100644 --- a/contracts/apps/WitnetRandomness.sol +++ b/contracts/apps/WitnetRandomness.sol @@ -26,7 +26,7 @@ contract WitnetRandomness using WitnetV2 for bytes32; using WitnetV2 for WitnetV2.RadonSLA; - bytes4 public immutable class = type(IWitnetRandomness).interfaceId; + bytes4 public immutable specs = type(IWitnetRandomness).interfaceId; uint256 public override latestRandomizeBlock; WitnetRequest public immutable override witnetRandomnessRequest; @@ -45,7 +45,7 @@ contract WitnetRandomness UsingWitnet(_wrb) { _transferOwnership(_operator); - assert(_wrb.class() == type(IWitnetRequestBoard).interfaceId); + assert(_wrb.specs() == type(IWitnetRequestBoard).interfaceId); WitnetRequestFactory _factory = witnet().factory(); WitnetBytecodes _registry = witnet().registry(); { diff --git a/contracts/core/defaults/WitnetBytecodesDefault.sol b/contracts/core/defaults/WitnetBytecodesDefault.sol index 3a9ec6e4e..5faa772e8 100644 --- a/contracts/core/defaults/WitnetBytecodesDefault.sol +++ b/contracts/core/defaults/WitnetBytecodesDefault.sol @@ -28,7 +28,7 @@ contract WitnetBytecodesDefault using WitnetEncodingLib for Witnet.RadonSLA; using WitnetEncodingLib for Witnet.RadonDataTypes; - bytes4 public immutable override class = type(IWitnetBytecodes).interfaceId; + bytes4 public immutable override specs = type(IWitnetBytecodes).interfaceId; constructor(bool _upgradable, bytes32 _versionTag) WitnetUpgradableBase( diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index c215c19b0..12b4996ec 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -34,7 +34,7 @@ abstract contract WitnetRequestBoardTrustableBase using WitnetCBOR for WitnetCBOR.CBOR; using WitnetV2 for WitnetV2.RadonSLA; - bytes4 public immutable override class = type(IWitnetRequestBoard).interfaceId; + bytes4 public immutable override specs = type(IWitnetRequestBoard).interfaceId; WitnetRequestFactory immutable public override factory; modifier checkCallbackRecipient(address _addr) { @@ -152,7 +152,7 @@ abstract contract WitnetRequestBoardTrustableBase __storage().base = base(); require(address(factory).code.length > 0, "WitnetRequestBoardTrustableBase: inexistent factory"); - require(factory.class() == type(IWitnetRequestFactory).interfaceId, "WitnetRequestBoardTrustableBase: uncompliant factory"); + require(factory.specs() == type(IWitnetRequestFactory).interfaceId, "WitnetRequestBoardTrustableBase: uncompliant factory"); require(address(factory.witnet()) == address(this), "WitnetRequestBoardTrustableBase: discordant factory"); // Set reporters diff --git a/contracts/core/defaults/WitnetRequestFactoryDefault.sol b/contracts/core/defaults/WitnetRequestFactoryDefault.sol index 2367b46a3..f333be976 100644 --- a/contracts/core/defaults/WitnetRequestFactoryDefault.sol +++ b/contracts/core/defaults/WitnetRequestFactoryDefault.sol @@ -184,7 +184,7 @@ contract WitnetRequestFactoryDefault ); } - function class() + function specs() virtual override(WitnetRequestFactory, WitnetRequestTemplate) external view returns (bytes4) @@ -288,7 +288,7 @@ contract WitnetRequestFactoryDefault __proxiable().implementation = base(); require(address(registry).code.length > 0, "WitnetRequestFactoryDefault: inexistent requests registry"); - require(registry.class() == type(IWitnetBytecodes).interfaceId, "WitnetRequestFactoryDefault: uncompliant requests registry"); + require(registry.specs() == type(IWitnetBytecodes).interfaceId, "WitnetRequestFactoryDefault: uncompliant requests registry"); emit Upgraded(msg.sender, base(), codehash(), version()); } diff --git a/contracts/interfaces/V2/IWitnetPriceSolver.sol b/contracts/interfaces/V2/IWitnetPriceSolver.sol index e6068e60e..f6aa7dd58 100644 --- a/contracts/interfaces/V2/IWitnetPriceSolver.sol +++ b/contracts/interfaces/V2/IWitnetPriceSolver.sol @@ -11,8 +11,8 @@ interface IWitnetPriceSolver { bytes32 drTxHash; Witnet.ResultStatus status; } - function class() external pure returns (bytes4); function delegator() external view returns (address); function solve(bytes4 feedId) external view returns (Price memory); + function specs() external pure returns (bytes4); function validate(bytes4 feedId, string[] calldata initdata) external; } \ No newline at end of file diff --git a/contracts/libs/WitnetPriceFeedsLib.sol b/contracts/libs/WitnetPriceFeedsLib.sol index 5d3c0ca62..b16bf2ce5 100644 --- a/contracts/libs/WitnetPriceFeedsLib.sol +++ b/contracts/libs/WitnetPriceFeedsLib.sol @@ -39,7 +39,7 @@ library WitnetPriceFeedsLib { } assert(_solver == _createdContract); require( - IWitnetPriceSolver(_solver).class() == type(IWitnetPriceSolver).interfaceId, + IWitnetPriceSolver(_solver).specs() == type(IWitnetPriceSolver).interfaceId, "WitnetPriceFeedsLib: uncompliant solver implementation" ); } From 14cbe7429339c84ecf78f2dcf0c96769a59682be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 23 Nov 2023 20:45:02 +0100 Subject: [PATCH 53/86] feat: Witnet*.class(): string --- contracts/WitnetBytecodes.sol | 3 +++ contracts/WitnetRequestBoard.sol | 3 +++ contracts/WitnetRequestFactory.sol | 1 + contracts/WitnetRequestTemplate.sol | 1 + .../defaults/WitnetRequestFactoryDefault.sol | 17 +++++++++++++++++ 5 files changed, 25 insertions(+) diff --git a/contracts/WitnetBytecodes.sol b/contracts/WitnetBytecodes.sol index 0a79a6271..6a1235331 100644 --- a/contracts/WitnetBytecodes.sol +++ b/contracts/WitnetBytecodes.sol @@ -9,5 +9,8 @@ abstract contract WitnetBytecodes is IWitnetBytecodes { + function class() virtual external view returns (string memory) { + return type(WitnetBytecodes).name; + } function specs() virtual external view returns (bytes4); } \ No newline at end of file diff --git a/contracts/WitnetRequestBoard.sol b/contracts/WitnetRequestBoard.sol index 85953ad18..37fc92f9f 100644 --- a/contracts/WitnetRequestBoard.sol +++ b/contracts/WitnetRequestBoard.sol @@ -12,6 +12,9 @@ abstract contract WitnetRequestBoard is IWitnetRequestBoard { + function class() virtual external view returns (string memory) { + return type(WitnetRequestBoard).name; + } function factory() virtual external view returns (WitnetRequestFactory); function registry() virtual external view returns (WitnetBytecodes); function specs() virtual external view returns (bytes4); diff --git a/contracts/WitnetRequestFactory.sol b/contracts/WitnetRequestFactory.sol index 7fb997b5e..b6cf5c61d 100644 --- a/contracts/WitnetRequestFactory.sol +++ b/contracts/WitnetRequestFactory.sol @@ -11,6 +11,7 @@ abstract contract WitnetRequestFactory is IWitnetRequestFactory { + function class() virtual external view returns (string memory); function registry() virtual external view returns (WitnetBytecodes); function specs() virtual external view returns (bytes4); function witnet() virtual external view returns (WitnetRequestBoard); diff --git a/contracts/WitnetRequestTemplate.sol b/contracts/WitnetRequestTemplate.sol index 9ad8835e6..5a6b47930 100644 --- a/contracts/WitnetRequestTemplate.sol +++ b/contracts/WitnetRequestTemplate.sol @@ -11,6 +11,7 @@ abstract contract WitnetRequestTemplate { event WitnetRequestBuilt(address indexed request, bytes32 indexed radHash, string[][] args); + function class() virtual external view returns (string memory); function factory() virtual external view returns (WitnetRequestFactory); function registry() virtual external view returns (WitnetBytecodes); function specs() virtual external view returns (bytes4); diff --git a/contracts/core/defaults/WitnetRequestFactoryDefault.sol b/contracts/core/defaults/WitnetRequestFactoryDefault.sol index f333be976..a3ef1b114 100644 --- a/contracts/core/defaults/WitnetRequestFactoryDefault.sol +++ b/contracts/core/defaults/WitnetRequestFactoryDefault.sol @@ -184,6 +184,23 @@ contract WitnetRequestFactoryDefault ); } + function class() + virtual override(WitnetRequestFactory, WitnetRequestTemplate) + external view + returns (string memory) + { + if ( + address(this) == _SELF + || address(this) == __proxy() + ) { + return type(WitnetRequestFactory).name; + } else if (__witnetRequest().radHash != bytes32(0)) { + return type(WitnetRequest).name; + } else { + return type(WitnetRequestTemplate).name; + } + } + function specs() virtual override(WitnetRequestFactory, WitnetRequestTemplate) external view From f562eec39157b779aecf314c2cd420a072ceff7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 23 Nov 2023 21:26:14 +0100 Subject: [PATCH 54/86] feat: contracts/apps/UsingWitnetRandomenss --- contracts/apps/UsingWitnetRandomness.sol | 127 +++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 contracts/apps/UsingWitnetRandomness.sol diff --git a/contracts/apps/UsingWitnetRandomness.sol b/contracts/apps/UsingWitnetRandomness.sol new file mode 100644 index 000000000..ba97b26b0 --- /dev/null +++ b/contracts/apps/UsingWitnetRandomness.sol @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.7.0 <0.9.0; +pragma experimental ABIEncoderV2; + +import "./WitnetConsumer.sol"; +import "../WitnetRequest.sol"; + +abstract contract UsingWitnetRandomness + is + WitnetConsumer +{ + using Witnet for bytes; + using WitnetCBOR for WitnetCBOR.CBOR; + using WitnetV2 for bytes32; + using WitnetV2 for WitnetV2.RadonSLA; + + bytes32 internal immutable __witnetRandomnessRadHash; + bytes32 private __defaultRandomizePackedSLA; + + constructor(WitnetRequestBoard _wrb, uint256 _maxRandomizeCallbackGas) + UsingWitnet(_wrb) + WitnetConsumer(_maxRandomizeCallbackGas) + { + // Build Witnet randomness request + { + WitnetRequestFactory _factory = witnet().factory(); + WitnetBytecodes _registry = witnet().registry(); + // Build own Witnet Randomness Request: + bytes32[] memory _retrievals = new bytes32[](1); + _retrievals[0] = _registry.verifyRadonRetrieval( + Witnet.RadonDataRequestMethods.Rng, + "", // no url + "", // no body + new string[2][](0), // no headers + hex"80" // no retrieval script + ); + Witnet.RadonFilter[] memory _filters; + bytes32 _aggregator = _registry.verifyRadonReducer(Witnet.RadonReducer({ + opcode: Witnet.RadonReducerOpcodes.Mode, + filters: _filters // no filters + })); + bytes32 _tally = _registry.verifyRadonReducer(Witnet.RadonReducer({ + opcode: Witnet.RadonReducerOpcodes.ConcatenateAndHash, + filters: _filters // no filters + })); + WitnetRequestTemplate _template = WitnetRequestTemplate(_factory.buildRequestTemplate( + _retrievals, + _aggregator, + _tally, + 0 + )); + __witnetRandomnessRadHash = WitnetRequest( + _template.buildRequest(new string[][](_retrievals.length)) + ).radHash(); + } + // Settle default randomize SLA: + __defaultRandomizePackedSLA = WitnetV2.RadonSLA({ + numWitnesses: 7, + witnessingCollateralRatio: 10 + }).packed(); + } + + function _defaultRandomizeSLA() internal view returns (WitnetV2.RadonSLA memory) { + return __defaultRandomizePackedSLA.toRadonSLA(); + } + + function _estimateRandomizeBaseFee() internal view returns (uint256) { + return _witnetEstimateBaseFee(32); + } + + /// @dev Returns index of the Most Significant Bit of the given number, applying De Bruijn O(1) algorithm. + function _msbDeBruijn32(uint32 _v) private pure returns (uint8) { + uint8[32] memory _bitPosition = [ + 0, 9, 1, 10, 13, 21, 2, 29, + 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, + 19, 27, 23, 6, 26, 5, 4, 31 + ]; + _v |= _v >> 1; + _v |= _v >> 2; + _v |= _v >> 4; + _v |= _v >> 8; + _v |= _v >> 16; + return _bitPosition[ + uint32(_v * uint256(0x07c4acdd)) >> 27 + ]; + } + + function _randomUniform(uint32 _range, uint256 _nonce, bytes32 _seed) internal pure returns (uint32) { + uint8 _flagBits = uint8(255 - _msbDeBruijn32(_range)); + uint256 _number = uint256( + keccak256( + abi.encode(_seed, _nonce) + ) + ) & uint256(2 ** _flagBits - 1); + return uint32((_number * _range) >> _flagBits); + } + + function _readRandomnessFromResultValue(WitnetCBOR.CBOR calldata cborValue) internal pure returns (bytes32) { + return cborValue.readBytes().toBytes32(); + } + + function __randomize(uint256 _witnetEvmReward) virtual internal returns (uint256) { + return __witnet.postRequest{value: _witnetEvmReward}( + __witnetRandomnessRadHash, + _defaultRandomizeSLA() + ); + } + + function __randomize( + uint256 _witnetEvmReward, + WitnetV2.RadonSLA calldata _witnetQuerySLA + ) + virtual internal + returns (uint256 _randomizeId) + { + return __witnet.postRequest{value: _witnetEvmReward}( + __witnetRandomnessRadHash, + _witnetQuerySLA + ); + } + + function __settleRandomizeDefaultSLA(WitnetV2.RadonSLA calldata sla) virtual internal { + __defaultRandomizePackedSLA = sla.packed(); + } +} \ No newline at end of file From 419ccacea11b8502fc79109778f41cfce467384b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 24 Nov 2023 10:57:39 +0100 Subject: [PATCH 55/86] fix: missing from upon WRB.postRequest --- contracts/core/defaults/WitnetRequestBoardTrustableBase.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index 12b4996ec..a77b218ab 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -785,6 +785,7 @@ abstract contract WitnetRequestBoardTrustableBase __request.slaPacked = _slaPacked; __request.evmReward = _getMsgValue(); } + __seekQuery(_queryId).from = msg.sender; } function __reportResult( From 94ac38cb7710cf20783340374a5ab5fc085984e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 24 Nov 2023 10:58:58 +0100 Subject: [PATCH 56/86] fix: packing/unpacking of WitnetV2.RadonSLA --- contracts/libs/WitnetV2.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/libs/WitnetV2.sol b/contracts/libs/WitnetV2.sol index 20a692bd2..4a20b2943 100644 --- a/contracts/libs/WitnetV2.sol +++ b/contracts/libs/WitnetV2.sol @@ -45,8 +45,8 @@ library WitnetV2 { internal pure returns (RadonSLA memory) { return RadonSLA({ - numWitnesses: uint8(uint(_packed >> 248)), - witnessingCollateralRatio: uint8(uint(_packed >> 240)) + numWitnesses: uint8(uint(_packed) >> 248), + witnessingCollateralRatio: uint8(uint(_packed) >> 240) }); } From 20d58b22d283643a1e3e62962911975f697a8eb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 24 Nov 2023 11:02:29 +0100 Subject: [PATCH 57/86] chore: optimize WitnetRandomnes --- contracts/apps/UsingWitnet.sol | 4 +-- contracts/apps/UsingWitnetRandomness.sol | 10 +++---- contracts/apps/UsingWitnetRequest.sol | 2 +- contracts/apps/UsingWitnetRequestTemplate.sol | 2 +- contracts/apps/WitnetConsumer.sol | 4 +-- contracts/apps/WitnetRandomness.sol | 28 +++++++------------ contracts/apps/WitnetRequestConsumer.sol | 4 +-- .../apps/WitnetRequestTemplateConsumer.sol | 4 +-- contracts/interfaces/IWitnetRandomness.sol | 3 +- contracts/mocks/WitnetRandomnessMock.sol | 6 +--- 10 files changed, 27 insertions(+), 40 deletions(-) diff --git a/contracts/apps/UsingWitnet.sol b/contracts/apps/UsingWitnet.sol index 0d7dda68e..940778e82 100644 --- a/contracts/apps/UsingWitnet.sol +++ b/contracts/apps/UsingWitnet.sol @@ -90,7 +90,7 @@ abstract contract UsingWitnet { function __witnetRequestData( uint256 _witnetEvmReward, bytes32 _witnetRadHash, - WitnetV2.RadonSLA calldata _witnetQuerySLA + WitnetV2.RadonSLA memory _witnetQuerySLA ) virtual internal returns (uint256) { @@ -103,7 +103,7 @@ abstract contract UsingWitnet { function __witnetRequestData( uint256 _witnetEvmReward, bytes calldata _witnetRadBytecode, - WitnetV2.RadonSLA calldata _witnetQuerySLA + WitnetV2.RadonSLA memory _witnetQuerySLA ) virtual internal returns (uint256) { diff --git a/contracts/apps/UsingWitnetRandomness.sol b/contracts/apps/UsingWitnetRandomness.sol index ba97b26b0..ad6b55658 100644 --- a/contracts/apps/UsingWitnetRandomness.sol +++ b/contracts/apps/UsingWitnetRandomness.sol @@ -72,11 +72,11 @@ abstract contract UsingWitnetRandomness /// @dev Returns index of the Most Significant Bit of the given number, applying De Bruijn O(1) algorithm. function _msbDeBruijn32(uint32 _v) private pure returns (uint8) { uint8[32] memory _bitPosition = [ - 0, 9, 1, 10, 13, 21, 2, 29, - 11, 14, 16, 18, 22, 25, 3, 30, - 8, 12, 20, 28, 15, 17, 24, 7, - 19, 27, 23, 6, 26, 5, 4, 31 - ]; + 0, 9, 1, 10, 13, 21, 2, 29, + 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, + 19, 27, 23, 6, 26, 5, 4, 31 + ]; _v |= _v >> 1; _v |= _v >> 2; _v |= _v >> 4; diff --git a/contracts/apps/UsingWitnetRequest.sol b/contracts/apps/UsingWitnetRequest.sol index 13412c5fb..40ae556ab 100644 --- a/contracts/apps/UsingWitnetRequest.sol +++ b/contracts/apps/UsingWitnetRequest.sol @@ -36,7 +36,7 @@ abstract contract UsingWitnetRequest function __witnetRequestData( uint256 _witnetEvmReward, - WitnetV2.RadonSLA calldata _witnetQuerySLA + WitnetV2.RadonSLA memory _witnetQuerySLA ) virtual internal returns (uint256) { diff --git a/contracts/apps/UsingWitnetRequestTemplate.sol b/contracts/apps/UsingWitnetRequestTemplate.sol index dcb0bd772..ffd54bbcb 100644 --- a/contracts/apps/UsingWitnetRequestTemplate.sol +++ b/contracts/apps/UsingWitnetRequestTemplate.sol @@ -46,7 +46,7 @@ abstract contract UsingWitnetRequestTemplate function __witnetRequestData( uint256 _witnetEvmReward, - WitnetV2.RadonSLA calldata _witnetQuerySLA, + WitnetV2.RadonSLA memory _witnetQuerySLA, string[][] memory _witnetRequestArgs ) virtual internal returns (uint256) diff --git a/contracts/apps/WitnetConsumer.sol b/contracts/apps/WitnetConsumer.sol index 862394752..1540142d7 100644 --- a/contracts/apps/WitnetConsumer.sol +++ b/contracts/apps/WitnetConsumer.sol @@ -54,7 +54,7 @@ abstract contract WitnetConsumer function __witnetRequestData( uint256 _witnetEvmReward, bytes32 _witnetRadHash, - WitnetV2.RadonSLA calldata _witnetQuerySLA + WitnetV2.RadonSLA memory _witnetQuerySLA ) virtual override internal returns (uint256) @@ -69,7 +69,7 @@ abstract contract WitnetConsumer function __witnetRequestData( uint256 _witnetEvmReward, bytes calldata _witnetRadBytecode, - WitnetV2.RadonSLA calldata _witnetQuerySLA + WitnetV2.RadonSLA memory _witnetQuerySLA ) virtual override internal returns (uint256) diff --git a/contracts/apps/WitnetRandomness.sol b/contracts/apps/WitnetRandomness.sol index 0803a1790..0d7266488 100644 --- a/contracts/apps/WitnetRandomness.sol +++ b/contracts/apps/WitnetRandomness.sol @@ -35,7 +35,6 @@ contract WitnetRandomness mapping (uint256 => RandomizeData) internal __randomize_; struct RandomizeData { - address from; uint256 prevBlock; uint256 nextBlock; uint256 witnetQueryId; @@ -170,13 +169,12 @@ contract WitnetRandomness virtual override returns (uint256) { - return witnet().estimateBaseFee(_gasPrice, 32); + return __witnet.estimateBaseFee(_gasPrice, 32); } /// Retrieves data of a randomization request that got successfully posted to the WRB within a given block. /// @dev Returns zero values if no randomness request was actually posted within a given block. /// @param _block Block number whose randomness request is being queried for. - /// @return _from Address from which the latest randomness request was posted. /// @return _id Unique request identifier as provided by the WRB. /// @return _prevBlock Block number in which a randomness request got posted just before this one. 0 if none. /// @return _nextBlock Block number in which a randomness request got posted just after this one, 0 if none. @@ -184,7 +182,6 @@ contract WitnetRandomness external view virtual override returns ( - address _from, uint256 _id, uint256 _prevBlock, uint256 _nextBlock @@ -192,7 +189,6 @@ contract WitnetRandomness { RandomizeData storage _data = __randomize_[_block]; _id = _data.witnetQueryId; - _from = _data.from; _prevBlock = _data.prevBlock; _nextBlock = _data.nextBlock; } @@ -212,7 +208,7 @@ contract WitnetRandomness virtual override returns (bytes32) { - if (__randomize_[_block].from == address(0)) { + if (__randomize_[_block].witnetQueryId == 0) { _block = getRandomnessNextBlock(_block); } uint256 _queryId = __randomize_[_block].witnetQueryId; @@ -237,7 +233,7 @@ contract WitnetRandomness virtual override returns (uint256) { - return ((__randomize_[_block].from != address(0)) + return ((__randomize_[_block].witnetQueryId != 0) ? __randomize_[_block].nextBlock // start search from the latest block : _searchNextBlock(_block, latestRandomizeBlock) @@ -326,22 +322,21 @@ contract WitnetRandomness function randomize() external payable virtual override - returns (uint256 _usedFunds) + returns (uint256) { if (latestRandomizeBlock < block.number) { // Post the Witnet Randomness request: - _usedFunds = _witnetEstimateBaseFee(tx.gasprice); - uint _queryId = witnet().postRequest{value: _usedFunds}( + uint _queryId = __witnetRequestData( + msg.value, __witnetRandomnessRadHash, __witnetRandomnessPackedSLA.toRadonSLA() ); // Keep Randomize data in storage: - RandomizeData storage _data = __randomize_[block.number]; - _data.witnetQueryId = _queryId; - _data.from = msg.sender; + RandomizeData storage __data = __randomize_[block.number]; + __data.witnetQueryId = _queryId; // Update block links: uint256 _prevBlock = latestRandomizeBlock; - _data.prevBlock = _prevBlock; + __data.prevBlock = _prevBlock; __randomize_[_prevBlock].nextBlock = block.number; latestRandomizeBlock = block.number; // Throw event: @@ -351,13 +346,10 @@ contract WitnetRandomness _queryId, __witnetRandomnessRadHash ); - // Transfer back unused tx value: - if (_usedFunds < msg.value) { - payable(msg.sender).transfer(msg.value - _usedFunds); - } } else { return upgradeRandomizeFee(block.number); } + return msg.value; } /// Increases Witnet fee related to a pending-to-be-solved randomness request, as much as it diff --git a/contracts/apps/WitnetRequestConsumer.sol b/contracts/apps/WitnetRequestConsumer.sol index ca7b3431b..83546d7bb 100644 --- a/contracts/apps/WitnetRequestConsumer.sol +++ b/contracts/apps/WitnetRequestConsumer.sol @@ -33,7 +33,7 @@ abstract contract WitnetRequestConsumer function __witnetRequestData( uint256 _witnetEvmReward, bytes32 _witnetRadHash, - WitnetV2.RadonSLA calldata _witnetQuerySLA + WitnetV2.RadonSLA memory _witnetQuerySLA ) virtual override(UsingWitnet, WitnetConsumer) internal returns (uint256) @@ -48,7 +48,7 @@ abstract contract WitnetRequestConsumer function __witnetRequestData( uint256 _witnetEvmReward, bytes calldata _witnetRadBytecode, - WitnetV2.RadonSLA calldata _witnetQuerySLA + WitnetV2.RadonSLA memory _witnetQuerySLA ) virtual override(UsingWitnet, WitnetConsumer) internal returns (uint256) diff --git a/contracts/apps/WitnetRequestTemplateConsumer.sol b/contracts/apps/WitnetRequestTemplateConsumer.sol index b08b1cc1f..b329fdf64 100644 --- a/contracts/apps/WitnetRequestTemplateConsumer.sol +++ b/contracts/apps/WitnetRequestTemplateConsumer.sol @@ -34,7 +34,7 @@ abstract contract WitnetRequestTemplateConsumer function __witnetRequestData( uint256 _witnetEvmReward, bytes32 _witnetRadHash, - WitnetV2.RadonSLA calldata _witnetQuerySLA + WitnetV2.RadonSLA memory _witnetQuerySLA ) virtual override(UsingWitnet, WitnetConsumer) internal returns (uint256) @@ -49,7 +49,7 @@ abstract contract WitnetRequestTemplateConsumer function __witnetRequestData( uint256 _witnetEvmReward, bytes calldata _witnetRadBytecode, - WitnetV2.RadonSLA calldata _witnetQuerySLA + WitnetV2.RadonSLA memory _witnetQuerySLA ) virtual override(UsingWitnet, WitnetConsumer) internal returns (uint256) diff --git a/contracts/interfaces/IWitnetRandomness.sol b/contracts/interfaces/IWitnetRandomness.sol index c6e561bce..1e57c354f 100644 --- a/contracts/interfaces/IWitnetRandomness.sol +++ b/contracts/interfaces/IWitnetRandomness.sol @@ -28,12 +28,11 @@ interface IWitnetRandomness { /// @notice Retrieves data of a randomization request that got successfully posted to the WRB within a given block. /// @dev Returns zero values if no randomness request was actually posted within a given block. /// @param _block Block number whose randomness request is being queried for. - /// @return _from Address from which the latest randomness request was posted. /// @return _id Unique request identifier as provided by the WRB. /// @return _prevBlock Block number in which a randomness request got posted just before this one. 0 if none. /// @return _nextBlock Block number in which a randomness request got posted just after this one, 0 if none. function getRandomizeData(uint256 _block) - external view returns (address _from, uint256 _id, uint256 _prevBlock, uint256 _nextBlock); + external view returns (uint256 _id, uint256 _prevBlock, uint256 _nextBlock); /// @notice Retrieves the randomness generated upon solving a request that was posted within a given block, /// if any, or to the _first_ request posted after that block, otherwise. Should the intended diff --git a/contracts/mocks/WitnetRandomnessMock.sol b/contracts/mocks/WitnetRandomnessMock.sol index f13ef281a..0d86c7f57 100644 --- a/contracts/mocks/WitnetRandomnessMock.sol +++ b/contracts/mocks/WitnetRandomnessMock.sol @@ -45,7 +45,6 @@ contract WitnetRandomnessMock /// Retrieves data of a randomization request that got successfully posted to the WRB within a given block. /// @dev Returns zero values if no randomness request was actually posted within a given block. /// @param _block Block number whose randomness request is being queried for. - /// @return _from Address from which the latest randomness request was posted. /// @return _id Unique request identifier as provided by the WRB. /// @return _prevBlock Block number in which a randomness request got posted just before this one. 0 if none. /// @return _nextBlock Block number in which a randomness request got posted just after this one, 0 if none. @@ -53,7 +52,6 @@ contract WitnetRandomnessMock external view virtual override returns ( - address _from, uint256 _id, uint256 _prevBlock, uint256 _nextBlock @@ -61,7 +59,6 @@ contract WitnetRandomnessMock { RandomizeData storage _data = __randomize_[_block]; _id = _data.witnetQueryId; - _from = _data.from; _prevBlock = _data.prevBlock; _nextBlock = _data.nextBlock; } @@ -80,7 +77,7 @@ contract WitnetRandomnessMock virtual override returns (bytes32) { - if (__randomize_[_block].from == address(0)) { + if (__randomize_[_block].witnetQueryId == 0) { _block = getRandomnessNextBlock(_block); } uint256 _queryId = __randomize_[_block].witnetQueryId; @@ -123,7 +120,6 @@ contract WitnetRandomnessMock // Post the Witnet Randomness request: uint _queryId = ++ __mockRandomizeLatestId; RandomizeData storage _data = __randomize_[block.number]; - _data.from = msg.sender; _data.witnetQueryId = _queryId; // Update block links: uint256 _prevBlock = latestRandomizeBlock; From 93a5ff13f137dd068d99e3cabe66756e50449cb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 24 Nov 2023 11:03:31 +0100 Subject: [PATCH 58/86] refactor: WRBData.numQueries -> WRBData.nonce --- .../core/defaults/WitnetRequestBoardTrustableBase.sol | 4 ++-- contracts/data/WitnetRequestBoardData.sol | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index a77b218ab..adac5da83 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -669,7 +669,7 @@ abstract contract WitnetRequestBoardTrustableBase override returns (uint256) { - return __storage().numQueries + 1; + return __storage().nonce + 1; } /// Gets the whole Query data contents, if any, no matter its current status. @@ -771,7 +771,7 @@ abstract contract WitnetRequestBoardTrustableBase function __newQuery() virtual internal returns (uint256) { - return ++ __storage().numQueries; + return ++ __storage().nonce; } function __postRequest(bytes32 _radHash, bytes32 _slaPacked) diff --git a/contracts/data/WitnetRequestBoardData.sol b/contracts/data/WitnetRequestBoardData.sol index 677f343d3..158125189 100644 --- a/contracts/data/WitnetRequestBoardData.sol +++ b/contracts/data/WitnetRequestBoardData.sol @@ -15,7 +15,7 @@ abstract contract WitnetRequestBoardData { struct WitnetBoardState { address base; address owner; - uint256 numQueries; + uint256 nonce; mapping (uint => Witnet.Query) queries; } @@ -34,7 +34,7 @@ abstract contract WitnetRequestBoardData { /// Asserts the given query was previously posted and that it was not yet deleted. modifier notDeleted(uint256 _queryId) { require( - _queryId > 0 && _queryId <= __storage().numQueries, + _queryId > 0 && _queryId <= __storage().nonce, "WitnetRequestBoard: not yet posted" ); require( @@ -54,7 +54,7 @@ abstract contract WitnetRequestBoardData { /// Asserts the given query was actually posted before calling this method. modifier wasPosted(uint256 _queryId) { require( - _queryId > 0 && _queryId <= __storage().numQueries, + _queryId > 0 && _queryId <= __storage().nonce, "WitnetRequestBoard: not yet posted" ); _; } @@ -110,7 +110,7 @@ abstract contract WitnetRequestBoardData { // is kept in storage, the query remains in "Posted" status: return Witnet.QueryStatus.Posted; } - else if (_queryId > __storage().numQueries) { + else if (_queryId > __storage().nonce) { // Requester's address is removed from storage only if // the query gets "Deleted" by its requester. return Witnet.QueryStatus.Deleted; From da7e40c05ebc741a0847ff74fff85f7c97373b55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Sat, 25 Nov 2023 08:11:47 +0100 Subject: [PATCH 59/86] refactor: Witnet.QueryStatus.Deleted -> Witnet.QueryStatus.Delivered --- contracts/apps/WitnetPriceFeeds.sol | 4 +- .../WitnetRequestBoardTrustableBase.sol | 43 +++++++------------ contracts/data/WitnetRequestBoardData.sol | 6 +-- contracts/interfaces/IWitnetRequestBoard.sol | 19 ++++---- contracts/libs/Witnet.sol | 2 +- 5 files changed, 29 insertions(+), 45 deletions(-) diff --git a/contracts/apps/WitnetPriceFeeds.sol b/contracts/apps/WitnetPriceFeeds.sol index c8fee5d8e..e229e14cc 100644 --- a/contracts/apps/WitnetPriceFeeds.sol +++ b/contracts/apps/WitnetPriceFeeds.sol @@ -633,13 +633,13 @@ contract WitnetPriceFeeds if (_latestStatus == Witnet.ResultStatus.Ready) { // If so, remove previous last valid query from the WRB: if (__feed.latestValidQueryId > 0) { - witnet.deleteQuery(__feed.latestValidQueryId); + witnet.fetchQueryResponse(__feed.latestValidQueryId); } __feed.latestValidQueryId = _latestId; } else { // Otherwise, try to delete latest query, as it was faulty // and we are about to post a new update request: - try witnet.deleteQuery(_latestId) {} catch {} + try witnet.fetchQueryResponse(_latestId) {} catch {} } // Post update request to the WRB: _latestId = witnet.postRequest{value: _usedFunds}( diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index adac5da83..d0e9ac395 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -395,19 +395,6 @@ abstract contract WitnetRequestBoardTrustableBase // ================================================================================================================ // --- IWitnetRequestBoard Requester methods ---------------------------------------------------------------------- - /// @notice Delete query without further ado. - /// @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 burnQuery(uint256 _queryId) - external - virtual override - onlyRequester(_queryId) - inStatus(_queryId, Witnet.QueryStatus.Reported) - { - delete __storage().queries[_queryId]; - } - /// @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; @@ -475,21 +462,6 @@ abstract contract WitnetRequestBoardTrustableBase ); } - /// 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) - public - virtual override - onlyRequester(_queryId) - inStatus(_queryId, Witnet.QueryStatus.Reported) - returns (Witnet.Response memory _response) - { - _response = __seekQuery(_queryId).response; - delete __storage().queries[_queryId]; - } - /// @notice Estimates the actual earnings (or loss), in WEI, that a reporter would get by reporting result to given query, /// @notice based on the gas price of the calling transaction. /// @dev Data requesters should consider upgrading the reward on queries providing no actual earnings. @@ -513,6 +485,21 @@ abstract contract WitnetRequestBoardTrustableBase } } + /// 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 fetchQueryResponse(uint256 _queryId) + public + virtual override + onlyRequester(_queryId) + inStatus(_queryId, Witnet.QueryStatus.Reported) + returns (Witnet.Response memory _response) + { + _response = __seekQuery(_queryId).response; + 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. diff --git a/contracts/data/WitnetRequestBoardData.sol b/contracts/data/WitnetRequestBoardData.sol index 158125189..5d034a92d 100644 --- a/contracts/data/WitnetRequestBoardData.sol +++ b/contracts/data/WitnetRequestBoardData.sol @@ -113,7 +113,7 @@ abstract contract WitnetRequestBoardData { else if (_queryId > __storage().nonce) { // Requester's address is removed from storage only if // the query gets "Deleted" by its requester. - return Witnet.QueryStatus.Deleted; + return Witnet.QueryStatus.Delivered; } else { return Witnet.QueryStatus.Unknown; } @@ -127,8 +127,8 @@ abstract contract WitnetRequestBoardData { return "WitnetRequestBoard: not in Posted status"; } else if (_status == Witnet.QueryStatus.Reported) { return "WitnetRequestBoard: not in Reported status"; - } else if (_status == Witnet.QueryStatus.Deleted) { - return "WitnetRequestBoard: not in Deleted status"; + } else if (_status == Witnet.QueryStatus.Delivered) { + return "WitnetRequestBoard: not in Delivered status"; } else { return "WitnetRequestBoard: bad mood"; } diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index c06aa1972..77faae20d 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -26,12 +26,6 @@ interface IWitnetRequestBoard { /// =============================================================================================================== /// --- Requester interface --------------------------------------------------------------------------------------- - /// @notice Delete query without further ado. - /// @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 burnQuery(uint256 queryId) external; - /// @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 view returns (Witnet.ResultError memory); @@ -50,20 +44,23 @@ interface IWitnetRequestBoard { /// @return _resultDrTxHash Witnet blockchain hash of the commit/reveal act that solved the query. function checkResultTraceability(uint256 queryId) external view returns (uint256 _resultTimestamp, bytes32 _resultDrTxHash); - /// @notice Retrieves a copy of all Witnet-provided data related to a previously posted request, removing the whole query from the WRB 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 returns (Witnet.Response memory); /// @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, uint256 resultMaxSize) external view returns (uint256); + + /// @notice Retrieves a copy of all Witnet-provided data related to a previously posted request, + /// removing the whole query from the WRB 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 fetchQueryResponse(uint256 queryId) external returns (Witnet.Response memory); /// @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 resultMaxSize Maximum expected size of returned data (in bytes). /// @param maxCallbackGas Maximum gas to be spent when reporting the data request result. function estimateBaseFeeWithCallback(uint256 gasPrice, uint256 maxCallbackGas) external view returns (uint256); diff --git a/contracts/libs/Witnet.sol b/contracts/libs/Witnet.sol index 6758615b5..429b9980d 100644 --- a/contracts/libs/Witnet.sol +++ b/contracts/libs/Witnet.sol @@ -23,7 +23,7 @@ library Witnet { Unknown, Posted, Reported, - Deleted + Delivered } /// Data kept in EVM-storage for every Request posted to the Witnet Request Board. From 1480638908b75b1fd526ebc658808e4ef6768598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Sat, 25 Nov 2023 08:23:12 +0100 Subject: [PATCH 60/86] feat: declare UsingWitnet contracts to be throwers of WRB events --- contracts/interfaces/IWitnetRequestBoard.sol | 18 --------------- .../interfaces/IWitnetRequestBoardEvents.sol | 22 +++++++++++++++++++ 2 files changed, 22 insertions(+), 18 deletions(-) create mode 100644 contracts/interfaces/IWitnetRequestBoardEvents.sol diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index 77faae20d..96f204efc 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -4,24 +4,6 @@ pragma solidity >=0.7.0 <0.9.0; import "../libs/WitnetV2.sol"; interface IWitnetRequestBoard { - - /// Emitted every time a new query containing some verified data request is posted to the WRB. - event NewQuery(uint256 indexed id, uint256 evmReward); - - /// Emitted every time a new query containing non-verified data request is posted to the WRB. - event NewQueryWithBytecode(uint256 indexed id, uint256 evmReward, bytes radBytecode); - - /// Emitted when the reward of some not-yet reported query is upgraded. - event QueryRewardUpgraded(uint256 indexed id, uint256 evmReward); - - /// Emitted when a query with no callback gets reported into the WRB. - event QueryReport(uint256 indexed id, uint256 evmGasPrice); - - /// Emitted when a query with a callback gets successfully reported into the WRB. - event QueryCallback(uint256 indexed id, uint256 evmGasPrice, uint256 evmCallbackGas); - - /// Emitted when a query with a callback cannot get reported into the WRB. - event QueryCallbackRevert(uint256 indexed id, uint256 evmGasPrice, uint256 evmCallbackGas, string evmReason); /// =============================================================================================================== /// --- Requester interface --------------------------------------------------------------------------------------- diff --git a/contracts/interfaces/IWitnetRequestBoardEvents.sol b/contracts/interfaces/IWitnetRequestBoardEvents.sol new file mode 100644 index 000000000..e711ffce3 --- /dev/null +++ b/contracts/interfaces/IWitnetRequestBoardEvents.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +interface IWitnetRequestBoardEvents { + /// Emitted every time a new query containing some verified data request is posted to the WRB. + event NewQuery(uint256 indexed id, uint256 evmReward); + + /// Emitted every time a new query containing non-verified data request is posted to the WRB. + event NewQueryWithBytecode(uint256 indexed id, uint256 evmReward, bytes radBytecode); + + /// Emitted when the reward of some not-yet reported query is upgraded. + event QueryRewardUpgraded(uint256 indexed id, uint256 evmReward); + + /// Emitted when a query with no callback gets reported into the WRB. + event QueryReport(uint256 indexed id, uint256 evmGasPrice); + + /// Emitted when a query with a callback gets successfully reported into the WRB. + event QueryCallback(uint256 indexed id, uint256 evmGasPrice, uint256 evmCallbackGas); + + /// Emitted when a query with a callback cannot get reported into the WRB. + event QueryCallbackRevert(uint256 indexed id, uint256 evmGasPrice, uint256 evmCallbackGas, string evmReason); +} From 846bebe9a9d9a6a66e4b24a0c8d2579aa2629b90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Sat, 25 Nov 2023 08:52:36 +0100 Subject: [PATCH 61/86] test/feat: polish callbacks implementation --- contracts/WitnetRequestBoard.sol | 4 +- contracts/apps/UsingWitnet.sol | 15 +- contracts/apps/UsingWitnetRandomness.sol | 8 +- contracts/apps/WitnetConsumer.sol | 28 +- contracts/apps/WitnetRandomness.sol | 2 +- contracts/apps/WitnetRequestConsumer.sol | 31 +- .../apps/WitnetRequestTemplateConsumer.sol | 33 +-- .../WitnetRequestBoardTrustableOvm2.sol | 13 +- .../WitnetRequestBoardTrustableReef.sol | 9 +- .../WitnetRequestBoardTrustableBase.sol | 280 +++++++++--------- .../WitnetRequestBoardTrustableDefault.sol | 35 ++- contracts/interfaces/IWitnetRequestBoard.sol | 19 +- .../IWitnetRequestBoardReporter.sol | 6 +- contracts/interfaces/V2/IWitnetConsumer.sol | 21 +- contracts/patterns/Payable.sol | 2 +- migrations/witnet.settings.js | 7 +- 16 files changed, 266 insertions(+), 247 deletions(-) diff --git a/contracts/WitnetRequestBoard.sol b/contracts/WitnetRequestBoard.sol index 37fc92f9f..fcb99ba96 100644 --- a/contracts/WitnetRequestBoard.sol +++ b/contracts/WitnetRequestBoard.sol @@ -5,12 +5,14 @@ pragma solidity >=0.7.0 <0.9.0; import "./WitnetBytecodes.sol"; import "./WitnetRequestFactory.sol"; import "./interfaces/IWitnetRequestBoard.sol"; +import "./interfaces/IWitnetRequestBoardEvents.sol"; /// @title Witnet Request Board functionality base contract. /// @author The Witnet Foundation. abstract contract WitnetRequestBoard is - IWitnetRequestBoard + IWitnetRequestBoard, + IWitnetRequestBoardEvents { function class() virtual external view returns (string memory) { return type(WitnetRequestBoard).name; diff --git a/contracts/apps/UsingWitnet.sol b/contracts/apps/UsingWitnet.sol index 940778e82..c34217ba1 100644 --- a/contracts/apps/UsingWitnet.sol +++ b/contracts/apps/UsingWitnet.sol @@ -8,8 +8,10 @@ import "../WitnetRequestBoard.sol"; /// @title The UsingWitnet contract /// @dev Witnet-aware contracts can inherit from this contract in order to interact with Witnet. /// @author The Witnet Foundation. -abstract contract UsingWitnet { - +abstract contract UsingWitnet + is + IWitnetRequestBoardEvents +{ WitnetRequestBoard internal immutable __witnet; /// @dev Include an address to specify the WitnetRequestBoard entry point address. @@ -47,7 +49,7 @@ abstract contract UsingWitnet { /// @dev Underestimates if the size of returned data is greater than `_resultMaxSize`. /// @param _resultMaxSize Maximum expected size of returned data (in bytes). function _witnetEstimateBaseFee(uint256 _resultMaxSize) - internal view + virtual internal view returns (uint256) { return __witnet.estimateBaseFee(tx.gasprice, _resultMaxSize); @@ -55,12 +57,13 @@ abstract contract UsingWitnet { /// @notice Estimate the minimum reward required for posting a data request, using `tx.gasprice` as a reference. /// @dev Underestimates if the size of returned data is greater than `_resultMaxSize`. + /// @param _resultMaxSize Maximum expected size of returned data (in bytes). /// @param _maxCallbackGas Maximum gas to be spent when reporting the data request result. - function _witnetEstimateBaseFeeWithCallback(uint256 _maxCallbackGas) + function _witnetEstimateBaseFeeWithCallback(uint256 _resultMaxSize, uint256 _maxCallbackGas) internal view returns (uint256) { - return __witnet.estimateBaseFeeWithCallback(tx.gasprice, _maxCallbackGas); + return __witnet.estimateBaseFeeWithCallback(tx.gasprice, _resultMaxSize, _maxCallbackGas); } function _witnetCheckQueryResultTraceability(uint256 _witnetQueryId) @@ -105,7 +108,7 @@ abstract contract UsingWitnet { bytes calldata _witnetRadBytecode, WitnetV2.RadonSLA memory _witnetQuerySLA ) - virtual internal returns (uint256) + internal returns (uint256) { return __witnet.postRequest{value: _witnetEvmReward}( _witnetRadBytecode, diff --git a/contracts/apps/UsingWitnetRandomness.sol b/contracts/apps/UsingWitnetRandomness.sol index ad6b55658..708b6e9e8 100644 --- a/contracts/apps/UsingWitnetRandomness.sol +++ b/contracts/apps/UsingWitnetRandomness.sol @@ -66,7 +66,7 @@ abstract contract UsingWitnetRandomness } function _estimateRandomizeBaseFee() internal view returns (uint256) { - return _witnetEstimateBaseFee(32); + return _witnetEstimateBaseFee(35); } /// @dev Returns index of the Most Significant Bit of the given number, applying De Bruijn O(1) algorithm. @@ -102,7 +102,8 @@ abstract contract UsingWitnetRandomness } function __randomize(uint256 _witnetEvmReward) virtual internal returns (uint256) { - return __witnet.postRequest{value: _witnetEvmReward}( + return __witnetRequestData( + _witnetEvmReward, __witnetRandomnessRadHash, _defaultRandomizeSLA() ); @@ -115,7 +116,8 @@ abstract contract UsingWitnetRandomness virtual internal returns (uint256 _randomizeId) { - return __witnet.postRequest{value: _witnetEvmReward}( + return __witnetRequestData( + _witnetEvmReward, __witnetRandomnessRadHash, _witnetQuerySLA ); diff --git a/contracts/apps/WitnetConsumer.sol b/contracts/apps/WitnetConsumer.sol index 1540142d7..0c02a8ed1 100644 --- a/contracts/apps/WitnetConsumer.sol +++ b/contracts/apps/WitnetConsumer.sol @@ -10,12 +10,7 @@ abstract contract WitnetConsumer UsingWitnet { uint256 private immutable __witnetReportCallbackMaxGas; - - modifier burnQueryAfterReport(uint256 _witnetQueryId) { - _; - __witnet.burnQuery(_witnetQueryId); - } - + modifier onlyFromWitnet { require(msg.sender == address(__witnet), "WitnetConsumer: unauthorized"); _; @@ -37,11 +32,11 @@ abstract contract WitnetConsumer /// =============================================================================================================== /// --- WitnetConsumer virtual methods ---------------------------------------------------------------------------- - function _witnetEstimateBaseFee() - virtual internal view + function _witnetEstimateBaseFee(uint256 _resultMaxSize) + virtual override internal view returns (uint256) { - return _witnetEstimateBaseFeeWithCallback(_witnetReportCallbackMaxGas()); + return _witnetEstimateBaseFeeWithCallback(_resultMaxSize, _witnetReportCallbackMaxGas()); } function _witnetReportCallbackMaxGas() @@ -66,19 +61,4 @@ abstract contract WitnetConsumer ); } - function __witnetRequestData( - uint256 _witnetEvmReward, - bytes calldata _witnetRadBytecode, - WitnetV2.RadonSLA memory _witnetQuerySLA - ) - virtual override internal - returns (uint256) - { - return __witnet.postRequestWithCallback{value: _witnetEvmReward}( - _witnetRadBytecode, - _witnetQuerySLA, - __witnetReportCallbackMaxGas - ); - } - } diff --git a/contracts/apps/WitnetRandomness.sol b/contracts/apps/WitnetRandomness.sol index 0d7266488..f82d33a66 100644 --- a/contracts/apps/WitnetRandomness.sol +++ b/contracts/apps/WitnetRandomness.sol @@ -169,7 +169,7 @@ contract WitnetRandomness virtual override returns (uint256) { - return __witnet.estimateBaseFee(_gasPrice, 32); + return __witnet.estimateBaseFee(_gasPrice, 35); } /// Retrieves data of a randomization request that got successfully posted to the WRB within a given block. diff --git a/contracts/apps/WitnetRequestConsumer.sol b/contracts/apps/WitnetRequestConsumer.sol index 83546d7bb..b6071366b 100644 --- a/contracts/apps/WitnetRequestConsumer.sol +++ b/contracts/apps/WitnetRequestConsumer.sol @@ -17,19 +17,28 @@ abstract contract WitnetRequestConsumer WitnetConsumer(_maxCallbackGas) { require( - _witnetEstimateBaseFeeWithCallback(_maxCallbackGas) > UsingWitnetRequest._witnetEstimateBaseFee(), - "WitnetRequestConsumer: max callback gas too low" + _witnetEstimateBaseFeeWithCallback(_witnetRequest.resultDataMaxSize(), _maxCallbackGas) + > UsingWitnetRequest._witnetEstimateBaseFee(), + "WitnetRequestConsumer: callback gas limit too low" ); } function _witnetEstimateBaseFee() - virtual override(UsingWitnetRequest, WitnetConsumer) + virtual override internal view returns (uint256) { - return WitnetConsumer._witnetEstimateBaseFee(); + return WitnetConsumer._witnetEstimateBaseFee(__witnetResultMaxSize); } + function _witnetEstimateBaseFee(uint256 _resultMaxSize) + virtual override(UsingWitnet, WitnetConsumer) + internal view + returns (uint256) + { + return WitnetConsumer._witnetEstimateBaseFee(_resultMaxSize); + } + function __witnetRequestData( uint256 _witnetEvmReward, bytes32 _witnetRadHash, @@ -45,18 +54,4 @@ abstract contract WitnetRequestConsumer ); } - function __witnetRequestData( - uint256 _witnetEvmReward, - bytes calldata _witnetRadBytecode, - WitnetV2.RadonSLA memory _witnetQuerySLA - ) - virtual override(UsingWitnet, WitnetConsumer) internal - returns (uint256) - { - return WitnetConsumer.__witnetRequestData( - _witnetEvmReward, - _witnetRadBytecode, - _witnetQuerySLA - ); - } } diff --git a/contracts/apps/WitnetRequestTemplateConsumer.sol b/contracts/apps/WitnetRequestTemplateConsumer.sol index b329fdf64..1f804cf1d 100644 --- a/contracts/apps/WitnetRequestTemplateConsumer.sol +++ b/contracts/apps/WitnetRequestTemplateConsumer.sol @@ -17,18 +17,27 @@ abstract contract WitnetRequestTemplateConsumer WitnetConsumer(_maxCallbackGas) { require( - _witnetEstimateBaseFeeWithCallback(_maxCallbackGas) > UsingWitnetRequestTemplate._witnetEstimateBaseFee(), - "WitnetRequestTemplateConsumer: max callback gas too low" + _witnetEstimateBaseFeeWithCallback(_requestTemplate.resultDataMaxSize(), _maxCallbackGas) + > UsingWitnetRequestTemplate._witnetEstimateBaseFee(), + "WitnetRequestTemplateConsumer: callback gas limit too low" ); } - function _witnetEstimateBaseFee() - virtual override(UsingWitnetRequestTemplate, WitnetConsumer) + function _witnetEstimateBaseFee() + virtual override internal view returns (uint256) { - return WitnetConsumer._witnetEstimateBaseFee(); + return WitnetConsumer._witnetEstimateBaseFee(__witnetResultMaxSize); + } + + function _witnetEstimateBaseFee(uint256 _resultMaxSize) + virtual override(UsingWitnet, WitnetConsumer) + internal view + returns (uint256) + { + return WitnetConsumer._witnetEstimateBaseFee(_resultMaxSize); } function __witnetRequestData( @@ -46,18 +55,4 @@ abstract contract WitnetRequestTemplateConsumer ); } - function __witnetRequestData( - uint256 _witnetEvmReward, - bytes calldata _witnetRadBytecode, - WitnetV2.RadonSLA memory _witnetQuerySLA - ) - virtual override(UsingWitnet, WitnetConsumer) internal - returns (uint256) - { - return WitnetConsumer.__witnetRequestData( - _witnetEvmReward, - _witnetRadBytecode, - _witnetQuerySLA - ); - } } diff --git a/contracts/core/customs/WitnetRequestBoardTrustableOvm2.sol b/contracts/core/customs/WitnetRequestBoardTrustableOvm2.sol index e00075c36..4246921da 100644 --- a/contracts/core/customs/WitnetRequestBoardTrustableOvm2.sol +++ b/contracts/core/customs/WitnetRequestBoardTrustableOvm2.sol @@ -28,6 +28,8 @@ contract WitnetRequestBoardTrustableOvm2 bool _upgradable, bytes32 _versionTag, uint256 _reportResultGasBase, + uint256 _reportResultWithCallbackGasBase, + uint256 _reportResultWithCallbackRevertGasBase, uint256 _sstoreFromZeroGas ) WitnetRequestBoardTrustableDefault( @@ -35,6 +37,8 @@ contract WitnetRequestBoardTrustableOvm2 _upgradable, _versionTag, _reportResultGasBase, + _reportResultWithCallbackGasBase, + _reportResultWithCallbackRevertGasBase, _sstoreFromZeroGas ) { @@ -63,13 +67,18 @@ contract WitnetRequestBoardTrustableOvm2 /// @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 _resultMaxSize Maximum expected size of returned data (in bytes). /// @param _maxCallbackGas Maximum gas to be spent when reporting the data request result. - function estimateBaseFeeWithCallback(uint256 _gasPrice, uint256 _maxCallbackGas) + function estimateBaseFeeWithCallback(uint256 _gasPrice, uint256 _resultMaxSize, uint256 _maxCallbackGas) public view virtual override returns (uint256) { - return WitnetRequestBoardTrustableDefault.estimateBaseFeeWithCallback(_gasPrice, _maxCallbackGas) + ( + return WitnetRequestBoardTrustableDefault.estimateBaseFeeWithCallback( + _gasPrice, + _resultMaxSize, + _maxCallbackGas + ) + ( _gasPrice * gasPriceOracleL1.getL1Fee( hex"c8f5cdd500000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000225820ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ) diff --git a/contracts/core/customs/WitnetRequestBoardTrustableReef.sol b/contracts/core/customs/WitnetRequestBoardTrustableReef.sol index 9d7feaeab..46c881494 100644 --- a/contracts/core/customs/WitnetRequestBoardTrustableReef.sol +++ b/contracts/core/customs/WitnetRequestBoardTrustableReef.sol @@ -22,6 +22,8 @@ contract WitnetRequestBoardTrustableReef bool _upgradable, bytes32 _versionTag, uint256 _reportResultGasBase, + uint256 _reportResultWithCallbackGasBase, + uint256 _reportResultWithCallbackRevertGasBase, uint256 _sstoreFromZeroGas ) WitnetRequestBoardTrustableDefault( @@ -29,6 +31,8 @@ contract WitnetRequestBoardTrustableReef _upgradable, _versionTag, _reportResultGasBase, + _reportResultWithCallbackGasBase, + _reportResultWithCallbackRevertGasBase, _sstoreFromZeroGas ) {} @@ -48,13 +52,14 @@ contract WitnetRequestBoardTrustableReef } /// @notice Estimate the minimum reward required for posting a data request with a callback. + /// @param _resultMaxSize Maximum expected size of returned data (in bytes). /// @param _maxCallbackGas Maximum gas to be spent when reporting the data request result. - function estimateBaseFeeWithCallback(uint256, uint256 _maxCallbackGas) + function estimateBaseFeeWithCallback(uint256, uint256 _resultMaxSize, uint256 _maxCallbackGas) public view virtual override returns (uint256) { - return WitnetRequestBoardTrustableDefault.estimateBaseFeeWithCallback(1, _maxCallbackGas); + return WitnetRequestBoardTrustableDefault.estimateBaseFeeWithCallback(1, _resultMaxSize, _maxCallbackGas); } diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index d0e9ac395..7fb2c8453 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -110,8 +110,9 @@ abstract contract WitnetRequestBoardTrustableBase /// @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 _resultMaxSize Maximum expected size of returned data (in bytes). /// @param _maxCallbackGas Maximum gas to be spent when reporting the data request result. - function estimateBaseFeeWithCallback(uint256 _gasPrice, uint256 _maxCallbackGas) virtual public view returns (uint256); + function estimateBaseFeeWithCallback(uint256 _gasPrice, uint256 _resultMaxSize, uint256 _maxCallbackGas) virtual public view returns (uint256); // ================================================================================================================ @@ -257,6 +258,7 @@ abstract contract WitnetRequestBoardTrustableBase override onlyReporters inStatus(_queryId, Witnet.QueryStatus.Posted) + returns (uint256) { require( _drTxHash != 0, @@ -268,15 +270,13 @@ abstract contract WitnetRequestBoardTrustableBase _cborBytes.length != 0, "WitnetRequestBoardTrustableDefault: result cannot be empty" ); + // Do actual report: // solhint-disable not-rely-on-time - _safeTransferTo( - payable(msg.sender), - __reportResult( - _queryId, - block.timestamp, - _drTxHash, - _cborBytes - ) + return __reportResultAndReward( + _queryId, + block.timestamp, + _drTxHash, + _cborBytes ); } @@ -300,6 +300,7 @@ abstract contract WitnetRequestBoardTrustableBase override onlyReporters inStatus(_queryId, Witnet.QueryStatus.Posted) + returns (uint256) { require( _timestamp <= block.timestamp, @@ -315,13 +316,13 @@ abstract contract WitnetRequestBoardTrustableBase _cborBytes.length != 0, "WitnetRequestBoardTrustableDefault: result cannot be empty" ); - // Transfer query's reward to the reporter: - _safeTransferTo(payable(msg.sender), __reportResult( + // Do actual report and return reward transfered to the reproter: + return __reportResultAndReward( _queryId, _timestamp, _drTxHash, _cborBytes - )); + ); } /// Reports Witnet-provided results to multiple requests within a single EVM tx. @@ -334,57 +335,55 @@ abstract contract WitnetRequestBoardTrustableBase /// - data request result in raw bytes. /// @param _verbose If true, emits a BatchReportError event for every failing report, if any. function reportResultBatch( - IWitnetRequestBoardReporter.BatchResult[] memory _batchResults, + IWitnetRequestBoardReporter.BatchResult[] calldata _batchResults, bool _verbose ) external override onlyReporters + returns (uint256 _batchReward) { - uint _batchReward; - uint _batchSize = _batchResults.length; - for ( uint _i = 0; _i < _batchSize; _i ++) { - BatchResult memory _result = _batchResults[_i]; - if (_statusOf(_result.queryId) != Witnet.QueryStatus.Posted) { + for ( uint _i = 0; _i < _batchResults.length; _i ++) { + if (_statusOf(_batchResults[_i].queryId) != Witnet.QueryStatus.Posted) { if (_verbose) { emit BatchReportError( - _result.queryId, + _batchResults[_i].queryId, "WitnetRequestBoardTrustableBase: bad queryId" ); } - } else if (_result.drTxHash == 0) { + } else if (_batchResults[_i].drTxHash == 0) { if (_verbose) { emit BatchReportError( - _result.queryId, + _batchResults[_i].queryId, "WitnetRequestBoardTrustableBase: bad drTxHash" ); } - } else if (_result.cborBytes.length == 0) { + } else if (_batchResults[_i].cborBytes.length == 0) { if (_verbose) { emit BatchReportError( - _result.queryId, + _batchResults[_i].queryId, "WitnetRequestBoardTrustableBase: bad cborBytes" ); } - } else if (_result.timestamp > 0 && _result.timestamp > block.timestamp) { + } else if (_batchResults[_i].timestamp > 0 && _batchResults[_i].timestamp > block.timestamp) { if (_verbose) { emit BatchReportError( - _result.queryId, + _batchResults[_i].queryId, "WitnetRequestBoardTrustableBase: bad timestamp" ); } } else { _batchReward += __reportResult( - _result.queryId, - _result.timestamp == 0 ? block.timestamp : _result.timestamp, - _result.drTxHash, - _result.cborBytes + _batchResults[_i].queryId, + _batchResults[_i].timestamp == 0 ? block.timestamp : _batchResults[_i].timestamp, + _batchResults[_i].drTxHash, + _batchResults[_i].cborBytes ); } } - // Transfer all successful rewards in one single shot to the authorized reporter, if any: + // Transfer rewards to all reported results in one single transfer to the reporter: if (_batchReward > 0) { - _safeTransferTo( + __safeTransferTo( payable(msg.sender), _batchReward ); @@ -465,22 +464,25 @@ abstract contract WitnetRequestBoardTrustableBase /// @notice Estimates the actual earnings (or loss), in WEI, that a reporter would get by reporting result to given query, /// @notice based on the gas price of the calling transaction. /// @dev Data requesters should consider upgrading the reward on queries providing no actual earnings. - function estimateQueryEarnings(uint256 _queryId) + function estimateQueryEarnings(uint256 _queryId, uint256 _gasPrice) virtual override external view returns (int256 _earnings) { Witnet.Request storage __request = __seekQueryRequest(_queryId); + + uint _maxResultSize = registry().lookupRadonRequestResultMaxSize(__request.radHash); _earnings = int(__request.evmReward); if (__request.maxCallbackGas > 0) { _earnings -= int(estimateBaseFeeWithCallback( - _getGasPrice(), + _gasPrice, + _maxResultSize, __request.maxCallbackGas )); } else { _earnings -= int(estimateBaseFee( - _getGasPrice(), - registry().lookupRadonRequestResultMaxSize(__request.radHash) + _gasPrice, + _maxResultSize )); } } @@ -587,7 +589,7 @@ abstract contract WitnetRequestBoardTrustableBase virtual override external payable checkCallbackRecipient(msg.sender) - checkReward(estimateBaseFeeWithCallback(_getGasPrice(), _queryMaxCallbackGas)) + checkReward(estimateBaseFeeWithCallback(_getGasPrice(), 32, _queryMaxCallbackGas)) checkSLA(_querySLA) returns (uint256 _queryId) { @@ -598,35 +600,6 @@ abstract contract WitnetRequestBoardTrustableBase __seekQueryRequest(_queryId).maxCallbackGas = _queryMaxCallbackGas; emit NewQuery(_queryId, _getMsgValue()); } - - /// @notice Requests the execution of the given Witnet Data Request bytecode, in expectation that it will be - /// @notice relayed and solved by the Witnet blockchain. A reward amount is escrowed by the Witnet Request Board - /// @notice that will be transferred to the reporter who relays back the Witnet-provided result to this request. - /// @dev Fails if, provided reward is too low. - /// @dev The caller must be a contract implementing the IWitnetConsumer interface. - /// @param _radBytecode 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 _queryMaxCallbackGas Maximum gas to be spent when reporting the data request result. - /// @return _queryId A unique query identifier. - function postRequestWithCallback( - bytes calldata _radBytecode, - WitnetV2.RadonSLA calldata _querySLA, - uint256 _queryMaxCallbackGas - ) - virtual override - external payable - checkCallbackRecipient(msg.sender) - checkReward(estimateBaseFeeWithCallback(_getGasPrice(), _queryMaxCallbackGas)) - checkSLA(_querySLA) - returns (uint256 _queryId) - { - _queryId = __postRequest( - registry().hashOf(_radBytecode), - _querySLA.packed() - ); - __seekQueryRequest(_queryId).maxCallbackGas = _queryMaxCallbackGas; - emit NewQueryWithBytecode(_queryId, _getMsgValue(), _radBytecode); - } /// 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 @@ -777,9 +750,9 @@ abstract contract WitnetRequestBoardTrustableBase function __reportResult( uint256 _queryId, - uint256 _timestamp, + uint256 _drTxTimestamp, bytes32 _drTxHash, - bytes memory _cborBytes + bytes calldata _cborBytes ) internal returns (uint256 _evmReward) @@ -791,96 +764,129 @@ abstract contract WitnetRequestBoardTrustableBase _evmReward = __request.evmReward; __request.evmReward = 0; - // write report traceability data in storage - // (could potentially be deleted from a callback method within same transaction) - Witnet.Response storage __response = __query.response; - // solhint-disable not-rely-on-time - __response.timestamp = _timestamp; - __response.drTxHash = _drTxHash; - __response.reporter = msg.sender; - // determine whether a callback is required if (__request.maxCallbackGas > 0) { - uint _evmCallbackGas = gasleft(); - bool _evmCallbackSuccess; - bytes memory _evmCallbackRevertBytes; + uint _evmCallbackActualGas = gasleft() - 6295; + bool _evmCallbackSuccess = false; + string memory _evmCallbackRevertMessage; // if callback is required, select which callback method to call // depending on whether the query was solved with or without errors: if (_cborBytes[0] == bytes1(0xd8)) { WitnetCBOR.CBOR[] memory _errors = WitnetCBOR.fromBytes(_cborBytes).readArray(); if (_errors.length < 2) { - // result with unknown error: - (_evmCallbackSuccess, _evmCallbackRevertBytes) = __query.from.call{gas: __request.maxCallbackGas}( - abi.encodeWithSelector(IWitnetConsumer.reportWitnetQueryError.selector, - _queryId, - Witnet.ResultErrorCodes.Unknown, - WitnetCBOR.CBOR({ - buffer: WitnetBuffer.Buffer({ data: hex"", cursor: 0}), - initialByte: 0, - majorType: 0, - additionalInformation: 0, - len: 0, - tag: 0 - }) - ) - ); + // try to report result with unknown error: + try IWitnetConsumer(__query.from).reportWitnetQueryError{gas: __request.maxCallbackGas}( + _queryId, + _drTxHash, + _drTxTimestamp, + block.number, + Witnet.ResultErrorCodes.Unknown, + WitnetCBOR.CBOR({ + buffer: WitnetBuffer.Buffer({ data: hex"", cursor: 0}), + initialByte: 0, + majorType: 0, + additionalInformation: 0, + len: 0, + tag: 0 + }) + ) { + _evmCallbackSuccess = true; + } catch Error(string memory err) { + _evmCallbackRevertMessage = err; + } } else { - // result with parsable error: - (_evmCallbackSuccess, _evmCallbackRevertBytes) = __query.from.call{gas: __request.maxCallbackGas}( - abi.encodeWithSelector(IWitnetConsumer.reportWitnetQueryError.selector, - _queryId, - Witnet.ResultErrorCodes(_errors[0].readUint()), - _errors[0] - ) - ); + // try to report result with parsable error: + try IWitnetConsumer(__query.from).reportWitnetQueryError{gas: __request.maxCallbackGas}( + _queryId, + _drTxHash, + _drTxTimestamp, + block.number, + Witnet.ResultErrorCodes(_errors[0].readUint()), + _errors[0] + ) { + _evmCallbackSuccess = true; + } catch Error(string memory err) { + _evmCallbackRevertMessage = err; + } } } else { - // result with no error - (_evmCallbackSuccess, _evmCallbackRevertBytes) = __query.from.call{gas: __request.maxCallbackGas}( - abi.encodeWithSelector(IWitnetConsumer.reportWitnetQueryResult.selector, - _queryId, - WitnetCBOR.fromBytes(_cborBytes) - ) - ); + // try to report result result with no error : + try IWitnetConsumer(__query.from).reportWitnetQueryResult{gas: __request.maxCallbackGas}( + _queryId, + _drTxHash, + _drTxTimestamp, + block.number, + WitnetCBOR.fromBytes(_cborBytes) + ) { + _evmCallbackSuccess = true; + } catch Error(string memory err) { + _evmCallbackRevertMessage = err; + } catch (bytes memory) {} } - _evmCallbackGas -= gasleft(); if (_evmCallbackSuccess) { + // => the callback run successfully emit QueryCallback( - _queryId, - _getGasPrice(), - _evmCallbackGas + _queryId, + _getGasPrice(), + _evmCallbackActualGas - gasleft() ); + // after successfull report, remove the whole query from storage: + delete __storage().queries[_queryId]; } else { - if (_evmCallbackRevertBytes.length < 68) { - emit QueryCallbackRevert( - _queryId, - _getGasPrice(), - _evmCallbackGas, - "WitnetRequestBoardTrustableDefault: unhandled callback revert" - ); - } else { - assembly { - _evmCallbackRevertBytes := add(_evmCallbackRevertBytes, 0x04) - } - emit QueryCallbackRevert( - _queryId, - _getGasPrice(), - _evmCallbackGas, - string(abi.encodePacked( - "WitnetRequestBoardTrustableDefault: callback revert: ", - _evmCallbackRevertBytes - )) - ); - } - } + // => the callback reverted + emit QueryCallbackRevert( + _queryId, + _getGasPrice(), + _evmCallbackActualGas - gasleft(), + bytes(_evmCallbackRevertMessage).length > 0 + ? _evmCallbackRevertMessage + : "WitnetRequestBoardTrustableDefault: callback gas limit exceeded?" + ); + // write query result and traceability data into storage: + __writeQueryResponse(_queryId, _drTxHash, _drTxTimestamp, _cborBytes); + } } else { - // no callback is involved, so just keep the cbor-encoded result in storage: - __response.cborBytes = _cborBytes; + // => no callback is involved emit QueryReport( _queryId, _getGasPrice() ); - } + // write query result and traceability data into storage + __writeQueryResponse(_queryId, _drTxHash, _drTxTimestamp, _cborBytes); + } + } + + function __writeQueryResponse( + uint256 _queryId, + bytes32 _drTxHash, + uint256 _drTxTimestamp, + bytes memory _cborBytes + ) + internal + { + __seekQuery(_queryId).response = Witnet.Response({ + timestamp: _drTxTimestamp, + drTxHash: _drTxHash, + reporter: msg.sender, + cborBytes: _cborBytes + }); + } + + function __reportResultAndReward( + uint256 _queryId, + uint256 _timestamp, + bytes32 _drTxHash, + bytes calldata _cborBytes + ) + internal + returns (uint256 _evmReward) + { + _evmReward = __reportResult(_queryId, _timestamp, _drTxHash, _cborBytes); + // transfer reward to reporter + __safeTransferTo( + payable(msg.sender), + _evmReward + ); } function __setReporters(address[] memory _reporters) internal { diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol b/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol index d3bf30358..af1f75043 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol @@ -17,6 +17,8 @@ contract WitnetRequestBoardTrustableDefault WitnetRequestBoardTrustableBase { uint256 internal immutable __reportResultGasBase; + uint256 internal immutable __reportResultWithCallbackGasBase; + uint256 internal immutable __reportResultWithCallbackRevertGasBase; uint256 internal immutable __sstoreFromZeroGas; constructor( @@ -24,6 +26,8 @@ contract WitnetRequestBoardTrustableDefault bool _upgradable, bytes32 _versionTag, uint256 _reportResultGasBase, + uint256 _reportResultWithCallbackGasBase, + uint256 _reportResultWithCallbackRevertGasBase, uint256 _sstoreFromZeroGas ) WitnetRequestBoardTrustableBase( @@ -34,6 +38,8 @@ contract WitnetRequestBoardTrustableDefault ) { __reportResultGasBase = _reportResultGasBase; + __reportResultWithCallbackGasBase = _reportResultWithCallbackGasBase; + __reportResultWithCallbackRevertGasBase = _reportResultWithCallbackRevertGasBase; __sstoreFromZeroGas = _sstoreFromZeroGas; } @@ -53,24 +59,39 @@ contract WitnetRequestBoardTrustableDefault return _gasPrice * ( __reportResultGasBase + __sstoreFromZeroGas * ( - 3 + _resultMaxSize / 32 + 5 + _resultMaxSize / 32 ) ); } /// @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 _resultMaxSize Maximum expected size of returned data (in bytes). /// @param _maxCallbackGas Maximum gas to be spent when reporting the data request result. - function estimateBaseFeeWithCallback(uint256 _gasPrice, uint256 _maxCallbackGas) + function estimateBaseFeeWithCallback(uint256 _gasPrice, uint256 _resultMaxSize, uint256 _maxCallbackGas) public view virtual override returns (uint256) { - return _gasPrice * ( - __reportResultGasBase - + 3 * __sstoreFromZeroGas - + _maxCallbackGas + uint _reportResultWithetCallbackGasThreshold = ( + __reportResultWithCallbackRevertGasBase + + __sstoreFromZeroGas * ( + 5 + _resultMaxSize / 32 + ) ); + if ( + _maxCallbackGas < _reportResultWithetCallbackGasThreshold + || __reportResultWithCallbackGasBase + _maxCallbackGas < _reportResultWithetCallbackGasThreshold + ) { + return (_gasPrice * _reportResultWithetCallbackGasThreshold); + } else { + return ( + _gasPrice * ( + __reportResultWithCallbackGasBase + + _maxCallbackGas + ) + ); + } } @@ -98,7 +119,7 @@ contract WitnetRequestBoardTrustableDefault /// Transfers ETHs to given address. /// @param _to Recipient address. /// @param _amount Amount of ETHs to transfer. - function _safeTransferTo(address payable _to, uint256 _amount) + function __safeTransferTo(address payable _to, uint256 _amount) internal virtual override { diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index 96f204efc..e64fe7265 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -44,12 +44,12 @@ interface IWitnetRequestBoard { /// @param gasPrice Expected gas price to pay upon posting the data request. /// @param resultMaxSize Maximum expected size of returned data (in bytes). /// @param maxCallbackGas Maximum gas to be spent when reporting the data request result. - function estimateBaseFeeWithCallback(uint256 gasPrice, uint256 maxCallbackGas) external view returns (uint256); + function estimateBaseFeeWithCallback(uint256 gasPrice, uint256 resultMaxSize, uint256 maxCallbackGas) external view returns (uint256); /// @notice Estimates the actual earnings (or loss), in WEI, that a reporter would get by reporting result to given query, /// @notice based on the gas price of the calling transaction. /// @dev Data requesters should consider upgrading the reward on queries providing no actual earnings. - function estimateQueryEarnings(uint256 queryId) external view returns (int256); + function estimateQueryEarnings(uint256 queryId, uint256 gasPrice) external view returns (int256); /// @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 @@ -92,21 +92,6 @@ interface IWitnetRequestBoard { uint256 maxCallbackGas ) external payable returns (uint256 queryId); - /// @notice Requests the execution of the given Witnet Data Request bytecode, in expectation that it will be - /// @notice relayed and solved by the Witnet blockchain. A reward amount is escrowed by the Witnet Request Board - /// @notice that will be transferred to the reporter who relays back the Witnet-provided result to this request. - /// @dev Fails if, provided reward is too low. - /// @dev The caller must be a contract implementing the IWitnetConsumer interface. - /// @param radBytecode 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 maxCallbackGas Maximum gas to be spent when reporting the data request result. - /// @return A unique query identifier. - function postRequestWithCallback( - bytes calldata radBytecode, - WitnetV2.RadonSLA calldata querySLA, - uint256 maxCallbackGas - ) external payable returns (uint256); - /// @notice Increments the reward of a previously posted request by adding the transaction value to it. /// @param queryId The unique query identifier. function upgradeQueryReward(uint256 queryId) external payable; diff --git a/contracts/interfaces/IWitnetRequestBoardReporter.sol b/contracts/interfaces/IWitnetRequestBoardReporter.sol index 28895bd9d..bb56b3461 100644 --- a/contracts/interfaces/IWitnetRequestBoardReporter.sol +++ b/contracts/interfaces/IWitnetRequestBoardReporter.sol @@ -19,7 +19,7 @@ interface IWitnetRequestBoardReporter { uint256 _queryId, bytes32 _drTxHash, bytes calldata _result - ) external; + ) external returns (uint256); /// @notice Reports the Witnet-provided result to a previously posted request. /// @dev Fails if: @@ -36,7 +36,7 @@ interface IWitnetRequestBoardReporter { uint256 _timestamp, bytes32 _drTxHash, bytes calldata _result - ) external; + ) external returns (uint256); /// @notice Reports Witnet-provided results to multiple requests within a single EVM tx. /// @dev Must emit a PostedResult event for every succesfully reported result. @@ -46,7 +46,7 @@ interface IWitnetRequestBoardReporter { /// - hash of the corresponding data request tx at the Witnet side-chain level; /// - data request result in raw bytes. /// @param _verbose If true, must emit a BatchReportError event for every failing report, if any. - function reportResultBatch(BatchResult[] calldata _batchResults, bool _verbose) external; + function reportResultBatch(BatchResult[] calldata _batchResults, bool _verbose) external returns (uint256); struct BatchResult { uint256 queryId; diff --git a/contracts/interfaces/V2/IWitnetConsumer.sol b/contracts/interfaces/V2/IWitnetConsumer.sol index c1b314c58..b46b84194 100644 --- a/contracts/interfaces/V2/IWitnetConsumer.sol +++ b/contracts/interfaces/V2/IWitnetConsumer.sol @@ -11,10 +11,16 @@ interface IWitnetConsumer { /// @dev by the WitnetConsumer contract. Within the implementation of this method, the WitnetConsumer /// @dev can call to the WRB as to retrieve the Witnet tracking information (i.e. the `witnetDrTxHash` /// @dev and `witnetDrCommitTxTimestamp`), or the finality status, of the result being reported. - /// @param queryId The unique identifier of the Witnet query being reported. + /// @param witnetQueryId The unique identifier of the Witnet query being reported. + /// @param witnetCommitRevealHash Hash of the commit/reveal witnessing act that took place in the Witnet blockahin. + /// @param witnetCommitTimestamp Timestamp when 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 cborValue The CBOR-encoded resulting value of the Witnet query being reported. function reportWitnetQueryResult( - uint256 queryId, + uint256 witnetQueryId, + bytes32 witnetCommitRevealHash, + uint256 witnetCommitTimestamp, + uint256 witnetEvmFinalityBlock, WitnetCBOR.CBOR calldata cborValue ) external; @@ -24,11 +30,18 @@ interface IWitnetConsumer { /// @dev by the WitnetConsumer contract. Within the implementation of this method, the WitnetConsumer /// @dev can call to the WRB as to retrieve the Witnet tracking information (i.e. the `witnetDrTxHash` /// @dev and `witnetDrCommitTxTimestamp`), or the finality status, of the result being reported. - /// @param queryId The unique identifier of the Witnet query being reported. + /// @param witnetQueryId The unique identifier of the Witnet query being reported. + /// @param witnetQueryId The unique identifier of the Witnet query being reported. + /// @param witnetCommitRevealHash Hash of the commit/reveal witnessing act that took place in the Witnet blockahin. + /// @param witnetCommitTimestamp Timestamp when 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 queryId, + uint256 witnetQueryId, + bytes32 witnetCommitRevealHash, + uint256 witnetCommitTimestamp, + uint256 witnetEvmFinalityBlock, Witnet.ResultErrorCodes errorCode, WitnetCBOR.CBOR calldata errorArgs ) external; diff --git a/contracts/patterns/Payable.sol b/contracts/patterns/Payable.sol index e31a8d1da..8313a0c71 100644 --- a/contracts/patterns/Payable.sol +++ b/contracts/patterns/Payable.sol @@ -20,5 +20,5 @@ abstract contract Payable { function _getMsgValue() internal view virtual returns (uint256); /// Perform safe transfer or whatever token is used for paying rewards. - function _safeTransferTo(address payable, uint256) internal virtual; + function __safeTransferTo(address payable, uint256) internal virtual; } diff --git a/migrations/witnet.settings.js b/migrations/witnet.settings.js index 16bcf2e8f..d05404f75 100644 --- a/migrations/witnet.settings.js +++ b/migrations/witnet.settings.js @@ -667,9 +667,12 @@ module.exports = { }, WitnetRequestBoard: { immutables: { - types: [ 'uint256', ], + types: [ 'uint256', 'uint256', 'uint256', 'uint256', ], values: [ - /* _reportResultGasLimit */ 133000, + /* _reportResultGasBase */ 57898, + /* _reportResultWithCallbackGasBase */ 72140, + /* _reportResultWithCallbackRevertGasBase */ 66685, + /* _sstoreFromZeroGas */ 20000, ] }, libs: [ "WitnetErrorsLib", ], From b6eb3471fa43dc04ff23e77d16d75bfdaf39ab2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Sat, 25 Nov 2023 08:55:37 +0100 Subject: [PATCH 62/86] chore: reorder methods on IWRB --- .../WitnetRequestBoardTrustableBase.sol | 650 +++++++++--------- contracts/interfaces/IWitnetRequestBoard.sol | 94 ++- 2 files changed, 368 insertions(+), 376 deletions(-) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index 7fb2c8453..08adaa0f0 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -174,225 +174,7 @@ abstract contract WitnetRequestBoardTrustableBase // ================================================================================================================ - // --- Full implementation of 'IWitnetRequestBoardAdmin' ---------------------------------------------------------- - - /// Gets admin/owner address. - function owner() - public view - override - returns (address) - { - return __storage().owner; - } - - /// Transfers ownership. - function transferOwnership(address _newOwner) - public - virtual override - onlyOwner - { - address _owner = __storage().owner; - if (_newOwner != _owner) { - __storage().owner = _newOwner; - emit OwnershipTransferred(_owner, _newOwner); - } - } - - - // ================================================================================================================ - // --- Full implementation of 'IWitnetRequestBoardAdminACLs' ------------------------------------------------------ - - /// Tells whether given address is included in the active reporters control list. - /// @param _reporter The address to be checked. - function isReporter(address _reporter) public view override returns (bool) { - return _acls().isReporter_[_reporter]; - } - - /// Adds given addresses to the active reporters control list. - /// @dev Can only be called from the owner address. - /// @dev Emits the `ReportersSet` event. - /// @param _reporters List of addresses to be added to the active reporters control list. - function setReporters(address[] memory _reporters) - public - override - onlyOwner - { - __setReporters(_reporters); - } - - /// Removes given addresses from the active reporters control list. - /// @dev Can only be called from the owner address. - /// @dev Emits the `ReportersUnset` event. - /// @param _exReporters List of addresses to be added to the active reporters control list. - function unsetReporters(address[] memory _exReporters) - public - override - onlyOwner - { - for (uint ix = 0; ix < _exReporters.length; ix ++) { - address _reporter = _exReporters[ix]; - _acls().isReporter_[_reporter] = false; - } - emit ReportersUnset(_exReporters); - } - - - // ================================================================================================================ - // --- IWitnetRequestBoard Reporter methods ----------------------------------------------------------------------- - - /// Reports the Witnet-provided result to a previously posted request. - /// @dev Will assume `block.timestamp` as the timestamp at which the request was solved. - /// @dev Fails if: - /// @dev - the `_queryId` is not in 'Posted' status. - /// @dev - provided `_drTxHash` is zero; - /// @dev - length of provided `_result` is zero. - /// @param _queryId The unique identifier of the data request. - /// @param _drTxHash The hash of the solving tally transaction in Witnet. - /// @param _cborBytes The result itself as bytes. - function reportResult( - uint256 _queryId, - bytes32 _drTxHash, - bytes calldata _cborBytes - ) - external - override - onlyReporters - inStatus(_queryId, Witnet.QueryStatus.Posted) - returns (uint256) - { - require( - _drTxHash != 0, - "WitnetRequestBoardTrustableDefault: Witnet drTxHash cannot be zero" - ); - // Ensures the result bytes do not have zero length - // This would not be a valid encoding with CBOR and could trigger a reentrancy attack - require( - _cborBytes.length != 0, - "WitnetRequestBoardTrustableDefault: result cannot be empty" - ); - // Do actual report: - // solhint-disable not-rely-on-time - return __reportResultAndReward( - _queryId, - block.timestamp, - _drTxHash, - _cborBytes - ); - } - - /// Reports the Witnet-provided result to a previously posted request. - /// @dev Fails if: - /// @dev - called from unauthorized address; - /// @dev - the `_queryId` is not in 'Posted' status. - /// @dev - provided `_drTxHash` is zero; - /// @dev - length of provided `_result` is zero. - /// @param _queryId The unique query identifier - /// @param _timestamp The timestamp of the solving tally transaction in Witnet. - /// @param _drTxHash The hash of the solving tally transaction in Witnet. - /// @param _cborBytes The result itself as bytes. - function reportResult( - uint256 _queryId, - uint256 _timestamp, - bytes32 _drTxHash, - bytes calldata _cborBytes - ) - external - override - onlyReporters - inStatus(_queryId, Witnet.QueryStatus.Posted) - returns (uint256) - { - require( - _timestamp <= block.timestamp, - "WitnetRequestBoardTrustableDefault: bad timestamp" - ); - require( - _drTxHash != 0, - "WitnetRequestBoardTrustableDefault: Witnet drTxHash cannot be zero" - ); - // Ensures the result bytes do not have zero length (this would not be a valid CBOR encoding - // and could trigger a reentrancy attack) - require( - _cborBytes.length != 0, - "WitnetRequestBoardTrustableDefault: result cannot be empty" - ); - // Do actual report and return reward transfered to the reproter: - return __reportResultAndReward( - _queryId, - _timestamp, - _drTxHash, - _cborBytes - ); - } - - /// Reports Witnet-provided results to multiple requests within a single EVM tx. - /// @dev Fails if called from unauthorized address. - /// @dev Emits a PostedResult event for every succesfully reported result, if any. - /// @param _batchResults Array of BatchedResult structs, every one containing: - /// - unique query identifier; - /// - timestamp of the solving tally txs in Witnet. If zero is provided, EVM-timestamp will be used instead; - /// - hash of the corresponding data request tx at the Witnet side-chain level; - /// - data request result in raw bytes. - /// @param _verbose If true, emits a BatchReportError event for every failing report, if any. - function reportResultBatch( - IWitnetRequestBoardReporter.BatchResult[] calldata _batchResults, - bool _verbose - ) - external - override - onlyReporters - returns (uint256 _batchReward) - { - for ( uint _i = 0; _i < _batchResults.length; _i ++) { - if (_statusOf(_batchResults[_i].queryId) != Witnet.QueryStatus.Posted) { - if (_verbose) { - emit BatchReportError( - _batchResults[_i].queryId, - "WitnetRequestBoardTrustableBase: bad queryId" - ); - } - } else if (_batchResults[_i].drTxHash == 0) { - if (_verbose) { - emit BatchReportError( - _batchResults[_i].queryId, - "WitnetRequestBoardTrustableBase: bad drTxHash" - ); - } - } else if (_batchResults[_i].cborBytes.length == 0) { - if (_verbose) { - emit BatchReportError( - _batchResults[_i].queryId, - "WitnetRequestBoardTrustableBase: bad cborBytes" - ); - } - } else if (_batchResults[_i].timestamp > 0 && _batchResults[_i].timestamp > block.timestamp) { - if (_verbose) { - emit BatchReportError( - _batchResults[_i].queryId, - "WitnetRequestBoardTrustableBase: bad timestamp" - ); - } - } else { - _batchReward += __reportResult( - _batchResults[_i].queryId, - _batchResults[_i].timestamp == 0 ? block.timestamp : _batchResults[_i].timestamp, - _batchResults[_i].drTxHash, - _batchResults[_i].cborBytes - ); - } - } - // Transfer rewards to all reported results in one single transfer to the reporter: - if (_batchReward > 0) { - __safeTransferTo( - payable(msg.sender), - _batchReward - ); - } - } - - - // ================================================================================================================ - // --- IWitnetRequestBoard Requester methods ---------------------------------------------------------------------- + // --- Partial implementation of IWitnetRequestBoard -------------------------------------------------------------- /// @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; @@ -492,50 +274,151 @@ abstract contract WitnetRequestBoardTrustableBase /// @dev the one that actually posted the given request. /// @param _queryId The unique query identifier. function fetchQueryResponse(uint256 _queryId) - public virtual override - onlyRequester(_queryId) + external inStatus(_queryId, Witnet.QueryStatus.Reported) + onlyRequester(_queryId) returns (Witnet.Response memory _response) { _response = __seekQuery(_queryId).response; 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. - /// @param _radHash The radHash of the Witnet Data Request. - /// @param _slaHash The slaHash of the Witnet Data Request. - function postRequest(bytes32 _radHash, bytes32 _slaHash) - virtual override - public payable - checkReward(estimateBaseFee(_getGasPrice(), 32)) - returns (uint256 _queryId) + /// Gets the whole Query data contents, if any, no matter its current status. + function getQueryData(uint256 _queryId) + external view + override + returns (Witnet.Query memory) { - _queryId = __postRequest(_radHash, _slaHash); - // Let observers know that a new request has been posted - emit NewQuery(_queryId, _getMsgValue()); + return __storage().queries[_queryId]; } - /// @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-provided result to this request. - /// @dev Fails if provided reward is too low. - /// @dev The result to the query will be saved into the WitnetRequestBoard storage. - /// @param _radHash 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 _radHash, - WitnetV2.RadonSLA calldata _querySLA - ) - virtual override - public payable - checkReward(estimateBaseFee(_getGasPrice(), 32)) - checkSLA(_querySLA) + /// Gets current status of given query. + function getQueryStatus(uint256 _queryId) + external view + override + returns (Witnet.QueryStatus) + { + return _statusOf(_queryId); + + } + + /// 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 getQueryRequest(uint256 _queryId) + external view + override + inStatus(_queryId, Witnet.QueryStatus.Posted) + returns (Witnet.Request memory) + { + return __seekQueryRequest(_queryId); + } + + /// 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 getQueryRequestBytecode(uint256 _queryId) + external view + virtual override + returns (bytes memory _bytecode) + { + require( + _statusOf(_queryId) != Witnet.QueryStatus.Unknown, + "WitnetRequestBoardTrustableBase: not yet posted" + ); + Witnet.Request storage __request = __seekQueryRequest(_queryId); + if (__request._addr != address(0)) { + _bytecode = IWitnetRequest(__request._addr).bytecode(); + } else if (__request.radHash != bytes32(0)) { + _bytecode = registry().bytecodeOf(__request.radHash); + } + } + + /// 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 getQueryResponse(uint256 _queryId) + external view + override + inStatus(_queryId, Witnet.QueryStatus.Reported) + returns (Witnet.Response memory _response) + { + return __seekQueryResponse(_queryId); + } + + /// 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 getQueryResponseResult(uint256 _queryId) + external view + override + inStatus(_queryId, Witnet.QueryStatus.Reported) + returns (Witnet.Result memory) + { + Witnet.Response storage _response = __seekQueryResponse(_queryId); + return _response.cborBytes.resultFromCborBytes(); + } + + /// 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 getQueryReward(uint256 _queryId) + external view + override + inStatus(_queryId, Witnet.QueryStatus.Posted) + returns (uint256) + { + return __seekQueryRequest(_queryId).evmReward; + } + + /// Returns next request id to be generated by the Witnet Request Board. + function getNextQueryId() + external view + override + returns (uint256) + { + return __storage().nonce + 1; + } + + /// 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) + virtual override + external payable + checkReward(estimateBaseFee(_getGasPrice(), 32)) + returns (uint256 _queryId) + { + _queryId = __postRequest(_radHash, _slaHash); + // Let observers know that a new request has been posted + emit NewQuery(_queryId, _getMsgValue()); + } + + /// @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-provided result to this request. + /// @dev Fails if provided reward is too low. + /// @dev The result to the query will be saved into the WitnetRequestBoard storage. + /// @param _radHash 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 _radHash, + WitnetV2.RadonSLA calldata _querySLA + ) + virtual override + external payable + checkReward(estimateBaseFee(_getGasPrice(), 32)) + checkSLA(_querySLA) returns (uint256 _queryId) { _queryId = __postRequest( @@ -559,7 +442,7 @@ abstract contract WitnetRequestBoardTrustableBase WitnetV2.RadonSLA calldata _querySLA ) virtual override - public payable + external payable checkReward(estimateBaseFee(_getGasPrice(), 32)) checkSLA(_querySLA) returns (uint256 _queryId) @@ -610,7 +493,7 @@ abstract contract WitnetRequestBoardTrustableBase /// @dev reward value gets below new recalculated threshold. /// @param _queryId The unique query identifier. function upgradeQueryReward(uint256 _queryId) - public payable + external payable virtual override inStatus(_queryId, Witnet.QueryStatus.Posted) { @@ -619,109 +502,222 @@ abstract contract WitnetRequestBoardTrustableBase emit QueryRewardUpgraded(_queryId, __request.evmReward); } - + // ================================================================================================================ - // --- 'IWitnetRequestBoard' Viewer methods ----------------------------------------------------------------------- + // --- Full implementation of IWitnetRequestBoardReporter --------------------------------------------------------- - /// Returns next request id to be generated by the Witnet Request Board. - function getNextQueryId() - external view + /// Reports the Witnet-provided result to a previously posted request. + /// @dev Will assume `block.timestamp` as the timestamp at which the request was solved. + /// @dev Fails if: + /// @dev - the `_queryId` is not in 'Posted' status. + /// @dev - provided `_drTxHash` is zero; + /// @dev - length of provided `_result` is zero. + /// @param _queryId The unique identifier of the data request. + /// @param _drTxHash The hash of the solving tally transaction in Witnet. + /// @param _cborBytes The result itself as bytes. + function reportResult( + uint256 _queryId, + bytes32 _drTxHash, + bytes calldata _cborBytes + ) + external override + onlyReporters + inStatus(_queryId, Witnet.QueryStatus.Posted) returns (uint256) { - return __storage().nonce + 1; + require( + _drTxHash != 0, + "WitnetRequestBoardTrustableDefault: Witnet drTxHash cannot be zero" + ); + // Ensures the result bytes do not have zero length + // This would not be a valid encoding with CBOR and could trigger a reentrancy attack + require( + _cborBytes.length != 0, + "WitnetRequestBoardTrustableDefault: result cannot be empty" + ); + // Do actual report: + // solhint-disable not-rely-on-time + return __reportResultAndReward( + _queryId, + block.timestamp, + _drTxHash, + _cborBytes + ); } - /// Gets the whole Query data contents, if any, no matter its current status. - function getQueryData(uint256 _queryId) - external view - override - returns (Witnet.Query memory) + /// Reports the Witnet-provided result to a previously posted request. + /// @dev Fails if: + /// @dev - called from unauthorized address; + /// @dev - the `_queryId` is not in 'Posted' status. + /// @dev - provided `_drTxHash` is zero; + /// @dev - length of provided `_result` is zero. + /// @param _queryId The unique query identifier + /// @param _timestamp The timestamp of the solving tally transaction in Witnet. + /// @param _drTxHash The hash of the solving tally transaction in Witnet. + /// @param _cborBytes The result itself as bytes. + function reportResult( + uint256 _queryId, + uint256 _timestamp, + bytes32 _drTxHash, + bytes calldata _cborBytes + ) + external + override + onlyReporters + inStatus(_queryId, Witnet.QueryStatus.Posted) + returns (uint256) { - return __storage().queries[_queryId]; + require( + _timestamp <= block.timestamp, + "WitnetRequestBoardTrustableDefault: bad timestamp" + ); + require( + _drTxHash != 0, + "WitnetRequestBoardTrustableDefault: Witnet drTxHash cannot be zero" + ); + // Ensures the result bytes do not have zero length (this would not be a valid CBOR encoding + // and could trigger a reentrancy attack) + require( + _cborBytes.length != 0, + "WitnetRequestBoardTrustableDefault: result cannot be empty" + ); + // Do actual report and return reward transfered to the reproter: + return __reportResultAndReward( + _queryId, + _timestamp, + _drTxHash, + _cborBytes + ); } - /// Gets current status of given query. - function getQueryStatus(uint256 _queryId) - external view + /// Reports Witnet-provided results to multiple requests within a single EVM tx. + /// @dev Fails if called from unauthorized address. + /// @dev Emits a PostedResult event for every succesfully reported result, if any. + /// @param _batchResults Array of BatchedResult structs, every one containing: + /// - unique query identifier; + /// - timestamp of the solving tally txs in Witnet. If zero is provided, EVM-timestamp will be used instead; + /// - hash of the corresponding data request tx at the Witnet side-chain level; + /// - data request result in raw bytes. + /// @param _verbose If true, emits a BatchReportError event for every failing report, if any. + function reportResultBatch( + IWitnetRequestBoardReporter.BatchResult[] calldata _batchResults, + bool _verbose + ) + external override - returns (Witnet.QueryStatus) + onlyReporters + returns (uint256 _batchReward) { - return _statusOf(_queryId); - + for ( uint _i = 0; _i < _batchResults.length; _i ++) { + if (_statusOf(_batchResults[_i].queryId) != Witnet.QueryStatus.Posted) { + if (_verbose) { + emit BatchReportError( + _batchResults[_i].queryId, + "WitnetRequestBoardTrustableBase: bad queryId" + ); + } + } else if (_batchResults[_i].drTxHash == 0) { + if (_verbose) { + emit BatchReportError( + _batchResults[_i].queryId, + "WitnetRequestBoardTrustableBase: bad drTxHash" + ); + } + } else if (_batchResults[_i].cborBytes.length == 0) { + if (_verbose) { + emit BatchReportError( + _batchResults[_i].queryId, + "WitnetRequestBoardTrustableBase: bad cborBytes" + ); + } + } else if (_batchResults[_i].timestamp > 0 && _batchResults[_i].timestamp > block.timestamp) { + if (_verbose) { + emit BatchReportError( + _batchResults[_i].queryId, + "WitnetRequestBoardTrustableBase: bad timestamp" + ); + } + } else { + _batchReward += __reportResult( + _batchResults[_i].queryId, + _batchResults[_i].timestamp == 0 ? block.timestamp : _batchResults[_i].timestamp, + _batchResults[_i].drTxHash, + _batchResults[_i].cborBytes + ); + } + } + // Transfer rewards to all reported results in one single transfer to the reporter: + if (_batchReward > 0) { + __safeTransferTo( + payable(msg.sender), + _batchReward + ); + } } - /// 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 getQueryRequest(uint256 _queryId) - external view + + // ================================================================================================================ + // --- Full implementation of 'IWitnetRequestBoardAdmin' ---------------------------------------------------------- + + /// Gets admin/owner address. + function owner() + public view override - inStatus(_queryId, Witnet.QueryStatus.Posted) - returns (Witnet.Request memory) + returns (address) { - return __seekQueryRequest(_queryId); + return __storage().owner; } - - /// 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 getQueryRequestBytecode(uint256 _queryId) - external view + + /// Transfers ownership. + function transferOwnership(address _newOwner) + public virtual override - returns (bytes memory _bytecode) + onlyOwner { - require( - _statusOf(_queryId) != Witnet.QueryStatus.Unknown, - "WitnetRequestBoardTrustableBase: not yet posted" - ); - Witnet.Request storage __request = __seekQueryRequest(_queryId); - if (__request._addr != address(0)) { - _bytecode = IWitnetRequest(__request._addr).bytecode(); - } else if (__request.radHash != bytes32(0)) { - _bytecode = registry().bytecodeOf(__request.radHash); + address _owner = __storage().owner; + if (_newOwner != _owner) { + __storage().owner = _newOwner; + emit OwnershipTransferred(_owner, _newOwner); } } - /// 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 getQueryResponse(uint256 _queryId) - external view - override - inStatus(_queryId, Witnet.QueryStatus.Reported) - returns (Witnet.Response memory _response) - { - return __seekQueryResponse(_queryId); + + // ================================================================================================================ + // --- Full implementation of 'IWitnetRequestBoardAdminACLs' ------------------------------------------------------ + + /// Tells whether given address is included in the active reporters control list. + /// @param _reporter The address to be checked. + function isReporter(address _reporter) public view override returns (bool) { + return _acls().isReporter_[_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 getQueryResponseResult(uint256 _queryId) - external view + /// Adds given addresses to the active reporters control list. + /// @dev Can only be called from the owner address. + /// @dev Emits the `ReportersSet` event. + /// @param _reporters List of addresses to be added to the active reporters control list. + function setReporters(address[] memory _reporters) + public override - inStatus(_queryId, Witnet.QueryStatus.Reported) - returns (Witnet.Result memory) + onlyOwner { - Witnet.Response storage _response = __seekQueryResponse(_queryId); - return _response.cborBytes.resultFromCborBytes(); + __setReporters(_reporters); } - /// 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 getQueryReward(uint256 _queryId) - external view + /// Removes given addresses from the active reporters control list. + /// @dev Can only be called from the owner address. + /// @dev Emits the `ReportersUnset` event. + /// @param _exReporters List of addresses to be added to the active reporters control list. + function unsetReporters(address[] memory _exReporters) + public override - inStatus(_queryId, Witnet.QueryStatus.Posted) - returns (uint256) + onlyOwner { - return __seekQueryRequest(_queryId).evmReward; + for (uint ix = 0; ix < _exReporters.length; ix ++) { + address _reporter = _exReporters[ix]; + _acls().isReporter_[_reporter] = false; + } + emit ReportersUnset(_exReporters); } diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index e64fe7265..2562195e3 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -26,19 +26,11 @@ interface IWitnetRequestBoard { /// @return _resultDrTxHash Witnet blockchain hash of the commit/reveal act that solved the query. function checkResultTraceability(uint256 queryId) external view returns (uint256 _resultTimestamp, bytes32 _resultDrTxHash); - /// @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, uint256 resultMaxSize) external view returns (uint256); - - /// @notice Retrieves a copy of all Witnet-provided data related to a previously posted request, - /// removing the whole query from the WRB 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 fetchQueryResponse(uint256 queryId) external returns (Witnet.Response memory); /// @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. @@ -51,6 +43,51 @@ interface IWitnetRequestBoard { /// @dev Data requesters should consider upgrading the reward on queries providing no actual earnings. function estimateQueryEarnings(uint256 queryId, uint256 gasPrice) external view returns (int256); + /// @notice Retrieves a copy of all Witnet-provided data related to a previously posted request, + /// removing the whole query from the WRB 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 fetchQueryResponse(uint256 queryId) external returns (Witnet.Response memory); + + /// @notice Gets the whole Query data contents, if any, no matter its current status. + function getQueryData(uint256 queryId) external view returns (Witnet.Query memory); + + /// @notice Gets current status of given query. + function getQueryStatus(uint256 queryId) external view returns (Witnet.QueryStatus); + + /// @notice 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 getQueryRequest(uint256 queryId) external view returns (Witnet.Request memory); + + /// @notice 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 getQueryRequestBytecode(uint256 queryId) external view returns (bytes memory); + + /// @notice Retrieves the whole `Witnet.Response` record referred to a previously posted Witnet Data Request. + /// @dev Fails if the `queryId` is not in 'Reported' status. + /// @param queryId The unique query identifier. + function getQueryResponse(uint256 queryId) external view returns (Witnet.Response memory); + + /// @notice 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 getQueryResponseResult(uint256 queryId) external view returns (Witnet.Result memory); + + /// @notice Returns next query id to be generated by the Witnet Request Board. + function getNextQueryId() external view returns (uint256); + + /// @notice Retrieves the reward currently set for the referred query. + /// @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 getQueryReward(uint256 queryId) 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-provided result to this request. @@ -95,48 +132,7 @@ interface IWitnetRequestBoard { /// @notice Increments the reward of a previously posted request by adding the transaction value to it. /// @param queryId The unique query identifier. function upgradeQueryReward(uint256 queryId) external payable; - - - /// =============================================================================================================== - /// --- Reader interface ------------------------------------------------------------------------------------------ - - /// @notice Returns next query id to be generated by the Witnet Request Board. - function getNextQueryId() external view returns (uint256); - - /// @notice Gets the whole Query data contents, if any, no matter its current status. - function getQueryData(uint256 queryId) external view returns (Witnet.Query memory); - - /// @notice Gets current status of given query. - function getQueryStatus(uint256 queryId) external view returns (Witnet.QueryStatus); - - /// @notice 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 getQueryRequest(uint256 queryId) external view returns (Witnet.Request memory); - - /// @notice 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 getQueryRequestBytecode(uint256 queryId) external view returns (bytes memory); - /// @notice Retrieves the whole `Witnet.Response` record referred to a previously posted Witnet Data Request. - /// @dev Fails if the `queryId` is not in 'Reported' status. - /// @param queryId The unique query identifier. - function getQueryResponse(uint256 queryId) external view returns (Witnet.Response memory); - - /// @notice 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 getQueryResponseResult(uint256 queryId) external view returns (Witnet.Result memory); - - /// @notice Retrieves the reward currently set for the referred query. - /// @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 getQueryReward(uint256 queryId) external view returns (uint256); /// =============================================================================================================== /// --- Deprecating methods --------------------------------------------------------------------------------------- From 7c2c088354252767fb54fa5ba7732301b1c03673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Sat, 25 Nov 2023 10:03:36 +0100 Subject: [PATCH 63/86] refactor: *Query* events -> *WitnetQuery* --- .../defaults/WitnetRequestBoardTrustableBase.sol | 12 ++++++------ contracts/interfaces/IWitnetRequestBoardEvents.sol | 11 ++++++----- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index 08adaa0f0..f4997e202 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -400,7 +400,7 @@ abstract contract WitnetRequestBoardTrustableBase { _queryId = __postRequest(_radHash, _slaHash); // Let observers know that a new request has been posted - emit NewQuery(_queryId, _getMsgValue()); + emit NewWitnetQuery(_queryId, _getMsgValue()); } /// @notice Requests the execution of the given Witnet Data Request, in expectation that it will be relayed and @@ -426,7 +426,7 @@ abstract contract WitnetRequestBoardTrustableBase _querySLA.packed() ); // Let observers know that a new request has been posted - emit NewQuery(_queryId, _getMsgValue()); + emit NewWitnetQuery(_queryId, _getMsgValue()); } /// @notice Requests the execution of the given Witnet Data Request bytecode, in expectation that it will be relayed and @@ -499,7 +499,7 @@ abstract contract WitnetRequestBoardTrustableBase { Witnet.Request storage __request = __seekQueryRequest(_queryId); __request.evmReward += _getMsgValue(); - emit QueryRewardUpgraded(_queryId, __request.evmReward); + emit WitnetQueryRewardUpgraded(_queryId, __request.evmReward); } @@ -821,7 +821,7 @@ abstract contract WitnetRequestBoardTrustableBase } if (_evmCallbackSuccess) { // => the callback run successfully - emit QueryCallback( + emit WitnetResponseDelivered( _queryId, _getGasPrice(), _evmCallbackActualGas - gasleft() @@ -830,7 +830,7 @@ abstract contract WitnetRequestBoardTrustableBase delete __storage().queries[_queryId]; } else { // => the callback reverted - emit QueryCallbackRevert( + emit WitnetResponseDeliveryFailed( _queryId, _getGasPrice(), _evmCallbackActualGas - gasleft(), @@ -843,7 +843,7 @@ abstract contract WitnetRequestBoardTrustableBase } } else { // => no callback is involved - emit QueryReport( + emit WitnetQueryReported( _queryId, _getGasPrice() ); diff --git a/contracts/interfaces/IWitnetRequestBoardEvents.sol b/contracts/interfaces/IWitnetRequestBoardEvents.sol index e711ffce3..ad5ac37e5 100644 --- a/contracts/interfaces/IWitnetRequestBoardEvents.sol +++ b/contracts/interfaces/IWitnetRequestBoardEvents.sol @@ -2,21 +2,22 @@ pragma solidity >=0.7.0 <0.9.0; interface IWitnetRequestBoardEvents { + /// Emitted every time a new query containing some verified data request is posted to the WRB. - event NewQuery(uint256 indexed id, uint256 evmReward); + event NewWitnetQuery(uint256 indexed id, uint256 evmReward); /// Emitted every time a new query containing non-verified data request is posted to the WRB. event NewQueryWithBytecode(uint256 indexed id, uint256 evmReward, bytes radBytecode); /// Emitted when the reward of some not-yet reported query is upgraded. - event QueryRewardUpgraded(uint256 indexed id, uint256 evmReward); + event WitnetQueryRewardUpgraded(uint256 indexed id, uint256 evmReward); /// Emitted when a query with no callback gets reported into the WRB. - event QueryReport(uint256 indexed id, uint256 evmGasPrice); + event WitnetQueryReported(uint256 indexed id, uint256 evmGasPrice); /// Emitted when a query with a callback gets successfully reported into the WRB. - event QueryCallback(uint256 indexed id, uint256 evmGasPrice, uint256 evmCallbackGas); + event WitnetResponseDelivered(uint256 indexed id, uint256 evmGasPrice, uint256 evmCallbackGas); /// Emitted when a query with a callback cannot get reported into the WRB. - event QueryCallbackRevert(uint256 indexed id, uint256 evmGasPrice, uint256 evmCallbackGas, string evmReason); + event WitnetResponseDeliveryFailed(uint256 indexed id, uint256 evmGasPrice, uint256 evmCallbackGas, string evmReason); } From edea9e874d0989bc9c8213a73c928e39e8ba4050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Sat, 25 Nov 2023 10:18:18 +0100 Subject: [PATCH 64/86] refactor: IWRB.checkResult* -> IWRB.getQuery* --- contracts/apps/UsingWitnet.sol | 8 +- contracts/apps/WitnetPriceFeeds.sol | 8 +- contracts/apps/WitnetRandomness.sol | 4 +- .../WitnetRequestBoardTrustableBase.sol | 188 ++++++++++-------- contracts/interfaces/IWitnetRequestBoard.sol | 51 +++-- .../interfaces/IWitnetRequestBoardEvents.sol | 6 +- 6 files changed, 142 insertions(+), 123 deletions(-) diff --git a/contracts/apps/UsingWitnet.sol b/contracts/apps/UsingWitnet.sol index c34217ba1..088d67e02 100644 --- a/contracts/apps/UsingWitnet.sol +++ b/contracts/apps/UsingWitnet.sol @@ -66,28 +66,28 @@ abstract contract UsingWitnet return __witnet.estimateBaseFeeWithCallback(tx.gasprice, _resultMaxSize, _maxCallbackGas); } - function _witnetCheckQueryResultTraceability(uint256 _witnetQueryId) + function _witnetCheckQueryResultAuditTrail(uint256 _witnetQueryId) internal view returns ( uint256 _witnetQueryResponseTimestamp, bytes32 _witnetQueryResponseDrTxHash ) { - return __witnet.checkResultTraceability(_witnetQueryId); + return __witnet.getQueryResultAuditTrail(_witnetQueryId); } function _witnetCheckQueryResultStatus(uint256 _witnetQueryId) internal view returns (Witnet.ResultStatus) { - return __witnet.checkResultStatus(_witnetQueryId); + return __witnet.getQueryResultStatus(_witnetQueryId); } function _witnetCheckQueryResultError(uint256 _witnetQueryId) internal view returns (Witnet.ResultError memory) { - return __witnet.checkResultError(_witnetQueryId); + return __witnet.getQueryResultError(_witnetQueryId); } function __witnetRequestData( diff --git a/contracts/apps/WitnetPriceFeeds.sol b/contracts/apps/WitnetPriceFeeds.sol index e229e14cc..13ce07490 100644 --- a/contracts/apps/WitnetPriceFeeds.sol +++ b/contracts/apps/WitnetPriceFeeds.sol @@ -159,7 +159,7 @@ contract WitnetPriceFeeds override external view returns (Witnet.Result memory) { - return witnet.getQueryResponseResult(_latestValidQueryId(feedId)); + return witnet.getQueryResult(_latestValidQueryId(feedId)); } function latestUpdateQueryId(bytes4 feedId) @@ -187,7 +187,7 @@ contract WitnetPriceFeeds override external view returns (Witnet.ResultError memory) { - return witnet.checkResultError(latestUpdateQueryId(feedId)); + return witnet.getQueryResultError(latestUpdateQueryId(feedId)); } function latestUpdateResultStatus(bytes4 feedId) @@ -560,7 +560,7 @@ contract WitnetPriceFeeds returns (Witnet.ResultStatus) { if (_queryId > 0) { - return witnet.checkResultStatus(_queryId); + return witnet.getQueryResultStatus(_queryId); } else { return Witnet.ResultStatus.Ready; } @@ -573,7 +573,7 @@ contract WitnetPriceFeeds uint _latestUpdateQueryId = latestUpdateQueryId(feedId); if ( _latestUpdateQueryId > 0 - && witnet.checkResultStatus(_latestUpdateQueryId) == Witnet.ResultStatus.Ready + && witnet.getQueryResultStatus(_latestUpdateQueryId) == Witnet.ResultStatus.Ready ) { return _latestUpdateQueryId; } else { diff --git a/contracts/apps/WitnetRandomness.sol b/contracts/apps/WitnetRandomness.sol index f82d33a66..3996166e6 100644 --- a/contracts/apps/WitnetRandomness.sol +++ b/contracts/apps/WitnetRandomness.sol @@ -213,9 +213,9 @@ contract WitnetRandomness } uint256 _queryId = __randomize_[_block].witnetQueryId; require(_queryId != 0, "WitnetRandomness: not randomized"); - Witnet.ResultStatus _resultStatus = witnet().checkResultStatus(_queryId); + Witnet.ResultStatus _resultStatus = witnet().getQueryResultStatus(_queryId); if (_resultStatus == Witnet.ResultStatus.Ready) { - return witnet().getQueryResponseResult(_queryId).asBytes32(); + return witnet().getQueryResult(_queryId).asBytes32(); } else if (_resultStatus == Witnet.ResultStatus.Error) { uint256 _nextRandomizeBlock = __randomize_[_block].nextBlock; require(_nextRandomizeBlock != 0, "WitnetRandomness: faulty randomize"); diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index f4997e202..53bd5905e 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -175,74 +175,7 @@ abstract contract WitnetRequestBoardTrustableBase // ================================================================================================================ // --- Partial implementation of IWitnetRequestBoard -------------------------------------------------------------- - - /// @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) - virtual public view - returns (Witnet.ResultStatus) - { - Witnet.QueryStatus _queryStatus = _statusOf(_queryId); - if (_queryStatus == Witnet.QueryStatus.Reported) { - bytes storage __cborValues = __seekQueryResponse(_queryId).cborBytes; - // determine whether reported result is an error by peeking the first byte - return (__cborValues[0] == bytes1(0xd8) - ? Witnet.ResultStatus.Error - : Witnet.ResultStatus.Ready - ); - } else if (_queryStatus == 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) - override external view - returns (Witnet.ResultError memory) - { - Witnet.ResultStatus _status = checkResultStatus(_queryId); - try WitnetErrorsLib.asResultError(_status, __seekQueryResponse(_queryId).cborBytes) - returns (Witnet.ResultError memory _resultError) - { - return _resultError; - } - 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" - }); - } - } - - /// @notice Returns query's result traceability data - /// @param _queryId The unique query identifier. - /// @return _resultTimestamp Timestamp at which the query was solved by the Witnet blockchain. - /// @return _resultDrTxHash Witnet blockchain hash of the commit/reveal act that solved the query. - function checkResultTraceability(uint256 _queryId) - external view - override - returns (uint256, bytes32) - { - Witnet.Response storage __response = __seekQueryResponse(_queryId); - return ( - __response.timestamp, - __response.drTxHash - ); - } - + /// @notice Estimates the actual earnings (or loss), in WEI, that a reporter would get by reporting result to given query, /// @notice based on the gas price of the calling transaction. /// @dev Data requesters should consider upgrading the reward on queries providing no actual earnings. @@ -293,16 +226,6 @@ abstract contract WitnetRequestBoardTrustableBase return __storage().queries[_queryId]; } - /// Gets current status of given query. - function getQueryStatus(uint256 _queryId) - external view - override - returns (Witnet.QueryStatus) - { - return _statusOf(_queryId); - - } - /// 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. @@ -310,7 +233,7 @@ abstract contract WitnetRequestBoardTrustableBase function getQueryRequest(uint256 _queryId) external view override - inStatus(_queryId, Witnet.QueryStatus.Posted) + // inStatus(_queryId, Witnet.QueryStatus.Posted) returns (Witnet.Request memory) { return __seekQueryRequest(_queryId); @@ -344,7 +267,7 @@ abstract contract WitnetRequestBoardTrustableBase function getQueryResponse(uint256 _queryId) external view override - inStatus(_queryId, Witnet.QueryStatus.Reported) + // inStatus(_queryId, Witnet.QueryStatus.Reported) returns (Witnet.Response memory _response) { return __seekQueryResponse(_queryId); @@ -353,16 +276,83 @@ abstract contract WitnetRequestBoardTrustableBase /// 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 getQueryResponseResult(uint256 _queryId) + function getQueryResult(uint256 _queryId) external view override - inStatus(_queryId, Witnet.QueryStatus.Reported) + // inStatus(_queryId, Witnet.QueryStatus.Reported) returns (Witnet.Result memory) { Witnet.Response storage _response = __seekQueryResponse(_queryId); return _response.cborBytes.resultFromCborBytes(); } + /// @notice Returns query's result traceability data + /// @param _queryId The unique query identifier. + /// @return _resultTimestamp Timestamp at which the query was solved by the Witnet blockchain. + /// @return _resultDrTxHash Witnet blockchain hash of the commit/reveal act that solved the query. + function getQueryResultAuditTrail(uint256 _queryId) + external view + override + returns (uint256, bytes32) + { + Witnet.Response storage __response = __seekQueryResponse(_queryId); + return ( + __response.timestamp, + __response.drTxHash + ); + } + + /// @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) + override external view + returns (Witnet.ResultError memory) + { + Witnet.ResultStatus _status = getQueryResultStatus(_queryId); + try WitnetErrorsLib.asResultError(_status, __seekQueryResponse(_queryId).cborBytes) + returns (Witnet.ResultError memory _resultError) + { + return _resultError; + } + 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" + }); + } + } + + /// @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 getQueryResultStatus(uint256 _queryId) + virtual public view + returns (Witnet.ResultStatus) + { + Witnet.QueryStatus _queryStatus = _statusOf(_queryId); + if (_queryStatus == Witnet.QueryStatus.Reported) { + bytes storage __cborValues = __seekQueryResponse(_queryId).cborBytes; + // determine whether reported result is an error by peeking the first byte + return (__cborValues[0] == bytes1(0xd8) + ? Witnet.ResultStatus.Error + : Witnet.ResultStatus.Ready + ); + } else if (_queryStatus == Witnet.QueryStatus.Posted) { + return Witnet.ResultStatus.Awaiting; + } else { + return Witnet.ResultStatus.Void; + } + } + /// 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. @@ -376,6 +366,16 @@ abstract contract WitnetRequestBoardTrustableBase return __seekQueryRequest(_queryId).evmReward; } + /// Gets current status of given query. + function getQueryStatus(uint256 _queryId) + external view + override + returns (Witnet.QueryStatus) + { + return _statusOf(_queryId); + + } + /// Returns next request id to be generated by the Witnet Request Board. function getNextQueryId() external view @@ -481,7 +481,29 @@ abstract contract WitnetRequestBoardTrustableBase _querySLA.packed() ); __seekQueryRequest(_queryId).maxCallbackGas = _queryMaxCallbackGas; - emit NewQuery(_queryId, _getMsgValue()); + emit NewWitnetQuery(_queryId, _getMsgValue()); + } + + function retryQuery(uint256 _queryId) + virtual override + external payable + inStatus(_queryId, Witnet.QueryStatus.Reported) + onlyRequester(_queryId) + returns (uint256 _newQuery) + { + _newQuery = __newQuery(); + __storage().queries[_newQuery] = __storage().queries[_queryId]; + // todo ... + } + + function retryQueryWithCallback(uint256 _queryId, uint256) + virtual override + external payable + inStatus(_queryId, Witnet.QueryStatus.Reported) + onlyRequester(_queryId) + returns (uint256) + { + // TODO } /// Increments the reward of a previously posted request by adding the transaction value to it. diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index 2562195e3..57aa59dfd 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -4,27 +4,6 @@ pragma solidity >=0.7.0 <0.9.0; import "../libs/WitnetV2.sol"; interface IWitnetRequestBoard { - - /// =============================================================================================================== - /// --- Requester interface --------------------------------------------------------------------------------------- - - /// @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 view returns (Witnet.ResultError 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 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) external view returns (Witnet.ResultStatus); - - /// @notice Returns query's result traceability data - /// @param queryId The unique query identifier. - /// @return _resultTimestamp Timestamp at which the query was solved by the Witnet blockchain. - /// @return _resultDrTxHash Witnet blockchain hash of the commit/reveal act that solved the query. - function checkResultTraceability(uint256 queryId) external view returns (uint256 _resultTimestamp, bytes32 _resultDrTxHash); /// @notice Estimate the minimum reward required for posting a data request. /// @dev Underestimates if the size of returned data is greater than `resultMaxSize`. @@ -53,9 +32,6 @@ interface IWitnetRequestBoard { /// @notice Gets the whole Query data contents, if any, no matter its current status. function getQueryData(uint256 queryId) external view returns (Witnet.Query memory); - /// @notice Gets current status of given query. - function getQueryStatus(uint256 queryId) external view returns (Witnet.QueryStatus); - /// @notice 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. @@ -77,10 +53,25 @@ interface IWitnetRequestBoard { /// @notice 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 getQueryResponseResult(uint256 queryId) external view returns (Witnet.Result memory); + function getQueryResult(uint256 queryId) external view returns (Witnet.Result memory); - /// @notice Returns next query id to be generated by the Witnet Request Board. - function getNextQueryId() external view returns (uint256); + /// @notice Returns query's result traceability data + /// @param queryId The unique query identifier. + /// @return _resultTimestamp Timestamp at which the query was solved by the Witnet blockchain. + /// @return _resultDrTxHash Witnet blockchain hash of the commit/reveal act that solved the query. + function getQueryResultAuditTrail(uint256 queryId) external view returns (uint256 _resultTimestamp, bytes32 _resultDrTxHash); + + /// @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 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 getQueryResultStatus(uint256 queryId) external view returns (Witnet.ResultStatus); /// @notice Retrieves the reward currently set for the referred query. /// @dev Fails if the `queryId` is not valid or, if it has already been @@ -88,6 +79,12 @@ interface IWitnetRequestBoard { /// @param queryId The unique query identifier. function getQueryReward(uint256 queryId) external view returns (uint256); + /// @notice Gets current status of given query. + function getQueryStatus(uint256 queryId) external view returns (Witnet.QueryStatus); + + /// @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-provided result to this request. diff --git a/contracts/interfaces/IWitnetRequestBoardEvents.sol b/contracts/interfaces/IWitnetRequestBoardEvents.sol index ad5ac37e5..ffc1b84fe 100644 --- a/contracts/interfaces/IWitnetRequestBoardEvents.sol +++ b/contracts/interfaces/IWitnetRequestBoardEvents.sol @@ -8,13 +8,13 @@ interface IWitnetRequestBoardEvents { /// Emitted every time a new query containing non-verified data request is posted to the WRB. event NewQueryWithBytecode(uint256 indexed id, uint256 evmReward, bytes radBytecode); - - /// Emitted when the reward of some not-yet reported query is upgraded. - event WitnetQueryRewardUpgraded(uint256 indexed id, uint256 evmReward); /// Emitted when a query with no callback gets reported into the WRB. event WitnetQueryReported(uint256 indexed id, uint256 evmGasPrice); + /// Emitted when the reward of some not-yet reported query is upgraded. + event WitnetQueryRewardUpgraded(uint256 indexed id, uint256 evmReward); + /// Emitted when a query with a callback gets successfully reported into the WRB. event WitnetResponseDelivered(uint256 indexed id, uint256 evmGasPrice, uint256 evmCallbackGas); From 901843636352a657875eb95134c85e2059d5db65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Tue, 28 Nov 2023 16:12:27 +0100 Subject: [PATCH 65/86] refactor: IWitnetConsumer, Witnet.Query*, Witnet.Request, Witnet.Response, WitnetV2.RadonSLA --- contracts/data/WitnetRequestBoardData.sol | 33 +- .../IWitnetRequestBoardReporter.sol | 40 +- contracts/interfaces/V2/IWitnetBytecodes.sol | 2 +- contracts/interfaces/V2/IWitnetConsumer.sol | 20 +- contracts/interfaces/V2/IWitnetFeeds.sol | 2 +- .../interfaces/V2/IWitnetPriceSolver.sol | 2 +- contracts/libs/Witnet.sol | 458 ++++++++++-------- contracts/libs/WitnetEncodingLib.sol | 4 +- contracts/libs/WitnetV2.sol | 41 +- 9 files changed, 337 insertions(+), 265 deletions(-) diff --git a/contracts/data/WitnetRequestBoardData.sol b/contracts/data/WitnetRequestBoardData.sol index 5d034a92d..ec9b09be2 100644 --- a/contracts/data/WitnetRequestBoardData.sol +++ b/contracts/data/WitnetRequestBoardData.sol @@ -98,22 +98,19 @@ abstract contract WitnetRequestBoardData { internal view returns (Witnet.QueryStatus) { - Witnet.Query storage _query = __storage().queries[_queryId]; - if (_query.response.drTxHash != 0) { - // Query is in "Reported" status as soon as the hash of the - // Witnet transaction that solved the query is reported - // back from a Witnet bridge: - return Witnet.QueryStatus.Reported; - } - else if (_query.from != address(0)) { - // Otherwise, while address from which the query was posted - // is kept in storage, the query remains in "Posted" status: + Witnet.Query storage __query = __storage().queries[_queryId]; + if (__query.response.tallyHash != bytes32(0)) { + if (__query.response.timestamp != 0) { + if (block.number >= Witnet.unpackEvmFinalityBlock(__query.response.fromFinality)) { + return Witnet.QueryStatus.Finalized; + } else { + return Witnet.QueryStatus.Reported; + } + } else { + return Witnet.QueryStatus.Undeliverable; + } + } else if (__query.request.fromCallbackGas != bytes32(0)) { return Witnet.QueryStatus.Posted; - } - else if (_queryId > __storage().nonce) { - // Requester's address is removed from storage only if - // the query gets "Deleted" by its requester. - return Witnet.QueryStatus.Delivered; } else { return Witnet.QueryStatus.Unknown; } @@ -127,8 +124,10 @@ abstract contract WitnetRequestBoardData { return "WitnetRequestBoard: not in Posted status"; } else if (_status == Witnet.QueryStatus.Reported) { return "WitnetRequestBoard: not in Reported status"; - } else if (_status == Witnet.QueryStatus.Delivered) { - return "WitnetRequestBoard: not in Delivered status"; + } else if (_status == Witnet.QueryStatus.Finalized) { + return "WitnetRequestBoard: not in Finalized status"; + } else if (_status == Witnet.QueryStatus.Undeliverable) { + return "WitnetRequestBoard: not in Undeliverable status"; } else { return "WitnetRequestBoard: bad mood"; } diff --git a/contracts/interfaces/IWitnetRequestBoardReporter.sol b/contracts/interfaces/IWitnetRequestBoardReporter.sol index bb56b3461..ede92a211 100644 --- a/contracts/interfaces/IWitnetRequestBoardReporter.sol +++ b/contracts/interfaces/IWitnetRequestBoardReporter.sol @@ -9,33 +9,33 @@ interface IWitnetRequestBoardReporter { /// @notice Reports the Witnet-provided result to a previously posted request. /// @dev Will assume `block.timestamp` as the timestamp at which the request was solved. /// @dev Fails if: - /// @dev - the `_queryId` is not in 'Posted' status. - /// @dev - provided `_drTxHash` is zero; + /// @dev - the `_witnetQueryId` is not in 'Posted' status. + /// @dev - provided `_tallyHash` is zero; /// @dev - length of provided `_result` is zero. - /// @param _queryId The unique identifier of the data request. - /// @param _drTxHash The hash of the corresponding data request transaction in Witnet. - /// @param _result The result itself as bytes. + /// @param witnetQueryId The unique identifier of the data request. + /// @param witnetResultTallyHash The hash of the corresponding data request transaction in Witnet. + /// @param witnetResultCborBytes The result itself as bytes. function reportResult( - uint256 _queryId, - bytes32 _drTxHash, - bytes calldata _result + uint256 witnetQueryId, + bytes32 witnetResultTallyHash, + bytes calldata witnetResultCborBytes ) external returns (uint256); /// @notice Reports the Witnet-provided result to a previously posted request. /// @dev Fails if: /// @dev - called from unauthorized address; - /// @dev - the `_queryId` is not in 'Posted' status. - /// @dev - provided `_drTxHash` is zero; + /// @dev - the `_witnetQueryId` is not in 'Posted' status. + /// @dev - provided `_tallyHash` is zero; /// @dev - length of provided `_result` is zero. - /// @param _queryId The unique query identifier - /// @param _timestamp The timestamp of the solving tally transaction in Witnet. - /// @param _drTxHash The hash of the corresponding data request transaction in Witnet. - /// @param _result The result itself as bytes. + /// @param witnetQueryId The unique query identifier + /// @param witnetResultTimestamp The timestamp of the solving tally transaction in Witnet. + /// @param witnetResultTallyHash The hash of the corresponding data request transaction in Witnet. + /// @param witnetResultCborBytes The result itself as bytes. function reportResult( - uint256 _queryId, - uint256 _timestamp, - bytes32 _drTxHash, - bytes calldata _result + uint256 witnetQueryId, + uint64 witnetResultTimestamp, + bytes32 witnetResultTallyHash, + bytes calldata witnetResultCborBytes ) external returns (uint256); /// @notice Reports Witnet-provided results to multiple requests within a single EVM tx. @@ -50,8 +50,8 @@ interface IWitnetRequestBoardReporter { struct BatchResult { uint256 queryId; - uint256 timestamp; - bytes32 drTxHash; + uint64 timestamp; + bytes32 tallyHash; bytes cborBytes; } diff --git a/contracts/interfaces/V2/IWitnetBytecodes.sol b/contracts/interfaces/V2/IWitnetBytecodes.sol index d33c22b98..c6d383fec 100644 --- a/contracts/interfaces/V2/IWitnetBytecodes.sol +++ b/contracts/interfaces/V2/IWitnetBytecodes.sol @@ -28,7 +28,7 @@ interface IWitnetBytecodes { function lookupRadonRetrievalResultDataType(bytes32 hash) external view returns (Witnet.RadonDataTypes); function lookupRadonRequestAggregator(bytes32 radHash) external view returns (Witnet.RadonReducer memory); - function lookupRadonRequestResultMaxSize(bytes32 radHash) external view returns (uint256); + function lookupRadonRequestResultMaxSize(bytes32 radHash) external view returns (uint16); 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); diff --git a/contracts/interfaces/V2/IWitnetConsumer.sol b/contracts/interfaces/V2/IWitnetConsumer.sol index b46b84194..8fcc4ce62 100644 --- a/contracts/interfaces/V2/IWitnetConsumer.sol +++ b/contracts/interfaces/V2/IWitnetConsumer.sol @@ -12,16 +12,16 @@ interface IWitnetConsumer { /// @dev can call to the WRB as to retrieve the Witnet tracking information (i.e. the `witnetDrTxHash` /// @dev and `witnetDrCommitTxTimestamp`), or the finality status, of the result being reported. /// @param witnetQueryId The unique identifier of the Witnet query being reported. - /// @param witnetCommitRevealHash Hash of the commit/reveal witnessing act that took place in the Witnet blockahin. - /// @param witnetCommitTimestamp Timestamp when the reported value was captured by the Witnet blockchain. + /// @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 cborValue The CBOR-encoded resulting value of the Witnet query being reported. + /// @param witnetResultCborValue The CBOR-encoded resulting value of the Witnet query being reported. function reportWitnetQueryResult( uint256 witnetQueryId, - bytes32 witnetCommitRevealHash, - uint256 witnetCommitTimestamp, + uint64 witnetResultTimestamp, + bytes32 witnetResultTallyHash, uint256 witnetEvmFinalityBlock, - WitnetCBOR.CBOR calldata cborValue + WitnetCBOR.CBOR calldata witnetResultCborValue ) external; /// @notice Method to be called from the WitnetRequestBoard contract as soon as the given Witnet `queryId` @@ -32,15 +32,15 @@ interface IWitnetConsumer { /// @dev and `witnetDrCommitTxTimestamp`), or the finality status, of the result being reported. /// @param witnetQueryId The unique identifier of the Witnet query being reported. /// @param witnetQueryId The unique identifier of the Witnet query being reported. - /// @param witnetCommitRevealHash Hash of the commit/reveal witnessing act that took place in the Witnet blockahin. - /// @param witnetCommitTimestamp Timestamp when the reported value was captured by the Witnet blockchain. + /// @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, - bytes32 witnetCommitRevealHash, - uint256 witnetCommitTimestamp, + uint64 witnetResultTimestamp, + bytes32 witnetResultTallyHash, uint256 witnetEvmFinalityBlock, Witnet.ResultErrorCodes errorCode, WitnetCBOR.CBOR calldata errorArgs diff --git a/contracts/interfaces/V2/IWitnetFeeds.sol b/contracts/interfaces/V2/IWitnetFeeds.sol index 59807c4b8..e21277fcc 100644 --- a/contracts/interfaces/V2/IWitnetFeeds.sol +++ b/contracts/interfaces/V2/IWitnetFeeds.sol @@ -26,7 +26,7 @@ interface IWitnetFeeds { function latestResult(bytes4 feedId) external view returns (Witnet.Result memory); function latestUpdateQueryId(bytes4 feedId) external view returns (uint256); - function latestUpdateRequest(bytes4 feedId) external view returns (Witnet.Request memory); + function latestUpdateRequest(bytes4 feedId) external view returns (bytes32, WitnetV2.RadonSLA memory); function latestUpdateResponse(bytes4 feedId) external view returns (Witnet.Response memory); function latestUpdateResultError(bytes4 feedId) external view returns (Witnet.ResultError memory); function latestUpdateResultStatus(bytes4 feedId) external view returns (Witnet.ResultStatus); diff --git a/contracts/interfaces/V2/IWitnetPriceSolver.sol b/contracts/interfaces/V2/IWitnetPriceSolver.sol index f6aa7dd58..afa5c8f29 100644 --- a/contracts/interfaces/V2/IWitnetPriceSolver.sol +++ b/contracts/interfaces/V2/IWitnetPriceSolver.sol @@ -8,7 +8,7 @@ interface IWitnetPriceSolver { struct Price { uint value; uint timestamp; - bytes32 drTxHash; + bytes32 tallyHash; Witnet.ResultStatus status; } function delegator() external view returns (address); diff --git a/contracts/libs/Witnet.sol b/contracts/libs/Witnet.sol index 429b9980d..9896ae47a 100644 --- a/contracts/libs/Witnet.sol +++ b/contracts/libs/Witnet.sol @@ -15,7 +15,6 @@ library Witnet { struct Query { Request request; Response response; - address from; // Address from which the request was posted. } /// Possible status of a Witnet query. @@ -23,25 +22,29 @@ library Witnet { Unknown, Posted, Reported, - Delivered + Undeliverable, + Finalized } /// Data kept in EVM-storage for every Request posted to the Witnet Request Board. struct Request { - address _addr; // Deprecating: Formerly used as address of the (deprecated) IWitnetRequest contract. - bytes32 slaPacked; // Radon SLA of the Witnet data request (packed). - bytes32 radHash; // Radon radHash of the Witnet data request. - uint256 _gasprice; // Deprecating: Formerly used as minimum gas price the DR resolver should pay on the solving tx. - uint256 evmReward; // Escrowed reward to be paid to the DR resolver. - uint256 maxCallbackGas; // Maximum gas to be spent when reporting the data request result. + bytes32 fromCallbackGas; // Packed: contains requester address in most significant bytes20, + // and max callback gas limit if a callback is required. + bytes32 SLA; // Packed: Service-Level Aggreement parameters upon which the data request + // will be solved by the Witnet blockchain. + bytes32 RAD; // Verified hash of the actual data request to be solved by the Witnet blockchain. + uint256 reserved1; // Reserved uint256 slot. + uint256 evmReward; // EVM reward to be paid to the relayer of the Witnet resolution to the data request. + bytes bytecode; // Raw bytecode of the data request to be solved by the Witnet blockchain (only if not yet verified). } /// Data kept in EVM-storage containing Witnet-provided response metadata and result. struct Response { - address reporter; // Address from which the result was reported. - uint256 timestamp; // Timestamp of the Witnet-provided result. - bytes32 drTxHash; // Hash of the Witnet transaction that solved the queried Data Request. - bytes cborBytes; // Witnet-provided result CBOR-bytes to the queried Data Request. + bytes32 fromFinality; // Packed: contains address from which the result to the data request was reported, and + // the EVM block at which the provided result can be considered to be final. + uint256 timestamp; // Timestamp at which data from data sources were retrieved by the Witnet blockchain. + bytes32 tallyHash; // Hash of the Witnet commit/reveal act that solved the data request. + bytes cborBytes; // CBOR-encoded result to the data request, as resolved by the Witnet blockchain. } /// Data struct containing the Witnet-provided result to a Data Request. @@ -55,7 +58,9 @@ library Witnet { Void, Awaiting, Ready, - Error + Error, + AwaitingReady, + AwaitingError } /// Data struct describing an error when trying to fetch a Witnet-provided result to a Data Request. @@ -276,67 +281,220 @@ library Witnet { uint64 minerCommitRevealFee; } - /// @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) + + /// =============================================================================================================== + /// --- '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) { - return ( - a.numWitnesses >= b.numWitnesses - && a.minConsensusPercentage >= b.minConsensusPercentage - && a.witnessReward >= b.witnessReward - && a.witnessCollateral >= b.witnessCollateral - && a.minerCommitRevealFee >= b.minerCommitRevealFee - ); + 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); } - function isValid(Witnet.RadonSLA memory sla) - internal pure returns (bool) + /// @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) { - return ( - sla.witnessReward > 0 - && sla.numWitnesses > 0 && sla.numWitnesses <= 127 - && sla.minConsensusPercentage > 50 && sla.minConsensusPercentage < 100 - && sla.witnessCollateral > 0 - && sla.witnessCollateral / sla.witnessReward <= 127 - ); + 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); + } } - function packed(RadonSLA memory sla) internal pure returns (bytes32) { - return bytes32( - uint(sla.witnessReward) - | sla.witnessCollateral << 64 - | sla.minerCommitRevealFee << 128 - | sla.numWitnesses << 248 - | sla.minConsensusPercentage << 232 - ); + /// @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); } - function toRadonSLA(bytes32 _packed) internal pure returns (RadonSLA memory) { - return RadonSLA({ - numWitnesses: uint8(uint(_packed >> 248)), - minConsensusPercentage: uint8(uint(_packed >> 232) & 0xff), - witnessReward: uint64(uint(_packed) & 0xffffffffffffffff), - witnessCollateral: uint64(uint(_packed >> 64) & 0xffffffffffffffff), - minerCommitRevealFee: uint64(uint(_packed >> 128) & 0xffffffffffffffff) - }); + + /// =============================================================================================================== + /// --- '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 totalWitnessingReward(Witnet.RadonSLA memory sla) - internal pure returns (uint64) + 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) { - return sla.witnessReward * sla.numWitnesses; + 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); + } + } } /// =============================================================================================================== - /// --- 'Witnet.Result' helper methods ---------------------------------------------------------------------------- + /// --- 'string' helper methods ----------------------------------------------------------------------------------- - modifier _isError(Result memory result) { - require(!result.success, "Witnet: no actual errors"); - _; + 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.Request' helper methods --------------------------------------------------------------------------- + + function packRequesterCallbackGasLimit(address requester, uint96 callbackGasLimit) internal pure returns (bytes32) { + return bytes32(uint(bytes32(bytes20(requester))) | callbackGasLimit); + } + + function unpackRequester(Request storage self) internal view returns (address) { + return address(bytes20(self.fromCallbackGas)); + } + + function unpackCallbackGasLimit(Request storage self) internal view returns (uint96) { + return uint96(uint(self.fromCallbackGas)); + } + + function unpackRequesterAndCallbackGasLimit(Request storage self) internal view returns (address, uint96) { + bytes32 _packed = self.fromCallbackGas; + return (address(bytes20(_packed)), uint96(uint(_packed))); + } + + + /// =============================================================================================================== + /// --- 'Witnet.Response' helper methods -------------------------------------------------------------------------- + + function packReporterEvmFinalityBlock(address reporter, uint256 evmFinalityBlock) internal pure returns (bytes32) { + return bytes32(uint(bytes32(bytes20(reporter))) << 96 | uint96(evmFinalityBlock)); + } + + function unpackWitnetReporter(Response storage self) internal view returns (address) { + return address(bytes20(self.fromFinality)); } + function unpackEvmFinalityBlock(Response storage self) internal view returns (uint256) { + return uint(uint96(uint(self.fromFinality))); + } + + function unpackEvmFinalityBlock(bytes32 fromFinality) internal pure returns (uint256) { + return uint(uint96(uint(fromFinality))); + } + + function unpackWitnetReporterAndEvmFinalityBlock(Response storage self) internal view returns (address, uint256) { + bytes32 _packed = self.fromFinality; + return (address(bytes20(_packed)), uint(uint96(uint(_packed)))); + } + + + /// =============================================================================================================== + /// --- 'Witnet.Result' helper methods ---------------------------------------------------------------------------- + modifier _isReady(Result memory result) { require(result.success, "Witnet: tried to decode value from errored result."); _; @@ -496,166 +654,58 @@ 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); - } + /// --- 'Witnet.RadonSLA' helper methods -------------------------------------------------------------------------- - /// @notice Converts bytes32 into string. - function toString(bytes32 _bytes32) - internal pure - returns (string memory) + /// @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) { - bytes memory _bytes = new bytes(_toStringLength(_bytes32)); - for (uint _i = 0; _i < _bytes.length;) { - _bytes[_i] = _bytes32[_i]; - unchecked { - _i ++; - } - } - return string(_bytes); + return ( + a.numWitnesses >= b.numWitnesses + && a.minConsensusPercentage >= b.minConsensusPercentage + && a.witnessReward >= b.witnessReward + && a.witnessCollateral >= b.witnessCollateral + && a.minerCommitRevealFee >= b.minerCommitRevealFee + ); } - function tryUint(string memory str) - internal pure - returns (uint res, bool) + function isValid(Witnet.RadonSLA memory sla) + internal pure returns (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); - } + return ( + sla.witnessReward > 0 + && sla.numWitnesses > 0 && sla.numWitnesses <= 127 + && sla.minConsensusPercentage > 50 && sla.minConsensusPercentage < 100 + && sla.witnessCollateral > 0 + && sla.witnessCollateral / sla.witnessReward <= 127 + ); } - - /// =============================================================================================================== - /// --- '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); + function toBytes32(RadonSLA memory sla) internal pure returns (bytes32) { + return bytes32( + uint(sla.witnessReward) + | sla.witnessCollateral << 64 + | sla.minerCommitRevealFee << 128 + | sla.numWitnesses << 248 + | sla.minConsensusPercentage << 232 + ); } - /// @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); - } + function toRadonSLA(bytes32 _packed) internal pure returns (RadonSLA memory) { + return RadonSLA({ + numWitnesses: uint8(uint(_packed >> 248)), + minConsensusPercentage: uint8(uint(_packed >> 232) & 0xff), + witnessReward: uint64(uint(_packed) & 0xffffffffffffffff), + witnessCollateral: uint64(uint(_packed >> 64) & 0xffffffffffffffff), + minerCommitRevealFee: uint64(uint(_packed >> 128) & 0xffffffffffffffff) + }); } - /// @notice Convert a `uint` into a string` representing its value. - function toString(uint v) - internal pure - returns (string memory) + function totalWitnessingReward(Witnet.RadonSLA memory sla) + internal pure returns (uint64) { - 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); + return sla.witnessReward * sla.numWitnesses; } diff --git a/contracts/libs/WitnetEncodingLib.sol b/contracts/libs/WitnetEncodingLib.sol index 654e6f4ac..ba679d55f 100644 --- a/contracts/libs/WitnetEncodingLib.sol +++ b/contracts/libs/WitnetEncodingLib.sol @@ -366,7 +366,7 @@ library WitnetEncodingLib { || dataType == Witnet.RadonDataTypes.Array || dataType == Witnet.RadonDataTypes.Map ) { - if (/*maxDataSize == 0 ||*/maxDataSize > 2048) { + if (maxDataSize == 0) { revert UnsupportedRadonDataType( uint8(dataType), maxDataSize @@ -378,7 +378,7 @@ library WitnetEncodingLib { || dataType == Witnet.RadonDataTypes.Float || dataType == Witnet.RadonDataTypes.Bool ) { - return 0; // TBD: size(dataType); + return 9; // TBD: size(dataType); } else { revert UnsupportedRadonDataType( uint8(dataType), diff --git a/contracts/libs/WitnetV2.sol b/contracts/libs/WitnetV2.sol index 4a20b2943..43fb46db2 100644 --- a/contracts/libs/WitnetV2.sol +++ b/contracts/libs/WitnetV2.sol @@ -14,30 +14,37 @@ library WitnetV2 { uint256 internal constant _WITNET_2_0_TIMESTAMP = _WITNET_GENESIS_TIMESTAMP + _WITNET_2_0_EPOCH * _WITNET_GENESIS_EPOCH_SECONDS; struct RadonSLA { - uint8 numWitnesses; - uint8 witnessingCollateralRatio; + /// @dev Number of witnessing nodes that will take part in the resolution of a data request within the Witnet blockchain: + uint8 witnessingCommitteeSize; + /// @dev Collateral-to-reward ratio that witnessing nodes will have to commit with when taking part in a data request resolution. + uint8 witnessingCollateralRatio; + /// @dev Minimum amount of $nanoWIT that all Witnet nodes participating in the resolution of a data request will receive as a reward: + uint64 witnessingWitReward; } function equalOrGreaterThan(RadonSLA memory a, RadonSLA memory b) internal pure returns (bool) { return ( - a.numWitnesses * a.witnessingCollateralRatio - >= b.numWitnesses * b.witnessingCollateralRatio + a.witnessingCommitteeSize * a.witnessingCollateralRatio * a.witnessingWitReward + >= b.witnessingCommitteeSize * b.witnessingCollateralRatio * b.witnessingWitReward ); } function isValid(RadonSLA calldata sla) internal pure returns (bool) { return ( - sla.numWitnesses > 0 && sla.numWitnesses <= 127 + sla.witnessingWitReward > 0 + && sla.witnessingCommitteeSize > 0 && sla.witnessingCommitteeSize <= 127 && sla.witnessingCollateralRatio > 0 && sla.witnessingCollateralRatio <= 127 ); } - function packed(RadonSLA memory sla) internal pure returns (bytes32) { + function toBytes32(RadonSLA memory sla) internal pure returns (bytes32) { return bytes32( - uint(sla.numWitnesses) << 248 + uint(sla.witnessingCommitteeSize) << 248 | uint(sla.witnessingCollateralRatio) << 240 + // | uint(sla.witnessingNotBeforeTimestamp) << 64 + | uint(sla.witnessingWitReward) ); } @@ -45,11 +52,27 @@ library WitnetV2 { internal pure returns (RadonSLA memory) { return RadonSLA({ - numWitnesses: uint8(uint(_packed) >> 248), - witnessingCollateralRatio: uint8(uint(_packed) >> 240) + witnessingCommitteeSize: uint8(uint(_packed) >> 248), + witnessingCollateralRatio: uint8(uint(_packed) >> 240), + // witnessingNotBeforeTimestamp: uint64(uint(_packed) >> 64), + witnessingWitReward: uint64(uint(_packed)) }); } + function totalWitnessingReward(WitnetV2.RadonSLA calldata sla) internal pure returns (uint64) { + return ( + (3 + sla.witnessingCommitteeSize) + * sla.witnessingWitReward + ); + } + + function totalWitnessingReward(bytes32 _packed) internal pure returns (uint64) { + return ( + (3 + (uint8(uint(_packed) << 248))) // 3 + witnessingCommitteSize + * uint64(uint(_packed)) // witnessingWitReward + ); + } + function timestampToWitnetEpoch(uint _timestamp) internal pure returns (uint) { if (_timestamp > _WITNET_2_0_TIMESTAMP ) { return ( From fce673dcf7c65c7a373a7cd65087178082597030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Tue, 28 Nov 2023 16:15:46 +0100 Subject: [PATCH 66/86] refactor: polish *WitnetRequestBoard* --- .../WitnetRequestBoardTrustableOvm2.sol | 12 +- .../WitnetRequestBoardTrustableReef.sol | 11 +- .../core/defaults/WitnetBytecodesDefault.sol | 4 +- .../WitnetRequestBoardTrustableDefault.sol | 35 ++-- contracts/data/WitnetRequestBoardData.sol | 23 +-- contracts/interfaces/IWitnetRequestBoard.sol | 149 +++++++++--------- .../interfaces/IWitnetRequestBoardEvents.sol | 15 +- migrations/scripts/3_core.js | 3 +- migrations/scripts/4_proxies.js | 2 +- migrations/witnet.settings.js | 46 +++--- 10 files changed, 149 insertions(+), 151 deletions(-) diff --git a/contracts/core/customs/WitnetRequestBoardTrustableOvm2.sol b/contracts/core/customs/WitnetRequestBoardTrustableOvm2.sol index 4246921da..85feec5dc 100644 --- a/contracts/core/customs/WitnetRequestBoardTrustableOvm2.sol +++ b/contracts/core/customs/WitnetRequestBoardTrustableOvm2.sol @@ -25,6 +25,7 @@ contract WitnetRequestBoardTrustableOvm2 constructor( WitnetRequestFactory _factory, + WitnetBytecodes _registry, bool _upgradable, bytes32 _versionTag, uint256 _reportResultGasBase, @@ -34,6 +35,7 @@ contract WitnetRequestBoardTrustableOvm2 ) WitnetRequestBoardTrustableDefault( _factory, + _registry, _upgradable, _versionTag, _reportResultGasBase, @@ -53,7 +55,7 @@ contract WitnetRequestBoardTrustableOvm2 /// @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, uint256 _resultMaxSize) + function estimateBaseFee(uint256 _gasPrice, uint16 _resultMaxSize) public view virtual override returns (uint256) @@ -67,17 +69,15 @@ contract WitnetRequestBoardTrustableOvm2 /// @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 _resultMaxSize Maximum expected size of returned data (in bytes). - /// @param _maxCallbackGas Maximum gas to be spent when reporting the data request result. - function estimateBaseFeeWithCallback(uint256 _gasPrice, uint256 _resultMaxSize, uint256 _maxCallbackGas) + /// @param _callbackGasLimit Maximum gas to be spent when reporting the data request result. + function estimateBaseFeeWithCallback(uint256 _gasPrice, uint96 _callbackGasLimit) public view virtual override returns (uint256) { return WitnetRequestBoardTrustableDefault.estimateBaseFeeWithCallback( _gasPrice, - _resultMaxSize, - _maxCallbackGas + _callbackGasLimit ) + ( _gasPrice * gasPriceOracleL1.getL1Fee( hex"c8f5cdd500000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000225820ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" diff --git a/contracts/core/customs/WitnetRequestBoardTrustableReef.sol b/contracts/core/customs/WitnetRequestBoardTrustableReef.sol index 46c881494..682c7f500 100644 --- a/contracts/core/customs/WitnetRequestBoardTrustableReef.sol +++ b/contracts/core/customs/WitnetRequestBoardTrustableReef.sol @@ -19,6 +19,7 @@ contract WitnetRequestBoardTrustableReef { constructor( WitnetRequestFactory _factory, + WitnetBytecodes _registry, bool _upgradable, bytes32 _versionTag, uint256 _reportResultGasBase, @@ -28,6 +29,7 @@ contract WitnetRequestBoardTrustableReef ) WitnetRequestBoardTrustableDefault( _factory, + _registry, _upgradable, _versionTag, _reportResultGasBase, @@ -43,7 +45,7 @@ contract WitnetRequestBoardTrustableReef /// @notice Estimate the minimum reward required for posting a data request. /// @dev Underestimates if the size of returned data is greater than `_resultMaxSize`. /// @param _resultMaxSize Maximum expected size of returned data (in bytes). - function estimateBaseFee(uint256, uint256 _resultMaxSize) + function estimateBaseFee(uint256, uint16 _resultMaxSize) public view virtual override returns (uint256) @@ -52,14 +54,13 @@ contract WitnetRequestBoardTrustableReef } /// @notice Estimate the minimum reward required for posting a data request with a callback. - /// @param _resultMaxSize Maximum expected size of returned data (in bytes). - /// @param _maxCallbackGas Maximum gas to be spent when reporting the data request result. - function estimateBaseFeeWithCallback(uint256, uint256 _resultMaxSize, uint256 _maxCallbackGas) + /// @param _callbackGasLimit Maximum gas to be spent when reporting the data request result. + function estimateBaseFeeWithCallback(uint256, uint96 _callbackGasLimit) public view virtual override returns (uint256) { - return WitnetRequestBoardTrustableDefault.estimateBaseFeeWithCallback(1, _resultMaxSize, _maxCallbackGas); + return WitnetRequestBoardTrustableDefault.estimateBaseFeeWithCallback(1, _callbackGasLimit); } diff --git a/contracts/core/defaults/WitnetBytecodesDefault.sol b/contracts/core/defaults/WitnetBytecodesDefault.sol index 5faa772e8..636a5fe66 100644 --- a/contracts/core/defaults/WitnetBytecodesDefault.sol +++ b/contracts/core/defaults/WitnetBytecodesDefault.sol @@ -259,9 +259,9 @@ contract WitnetBytecodesDefault function lookupRadonRequestResultMaxSize(bytes32 _radHash) external view override - returns (uint256) + returns (uint16) { - return __requests(_radHash).resultMaxSize; + return uint16(__requests(_radHash).resultMaxSize); } function lookupRadonRequestSources(bytes32 _radHash) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol b/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol index af1f75043..eb71a0cc2 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableDefault.sol @@ -23,6 +23,7 @@ contract WitnetRequestBoardTrustableDefault constructor( WitnetRequestFactory _factory, + WitnetBytecodes _registry, bool _upgradable, bytes32 _versionTag, uint256 _reportResultGasBase, @@ -32,6 +33,7 @@ contract WitnetRequestBoardTrustableDefault ) WitnetRequestBoardTrustableBase( _factory, + _registry, _upgradable, _versionTag, address(0) @@ -51,7 +53,7 @@ contract WitnetRequestBoardTrustableDefault /// @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, uint256 _resultMaxSize) + function estimateBaseFee(uint256 _gasPrice, uint16 _resultMaxSize) public view virtual override returns (uint256) @@ -59,37 +61,38 @@ contract WitnetRequestBoardTrustableDefault return _gasPrice * ( __reportResultGasBase + __sstoreFromZeroGas * ( - 5 + _resultMaxSize / 32 + 5 + (_resultMaxSize == 0 ? 0 : _resultMaxSize - 1) / 32 ) ); } /// @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 _resultMaxSize Maximum expected size of returned data (in bytes). - /// @param _maxCallbackGas Maximum gas to be spent when reporting the data request result. - function estimateBaseFeeWithCallback(uint256 _gasPrice, uint256 _resultMaxSize, uint256 _maxCallbackGas) + /// @param _callbackGasLimit Maximum gas to be spent when reporting the data request result. + function estimateBaseFeeWithCallback(uint256 _gasPrice, uint96 _callbackGasLimit) public view virtual override returns (uint256) { - uint _reportResultWithetCallbackGasThreshold = ( + uint _reportResultWithCallbackGasThreshold = ( __reportResultWithCallbackRevertGasBase - + __sstoreFromZeroGas * ( - 5 + _resultMaxSize / 32 - ) + + 3 * __sstoreFromZeroGas ); if ( - _maxCallbackGas < _reportResultWithetCallbackGasThreshold - || __reportResultWithCallbackGasBase + _maxCallbackGas < _reportResultWithetCallbackGasThreshold + _callbackGasLimit < _reportResultWithCallbackGasThreshold + || __reportResultWithCallbackGasBase + _callbackGasLimit < _reportResultWithCallbackGasThreshold ) { - return (_gasPrice * _reportResultWithetCallbackGasThreshold); + return ( + _gasPrice + * _reportResultWithCallbackGasThreshold + ); } else { return ( - _gasPrice * ( - __reportResultWithCallbackGasBase - + _maxCallbackGas - ) + _gasPrice + * ( + __reportResultWithCallbackGasBase + + _callbackGasLimit + ) ); } } diff --git a/contracts/data/WitnetRequestBoardData.sol b/contracts/data/WitnetRequestBoardData.sol index ec9b09be2..e635ea111 100644 --- a/contracts/data/WitnetRequestBoardData.sol +++ b/contracts/data/WitnetRequestBoardData.sol @@ -8,6 +8,8 @@ import "../libs/Witnet.sol"; /// @author The Witnet Foundation. abstract contract WitnetRequestBoardData { + using Witnet for Witnet.Request; + bytes32 internal constant _WITNET_REQUEST_BOARD_DATA_SLOTHASH = /* keccak256("io.witnet.boards.data") */ 0xf595240b351bc8f951c2f53b26f4e78c32cb62122cf76c19b7fdda7d4968e183; @@ -31,33 +33,14 @@ abstract contract WitnetRequestBoardData { ); _; } - /// Asserts the given query was previously posted and that it was not yet deleted. - modifier notDeleted(uint256 _queryId) { - require( - _queryId > 0 && _queryId <= __storage().nonce, - "WitnetRequestBoard: not yet posted" - ); - require( - __seekQuery(_queryId).from != address(0), - "WitnetRequestBoard: deleted" - ); _; - } - /// Asserts the caller actually posted the referred query. modifier onlyRequester(uint256 _queryId) { require( - msg.sender == __seekQuery(_queryId).from, + msg.sender == __seekQueryRequest(_queryId).unpackRequester(), "WitnetRequestBoardBase: not the requester" ); _; } - /// Asserts the given query was actually posted before calling this method. - modifier wasPosted(uint256 _queryId) { - require( - _queryId > 0 && _queryId <= __storage().nonce, - "WitnetRequestBoard: not yet posted" - ); _; - } // ================================================================================================================ // --- Internal functions ----------------------------------------------------------------------------------------- diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index 57aa59dfd..f28076d1e 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -9,57 +9,62 @@ interface IWitnetRequestBoard { /// @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, uint256 resultMaxSize) external view returns (uint256); + 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 WitnetBytecodes 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 resultMaxSize Maximum expected size of returned data (in bytes). - /// @param maxCallbackGas Maximum gas to be spent when reporting the data request result. - function estimateBaseFeeWithCallback(uint256 gasPrice, uint256 resultMaxSize, uint256 maxCallbackGas) external view returns (uint256); + /// @param callbackGasLimit Maximum gas to be spent when reporting the data request result. + function estimateBaseFeeWithCallback(uint256 gasPrice, uint96 callbackGasLimit) external view returns (uint256); /// @notice Estimates the actual earnings (or loss), in WEI, that a reporter would get by reporting result to given query, - /// @notice based on the gas price of the calling transaction. - /// @dev Data requesters should consider upgrading the reward on queries providing no actual earnings. + /// @notice based on the gas price of the calling transaction. Data requesters should consider upgrading the reward on + /// @notice queries providing no actual earnings. + /// @dev Fails if the query does not exist, or if deleted. function estimateQueryEarnings(uint256 queryId, uint256 gasPrice) external view returns (int256); - - /// @notice Retrieves a copy of all Witnet-provided data related to a previously posted request, + + /// @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 `queryId` is not in 'Reported' status, or called from an address different to + /// @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 (Witnet.Response memory); - + /// @notice Gets the whole Query data contents, if any, no matter its current status. - function getQueryData(uint256 queryId) external view returns (Witnet.Query memory); - - /// @notice 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 getQueryRequest(uint256 queryId) external view returns (Witnet.Request memory); + function getQuery(uint256 queryId) external view returns (Witnet.Query memory); /// @notice 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. + /// @dev Fails if the query does not exist. /// @param queryId The unique query identifier. - function getQueryRequestBytecode(uint256 queryId) external view returns (bytes memory); - + function getQueryBytecode(uint256 queryId) external view returns (bytes memory); + + /// @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 (bytes32, WitnetV2.RadonSLA memory); + /// @notice Retrieves the whole `Witnet.Response` record referred to a previously posted Witnet Data Request. - /// @dev Fails if the `queryId` is not in 'Reported' status. /// @param queryId The unique query identifier. function getQueryResponse(uint256 queryId) external view returns (Witnet.Response memory); - /// @notice Retrieves the Witnet-provided CBOR-bytes result of a previously posted request. - /// @dev Fails if the `queryId` is not in 'Reported' status. + /// @notice Retrieves the Witnet-provable CBOR-bytes result of a previously posted request. /// @param queryId The unique query identifier. function getQueryResult(uint256 queryId) external view returns (Witnet.Result memory); - /// @notice Returns query's result traceability data + /// @notice Returns reference to the commit/reveal act that took place on the Witnet blockchain. /// @param queryId The unique query identifier. - /// @return _resultTimestamp Timestamp at which the query was solved by the Witnet blockchain. - /// @return _resultDrTxHash Witnet blockchain hash of the commit/reveal act that solved the query. - function getQueryResultAuditTrail(uint256 queryId) external view returns (uint256 _resultTimestamp, bytes32 _resultDrTxHash); + /// @return witnetTimestamp Timestamp at which the query was solved by the Witnet blockchain. + /// @return witnetTallyHash Hash of the commit/reveal act that solved the query on the Witnet blockchain. + /// @return witnetEvmFinalityBlock EVM block at which the provided data can be considered to be final. + function getQueryResultAuditTrail(uint256 queryId) external view returns ( + uint256 witnetTimestamp, + bytes32 witnetTallyHash, + uint256 witnetEvmFinalityBlock + ); /// @notice Gets error code identifying some possible failure on the resolution of the given query. /// @param queryId The unique query identifier. @@ -68,79 +73,79 @@ interface IWitnetRequestBoard { /// @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. + /// @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 getQueryResultStatus(uint256 queryId) external view returns (Witnet.ResultStatus); /// @notice Retrieves the reward currently set for the referred query. - /// @dev Fails if the `queryId` is not valid or, if it has already been - /// @dev reported, or deleted. + /// @dev Fails if the `queryId` is not valid or, if it has already been reported, delivered, or deleted. /// @param queryId The unique query identifier. function getQueryReward(uint256 queryId) external view returns (uint256); /// @notice Gets current status of given query. function getQueryStatus(uint256 queryId) external view returns (Witnet.QueryStatus); - /// @notice Returns next query id to be generated by the Witnet Request Board. - function getNextQueryId() external view returns (uint256); + // /// @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-provided result to this request. - /// @dev Fails if provided reward is too low. - /// @dev The result to the query will be saved into the WitnetRequestBoard storage. - /// @param radHash The RAD hash of the data request to be solved by Witnet. + /// @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 WitnetBytecodes 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 radHash, + bytes32 queryRAD, WitnetV2.RadonSLA calldata querySLA ) external payable returns (uint256 queryId); - /// @notice Requests the execution of the given Witnet Data Request bytecode, 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-provided result to this request. - /// @dev Fails if provided reward is too low. - /// @dev The result to the query will be saved into the WitnetRequestBoard storage. - /// @param radBytecode The raw bytecode of the Witnet Data Request to be solved by Witnet. - /// @param querySLA The data query SLA to be fulfilled by the Witnet blockchain. - /// @return A unique query identifier. - function postRequest( - bytes calldata radBytecode, - WitnetV2.RadonSLA calldata querySLA - ) external payable returns (uint256); + /// @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 `WitnetResponseDeliveryFailed` + /// @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 WitnetBytecodes 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, + uint96 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-provided result to this request. - /// @dev Fails if, provided reward is too low. - /// @dev The caller must be a contract implementing the IWitnetConsumer interface. - /// @param radHash The RAD hash of the data request to be solved by Witnet. + /// @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 `WitnetResponseDeliveryFailed` + /// @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 maxCallbackGas Maximum gas to be spent when reporting the data request result. + /// @param queryCallbackGasLimit Maximum gas to be spent when reporting the data request result. /// @return queryId Unique query identifier. function postRequestWithCallback( - bytes32 radHash, + bytes calldata queryUnverifiedBytecode, WitnetV2.RadonSLA calldata querySLA, - uint256 maxCallbackGas + uint96 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 upgradeQueryReward(uint256 queryId) external payable; - - - /// =============================================================================================================== - /// --- Deprecating methods --------------------------------------------------------------------------------------- - - /// @notice Requests the execution of the given Witnet Data Request in expectation that it will be relayed and solved by the Witnet blockchain. - /// @notice A reward amount is escrowed by the Witnet Request Board that will be transferred to the reporter who relays back the Witnet-provided - /// @notice result to this request. - /// @dev Fails if, provided reward is too low. - /// @param radHash The RAD hash of the data request to be solved by Witnet. - /// @param slaHash The SLA hash of the data request to be solved by Witnet. - /// @return queryId Unique query identifier. - function postRequest(bytes32 radHash, bytes32 slaHash) external payable returns (uint256 queryId); } diff --git a/contracts/interfaces/IWitnetRequestBoardEvents.sol b/contracts/interfaces/IWitnetRequestBoardEvents.sol index ffc1b84fe..1c7ab7f2e 100644 --- a/contracts/interfaces/IWitnetRequestBoardEvents.sol +++ b/contracts/interfaces/IWitnetRequestBoardEvents.sol @@ -1,13 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.7.0 <0.9.0; +import "../libs/WitnetV2.sol"; + interface IWitnetRequestBoardEvents { /// Emitted every time a new query containing some verified data request is posted to the WRB. - event NewWitnetQuery(uint256 indexed id, uint256 evmReward); - - /// Emitted every time a new query containing non-verified data request is posted to the WRB. - event NewQueryWithBytecode(uint256 indexed id, uint256 evmReward, bytes radBytecode); + event WitnetQuery(uint256 indexed id, uint64 witReward, uint256 evmReward); /// Emitted when a query with no callback gets reported into the WRB. event WitnetQueryReported(uint256 indexed id, uint256 evmGasPrice); @@ -19,5 +18,11 @@ interface IWitnetRequestBoardEvents { event WitnetResponseDelivered(uint256 indexed id, uint256 evmGasPrice, uint256 evmCallbackGas); /// Emitted when a query with a callback cannot get reported into the WRB. - event WitnetResponseDeliveryFailed(uint256 indexed id, uint256 evmGasPrice, uint256 evmCallbackGas, string evmReason); + event WitnetResponseDeliveryFailed( + uint256 indexed id, + bytes resultCborBytes, + uint256 evmGasPrice, + uint256 evmCallbackGas, + string evmCallbackRevertReason + ); } diff --git a/migrations/scripts/3_core.js b/migrations/scripts/3_core.js index 2248dd485..887ae59af 100644 --- a/migrations/scripts/3_core.js +++ b/migrations/scripts/3_core.js @@ -72,8 +72,9 @@ module.exports = async function (_, network, [, from]) { key: targets.WitnetRequestBoard, libs: specs.WitnetRequestBoard.libs, immutables: specs.WitnetRequestBoard.immutables, - intrinsics: { types: [ 'address', 'bool', 'bytes32' ], values: [ + intrinsics: { types: [ 'address', 'address', 'bool', 'bytes32' ], values: [ /* _factory */ await determineProxyAddr(from, specs.WitnetRequestFactory?.vanity || 2), + /* _registry */ await determineProxyAddr(from, specs.WitnetBytecodes?.vanity || 1), /* _upgradable */ true, /* _versionTag */ utils.fromAscii(version), ]}, diff --git a/migrations/scripts/4_proxies.js b/migrations/scripts/4_proxies.js index 3b4145096..e5fbcf5d7 100644 --- a/migrations/scripts/4_proxies.js +++ b/migrations/scripts/4_proxies.js @@ -100,7 +100,7 @@ async function deploy(target) { const oldAddr = await getProxyImplementation(from, addresses[ecosystem][network][key]) const oldImpl = await artifacts.require(targets[key]).at(oldAddr) const newImpl = await artifacts.require(targets[key]).deployed() - if (oldAddr != newImpl.address) { + if (oldAddr !== newImpl.address) { utils.traceHeader(`Upgrading '${key}'...`) const oldVersion = await oldImpl.version.call({ from }) const newVersion = await newImpl.version.call({ from }) diff --git a/migrations/witnet.settings.js b/migrations/witnet.settings.js index d05404f75..80bcc6faf 100644 --- a/migrations/witnet.settings.js +++ b/migrations/witnet.settings.js @@ -669,14 +669,14 @@ module.exports = { immutables: { types: [ 'uint256', 'uint256', 'uint256', 'uint256', ], values: [ - /* _reportResultGasBase */ 57898, - /* _reportResultWithCallbackGasBase */ 72140, - /* _reportResultWithCallbackRevertGasBase */ 66685, + /* _reportResultGasBase */ 58282, + /* _reportResultWithCallbackGasBase */ 65273, + /* _reportResultWithCallbackRevertGasBase */ 69546, /* _sstoreFromZeroGas */ 20000, ] }, libs: [ "WitnetErrorsLib", ], - vanity: 83581, + vanity: 899032812, // => 0x000071F0c823bD30D2Bf4CD1E829Eba5A6070000 }, WitnetRequestFactory: { vanity: 178848, @@ -690,7 +690,7 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasLimit */ 155000, + /* _reportResultGasBase */ 155000, ] }, }, @@ -699,7 +699,7 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasLimit */ 114000, + /* _reportResultGasBase */ 114000, ] }, }, @@ -708,7 +708,7 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasLimit */ 78500, + /* _reportResultGasBase */ 78500, ] }, }, @@ -717,7 +717,7 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasLimit */ 225000, + /* _reportResultGasBase */ 225000, ] }, }, @@ -726,7 +726,7 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasLimit */ 225000, + /* _reportResultGasBase */ 225000, ] }, }, @@ -735,7 +735,7 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasLimit */ 137500, + /* _reportResultGasBase */ 137500, ] }, }, @@ -744,7 +744,7 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasLimit */ 85000, + /* _reportResultGasBase */ 85000, ] }, }, @@ -753,7 +753,7 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasLimit */ 530000, + /* _reportResultGasBase */ 530000, ] }, }, @@ -762,7 +762,7 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasLimit */ 85000, + /* _reportResultGasBase */ 85000, ] }, }, @@ -771,7 +771,7 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasLimit */ 92500, + /* _reportResultGasBase */ 92500, ] }, }, @@ -780,7 +780,7 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasLimit */ 105000, + /* _reportResultGasBase */ 105000, ] }, }, @@ -789,7 +789,7 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasLimit */ 85000, + /* _reportResultGasBase */ 85000, ] }, }, @@ -798,7 +798,7 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasLimit */ 134800, + /* _reportResultGasBase */ 134800, ] }, }, @@ -807,7 +807,7 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasLimit */ 115000, + /* _reportResultGasBase */ 115000, ] }, }, @@ -816,7 +816,7 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasLimit */ 145000, + /* _reportResultGasBase */ 145000, ] }, }, @@ -825,7 +825,7 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasLimit */ 135000, + /* _reportResultGasBase */ 135000, ] }, }, @@ -834,7 +834,7 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasLimit */ "0x3100A1CAC7EF19DC", + /* _reportResultGasBase */ "0x3100A1CAC7EF19DC", ] }, }, @@ -843,10 +843,10 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasLimit */ 83949, + /* _reportResultGasBase */ 83949, ] }, }, }, }, -} +} \ No newline at end of file From a2e60428714eceaabfd4fa7122e03d4b006d7c2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Tue, 28 Nov 2023 16:17:15 +0100 Subject: [PATCH 67/86] feat: optimize WitnetRequestBoardTrustableBase --- .../WitnetRequestBoardTrustableBase.sol | 830 ++++++++++-------- 1 file changed, 458 insertions(+), 372 deletions(-) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index 53bd5905e..2c4704f8a 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -30,24 +30,29 @@ abstract contract WitnetRequestBoardTrustableBase Payable { using Witnet for bytes; + using Witnet for Witnet.Request; + using Witnet for Witnet.Response; using Witnet for Witnet.Result; using WitnetCBOR for WitnetCBOR.CBOR; using WitnetV2 for WitnetV2.RadonSLA; bytes4 public immutable override specs = type(IWitnetRequestBoard).interfaceId; + bytes4 public immutable group = bytes4(keccak256(abi.encode(address(this), block.chainid))); + WitnetRequestFactory immutable public override factory; + WitnetBytecodes immutable public override registry; - modifier checkCallbackRecipient(address _addr) { + modifier checkCallbackRecipient(address _addr, uint96 _callbackGasLimit) { require( - _addr.code.length > 0 && IWitnetConsumer(_addr).reportableFrom(address(this)), - "WitnetRequestBoardTrustableBase: invalid callback recipient" + _addr.code.length > 0 && IWitnetConsumer(_addr).reportableFrom(address(this)) && _callbackGasLimit > 0, + "WitnetRequestBoardTrustableBase: invalid callback" ); _; } modifier checkReward(uint256 _baseFee) { require( _getMsgValue() >= _baseFee, - "WitnetRequestBoardTrustableBase: reward too low" + "WitnetRequestBoardTrustableBase: insufficient reward" ); _; } @@ -60,6 +65,7 @@ abstract contract WitnetRequestBoardTrustableBase constructor( WitnetRequestFactory _factory, + WitnetBytecodes _registry, bool _upgradable, bytes32 _versionTag, address _currency @@ -71,12 +77,9 @@ abstract contract WitnetRequestBoardTrustableBase "io.witnet.proxiable.board" ) { - assert(address(_factory) != address(0)); + assert(address(_factory) != address(0) && address(_registry) != address(0)); factory = _factory; - } - - function registry() public view virtual override returns (WitnetBytecodes) { - return factory.registry(); + registry = _registry; } receive() external payable { @@ -106,13 +109,12 @@ abstract contract WitnetRequestBoardTrustableBase /// @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, uint256 _resultMaxSize) virtual public view returns (uint256); + function estimateBaseFee(uint256 _gasPrice, uint16 _resultMaxSize) virtual public 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 _resultMaxSize Maximum expected size of returned data (in bytes). - /// @param _maxCallbackGas Maximum gas to be spent when reporting the data request result. - function estimateBaseFeeWithCallback(uint256 _gasPrice, uint256 _resultMaxSize, uint256 _maxCallbackGas) virtual public view returns (uint256); + /// @param _callbackGasLimit Maximum gas to be spent when reporting the data request result. + function estimateBaseFeeWithCallback(uint256 _gasPrice, uint96 _callbackGasLimit) virtual public view returns (uint256); // ================================================================================================================ @@ -152,9 +154,19 @@ abstract contract WitnetRequestBoardTrustableBase } __storage().base = base(); - require(address(factory).code.length > 0, "WitnetRequestBoardTrustableBase: inexistent factory"); - require(factory.specs() == type(IWitnetRequestFactory).interfaceId, "WitnetRequestBoardTrustableBase: uncompliant factory"); - require(address(factory.witnet()) == address(this), "WitnetRequestBoardTrustableBase: discordant factory"); + require( + address(factory).code.length > 0, + "WitnetRequestBoardTrustableBase: inexistent factory" + ); + require( + factory.specs() == type(IWitnetRequestFactory).interfaceId, + "WitnetRequestBoardTrustableBase: uncompliant factory" + ); + require( + address(factory.witnet()) == address(this) + && address(factory.registry()) == address(registry), + "WitnetRequestBoardTrustableBase: discordant factory" + ); // Set reporters __setReporters(_reporters); @@ -175,141 +187,164 @@ abstract contract WitnetRequestBoardTrustableBase // ================================================================================================================ // --- Partial implementation of IWitnetRequestBoard -------------------------------------------------------------- + + /// @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 radHash The hash of some Witnet Data Request previously posted in the WitnetBytecodes registry. + function estimateBaseFee(uint256 gasPrice, bytes32 radHash) + override + public view + returns (uint256) + { + uint16 _resultMaxSize = registry.lookupRadonRequestResultMaxSize(radHash); + require( + _resultMaxSize > 0, + "WitnetRequestBoardTrustableDefault: invalid RAD" + ); + return estimateBaseFee( + gasPrice, + _resultMaxSize + ); + } /// @notice Estimates the actual earnings (or loss), in WEI, that a reporter would get by reporting result to given query, - /// @notice based on the gas price of the calling transaction. - /// @dev Data requesters should consider upgrading the reward on queries providing no actual earnings. - function estimateQueryEarnings(uint256 _queryId, uint256 _gasPrice) + /// @notice based on the gas price of the calling transaction. Data requesters should consider upgrading the reward on + /// @notice queries providing no actual earnings. + /// @dev Fails if the query does not exist, or if deleted. + function estimateQueryEarnings(uint256 _witnetQueryId, uint256 _gasPrice) virtual override external view returns (int256 _earnings) { - Witnet.Request storage __request = __seekQueryRequest(_queryId); + Witnet.Request storage __request = __seekQueryRequest(_witnetQueryId); - uint _maxResultSize = registry().lookupRadonRequestResultMaxSize(__request.radHash); _earnings = int(__request.evmReward); - if (__request.maxCallbackGas > 0) { + uint96 _callbackGasLimit = __request.unpackCallbackGasLimit(); + if (_callbackGasLimit > 0) { _earnings -= int(estimateBaseFeeWithCallback( - _gasPrice, - _maxResultSize, - __request.maxCallbackGas + _gasPrice, + _callbackGasLimit )); } else { _earnings -= int(estimateBaseFee( _gasPrice, - _maxResultSize + __request.RAD )); } } /// 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 Fails if the `_witnetQueryId` 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 fetchQueryResponse(uint256 _queryId) + /// @param _witnetQueryId The unique query identifier. + function fetchQueryResponse(uint256 _witnetQueryId) virtual override external - inStatus(_queryId, Witnet.QueryStatus.Reported) - onlyRequester(_queryId) + inStatus(_witnetQueryId, Witnet.QueryStatus.Reported) + onlyRequester(_witnetQueryId) returns (Witnet.Response memory _response) { - _response = __seekQuery(_queryId).response; - delete __storage().queries[_queryId]; + _response = __seekQuery(_witnetQueryId).response; + delete __storage().queries[_witnetQueryId]; } /// Gets the whole Query data contents, if any, no matter its current status. - function getQueryData(uint256 _queryId) + function getQuery(uint256 _witnetQueryId) external view override returns (Witnet.Query memory) { - return __storage().queries[_queryId]; - } - - /// 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 getQueryRequest(uint256 _queryId) - external view - override - // inStatus(_queryId, Witnet.QueryStatus.Posted) - returns (Witnet.Request memory) - { - return __seekQueryRequest(_queryId); + return __storage().queries[_witnetQueryId]; } - /// 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 getQueryRequestBytecode(uint256 _queryId) + /// @notice Retrieves the serialized bytecode of a previously posted Witnet Data Request. + /// @dev Fails if the query does not exist. + /// @param _witnetQueryId The unique query identifier. + function getQueryBytecode(uint256 _witnetQueryId) external view virtual override - returns (bytes memory _bytecode) + returns (bytes memory) { require( - _statusOf(_queryId) != Witnet.QueryStatus.Unknown, - "WitnetRequestBoardTrustableBase: not yet posted" + _statusOf(_witnetQueryId) != Witnet.QueryStatus.Unknown, + "WitnetRequestBoardTrustableBase: unknown query" ); - Witnet.Request storage __request = __seekQueryRequest(_queryId); - if (__request._addr != address(0)) { - _bytecode = IWitnetRequest(__request._addr).bytecode(); - } else if (__request.radHash != bytes32(0)) { - _bytecode = registry().bytecodeOf(__request.radHash); + Witnet.Request storage __request = __seekQueryRequest(_witnetQueryId); + if (__request.RAD != bytes32(0)) { + return registry.bytecodeOf(__request.RAD); + } else { + return __request.bytecode; } } - /// 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 getQueryResponse(uint256 _queryId) + /// @notice Retrieves the RAD hash and SLA parameters of the given query. + /// @param _witnetQueryId The unique query identifier. + function getQueryRequest(uint256 _witnetQueryId) + external view + override + returns (bytes32, WitnetV2.RadonSLA memory) + { + Witnet.Request storage __request = __seekQueryRequest(_witnetQueryId); + return ( + __request.RAD == bytes32(0) ? registry.hashOf(__request.bytecode) : __request.RAD, + WitnetV2.toRadonSLA(__request.SLA) + ); + } + + /// Retrieves the Witnet-provable result, and metadata, to a previously posted request. + /// @dev Fails if the `_witnetQueryId` is not in 'Reported' status. + /// @param _witnetQueryId The unique query identifier + function getQueryResponse(uint256 _witnetQueryId) external view override - // inStatus(_queryId, Witnet.QueryStatus.Reported) returns (Witnet.Response memory _response) { - return __seekQueryResponse(_queryId); + return __seekQueryResponse(_witnetQueryId); } - /// 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 getQueryResult(uint256 _queryId) + /// @notice Retrieves the Witnet-provable CBOR-bytes result of a previously posted request. + /// @param _witnetQueryId The unique query identifier. + function getQueryResult(uint256 _witnetQueryId) external view override - // inStatus(_queryId, Witnet.QueryStatus.Reported) returns (Witnet.Result memory) { - Witnet.Response storage _response = __seekQueryResponse(_queryId); + // todo: fail if not in finalized status ? + Witnet.Response storage _response = __seekQueryResponse(_witnetQueryId); return _response.cborBytes.resultFromCborBytes(); } - /// @notice Returns query's result traceability data - /// @param _queryId The unique query identifier. - /// @return _resultTimestamp Timestamp at which the query was solved by the Witnet blockchain. - /// @return _resultDrTxHash Witnet blockchain hash of the commit/reveal act that solved the query. - function getQueryResultAuditTrail(uint256 _queryId) + /// @notice Returns reference to the commit/reveal act that took place on the Witnet blockchain. + /// @param _witnetQueryId The unique query identifier. + /// @return _witnetTimestamp Timestamp at which the query was solved by the Witnet blockchain. + /// @return _witnetTallyHash Hash of the commit/reveal act that solved the query on the Witnet blockchain. + /// @return _witnetEvmFinalityBlock EVM block at which the provided data can be considered to be final. + function getQueryResultAuditTrail(uint256 _witnetQueryId) external view override - returns (uint256, bytes32) + returns ( + uint256 _witnetTimestamp, + bytes32 _witnetTallyHash, + uint256 _witnetEvmFinalityBlock + ) { - Witnet.Response storage __response = __seekQueryResponse(_queryId); + Witnet.Response storage __response = __seekQueryResponse(_witnetQueryId); return ( __response.timestamp, - __response.drTxHash + __response.tallyHash, + __response.unpackEvmFinalityBlock() ); } /// @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) + /// @param _witnetQueryId The unique query identifier. + function getQueryResultError(uint256 _witnetQueryId) override external view returns (Witnet.ResultError memory) { - Witnet.ResultStatus _status = getQueryResultStatus(_queryId); - try WitnetErrorsLib.asResultError(_status, __seekQueryResponse(_queryId).cborBytes) + Witnet.ResultStatus _status = getQueryResultStatus(_witnetQueryId); + try WitnetErrorsLib.asResultError(_status, __seekQueryResponse(_witnetQueryId).cborBytes) returns (Witnet.ResultError memory _resultError) { return _resultError; @@ -333,20 +368,31 @@ abstract contract WitnetRequestBoardTrustableBase /// @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 getQueryResultStatus(uint256 _queryId) + /// @param _witnetQueryId The unique query identifier. + function getQueryResultStatus(uint256 _witnetQueryId) virtual public view returns (Witnet.ResultStatus) { - Witnet.QueryStatus _queryStatus = _statusOf(_queryId); - if (_queryStatus == Witnet.QueryStatus.Reported) { - bytes storage __cborValues = __seekQueryResponse(_queryId).cborBytes; + Witnet.QueryStatus _queryStatus = _statusOf(_witnetQueryId); + if ( + _queryStatus == Witnet.QueryStatus.Finalized + || _queryStatus == Witnet.QueryStatus.Reported + ) { + bytes storage __cborValues = __seekQueryResponse(_witnetQueryId).cborBytes; // determine whether reported result is an error by peeking the first byte - return (__cborValues[0] == bytes1(0xd8) - ? Witnet.ResultStatus.Error - : Witnet.ResultStatus.Ready + return (__cborValues[0] == bytes1(0xd8) + ? (_queryStatus == Witnet.QueryStatus.Finalized + ? Witnet.ResultStatus.Error + : Witnet.ResultStatus.AwaitingError + ) : (_queryStatus == Witnet.QueryStatus.Finalized + ? Witnet.ResultStatus.Ready + : Witnet.ResultStatus.AwaitingReady + ) ); - } else if (_queryStatus == Witnet.QueryStatus.Posted) { + } else if ( + _queryStatus == Witnet.QueryStatus.Posted + || _queryStatus == Witnet.QueryStatus.Undeliverable + ) { return Witnet.ResultStatus.Awaiting; } else { return Witnet.ResultStatus.Void; @@ -354,266 +400,240 @@ abstract contract WitnetRequestBoardTrustableBase } /// 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 Fails if the `_witnetQueryId` is not valid or, if it has already been /// @dev reported, or deleted. - /// @param _queryId The unique query identifier - function getQueryReward(uint256 _queryId) - external view + /// @param _witnetQueryId The unique query identifier + function getQueryReward(uint256 _witnetQueryId) override - inStatus(_queryId, Witnet.QueryStatus.Posted) + external view + inStatus(_witnetQueryId, Witnet.QueryStatus.Posted) returns (uint256) { - return __seekQueryRequest(_queryId).evmReward; + return __seekQueryRequest(_witnetQueryId).evmReward; } /// Gets current status of given query. - function getQueryStatus(uint256 _queryId) + function getQueryStatus(uint256 _witnetQueryId) external view override returns (Witnet.QueryStatus) { - return _statusOf(_queryId); + return _statusOf(_witnetQueryId); } - /// Returns next request id to be generated by the Witnet Request Board. - function getNextQueryId() - external view - override - returns (uint256) - { - return __storage().nonce + 1; - } - - /// 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) - virtual override - external payable - checkReward(estimateBaseFee(_getGasPrice(), 32)) - returns (uint256 _queryId) - { - _queryId = __postRequest(_radHash, _slaHash); - // Let observers know that a new request has been posted - emit NewWitnetQuery(_queryId, _getMsgValue()); - } /// @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-provided result to this request. - /// @dev Fails if provided reward is too low. - /// @dev The result to the query will be saved into the WitnetRequestBoard storage. - /// @param _radHash The RAD hash of the data request to be solved by Witnet. + /// @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 WitnetBytecodes 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 _radHash, - WitnetV2.RadonSLA calldata _querySLA - ) - virtual override - external payable - checkReward(estimateBaseFee(_getGasPrice(), 32)) - checkSLA(_querySLA) - returns (uint256 _queryId) - { - _queryId = __postRequest( - _radHash, - _querySLA.packed() - ); - // Let observers know that a new request has been posted - emit NewWitnetQuery(_queryId, _getMsgValue()); - } - - /// @notice Requests the execution of the given Witnet Data Request bytecode, 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-provided result to this request. - /// @dev Fails if provided reward is too low. - /// @dev The result to the query will be saved into the WitnetRequestBoard storage. - /// @param _radBytecode The raw bytecode of the Witnet Data Request to be solved by Witnet. - /// @param _querySLA The data query SLA to be fulfilled by the Witnet blockchain. - /// @return _queryId A unique query identifier. + /// @return _witnetQueryId Unique query identifier. function postRequest( - bytes calldata _radBytecode, + bytes32 _queryRAD, WitnetV2.RadonSLA calldata _querySLA ) virtual override external payable - checkReward(estimateBaseFee(_getGasPrice(), 32)) + checkReward(estimateBaseFee(_getGasPrice(), _queryRAD))//32))// _queryRAD)) checkSLA(_querySLA) - returns (uint256 _queryId) - { - _queryId = __postRequest( - registry().hashOf(_radBytecode), - _querySLA.packed() + returns (uint256 _witnetQueryId) + { + _witnetQueryId = __postRequest(_queryRAD, _querySLA.toBytes32(), 0); + // Let Web3 observers know that a new request has been posted + emit WitnetQuery( + _witnetQueryId, + _querySLA.totalWitnessingReward(), + _getMsgValue() ); - // Let observers know that a new request has been posted - emit NewQueryWithBytecode(_queryId, _getMsgValue(), _radBytecode); } /// @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-provided result to this request. - /// @dev Fails if, provided reward is too low. - /// @dev The caller must be a contract implementing the IWitnetConsumer interface. - /// @param _radHash The RAD hash of the data request to be solved by Witnet. + /// @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 `WitnetResponseDeliveryFailed` + /// @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 WitnetBytecodes registry; + /// @dev - invalid SLA parameters were provided; + /// @dev - zero callback gas limit is 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 _queryMaxCallbackGas Maximum gas to be spent when reporting the data request result. - /// @return _queryId Unique query identifier. + /// @param _queryCallbackGasLimit Maximum gas to be spent when reporting the data request result. + /// @return _witnetQueryId Unique query identifier. function postRequestWithCallback( - bytes32 _radHash, + bytes32 _queryRAD, WitnetV2.RadonSLA calldata _querySLA, - uint256 _queryMaxCallbackGas + uint96 _queryCallbackGasLimit ) virtual override external payable - checkCallbackRecipient(msg.sender) - checkReward(estimateBaseFeeWithCallback(_getGasPrice(), 32, _queryMaxCallbackGas)) + checkCallbackRecipient(msg.sender, _queryCallbackGasLimit) + checkReward(estimateBaseFeeWithCallback(_getGasPrice(), _queryCallbackGasLimit)) checkSLA(_querySLA) - returns (uint256 _queryId) + returns (uint256 _witnetQueryId) { - _queryId = __postRequest( - _radHash, - _querySLA.packed() + _witnetQueryId = __postRequest( + _queryRAD, + _querySLA.toBytes32(), + _queryCallbackGasLimit + ); + emit WitnetQuery( + _witnetQueryId, + _querySLA.totalWitnessingReward(), + _getMsgValue() ); - __seekQueryRequest(_queryId).maxCallbackGas = _queryMaxCallbackGas; - emit NewWitnetQuery(_queryId, _getMsgValue()); - } - - function retryQuery(uint256 _queryId) - virtual override - external payable - inStatus(_queryId, Witnet.QueryStatus.Reported) - onlyRequester(_queryId) - returns (uint256 _newQuery) - { - _newQuery = __newQuery(); - __storage().queries[_newQuery] = __storage().queries[_queryId]; - // todo ... } - function retryQueryWithCallback(uint256 _queryId, uint256) + /// @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 `WitnetResponseDeliveryFailed` + /// @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 - zero callback gas limit is 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 _witnetQueryId Unique query identifier. + function postRequestWithCallback( + bytes calldata _queryUnverifiedBytecode, + WitnetV2.RadonSLA calldata _querySLA, + uint96 _queryCallbackGasLimit + ) virtual override - external payable - inStatus(_queryId, Witnet.QueryStatus.Reported) - onlyRequester(_queryId) - returns (uint256) + external payable + checkCallbackRecipient(msg.sender, _queryCallbackGasLimit) + checkReward(estimateBaseFeeWithCallback(_getGasPrice(), _queryCallbackGasLimit)) + checkSLA(_querySLA) + returns (uint256 _witnetQueryId) { - // TODO + _witnetQueryId = __postRequest( + bytes32(0), + _querySLA.toBytes32(), + _queryCallbackGasLimit + ); + __seekQueryRequest(_witnetQueryId).bytecode = _queryUnverifiedBytecode; + emit WitnetQuery( + _witnetQueryId, + _querySLA.totalWitnessingReward(), + _getMsgValue() + ); } - + /// 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 upgradeQueryReward(uint256 _queryId) + /// @dev Fails if the `_witnetQueryId` is not in 'Posted' status. + /// @param _witnetQueryId The unique query identifier. + function upgradeQueryReward(uint256 _witnetQueryId) external payable virtual override - inStatus(_queryId, Witnet.QueryStatus.Posted) + inStatus(_witnetQueryId, Witnet.QueryStatus.Posted) { - Witnet.Request storage __request = __seekQueryRequest(_queryId); + Witnet.Request storage __request = __seekQueryRequest(_witnetQueryId); __request.evmReward += _getMsgValue(); - emit WitnetQueryRewardUpgraded(_queryId, __request.evmReward); + emit WitnetQueryRewardUpgraded(_witnetQueryId, __request.evmReward); } // ================================================================================================================ // --- Full implementation of IWitnetRequestBoardReporter --------------------------------------------------------- - /// Reports the Witnet-provided result to a previously posted request. + /// Reports the Witnet-provable result to a previously posted request. /// @dev Will assume `block.timestamp` as the timestamp at which the request was solved. /// @dev Fails if: - /// @dev - the `_queryId` is not in 'Posted' status. - /// @dev - provided `_drTxHash` is zero; + /// @dev - the `_witnetQueryId` is not in 'Posted' status. + /// @dev - provided `_witnetResultTallyHash` is zero; /// @dev - length of provided `_result` is zero. - /// @param _queryId The unique identifier of the data request. - /// @param _drTxHash The hash of the solving tally transaction in Witnet. - /// @param _cborBytes The result itself as bytes. + /// @param _witnetQueryId The unique identifier of the data request. + /// @param _witnetResultTallyHash Hash of the commit/reveal witnessing act that took place in the Witnet blockahin. + /// @param _witnetResultCborBytes The result itself as bytes. function reportResult( - uint256 _queryId, - bytes32 _drTxHash, - bytes calldata _cborBytes + uint256 _witnetQueryId, + bytes32 _witnetResultTallyHash, + bytes calldata _witnetResultCborBytes ) external override onlyReporters - inStatus(_queryId, Witnet.QueryStatus.Posted) + inStatus(_witnetQueryId, Witnet.QueryStatus.Posted) returns (uint256) { require( - _drTxHash != 0, - "WitnetRequestBoardTrustableDefault: Witnet drTxHash cannot be zero" + _witnetResultTallyHash != 0, + "WitnetRequestBoardTrustableDefault: tally has cannot be zero" ); // Ensures the result bytes do not have zero length // This would not be a valid encoding with CBOR and could trigger a reentrancy attack require( - _cborBytes.length != 0, + _witnetResultCborBytes.length != 0, "WitnetRequestBoardTrustableDefault: result cannot be empty" ); // Do actual report: // solhint-disable not-rely-on-time return __reportResultAndReward( - _queryId, - block.timestamp, - _drTxHash, - _cborBytes + _witnetQueryId, + uint64(block.timestamp), + _witnetResultTallyHash, + _witnetResultCborBytes ); } - /// Reports the Witnet-provided result to a previously posted request. + /// Reports the Witnet-provable result to a previously posted request. /// @dev Fails if: /// @dev - called from unauthorized address; - /// @dev - the `_queryId` is not in 'Posted' status. - /// @dev - provided `_drTxHash` is zero; - /// @dev - length of provided `_result` is zero. - /// @param _queryId The unique query identifier - /// @param _timestamp The timestamp of the solving tally transaction in Witnet. - /// @param _drTxHash The hash of the solving tally transaction in Witnet. - /// @param _cborBytes The result itself as bytes. + /// @dev - the `_witnetQueryId` is not in 'Posted' status. + /// @dev - provided `_witnetResultTallyHash` is zero; + /// @dev - length of provided `_witnetResultCborBytes` is zero. + /// @param _witnetQueryId The unique query identifier + /// @param _witnetResultTimestamp Timestamp at which the reported value was captured by the Witnet blockchain. + /// @param _witnetResultTallyHash Hash of the commit/reveal witnessing act that took place in the Witnet blockahin. + /// @param _witnetResultCborBytes The result itself as bytes. function reportResult( - uint256 _queryId, - uint256 _timestamp, - bytes32 _drTxHash, - bytes calldata _cborBytes + uint256 _witnetQueryId, + uint64 _witnetResultTimestamp, + bytes32 _witnetResultTallyHash, + bytes calldata _witnetResultCborBytes ) external override onlyReporters - inStatus(_queryId, Witnet.QueryStatus.Posted) + inStatus(_witnetQueryId, Witnet.QueryStatus.Posted) returns (uint256) { require( - _timestamp <= block.timestamp, + _witnetResultTimestamp <= block.timestamp, "WitnetRequestBoardTrustableDefault: bad timestamp" ); require( - _drTxHash != 0, - "WitnetRequestBoardTrustableDefault: Witnet drTxHash cannot be zero" + _witnetResultTallyHash != 0, + "WitnetRequestBoardTrustableDefault: Witnet tallyHash cannot be zero" ); // Ensures the result bytes do not have zero length (this would not be a valid CBOR encoding // and could trigger a reentrancy attack) require( - _cborBytes.length != 0, + _witnetResultCborBytes.length != 0, "WitnetRequestBoardTrustableDefault: result cannot be empty" ); // Do actual report and return reward transfered to the reproter: return __reportResultAndReward( - _queryId, - _timestamp, - _drTxHash, - _cborBytes + _witnetQueryId, + _witnetResultTimestamp, + _witnetResultTallyHash, + _witnetResultCborBytes ); } - /// Reports Witnet-provided results to multiple requests within a single EVM tx. + /// Reports Witnet-provable results to multiple requests within a single EVM tx. /// @dev Fails if called from unauthorized address. /// @dev Emits a PostedResult event for every succesfully reported result, if any. /// @param _batchResults Array of BatchedResult structs, every one containing: @@ -639,11 +659,11 @@ abstract contract WitnetRequestBoardTrustableBase "WitnetRequestBoardTrustableBase: bad queryId" ); } - } else if (_batchResults[_i].drTxHash == 0) { + } else if (_batchResults[_i].tallyHash == 0) { if (_verbose) { emit BatchReportError( _batchResults[_i].queryId, - "WitnetRequestBoardTrustableBase: bad drTxHash" + "WitnetRequestBoardTrustableBase: bad tallyHash" ); } } else if (_batchResults[_i].cborBytes.length == 0) { @@ -663,8 +683,8 @@ abstract contract WitnetRequestBoardTrustableBase } else { _batchReward += __reportResult( _batchResults[_i].queryId, - _batchResults[_i].timestamp == 0 ? block.timestamp : _batchResults[_i].timestamp, - _batchResults[_i].drTxHash, + _batchResults[_i].timestamp == 0 ? uint64(block.timestamp) : _batchResults[_i].timestamp, + _batchResults[_i].tallyHash, _batchResults[_i].cborBytes ); } @@ -746,160 +766,137 @@ abstract contract WitnetRequestBoardTrustableBase // ================================================================================================================ // --- Internal functions ----------------------------------------------------------------------------------------- - function __newQuery() - virtual internal returns (uint256) + function __newQueryId(bytes32 _queryRAD, bytes32 _querySLA) + virtual internal view + returns (uint256) { - return ++ __storage().nonce; + return uint(keccak256(abi.encode( + group, + block.number, + msg.sender, + _queryRAD, + _querySLA + ))); } - function __postRequest(bytes32 _radHash, bytes32 _slaPacked) + function __postRequest(bytes32 _radHash, bytes32 _packedSLA, uint96 _callbackGasLimit) virtual internal - returns (uint256 _queryId) + returns (uint256 _witnetQueryId) { - _queryId = __newQuery(); - Witnet.Request storage __request = __seekQueryRequest(_queryId); + _witnetQueryId = __newQueryId(_radHash, _packedSLA); + Witnet.Request storage __request = __seekQueryRequest(_witnetQueryId); + require( + __request.fromCallbackGas == bytes32(0), + "WitnetRequestBoardTrustableBase: already posted" + ); { - __request.radHash = _radHash; - __request.slaPacked = _slaPacked; + __request.fromCallbackGas = Witnet.packRequesterCallbackGasLimit(msg.sender, _callbackGasLimit); + __request.RAD = _radHash; + __request.SLA = _packedSLA; __request.evmReward = _getMsgValue(); } - __seekQuery(_queryId).from = msg.sender; } function __reportResult( - uint256 _queryId, - uint256 _drTxTimestamp, - bytes32 _drTxHash, - bytes calldata _cborBytes + uint256 _witnetQueryId, + uint64 _witnetResultTimestamp, + bytes32 _witnetResultTallyHash, + bytes calldata _witnetResultCborBytes ) - internal + virtual internal returns (uint256 _evmReward) { - Witnet.Query storage __query = __seekQuery(_queryId); + // read requester address and whether a callback was requested: + Witnet.Request storage __request = __seekQueryRequest(_witnetQueryId); + (address _evmRequester, uint96 _evmCallbackGasLimit) = __request.unpackRequesterAndCallbackGasLimit(); - // read and erase query report reward - Witnet.Request storage __request = __query.request; + // read query EVM reward: _evmReward = __request.evmReward; + + // set EVM reward right now as to avoid re-entrancy attacks: __request.evmReward = 0; // determine whether a callback is required - if (__request.maxCallbackGas > 0) { - uint _evmCallbackActualGas = gasleft() - 6295; - bool _evmCallbackSuccess = false; - string memory _evmCallbackRevertMessage; - // if callback is required, select which callback method to call - // depending on whether the query was solved with or without errors: - if (_cborBytes[0] == bytes1(0xd8)) { - WitnetCBOR.CBOR[] memory _errors = WitnetCBOR.fromBytes(_cborBytes).readArray(); - if (_errors.length < 2) { - // try to report result with unknown error: - try IWitnetConsumer(__query.from).reportWitnetQueryError{gas: __request.maxCallbackGas}( - _queryId, - _drTxHash, - _drTxTimestamp, - block.number, - Witnet.ResultErrorCodes.Unknown, - WitnetCBOR.CBOR({ - buffer: WitnetBuffer.Buffer({ data: hex"", cursor: 0}), - initialByte: 0, - majorType: 0, - additionalInformation: 0, - len: 0, - tag: 0 - }) - ) { - _evmCallbackSuccess = true; - } catch Error(string memory err) { - _evmCallbackRevertMessage = err; - } - } else { - // try to report result with parsable error: - try IWitnetConsumer(__query.from).reportWitnetQueryError{gas: __request.maxCallbackGas}( - _queryId, - _drTxHash, - _drTxTimestamp, - block.number, - Witnet.ResultErrorCodes(_errors[0].readUint()), - _errors[0] - ) { - _evmCallbackSuccess = true; - } catch Error(string memory err) { - _evmCallbackRevertMessage = err; - } - } - } else { - // try to report result result with no error : - try IWitnetConsumer(__query.from).reportWitnetQueryResult{gas: __request.maxCallbackGas}( - _queryId, - _drTxHash, - _drTxTimestamp, - block.number, - WitnetCBOR.fromBytes(_cborBytes) - ) { - _evmCallbackSuccess = true; - } catch Error(string memory err) { - _evmCallbackRevertMessage = err; - } catch (bytes memory) {} - } + if (_evmCallbackGasLimit > 0) { + ( + uint256 _evmCallbackActualGas, + bool _evmCallbackSuccess, + string memory _evmCallbackRevertMessage + ) = __reportResultCallback( + _witnetQueryId, + _witnetResultTimestamp, + _witnetResultTallyHash, + _witnetResultCborBytes, + _evmRequester, + _evmCallbackGasLimit + ); if (_evmCallbackSuccess) { // => the callback run successfully emit WitnetResponseDelivered( - _queryId, + _witnetQueryId, _getGasPrice(), - _evmCallbackActualGas - gasleft() + _evmCallbackActualGas + ); + // upon successfull delivery, the audit trail is saved into storage, but not the actual result + // as it was already passed over to the requester: + __writeQueryResponse( + _witnetQueryId, + _witnetResultTimestamp, + _witnetResultTallyHash, + hex"" ); - // after successfull report, remove the whole query from storage: - delete __storage().queries[_queryId]; } else { // => the callback reverted emit WitnetResponseDeliveryFailed( - _queryId, + _witnetQueryId, + _witnetResultCborBytes, _getGasPrice(), - _evmCallbackActualGas - gasleft(), - bytes(_evmCallbackRevertMessage).length > 0 - ? _evmCallbackRevertMessage - : "WitnetRequestBoardTrustableDefault: callback gas limit exceeded?" + _evmCallbackActualGas, + bytes(_evmCallbackRevertMessage).length > 0 + ? _evmCallbackRevertMessage + : "WitnetRequestBoardTrustableBase: callback exceeded gas limit" ); - // write query result and traceability data into storage: - __writeQueryResponse(_queryId, _drTxHash, _drTxTimestamp, _cborBytes); - } + // upon failing delivery, only the witnet result tally hash is saved into storage, + // as to distinguish Reported vs Undelivered status. The query result is not saved + // into storage as to avoid buffer-overflow attacks (on reporters): + __writeQueryResponse( + _witnetQueryId, + 0, + _witnetResultTallyHash, + hex"" + ); + } } else { // => no callback is involved emit WitnetQueryReported( - _queryId, + _witnetQueryId, _getGasPrice() ); - // write query result and traceability data into storage - __writeQueryResponse(_queryId, _drTxHash, _drTxTimestamp, _cborBytes); + // write query result and audit trail data into storage + __writeQueryResponse( + _witnetQueryId, + _witnetResultTimestamp, + _witnetResultTallyHash, + _witnetResultCborBytes + ); } } - function __writeQueryResponse( - uint256 _queryId, - bytes32 _drTxHash, - uint256 _drTxTimestamp, - bytes memory _cborBytes - ) - internal - { - __seekQuery(_queryId).response = Witnet.Response({ - timestamp: _drTxTimestamp, - drTxHash: _drTxHash, - reporter: msg.sender, - cborBytes: _cborBytes - }); - } - function __reportResultAndReward( - uint256 _queryId, - uint256 _timestamp, - bytes32 _drTxHash, - bytes calldata _cborBytes + uint256 _witnetQueryId, + uint64 _witnetResultTimestamp, + bytes32 _witnetResultTallyHash, + bytes calldata _witnetResultCborBytes ) - internal + virtual internal returns (uint256 _evmReward) { - _evmReward = __reportResult(_queryId, _timestamp, _drTxHash, _cborBytes); + _evmReward = __reportResult( + _witnetQueryId, + _witnetResultTimestamp, + _witnetResultTallyHash, + _witnetResultCborBytes + ); // transfer reward to reporter __safeTransferTo( payable(msg.sender), @@ -907,7 +904,80 @@ abstract contract WitnetRequestBoardTrustableBase ); } - function __setReporters(address[] memory _reporters) internal { + function __reportResultCallback( + uint256 _witnetQueryId, + uint64 _witnetResultTimestamp, + bytes32 _witnetResultTallyHash, + bytes calldata _witnetResultCborBytes, + address _evmRequester, + uint256 _evmCallbackGasLimit + ) + virtual internal + returns ( + uint256 _evmCallbackActualGas, + bool _evmCallbackSuccess, + string memory _evmCallbackRevertMessage + ) + { + _evmCallbackActualGas = gasleft(); + if (_witnetResultCborBytes[0] == bytes1(0xd8)) { + WitnetCBOR.CBOR[] memory _errors = WitnetCBOR.fromBytes(_witnetResultCborBytes).readArray(); + if (_errors.length < 2) { + // try to report result with unknown error: + try IWitnetConsumer(_evmRequester).reportWitnetQueryError{gas: _evmCallbackGasLimit}( + _witnetQueryId, + _witnetResultTimestamp, + _witnetResultTallyHash, + block.number, + Witnet.ResultErrorCodes.Unknown, + WitnetCBOR.CBOR({ + buffer: WitnetBuffer.Buffer({ data: hex"", cursor: 0}), + initialByte: 0, + majorType: 0, + additionalInformation: 0, + len: 0, + tag: 0 + }) + ) { + _evmCallbackSuccess = true; + } catch Error(string memory err) { + _evmCallbackRevertMessage = err; + } + } else { + // try to report result with parsable error: + try IWitnetConsumer(_evmRequester).reportWitnetQueryError{gas: _evmCallbackGasLimit}( + _witnetQueryId, + _witnetResultTimestamp, + _witnetResultTallyHash, + block.number, + Witnet.ResultErrorCodes(_errors[0].readUint()), + _errors[0] + ) { + _evmCallbackSuccess = true; + } catch Error(string memory err) { + _evmCallbackRevertMessage = err; + } + } + } else { + // try to report result result with no error : + try IWitnetConsumer(_evmRequester).reportWitnetQueryResult{gas: _evmCallbackGasLimit}( + _witnetQueryId, + _witnetResultTimestamp, + _witnetResultTallyHash, + block.number, + WitnetCBOR.fromBytes(_witnetResultCborBytes) + ) { + _evmCallbackSuccess = true; + } catch Error(string memory err) { + _evmCallbackRevertMessage = err; + } catch (bytes memory) {} + } + _evmCallbackActualGas -= gasleft(); + } + + function __setReporters(address[] memory _reporters) + virtual internal + { for (uint ix = 0; ix < _reporters.length; ix ++) { address _reporter = _reporters[ix]; _acls().isReporter_[_reporter] = true; @@ -915,4 +985,20 @@ abstract contract WitnetRequestBoardTrustableBase emit ReportersSet(_reporters); } + function __writeQueryResponse( + uint256 _witnetQueryId, + uint64 _witnetResultTimestamp, + bytes32 _witnetResultTallyHash, + bytes memory _witnetResultCborBytes + ) + virtual internal + { + __seekQuery(_witnetQueryId).response = Witnet.Response({ + fromFinality: Witnet.packReporterEvmFinalityBlock(msg.sender, block.number), + timestamp: _witnetResultTimestamp, + tallyHash: _witnetResultTallyHash, + cborBytes: _witnetResultCborBytes + }); + } + } \ No newline at end of file From 44723a85f5b782c01efe66f10590ba1343716d12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Tue, 28 Nov 2023 16:20:13 +0100 Subject: [PATCH 68/86] chore: arrange contract/apps/* to latest changes --- contracts/apps/UsingWitnet.sol | 35 +++----------- contracts/apps/UsingWitnetRandomness.sol | 46 ++++++------------ contracts/apps/UsingWitnetRequest.sol | 6 +-- contracts/apps/UsingWitnetRequestTemplate.sol | 6 +-- contracts/apps/WitnetConsumer.sol | 47 ++++++++++++++----- contracts/apps/WitnetPriceFeeds.sol | 18 +++---- contracts/apps/WitnetRandomness.sol | 13 ++--- contracts/apps/WitnetRequestConsumer.sol | 32 +++++++++---- .../apps/WitnetRequestTemplateConsumer.sol | 35 ++++++++++---- contracts/mocks/WitnetRandomnessMock.sol | 2 +- 10 files changed, 129 insertions(+), 111 deletions(-) diff --git a/contracts/apps/UsingWitnet.sol b/contracts/apps/UsingWitnet.sol index 088d67e02..546fd4349 100644 --- a/contracts/apps/UsingWitnet.sol +++ b/contracts/apps/UsingWitnet.sol @@ -48,29 +48,19 @@ abstract contract UsingWitnet /// @notice Estimate the minimum reward required for posting a data request, using `tx.gasprice` as a reference. /// @dev Underestimates if the size of returned data is greater than `_resultMaxSize`. /// @param _resultMaxSize Maximum expected size of returned data (in bytes). - function _witnetEstimateBaseFee(uint256 _resultMaxSize) + function _witnetEstimateBaseFee(uint16 _resultMaxSize) virtual internal view returns (uint256) { return __witnet.estimateBaseFee(tx.gasprice, _resultMaxSize); } - /// @notice Estimate the minimum reward required for posting a data request, using `tx.gasprice` as a reference. - /// @dev Underestimates if the size of returned data is greater than `_resultMaxSize`. - /// @param _resultMaxSize Maximum expected size of returned data (in bytes). - /// @param _maxCallbackGas Maximum gas to be spent when reporting the data request result. - function _witnetEstimateBaseFeeWithCallback(uint256 _resultMaxSize, uint256 _maxCallbackGas) - internal view - returns (uint256) - { - return __witnet.estimateBaseFeeWithCallback(tx.gasprice, _resultMaxSize, _maxCallbackGas); - } - function _witnetCheckQueryResultAuditTrail(uint256 _witnetQueryId) internal view returns ( - uint256 _witnetQueryResponseTimestamp, - bytes32 _witnetQueryResponseDrTxHash + uint256 _witnetResultTimestamp, + bytes32 _witnetResultTallyHash, + uint256 _witnetEvmFinalityBlock ) { return __witnet.getQueryResultAuditTrail(_witnetQueryId); @@ -92,8 +82,8 @@ abstract contract UsingWitnet function __witnetRequestData( uint256 _witnetEvmReward, - bytes32 _witnetRadHash, - WitnetV2.RadonSLA memory _witnetQuerySLA + WitnetV2.RadonSLA memory _witnetQuerySLA, + bytes32 _witnetRadHash ) virtual internal returns (uint256) { @@ -102,17 +92,4 @@ abstract contract UsingWitnet _witnetQuerySLA ); } - - function __witnetRequestData( - uint256 _witnetEvmReward, - bytes calldata _witnetRadBytecode, - WitnetV2.RadonSLA memory _witnetQuerySLA - ) - internal returns (uint256) - { - return __witnet.postRequest{value: _witnetEvmReward}( - _witnetRadBytecode, - _witnetQuerySLA - ); - } } diff --git a/contracts/apps/UsingWitnetRandomness.sol b/contracts/apps/UsingWitnetRandomness.sol index 708b6e9e8..df034d3f0 100644 --- a/contracts/apps/UsingWitnetRandomness.sol +++ b/contracts/apps/UsingWitnetRandomness.sol @@ -18,9 +18,9 @@ abstract contract UsingWitnetRandomness bytes32 internal immutable __witnetRandomnessRadHash; bytes32 private __defaultRandomizePackedSLA; - constructor(WitnetRequestBoard _wrb, uint256 _maxRandomizeCallbackGas) + constructor(WitnetRequestBoard _wrb, uint96 _randomizeCallbackGasLimit) UsingWitnet(_wrb) - WitnetConsumer(_maxRandomizeCallbackGas) + WitnetConsumer(_randomizeCallbackGasLimit) { // Build Witnet randomness request { @@ -48,7 +48,7 @@ abstract contract UsingWitnetRandomness _retrievals, _aggregator, _tally, - 0 + 35 // CBOR overhead (3 bytes) + payload (32 bytes) )); __witnetRandomnessRadHash = WitnetRequest( _template.buildRequest(new string[][](_retrievals.length)) @@ -56,9 +56,10 @@ abstract contract UsingWitnetRandomness } // Settle default randomize SLA: __defaultRandomizePackedSLA = WitnetV2.RadonSLA({ - numWitnesses: 7, - witnessingCollateralRatio: 10 - }).packed(); + witnessingCommitteeSize: 7, + witnessingCollateralRatio: 10, + witnessingWitReward: 10 ** 9 + }).toBytes32(); } function _defaultRandomizeSLA() internal view returns (WitnetV2.RadonSLA memory) { @@ -69,32 +70,13 @@ abstract contract UsingWitnetRandomness return _witnetEstimateBaseFee(35); } - /// @dev Returns index of the Most Significant Bit of the given number, applying De Bruijn O(1) algorithm. - function _msbDeBruijn32(uint32 _v) private pure returns (uint8) { - uint8[32] memory _bitPosition = [ - 0, 9, 1, 10, 13, 21, 2, 29, - 11, 14, 16, 18, 22, 25, 3, 30, - 8, 12, 20, 28, 15, 17, 24, 7, - 19, 27, 23, 6, 26, 5, 4, 31 - ]; - _v |= _v >> 1; - _v |= _v >> 2; - _v |= _v >> 4; - _v |= _v >> 8; - _v |= _v >> 16; - return _bitPosition[ - uint32(_v * uint256(0x07c4acdd)) >> 27 - ]; - } - function _randomUniform(uint32 _range, uint256 _nonce, bytes32 _seed) internal pure returns (uint32) { - uint8 _flagBits = uint8(255 - _msbDeBruijn32(_range)); uint256 _number = uint256( keccak256( abi.encode(_seed, _nonce) ) - ) & uint256(2 ** _flagBits - 1); - return uint32((_number * _range) >> _flagBits); + ) & uint256(2 ** 224 - 1); + return uint32((_number * _range) >> 224); } function _readRandomnessFromResultValue(WitnetCBOR.CBOR calldata cborValue) internal pure returns (bytes32) { @@ -104,8 +86,8 @@ abstract contract UsingWitnetRandomness function __randomize(uint256 _witnetEvmReward) virtual internal returns (uint256) { return __witnetRequestData( _witnetEvmReward, - __witnetRandomnessRadHash, - _defaultRandomizeSLA() + _defaultRandomizeSLA(), + __witnetRandomnessRadHash ); } @@ -118,12 +100,12 @@ abstract contract UsingWitnetRandomness { return __witnetRequestData( _witnetEvmReward, - __witnetRandomnessRadHash, - _witnetQuerySLA + _witnetQuerySLA, + __witnetRandomnessRadHash ); } function __settleRandomizeDefaultSLA(WitnetV2.RadonSLA calldata sla) virtual internal { - __defaultRandomizePackedSLA = sla.packed(); + __defaultRandomizePackedSLA = sla.toBytes32(); } } \ No newline at end of file diff --git a/contracts/apps/UsingWitnetRequest.sol b/contracts/apps/UsingWitnetRequest.sol index 40ae556ab..3e75ca492 100644 --- a/contracts/apps/UsingWitnetRequest.sol +++ b/contracts/apps/UsingWitnetRequest.sol @@ -10,7 +10,7 @@ abstract contract UsingWitnetRequest WitnetRequest immutable public dataRequest; bytes32 immutable internal __witnetRequestRadHash; - uint256 immutable internal __witnetResultMaxSize; + uint16 immutable internal __witnetResultMaxSize; constructor (WitnetRequest _witnetRequest) UsingWitnet(_witnetRequest.witnet()) @@ -42,8 +42,8 @@ abstract contract UsingWitnetRequest { return __witnetRequestData( _witnetEvmReward, - __witnetRequestRadHash, - _witnetQuerySLA + _witnetQuerySLA, + __witnetRequestRadHash ); } diff --git a/contracts/apps/UsingWitnetRequestTemplate.sol b/contracts/apps/UsingWitnetRequestTemplate.sol index ffd54bbcb..c95d591da 100644 --- a/contracts/apps/UsingWitnetRequestTemplate.sol +++ b/contracts/apps/UsingWitnetRequestTemplate.sol @@ -9,7 +9,7 @@ abstract contract UsingWitnetRequestTemplate { WitnetRequestTemplate immutable public dataRequestTemplate; - uint256 immutable internal __witnetResultMaxSize; + uint16 immutable internal __witnetResultMaxSize; constructor (WitnetRequestTemplate _requestTemplate) UsingWitnet(_requestTemplate.witnet()) @@ -53,8 +53,8 @@ abstract contract UsingWitnetRequestTemplate { return __witnetRequestData( _witnetEvmReward, - _witnetBuildRadHash(_witnetRequestArgs), - _witnetQuerySLA + _witnetQuerySLA, + _witnetBuildRadHash(_witnetRequestArgs) ); } diff --git a/contracts/apps/WitnetConsumer.sol b/contracts/apps/WitnetConsumer.sol index 0c02a8ed1..3a460dc29 100644 --- a/contracts/apps/WitnetConsumer.sol +++ b/contracts/apps/WitnetConsumer.sol @@ -9,15 +9,15 @@ abstract contract WitnetConsumer IWitnetConsumer, UsingWitnet { - uint256 private immutable __witnetReportCallbackMaxGas; + uint96 private immutable __witnetReportCallbackGasLimit; modifier onlyFromWitnet { require(msg.sender == address(__witnet), "WitnetConsumer: unauthorized"); _; } - constructor (uint256 _maxCallbackGas) { - __witnetReportCallbackMaxGas = _maxCallbackGas; + constructor (uint96 _maxCallbackGas) { + __witnetReportCallbackGasLimit = _maxCallbackGas; } @@ -32,24 +32,35 @@ abstract contract WitnetConsumer /// =============================================================================================================== /// --- WitnetConsumer virtual methods ---------------------------------------------------------------------------- - function _witnetEstimateBaseFee(uint256 _resultMaxSize) + function _witnetEstimateBaseFee(uint16) virtual override internal view returns (uint256) { - return _witnetEstimateBaseFeeWithCallback(_resultMaxSize, _witnetReportCallbackMaxGas()); + return _witnetEstimateBaseFeeWithCallback(_witnetReportCallbackGasLimit()); } - function _witnetReportCallbackMaxGas() - virtual internal view + + /// @notice Estimate the minimum reward required for posting a data request, using `tx.gasprice` as a reference. + /// @dev Underestimates if the size of returned data is greater than `_resultMaxSize`. + /// @param _callbackGasLimit Maximum gas to be spent when reporting the data request result. + function _witnetEstimateBaseFeeWithCallback(uint96 _callbackGasLimit) + virtual internal view returns (uint256) { - return __witnetReportCallbackMaxGas; + return __witnet.estimateBaseFeeWithCallback(tx.gasprice, _callbackGasLimit); + } + + function _witnetReportCallbackGasLimit() + virtual internal view + returns (uint96) + { + return __witnetReportCallbackGasLimit; } function __witnetRequestData( uint256 _witnetEvmReward, - bytes32 _witnetRadHash, - WitnetV2.RadonSLA memory _witnetQuerySLA + WitnetV2.RadonSLA memory _witnetQuerySLA, + bytes32 _witnetRadHash ) virtual override internal returns (uint256) @@ -57,7 +68,21 @@ abstract contract WitnetConsumer return __witnet.postRequestWithCallback{value: _witnetEvmReward}( _witnetRadHash, _witnetQuerySLA, - __witnetReportCallbackMaxGas + __witnetReportCallbackGasLimit + ); + } + + function __witnetRequestData( + uint256 _witnetEvmReward, + WitnetV2.RadonSLA memory _witnetQuerySLA, + bytes calldata _witnetRequestBytecode + ) + virtual internal returns (uint256) + { + return __witnet.postRequestWithCallback{value: _witnetEvmReward}( + _witnetRequestBytecode, + _witnetQuerySLA, + __witnetReportCallbackGasLimit ); } diff --git a/contracts/apps/WitnetPriceFeeds.sol b/contracts/apps/WitnetPriceFeeds.sol index 13ce07490..515f82648 100644 --- a/contracts/apps/WitnetPriceFeeds.sol +++ b/contracts/apps/WitnetPriceFeeds.sol @@ -27,6 +27,7 @@ contract WitnetPriceFeeds WitnetPriceFeedsData { using Witnet for Witnet.Result; + using Witnet for Witnet.Response; using WitnetV2 for WitnetV2.RadonSLA; bytes4 immutable public specs = type(IWitnetPriceFeeds).interfaceId; @@ -45,8 +46,9 @@ contract WitnetPriceFeeds ); witnet = _wrb; __settleDefaultRadonSLA(WitnetV2.RadonSLA({ - numWitnesses: 5, - witnessingCollateralRatio: 10 + witnessingCommitteeSize: 5, + witnessingCollateralRatio: 10, + witnessingWitReward: 10 ** 9 })); } @@ -171,7 +173,7 @@ contract WitnetPriceFeeds function latestUpdateRequest(bytes4 feedId) override external view - returns (Witnet.Request memory) + returns (bytes32, WitnetV2.RadonSLA memory) { return witnet.getQueryRequest(latestUpdateQueryId(feedId)); } @@ -459,7 +461,7 @@ contract WitnetPriceFeeds return IWitnetPriceSolver.Price({ value: _latestResult.asUint(), timestamp: _latestResponse.timestamp, - drTxHash: _latestResponse.drTxHash, + tallyHash: _latestResponse.tallyHash, status: latestUpdateResultStatus(feedId) }); } else { @@ -485,7 +487,7 @@ contract WitnetPriceFeeds return IWitnetPriceSolver.Price({ value: 0, timestamp: 0, - drTxHash: 0, + tallyHash: 0, status: latestUpdateResultStatus(feedId) }); } @@ -613,7 +615,7 @@ contract WitnetPriceFeeds _usedFunds = estimateUpdateBaseFee(tx.gasprice); require( msg.value >= _usedFunds, - "WitnetPriceFeeds: reward too low" + "WitnetPriceFeeds: insufficient reward" ); uint _latestId = __feed.latestUpdateQueryId; Witnet.ResultStatus _latestStatus = _checkQueryResultStatus(_latestId); @@ -651,7 +653,7 @@ contract WitnetPriceFeeds emit UpdatingFeed( msg.sender, feedId, - querySLA.packed(), + querySLA.toBytes32(), _usedFunds ); } @@ -670,6 +672,6 @@ contract WitnetPriceFeeds } function __settleDefaultRadonSLA(WitnetV2.RadonSLA memory sla) internal { - __storage().packedDefaultSLA = WitnetV2.packed(sla); + __storage().packedDefaultSLA = WitnetV2.toBytes32(sla); } } diff --git a/contracts/apps/WitnetRandomness.sol b/contracts/apps/WitnetRandomness.sol index 3996166e6..5a3990f21 100644 --- a/contracts/apps/WitnetRandomness.sol +++ b/contracts/apps/WitnetRandomness.sol @@ -70,7 +70,7 @@ contract WitnetRandomness _retrievals, _aggregator, _tally, - 0 + 35 // CBOR overhead (3 bytes) + payload (32 bytes) )); witnetRandomnessRequest = WitnetRequest(_template.buildRequest(new string[][](_retrievals.length))); __witnetRandomnessRadHash = witnetRandomnessRequest.radHash(); @@ -328,8 +328,8 @@ contract WitnetRandomness // Post the Witnet Randomness request: uint _queryId = __witnetRequestData( msg.value, - __witnetRandomnessRadHash, - __witnetRandomnessPackedSLA.toRadonSLA() + __witnetRandomnessPackedSLA.toRadonSLA(), + __witnetRandomnessRadHash ); // Keep Randomize data in storage: RandomizeData storage __data = __randomize_[block.number]; @@ -465,8 +465,9 @@ contract WitnetRandomness function __initializeWitnetRandomnessSLA() virtual internal { __settleWitnetRandomnessSLA(WitnetV2.RadonSLA({ - numWitnesses: 5, - witnessingCollateralRatio: 10 + witnessingCommitteeSize: 5, + witnessingCollateralRatio: 10, + witnessingWitReward: 10 ** 9 })); } @@ -474,7 +475,7 @@ contract WitnetRandomness internal returns (bytes32 _packed) { - _packed = sla.packed(); + _packed = sla.toBytes32(); __witnetRandomnessPackedSLA = _packed; } diff --git a/contracts/apps/WitnetRequestConsumer.sol b/contracts/apps/WitnetRequestConsumer.sol index b6071366b..e8f4e0ec5 100644 --- a/contracts/apps/WitnetRequestConsumer.sol +++ b/contracts/apps/WitnetRequestConsumer.sol @@ -12,14 +12,14 @@ abstract contract WitnetRequestConsumer using WitnetCBOR for WitnetCBOR.CBOR; using WitnetCBOR for WitnetCBOR.CBOR[]; - constructor(WitnetRequest _witnetRequest, uint256 _maxCallbackGas) + constructor(WitnetRequest _witnetRequest, uint96 _callbackGasLimit) UsingWitnetRequest(_witnetRequest) - WitnetConsumer(_maxCallbackGas) + WitnetConsumer(_callbackGasLimit) { require( - _witnetEstimateBaseFeeWithCallback(_witnetRequest.resultDataMaxSize(), _maxCallbackGas) + _witnetEstimateBaseFeeWithCallback(_callbackGasLimit) > UsingWitnetRequest._witnetEstimateBaseFee(), - "WitnetRequestConsumer: callback gas limit too low" + "WitnetRequestConsumer: insufficient callback gas limit" ); } @@ -31,7 +31,7 @@ abstract contract WitnetRequestConsumer return WitnetConsumer._witnetEstimateBaseFee(__witnetResultMaxSize); } - function _witnetEstimateBaseFee(uint256 _resultMaxSize) + function _witnetEstimateBaseFee(uint16 _resultMaxSize) virtual override(UsingWitnet, WitnetConsumer) internal view returns (uint256) @@ -41,17 +41,31 @@ abstract contract WitnetRequestConsumer function __witnetRequestData( uint256 _witnetEvmReward, - bytes32 _witnetRadHash, - WitnetV2.RadonSLA memory _witnetQuerySLA + WitnetV2.RadonSLA memory _witnetQuerySLA, + bytes32 _witnetRadHash ) virtual override(UsingWitnet, WitnetConsumer) internal returns (uint256) { return WitnetConsumer.__witnetRequestData( _witnetEvmReward, - _witnetRadHash, - _witnetQuerySLA + _witnetQuerySLA, + _witnetRadHash ); } + function __witnetRequestData( + uint256 _witnetEvmReward, + WitnetV2.RadonSLA memory _witnetQuerySLA + ) + virtual override internal + returns (uint256) + { + return WitnetConsumer.__witnetRequestData( + _witnetEvmReward, + _witnetQuerySLA, + __witnetRequestRadHash + ); + } + } diff --git a/contracts/apps/WitnetRequestTemplateConsumer.sol b/contracts/apps/WitnetRequestTemplateConsumer.sol index 1f804cf1d..7adad22c5 100644 --- a/contracts/apps/WitnetRequestTemplateConsumer.sol +++ b/contracts/apps/WitnetRequestTemplateConsumer.sol @@ -12,14 +12,14 @@ abstract contract WitnetRequestTemplateConsumer using WitnetCBOR for WitnetCBOR.CBOR; using WitnetCBOR for WitnetCBOR.CBOR[]; - constructor(WitnetRequestTemplate _requestTemplate, uint256 _maxCallbackGas) + constructor(WitnetRequestTemplate _requestTemplate, uint96 _callbackGasLimit) UsingWitnetRequestTemplate(_requestTemplate) - WitnetConsumer(_maxCallbackGas) + WitnetConsumer(_callbackGasLimit) { require( - _witnetEstimateBaseFeeWithCallback(_requestTemplate.resultDataMaxSize(), _maxCallbackGas) + _witnetEstimateBaseFeeWithCallback(_callbackGasLimit) > UsingWitnetRequestTemplate._witnetEstimateBaseFee(), - "WitnetRequestTemplateConsumer: callback gas limit too low" + "WitnetRequestTemplateConsumer: insufficient callback gas limit" ); } @@ -32,7 +32,7 @@ abstract contract WitnetRequestTemplateConsumer return WitnetConsumer._witnetEstimateBaseFee(__witnetResultMaxSize); } - function _witnetEstimateBaseFee(uint256 _resultMaxSize) + function _witnetEstimateBaseFee(uint16 _resultMaxSize) virtual override(UsingWitnet, WitnetConsumer) internal view returns (uint256) @@ -42,17 +42,34 @@ abstract contract WitnetRequestTemplateConsumer function __witnetRequestData( uint256 _witnetEvmReward, - bytes32 _witnetRadHash, - WitnetV2.RadonSLA memory _witnetQuerySLA + WitnetV2.RadonSLA memory _witnetQuerySLA, + bytes32 _witnetRadHash ) virtual override(UsingWitnet, WitnetConsumer) internal returns (uint256) { return WitnetConsumer.__witnetRequestData( _witnetEvmReward, - _witnetRadHash, - _witnetQuerySLA + _witnetQuerySLA, + _witnetRadHash ); } + function __witnetRequestData( + uint256 _witnetEvmReward, + WitnetV2.RadonSLA memory _witnetQuerySLA, + string[][] memory _witnetRequestArgs + ) + virtual override internal + returns (uint256) + { + return WitnetConsumer.__witnetRequestData( + _witnetEvmReward, + _witnetQuerySLA, + _witnetBuildRadHash(_witnetRequestArgs) + ); + } + + + } diff --git a/contracts/mocks/WitnetRandomnessMock.sol b/contracts/mocks/WitnetRandomnessMock.sol index 0d86c7f57..6e15db063 100644 --- a/contracts/mocks/WitnetRandomnessMock.sol +++ b/contracts/mocks/WitnetRandomnessMock.sol @@ -115,7 +115,7 @@ contract WitnetRandomnessMock _usedFunds = __mockRandomizeFee; require( msg.value >= _usedFunds, - "WitnetRandomnessMock: reward too low" + "WitnetRandomnessMock: insufficient reward" ); // Post the Witnet Randomness request: uint _queryId = ++ __mockRandomizeLatestId; From 88065dc6de7e451f07f081501fa8b4413db8637d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Tue, 28 Nov 2023 16:56:50 +0100 Subject: [PATCH 69/86] refactor: changes on Witnet.* -> WitnetV2.* --- contracts/apps/UsingWitnet.sol | 4 +- contracts/apps/WitnetPriceFeeds.sol | 32 ++- contracts/apps/WitnetRandomness.sol | 9 +- .../WitnetRequestBoardTrustableBase.sol | 78 +++--- contracts/data/WitnetRequestBoardData.sol | 40 +-- contracts/interfaces/IWitnetRequestBoard.sol | 10 +- contracts/interfaces/V2/IWitnetFeeds.sol | 6 +- .../interfaces/V2/IWitnetPriceSolver.sol | 2 +- contracts/libs/Witnet.sol | 262 +++++++++--------- contracts/libs/WitnetErrorsLib.sol | 8 +- contracts/libs/WitnetV2.sol | 105 ++++++- 11 files changed, 327 insertions(+), 229 deletions(-) diff --git a/contracts/apps/UsingWitnet.sol b/contracts/apps/UsingWitnet.sol index 546fd4349..f19147db5 100644 --- a/contracts/apps/UsingWitnet.sol +++ b/contracts/apps/UsingWitnet.sol @@ -42,7 +42,7 @@ abstract contract UsingWitnet internal view returns (bool) { - return __witnet.getQueryStatus(_id) == Witnet.QueryStatus.Reported; + return __witnet.getQueryStatus(_id) == WitnetV2.QueryStatus.Reported; } /// @notice Estimate the minimum reward required for posting a data request, using `tx.gasprice` as a reference. @@ -68,7 +68,7 @@ abstract contract UsingWitnet function _witnetCheckQueryResultStatus(uint256 _witnetQueryId) internal view - returns (Witnet.ResultStatus) + returns (WitnetV2.ResultStatus) { return __witnet.getQueryResultStatus(_witnetQueryId); } diff --git a/contracts/apps/WitnetPriceFeeds.sol b/contracts/apps/WitnetPriceFeeds.sol index 515f82648..2ffcbffa5 100644 --- a/contracts/apps/WitnetPriceFeeds.sol +++ b/contracts/apps/WitnetPriceFeeds.sol @@ -27,7 +27,7 @@ contract WitnetPriceFeeds WitnetPriceFeedsData { using Witnet for Witnet.Result; - using Witnet for Witnet.Response; + using WitnetV2 for WitnetV2.Response; using WitnetV2 for WitnetV2.RadonSLA; bytes4 immutable public specs = type(IWitnetPriceFeeds).interfaceId; @@ -152,7 +152,7 @@ contract WitnetPriceFeeds function latestResponse(bytes4 feedId) override public view - returns (Witnet.Response memory) + returns (WitnetV2.Response memory) { return witnet.getQueryResponse(_latestValidQueryId(feedId)); } @@ -180,7 +180,7 @@ contract WitnetPriceFeeds function latestUpdateResponse(bytes4 feedId) override external view - returns (Witnet.Response memory) + returns (WitnetV2.Response memory) { return witnet.getQueryResponse(latestUpdateQueryId(feedId)); } @@ -194,7 +194,7 @@ contract WitnetPriceFeeds function latestUpdateResultStatus(bytes4 feedId) override public view - returns (Witnet.ResultStatus) + returns (WitnetV2.ResultStatus) { return _checkQueryResultStatus(latestUpdateQueryId(feedId)); } @@ -456,7 +456,7 @@ contract WitnetPriceFeeds { uint _queryId = _latestValidQueryId(feedId); if (_queryId > 0) { - Witnet.Response memory _latestResponse = latestResponse(feedId); + WitnetV2.Response memory _latestResponse = latestResponse(feedId); Witnet.Result memory _latestResult = Witnet.resultFromCborBytes(_latestResponse.cborBytes); return IWitnetPriceSolver.Price({ value: _latestResult.asUint(), @@ -545,11 +545,13 @@ contract WitnetPriceFeeds return ( int(_latestPrice.value), _latestPrice.timestamp, - _latestPrice.status == Witnet.ResultStatus.Ready + _latestPrice.status == WitnetV2.ResultStatus.Ready ? 200 - : _latestPrice.status == Witnet.ResultStatus.Awaiting - ? 404 - : 400 + : ( + _latestPrice.status == WitnetV2.ResultStatus.Awaiting + || _latestPrice.status == WitnetV2.ResultStatus.AwaitingReady + || _latestPrice.status == WitnetV2.ResultStatus.AwaitingError + ) ? 404 : 400 ); } @@ -559,12 +561,12 @@ contract WitnetPriceFeeds function _checkQueryResultStatus(uint _queryId) internal view - returns (Witnet.ResultStatus) + returns (WitnetV2.ResultStatus) { if (_queryId > 0) { return witnet.getQueryResultStatus(_queryId); } else { - return Witnet.ResultStatus.Ready; + return WitnetV2.ResultStatus.Ready; } } @@ -575,7 +577,7 @@ contract WitnetPriceFeeds uint _latestUpdateQueryId = latestUpdateQueryId(feedId); if ( _latestUpdateQueryId > 0 - && witnet.getQueryResultStatus(_latestUpdateQueryId) == Witnet.ResultStatus.Ready + && witnet.getQueryResultStatus(_latestUpdateQueryId) == WitnetV2.ResultStatus.Ready ) { return _latestUpdateQueryId; } else { @@ -618,8 +620,8 @@ contract WitnetPriceFeeds "WitnetPriceFeeds: insufficient reward" ); uint _latestId = __feed.latestUpdateQueryId; - Witnet.ResultStatus _latestStatus = _checkQueryResultStatus(_latestId); - if (_latestStatus == Witnet.ResultStatus.Awaiting) { + WitnetV2.ResultStatus _latestStatus = _checkQueryResultStatus(_latestId); + if (_latestStatus == WitnetV2.ResultStatus.Awaiting) { // latest update is still pending, so just increase the reward // accordingly to current tx gasprice: int _deltaReward = int(witnet.getQueryReward(_latestId)) - int(_usedFunds); @@ -632,7 +634,7 @@ contract WitnetPriceFeeds } } else { // Check if latest update ended successfully: - if (_latestStatus == Witnet.ResultStatus.Ready) { + if (_latestStatus == WitnetV2.ResultStatus.Ready) { // If so, remove previous last valid query from the WRB: if (__feed.latestValidQueryId > 0) { witnet.fetchQueryResponse(__feed.latestValidQueryId); diff --git a/contracts/apps/WitnetRandomness.sol b/contracts/apps/WitnetRandomness.sol index 5a3990f21..cdb357d5d 100644 --- a/contracts/apps/WitnetRandomness.sol +++ b/contracts/apps/WitnetRandomness.sol @@ -213,10 +213,10 @@ contract WitnetRandomness } uint256 _queryId = __randomize_[_block].witnetQueryId; require(_queryId != 0, "WitnetRandomness: not randomized"); - Witnet.ResultStatus _resultStatus = witnet().getQueryResultStatus(_queryId); - if (_resultStatus == Witnet.ResultStatus.Ready) { + WitnetV2.ResultStatus _resultStatus = witnet().getQueryResultStatus(_queryId); + if (_resultStatus == WitnetV2.ResultStatus.Ready) { return witnet().getQueryResult(_queryId).asBytes32(); - } else if (_resultStatus == Witnet.ResultStatus.Error) { + } else if (_resultStatus == WitnetV2.ResultStatus.Error) { uint256 _nextRandomizeBlock = __randomize_[_block].nextBlock; require(_nextRandomizeBlock != 0, "WitnetRandomness: faulty randomize"); return getRandomnessAfter(_nextRandomizeBlock); @@ -265,9 +265,10 @@ contract WitnetRandomness returns (bool) { RandomizeData storage _data = __randomize_[_block]; + WitnetV2.QueryStatus _qstatus = witnet().getQueryStatus(_data.witnetQueryId); return ( _data.witnetQueryId != 0 - && witnet().getQueryStatus(_data.witnetQueryId) == Witnet.QueryStatus.Reported + && (_qstatus == WitnetV2.QueryStatus.Finalized) ); } diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index 2c4704f8a..ccadccffe 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -30,11 +30,11 @@ abstract contract WitnetRequestBoardTrustableBase Payable { using Witnet for bytes; - using Witnet for Witnet.Request; - using Witnet for Witnet.Response; using Witnet for Witnet.Result; using WitnetCBOR for WitnetCBOR.CBOR; using WitnetV2 for WitnetV2.RadonSLA; + using WitnetV2 for WitnetV2.Request; + using WitnetV2 for WitnetV2.Response; bytes4 public immutable override specs = type(IWitnetRequestBoard).interfaceId; bytes4 public immutable group = bytes4(keccak256(abi.encode(address(this), block.chainid))); @@ -217,7 +217,7 @@ abstract contract WitnetRequestBoardTrustableBase external view returns (int256 _earnings) { - Witnet.Request storage __request = __seekQueryRequest(_witnetQueryId); + WitnetV2.Request storage __request = __seekQueryRequest(_witnetQueryId); _earnings = int(__request.evmReward); uint96 _callbackGasLimit = __request.unpackCallbackGasLimit(); @@ -241,9 +241,9 @@ abstract contract WitnetRequestBoardTrustableBase function fetchQueryResponse(uint256 _witnetQueryId) virtual override external - inStatus(_witnetQueryId, Witnet.QueryStatus.Reported) + inStatus(_witnetQueryId, WitnetV2.QueryStatus.Reported) onlyRequester(_witnetQueryId) - returns (Witnet.Response memory _response) + returns (WitnetV2.Response memory _response) { _response = __seekQuery(_witnetQueryId).response; delete __storage().queries[_witnetQueryId]; @@ -253,7 +253,7 @@ abstract contract WitnetRequestBoardTrustableBase function getQuery(uint256 _witnetQueryId) external view override - returns (Witnet.Query memory) + returns (WitnetV2.Query memory) { return __storage().queries[_witnetQueryId]; } @@ -267,10 +267,10 @@ abstract contract WitnetRequestBoardTrustableBase returns (bytes memory) { require( - _statusOf(_witnetQueryId) != Witnet.QueryStatus.Unknown, + _statusOf(_witnetQueryId) != WitnetV2.QueryStatus.Unknown, "WitnetRequestBoardTrustableBase: unknown query" ); - Witnet.Request storage __request = __seekQueryRequest(_witnetQueryId); + WitnetV2.Request storage __request = __seekQueryRequest(_witnetQueryId); if (__request.RAD != bytes32(0)) { return registry.bytecodeOf(__request.RAD); } else { @@ -285,7 +285,7 @@ abstract contract WitnetRequestBoardTrustableBase override returns (bytes32, WitnetV2.RadonSLA memory) { - Witnet.Request storage __request = __seekQueryRequest(_witnetQueryId); + WitnetV2.Request storage __request = __seekQueryRequest(_witnetQueryId); return ( __request.RAD == bytes32(0) ? registry.hashOf(__request.bytecode) : __request.RAD, WitnetV2.toRadonSLA(__request.SLA) @@ -298,7 +298,7 @@ abstract contract WitnetRequestBoardTrustableBase function getQueryResponse(uint256 _witnetQueryId) external view override - returns (Witnet.Response memory _response) + returns (WitnetV2.Response memory _response) { return __seekQueryResponse(_witnetQueryId); } @@ -311,7 +311,7 @@ abstract contract WitnetRequestBoardTrustableBase returns (Witnet.Result memory) { // todo: fail if not in finalized status ? - Witnet.Response storage _response = __seekQueryResponse(_witnetQueryId); + WitnetV2.Response storage _response = __seekQueryResponse(_witnetQueryId); return _response.cborBytes.resultFromCborBytes(); } @@ -329,7 +329,7 @@ abstract contract WitnetRequestBoardTrustableBase uint256 _witnetEvmFinalityBlock ) { - Witnet.Response storage __response = __seekQueryResponse(_witnetQueryId); + WitnetV2.Response storage __response = __seekQueryResponse(_witnetQueryId); return ( __response.timestamp, __response.tallyHash, @@ -343,7 +343,7 @@ abstract contract WitnetRequestBoardTrustableBase override external view returns (Witnet.ResultError memory) { - Witnet.ResultStatus _status = getQueryResultStatus(_witnetQueryId); + WitnetV2.ResultStatus _status = getQueryResultStatus(_witnetQueryId); try WitnetErrorsLib.asResultError(_status, __seekQueryResponse(_witnetQueryId).cborBytes) returns (Witnet.ResultError memory _resultError) { @@ -371,31 +371,31 @@ abstract contract WitnetRequestBoardTrustableBase /// @param _witnetQueryId The unique query identifier. function getQueryResultStatus(uint256 _witnetQueryId) virtual public view - returns (Witnet.ResultStatus) + returns (WitnetV2.ResultStatus) { - Witnet.QueryStatus _queryStatus = _statusOf(_witnetQueryId); + WitnetV2.QueryStatus _queryStatus = _statusOf(_witnetQueryId); if ( - _queryStatus == Witnet.QueryStatus.Finalized - || _queryStatus == Witnet.QueryStatus.Reported + _queryStatus == WitnetV2.QueryStatus.Finalized + || _queryStatus == WitnetV2.QueryStatus.Reported ) { bytes storage __cborValues = __seekQueryResponse(_witnetQueryId).cborBytes; // determine whether reported result is an error by peeking the first byte return (__cborValues[0] == bytes1(0xd8) - ? (_queryStatus == Witnet.QueryStatus.Finalized - ? Witnet.ResultStatus.Error - : Witnet.ResultStatus.AwaitingError - ) : (_queryStatus == Witnet.QueryStatus.Finalized - ? Witnet.ResultStatus.Ready - : Witnet.ResultStatus.AwaitingReady + ? (_queryStatus == WitnetV2.QueryStatus.Finalized + ? WitnetV2.ResultStatus.Error + : WitnetV2.ResultStatus.AwaitingError + ) : (_queryStatus == WitnetV2.QueryStatus.Finalized + ? WitnetV2.ResultStatus.Ready + : WitnetV2.ResultStatus.AwaitingReady ) ); } else if ( - _queryStatus == Witnet.QueryStatus.Posted - || _queryStatus == Witnet.QueryStatus.Undeliverable + _queryStatus == WitnetV2.QueryStatus.Posted + || _queryStatus == WitnetV2.QueryStatus.Undeliverable ) { - return Witnet.ResultStatus.Awaiting; + return WitnetV2.ResultStatus.Awaiting; } else { - return Witnet.ResultStatus.Void; + return WitnetV2.ResultStatus.Void; } } @@ -406,7 +406,7 @@ abstract contract WitnetRequestBoardTrustableBase function getQueryReward(uint256 _witnetQueryId) override external view - inStatus(_witnetQueryId, Witnet.QueryStatus.Posted) + inStatus(_witnetQueryId, WitnetV2.QueryStatus.Posted) returns (uint256) { return __seekQueryRequest(_witnetQueryId).evmReward; @@ -416,7 +416,7 @@ abstract contract WitnetRequestBoardTrustableBase function getQueryStatus(uint256 _witnetQueryId) external view override - returns (Witnet.QueryStatus) + returns (WitnetV2.QueryStatus) { return _statusOf(_witnetQueryId); @@ -537,9 +537,9 @@ abstract contract WitnetRequestBoardTrustableBase function upgradeQueryReward(uint256 _witnetQueryId) external payable virtual override - inStatus(_witnetQueryId, Witnet.QueryStatus.Posted) + inStatus(_witnetQueryId, WitnetV2.QueryStatus.Posted) { - Witnet.Request storage __request = __seekQueryRequest(_witnetQueryId); + WitnetV2.Request storage __request = __seekQueryRequest(_witnetQueryId); __request.evmReward += _getMsgValue(); emit WitnetQueryRewardUpgraded(_witnetQueryId, __request.evmReward); } @@ -565,7 +565,7 @@ abstract contract WitnetRequestBoardTrustableBase external override onlyReporters - inStatus(_witnetQueryId, Witnet.QueryStatus.Posted) + inStatus(_witnetQueryId, WitnetV2.QueryStatus.Posted) returns (uint256) { require( @@ -607,7 +607,7 @@ abstract contract WitnetRequestBoardTrustableBase external override onlyReporters - inStatus(_witnetQueryId, Witnet.QueryStatus.Posted) + inStatus(_witnetQueryId, WitnetV2.QueryStatus.Posted) returns (uint256) { require( @@ -652,7 +652,7 @@ abstract contract WitnetRequestBoardTrustableBase returns (uint256 _batchReward) { for ( uint _i = 0; _i < _batchResults.length; _i ++) { - if (_statusOf(_batchResults[_i].queryId) != Witnet.QueryStatus.Posted) { + if (_statusOf(_batchResults[_i].queryId) != WitnetV2.QueryStatus.Posted) { if (_verbose) { emit BatchReportError( _batchResults[_i].queryId, @@ -784,13 +784,13 @@ abstract contract WitnetRequestBoardTrustableBase returns (uint256 _witnetQueryId) { _witnetQueryId = __newQueryId(_radHash, _packedSLA); - Witnet.Request storage __request = __seekQueryRequest(_witnetQueryId); + WitnetV2.Request storage __request = __seekQueryRequest(_witnetQueryId); require( __request.fromCallbackGas == bytes32(0), "WitnetRequestBoardTrustableBase: already posted" ); { - __request.fromCallbackGas = Witnet.packRequesterCallbackGasLimit(msg.sender, _callbackGasLimit); + __request.fromCallbackGas = WitnetV2.packRequesterCallbackGasLimit(msg.sender, _callbackGasLimit); __request.RAD = _radHash; __request.SLA = _packedSLA; __request.evmReward = _getMsgValue(); @@ -807,7 +807,7 @@ abstract contract WitnetRequestBoardTrustableBase returns (uint256 _evmReward) { // read requester address and whether a callback was requested: - Witnet.Request storage __request = __seekQueryRequest(_witnetQueryId); + WitnetV2.Request storage __request = __seekQueryRequest(_witnetQueryId); (address _evmRequester, uint96 _evmCallbackGasLimit) = __request.unpackRequesterAndCallbackGasLimit(); // read query EVM reward: @@ -993,8 +993,8 @@ abstract contract WitnetRequestBoardTrustableBase ) virtual internal { - __seekQuery(_witnetQueryId).response = Witnet.Response({ - fromFinality: Witnet.packReporterEvmFinalityBlock(msg.sender, block.number), + __seekQuery(_witnetQueryId).response = WitnetV2.Response({ + fromFinality: WitnetV2.packReporterEvmFinalityBlock(msg.sender, block.number), timestamp: _witnetResultTimestamp, tallyHash: _witnetResultTallyHash, cborBytes: _witnetResultCborBytes diff --git a/contracts/data/WitnetRequestBoardData.sol b/contracts/data/WitnetRequestBoardData.sol index e635ea111..2b4ab01b8 100644 --- a/contracts/data/WitnetRequestBoardData.sol +++ b/contracts/data/WitnetRequestBoardData.sol @@ -2,13 +2,13 @@ pragma solidity >=0.7.0 <0.9.0; -import "../libs/Witnet.sol"; +import "../libs/WitnetV2.sol"; /// @title Witnet Request Board base data model. /// @author The Witnet Foundation. abstract contract WitnetRequestBoardData { - using Witnet for Witnet.Request; + using WitnetV2 for WitnetV2.Request; bytes32 internal constant _WITNET_REQUEST_BOARD_DATA_SLOTHASH = /* keccak256("io.witnet.boards.data") */ @@ -18,7 +18,7 @@ abstract contract WitnetRequestBoardData { address base; address owner; uint256 nonce; - mapping (uint => Witnet.Query) queries; + mapping (uint => WitnetV2.Query) queries; } constructor() { @@ -26,7 +26,7 @@ abstract contract WitnetRequestBoardData { } /// Asserts the given query is currently in the given status. - modifier inStatus(uint256 _queryId, Witnet.QueryStatus _status) { + modifier inStatus(uint256 _queryId, WitnetV2.QueryStatus _status) { require( _statusOf(_queryId) == _status, _statusOfRevertMessage(_status) @@ -46,14 +46,14 @@ abstract contract WitnetRequestBoardData { // --- Internal functions ----------------------------------------------------------------------------------------- /// Gets query storage by query id. - function __seekQuery(uint256 _queryId) internal view returns (Witnet.Query storage) { + function __seekQuery(uint256 _queryId) internal view returns (WitnetV2.Query storage) { return __storage().queries[_queryId]; } /// Gets the Witnet.Request part of a given query. function __seekQueryRequest(uint256 _queryId) internal view - returns (Witnet.Request storage) + returns (WitnetV2.Request storage) { return __storage().queries[_queryId].request; } @@ -61,7 +61,7 @@ abstract contract WitnetRequestBoardData { /// Gets the Witnet.Result part of a given query. function __seekQueryResponse(uint256 _queryId) internal view - returns (Witnet.Response storage) + returns (WitnetV2.Response storage) { return __storage().queries[_queryId].response; } @@ -79,37 +79,37 @@ abstract contract WitnetRequestBoardData { /// Gets current status of given query. function _statusOf(uint256 _queryId) internal view - returns (Witnet.QueryStatus) + returns (WitnetV2.QueryStatus) { - Witnet.Query storage __query = __storage().queries[_queryId]; + WitnetV2.Query storage __query = __storage().queries[_queryId]; if (__query.response.tallyHash != bytes32(0)) { if (__query.response.timestamp != 0) { - if (block.number >= Witnet.unpackEvmFinalityBlock(__query.response.fromFinality)) { - return Witnet.QueryStatus.Finalized; + if (block.number >= WitnetV2.unpackEvmFinalityBlock(__query.response.fromFinality)) { + return WitnetV2.QueryStatus.Finalized; } else { - return Witnet.QueryStatus.Reported; + return WitnetV2.QueryStatus.Reported; } } else { - return Witnet.QueryStatus.Undeliverable; + return WitnetV2.QueryStatus.Undeliverable; } } else if (__query.request.fromCallbackGas != bytes32(0)) { - return Witnet.QueryStatus.Posted; + return WitnetV2.QueryStatus.Posted; } else { - return Witnet.QueryStatus.Unknown; + return WitnetV2.QueryStatus.Unknown; } } - function _statusOfRevertMessage(Witnet.QueryStatus _status) + function _statusOfRevertMessage(WitnetV2.QueryStatus _status) internal pure returns (string memory) { - if (_status == Witnet.QueryStatus.Posted) { + if (_status == WitnetV2.QueryStatus.Posted) { return "WitnetRequestBoard: not in Posted status"; - } else if (_status == Witnet.QueryStatus.Reported) { + } else if (_status == WitnetV2.QueryStatus.Reported) { return "WitnetRequestBoard: not in Reported status"; - } else if (_status == Witnet.QueryStatus.Finalized) { + } else if (_status == WitnetV2.QueryStatus.Finalized) { return "WitnetRequestBoard: not in Finalized status"; - } else if (_status == Witnet.QueryStatus.Undeliverable) { + } else if (_status == WitnetV2.QueryStatus.Undeliverable) { return "WitnetRequestBoard: not in Undeliverable status"; } else { return "WitnetRequestBoard: bad mood"; diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/IWitnetRequestBoard.sol index f28076d1e..4a0894a05 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/IWitnetRequestBoard.sol @@ -33,10 +33,10 @@ interface IWitnetRequestBoard { /// @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 (Witnet.Response memory); + 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 (Witnet.Query memory); + function getQuery(uint256 queryId) external view returns (WitnetV2.Query memory); /// @notice Retrieves the serialized bytecode of a previously posted Witnet Data Request. /// @dev Fails if the query does not exist. @@ -49,7 +49,7 @@ interface IWitnetRequestBoard { /// @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 (Witnet.Response memory); + function getQueryResponse(uint256 queryId) external view returns (WitnetV2.Response memory); /// @notice Retrieves the Witnet-provable CBOR-bytes result of a previously posted request. /// @param queryId The unique query identifier. @@ -76,7 +76,7 @@ interface IWitnetRequestBoard { /// @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 getQueryResultStatus(uint256 queryId) external view returns (Witnet.ResultStatus); + function getQueryResultStatus(uint256 queryId) external view returns (WitnetV2.ResultStatus); /// @notice Retrieves the reward currently set for the referred query. /// @dev Fails if the `queryId` is not valid or, if it has already been reported, delivered, or deleted. @@ -84,7 +84,7 @@ interface IWitnetRequestBoard { function getQueryReward(uint256 queryId) external view returns (uint256); /// @notice Gets current status of given query. - function getQueryStatus(uint256 queryId) external view returns (Witnet.QueryStatus); + function getQueryStatus(uint256 queryId) external view returns (WitnetV2.QueryStatus); // /// @notice Returns next query id to be generated by the Witnet Request Board. // function getNextQueryId() external view returns (uint256); diff --git a/contracts/interfaces/V2/IWitnetFeeds.sol b/contracts/interfaces/V2/IWitnetFeeds.sol index e21277fcc..d0721b3df 100644 --- a/contracts/interfaces/V2/IWitnetFeeds.sol +++ b/contracts/interfaces/V2/IWitnetFeeds.sol @@ -22,14 +22,14 @@ interface IWitnetFeeds { function defaultRadonSLA() external view returns (WitnetV2.RadonSLA memory); function estimateUpdateBaseFee(uint256 evmGasPrice) external view returns (uint); - function latestResponse(bytes4 feedId) external view returns (Witnet.Response memory); + function latestResponse(bytes4 feedId) external view returns (WitnetV2.Response memory); function latestResult(bytes4 feedId) external view returns (Witnet.Result memory); function latestUpdateQueryId(bytes4 feedId) external view returns (uint256); function latestUpdateRequest(bytes4 feedId) external view returns (bytes32, WitnetV2.RadonSLA memory); - function latestUpdateResponse(bytes4 feedId) external view returns (Witnet.Response memory); + function latestUpdateResponse(bytes4 feedId) external view returns (WitnetV2.Response memory); function latestUpdateResultError(bytes4 feedId) external view returns (Witnet.ResultError memory); - function latestUpdateResultStatus(bytes4 feedId) external view returns (Witnet.ResultStatus); + function latestUpdateResultStatus(bytes4 feedId) external view returns (WitnetV2.ResultStatus); function lookupBytecode(bytes4 feedId) external view returns (bytes memory); function lookupRadHash(bytes4 feedId) external view returns (bytes32); diff --git a/contracts/interfaces/V2/IWitnetPriceSolver.sol b/contracts/interfaces/V2/IWitnetPriceSolver.sol index afa5c8f29..9cd5ce030 100644 --- a/contracts/interfaces/V2/IWitnetPriceSolver.sol +++ b/contracts/interfaces/V2/IWitnetPriceSolver.sol @@ -9,7 +9,7 @@ interface IWitnetPriceSolver { uint value; uint timestamp; bytes32 tallyHash; - Witnet.ResultStatus status; + WitnetV2.ResultStatus status; } function delegator() external view returns (address); function solve(bytes4 feedId) external view returns (Price memory); diff --git a/contracts/libs/Witnet.sol b/contracts/libs/Witnet.sol index 9896ae47a..94fcf09ec 100644 --- a/contracts/libs/Witnet.sol +++ b/contracts/libs/Witnet.sol @@ -11,41 +11,41 @@ library Witnet { using WitnetCBOR for WitnetCBOR.CBOR; using WitnetCBOR for WitnetCBOR.CBOR[]; - /// Struct containing both request and response data related to every query posted to the Witnet Request Board - struct Query { - Request request; - Response response; - } - - /// Possible status of a Witnet query. - enum QueryStatus { - Unknown, - Posted, - Reported, - Undeliverable, - Finalized - } - - /// Data kept in EVM-storage for every Request posted to the Witnet Request Board. - struct Request { - bytes32 fromCallbackGas; // Packed: contains requester address in most significant bytes20, - // and max callback gas limit if a callback is required. - bytes32 SLA; // Packed: Service-Level Aggreement parameters upon which the data request - // will be solved by the Witnet blockchain. - bytes32 RAD; // Verified hash of the actual data request to be solved by the Witnet blockchain. - uint256 reserved1; // Reserved uint256 slot. - uint256 evmReward; // EVM reward to be paid to the relayer of the Witnet resolution to the data request. - bytes bytecode; // Raw bytecode of the data request to be solved by the Witnet blockchain (only if not yet verified). - } - - /// Data kept in EVM-storage containing Witnet-provided response metadata and result. - struct Response { - bytes32 fromFinality; // Packed: contains address from which the result to the data request was reported, and - // the EVM block at which the provided result can be considered to be final. - uint256 timestamp; // Timestamp at which data from data sources were retrieved by the Witnet blockchain. - bytes32 tallyHash; // Hash of the Witnet commit/reveal act that solved the data request. - bytes cborBytes; // CBOR-encoded result to the data request, as resolved by the Witnet blockchain. - } + // /// Struct containing both request and response data related to every query posted to the Witnet Request Board + // struct Query { + // Request request; + // Response response; + // } + + // /// Possible status of a Witnet query. + // enum QueryStatus { + // Unknown, + // Posted, + // Reported, + // Undeliverable, + // Finalized + // } + + // /// Data kept in EVM-storage for every Request posted to the Witnet Request Board. + // struct Request { + // bytes32 fromCallbackGas; // Packed: contains requester address in most significant bytes20, + // // and max callback gas limit if a callback is required. + // bytes32 SLA; // Packed: Service-Level Aggreement parameters upon which the data request + // // will be solved by the Witnet blockchain. + // bytes32 RAD; // Verified hash of the actual data request to be solved by the Witnet blockchain. + // uint256 reserved1; // Reserved uint256 slot. + // uint256 evmReward; // EVM reward to be paid to the relayer of the Witnet resolution to the data request. + // bytes bytecode; // Raw bytecode of the data request to be solved by the Witnet blockchain (only if not yet verified). + // } + + // /// Data kept in EVM-storage containing Witnet-provided response metadata and result. + // struct Response { + // bytes32 fromFinality; // Packed: contains address from which the result to the data request was reported, and + // // the EVM block at which the provided result can be considered to be final. + // uint256 timestamp; // Timestamp at which data from data sources were retrieved by the Witnet blockchain. + // bytes32 tallyHash; // Hash of the Witnet commit/reveal act that solved the data request. + // bytes cborBytes; // CBOR-encoded result to the data request, as resolved by the Witnet blockchain. + // } /// Data struct containing the Witnet-provided result to a Data Request. struct Result { @@ -53,15 +53,15 @@ library Witnet { WitnetCBOR.CBOR value; // Resulting value, in CBOR-serialized bytes. } - /// Final query's result status from a requester's point of view. - enum ResultStatus { - Void, - Awaiting, - Ready, - Error, - AwaitingReady, - AwaitingError - } + // /// Final query's result status from a requester's point of view. + // enum ResultStatus { + // Void, + // Awaiting, + // Ready, + // Error, + // AwaitingReady, + // AwaitingError + // } /// Data struct describing an error when trying to fetch a Witnet-provided result to a Data Request. struct ResultError { @@ -446,50 +446,50 @@ library Witnet { } - /// =============================================================================================================== - /// --- 'Witnet.Request' helper methods --------------------------------------------------------------------------- + // /// =============================================================================================================== + // /// --- 'Witnet.Request' helper methods --------------------------------------------------------------------------- - function packRequesterCallbackGasLimit(address requester, uint96 callbackGasLimit) internal pure returns (bytes32) { - return bytes32(uint(bytes32(bytes20(requester))) | callbackGasLimit); - } + // function packRequesterCallbackGasLimit(address requester, uint96 callbackGasLimit) internal pure returns (bytes32) { + // return bytes32(uint(bytes32(bytes20(requester))) | callbackGasLimit); + // } - function unpackRequester(Request storage self) internal view returns (address) { - return address(bytes20(self.fromCallbackGas)); - } + // function unpackRequester(Request storage self) internal view returns (address) { + // return address(bytes20(self.fromCallbackGas)); + // } - function unpackCallbackGasLimit(Request storage self) internal view returns (uint96) { - return uint96(uint(self.fromCallbackGas)); - } + // function unpackCallbackGasLimit(Request storage self) internal view returns (uint96) { + // return uint96(uint(self.fromCallbackGas)); + // } - function unpackRequesterAndCallbackGasLimit(Request storage self) internal view returns (address, uint96) { - bytes32 _packed = self.fromCallbackGas; - return (address(bytes20(_packed)), uint96(uint(_packed))); - } + // function unpackRequesterAndCallbackGasLimit(Request storage self) internal view returns (address, uint96) { + // bytes32 _packed = self.fromCallbackGas; + // return (address(bytes20(_packed)), uint96(uint(_packed))); + // } - /// =============================================================================================================== - /// --- 'Witnet.Response' helper methods -------------------------------------------------------------------------- + // /// =============================================================================================================== + // /// --- 'Witnet.Response' helper methods -------------------------------------------------------------------------- - function packReporterEvmFinalityBlock(address reporter, uint256 evmFinalityBlock) internal pure returns (bytes32) { - return bytes32(uint(bytes32(bytes20(reporter))) << 96 | uint96(evmFinalityBlock)); - } + // function packReporterEvmFinalityBlock(address reporter, uint256 evmFinalityBlock) internal pure returns (bytes32) { + // return bytes32(uint(bytes32(bytes20(reporter))) << 96 | uint96(evmFinalityBlock)); + // } - function unpackWitnetReporter(Response storage self) internal view returns (address) { - return address(bytes20(self.fromFinality)); - } + // function unpackWitnetReporter(Response storage self) internal view returns (address) { + // return address(bytes20(self.fromFinality)); + // } - function unpackEvmFinalityBlock(Response storage self) internal view returns (uint256) { - return uint(uint96(uint(self.fromFinality))); - } + // function unpackEvmFinalityBlock(Response storage self) internal view returns (uint256) { + // return uint(uint96(uint(self.fromFinality))); + // } - function unpackEvmFinalityBlock(bytes32 fromFinality) internal pure returns (uint256) { - return uint(uint96(uint(fromFinality))); - } + // function unpackEvmFinalityBlock(bytes32 fromFinality) internal pure returns (uint256) { + // return uint(uint96(uint(fromFinality))); + // } - function unpackWitnetReporterAndEvmFinalityBlock(Response storage self) internal view returns (address, uint256) { - bytes32 _packed = self.fromFinality; - return (address(bytes20(_packed)), uint(uint96(uint(_packed)))); - } + // function unpackWitnetReporterAndEvmFinalityBlock(Response storage self) internal view returns (address, uint256) { + // bytes32 _packed = self.fromFinality; + // return (address(bytes20(_packed)), uint(uint96(uint(_packed)))); + // } /// =============================================================================================================== @@ -653,60 +653,60 @@ library Witnet { } - /// =============================================================================================================== - /// --- 'Witnet.RadonSLA' helper methods -------------------------------------------------------------------------- - - /// @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 - ); - } - - function isValid(Witnet.RadonSLA memory sla) - internal pure returns (bool) - { - return ( - sla.witnessReward > 0 - && sla.numWitnesses > 0 && sla.numWitnesses <= 127 - && sla.minConsensusPercentage > 50 && sla.minConsensusPercentage < 100 - && sla.witnessCollateral > 0 - && sla.witnessCollateral / sla.witnessReward <= 127 - ); - } - - function toBytes32(RadonSLA memory sla) internal pure returns (bytes32) { - return bytes32( - uint(sla.witnessReward) - | sla.witnessCollateral << 64 - | sla.minerCommitRevealFee << 128 - | sla.numWitnesses << 248 - | sla.minConsensusPercentage << 232 - ); - } - - function toRadonSLA(bytes32 _packed) internal pure returns (RadonSLA memory) { - return RadonSLA({ - numWitnesses: uint8(uint(_packed >> 248)), - minConsensusPercentage: uint8(uint(_packed >> 232) & 0xff), - witnessReward: uint64(uint(_packed) & 0xffffffffffffffff), - witnessCollateral: uint64(uint(_packed >> 64) & 0xffffffffffffffff), - minerCommitRevealFee: uint64(uint(_packed >> 128) & 0xffffffffffffffff) - }); - } - - function totalWitnessingReward(Witnet.RadonSLA memory sla) - internal pure returns (uint64) - { - return sla.witnessReward * sla.numWitnesses; - } + // /// =============================================================================================================== + // /// --- 'Witnet.RadonSLA' helper methods -------------------------------------------------------------------------- + + // /// @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 + // ); + // } + + // function isValid(Witnet.RadonSLA memory sla) + // internal pure returns (bool) + // { + // return ( + // sla.witnessReward > 0 + // && sla.numWitnesses > 0 && sla.numWitnesses <= 127 + // && sla.minConsensusPercentage > 50 && sla.minConsensusPercentage < 100 + // && sla.witnessCollateral > 0 + // && sla.witnessCollateral / sla.witnessReward <= 127 + // ); + // } + + // function toBytes32(RadonSLA memory sla) internal pure returns (bytes32) { + // return bytes32( + // uint(sla.witnessReward) + // | sla.witnessCollateral << 64 + // | sla.minerCommitRevealFee << 128 + // | sla.numWitnesses << 248 + // | sla.minConsensusPercentage << 232 + // ); + // } + + // function toRadonSLA(bytes32 _packed) internal pure returns (RadonSLA memory) { + // return RadonSLA({ + // numWitnesses: uint8(uint(_packed >> 248)), + // minConsensusPercentage: uint8(uint(_packed >> 232) & 0xff), + // witnessReward: uint64(uint(_packed) & 0xffffffffffffffff), + // witnessCollateral: uint64(uint(_packed >> 64) & 0xffffffffffffffff), + // minerCommitRevealFee: uint64(uint(_packed >> 128) & 0xffffffffffffffff) + // }); + // } + + // function totalWitnessingReward(Witnet.RadonSLA memory sla) + // internal pure returns (uint64) + // { + // return sla.witnessReward * sla.numWitnesses; + // } /// =============================================================================================================== diff --git a/contracts/libs/WitnetErrorsLib.sol b/contracts/libs/WitnetErrorsLib.sol index ae1f38ec6..d32ee65e5 100644 --- a/contracts/libs/WitnetErrorsLib.sol +++ b/contracts/libs/WitnetErrorsLib.sol @@ -3,7 +3,7 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "./Witnet.sol"; +import "./WitnetV2.sol"; /// @title A library for interpreting Witnet resolution errors /// @author The Witnet Foundation. @@ -28,16 +28,16 @@ library WitnetErrorsLib { ); } - function asResultError(Witnet.ResultStatus _status, bytes memory _cborBytes) + function asResultError(WitnetV2.ResultStatus _status, bytes memory _cborBytes) public pure returns (Witnet.ResultError memory) { - if (_status == Witnet.ResultStatus.Awaiting) { + if (_status == WitnetV2.ResultStatus.Awaiting) { return Witnet.ResultError({ code: Witnet.ResultErrorCodes.Unknown, reason: "WitnetRequestBoard: not yet solved" }); - } else if (_status == Witnet.ResultStatus.Void) { + } else if (_status == WitnetV2.ResultStatus.Void) { return Witnet.ResultError({ code: Witnet.ResultErrorCodes.Unknown, reason: "WitnetRequestBoard: unknown query" diff --git a/contracts/libs/WitnetV2.sol b/contracts/libs/WitnetV2.sol index 43fb46db2..0cb3454ef 100644 --- a/contracts/libs/WitnetV2.sol +++ b/contracts/libs/WitnetV2.sol @@ -6,12 +6,51 @@ import "./Witnet.sol"; library WitnetV2 { - uint256 internal constant _WITNET_GENESIS_TIMESTAMP = 1602666045; - uint256 internal constant _WITNET_GENESIS_EPOCH_SECONDS = 45; + /// Struct containing both request and response data related to every query posted to the Witnet Request Board + struct Query { + Request request; + Response response; + } - uint256 internal constant _WITNET_2_0_EPOCH = 1234567; - uint256 internal constant _WITNET_2_0_EPOCH_SECONDS = 30; - uint256 internal constant _WITNET_2_0_TIMESTAMP = _WITNET_GENESIS_TIMESTAMP + _WITNET_2_0_EPOCH * _WITNET_GENESIS_EPOCH_SECONDS; + /// Possible status of a Witnet query. + enum QueryStatus { + Unknown, + Posted, + Reported, + Undeliverable, + Finalized + } + + /// Data kept in EVM-storage for every Request posted to the Witnet Request Board. + struct Request { + bytes32 fromCallbackGas; // Packed: contains requester address in most significant bytes20, + // and max callback gas limit if a callback is required. + bytes32 SLA; // Packed: Service-Level Aggreement parameters upon which the data request + // will be solved by the Witnet blockchain. + bytes32 RAD; // Verified hash of the actual data request to be solved by the Witnet blockchain. + uint256 reserved1; // Reserved uint256 slot. + uint256 evmReward; // EVM reward to be paid to the relayer of the Witnet resolution to the data request. + bytes bytecode; // Raw bytecode of the data request to be solved by the Witnet blockchain (only if not yet verified). + } + + /// Data kept in EVM-storage containing Witnet-provided response metadata and result. + struct Response { + bytes32 fromFinality; // Packed: contains address from which the result to the data request was reported, and + // the EVM block at which the provided result can be considered to be final. + uint256 timestamp; // Timestamp at which data from data sources were retrieved by the Witnet blockchain. + bytes32 tallyHash; // Hash of the Witnet commit/reveal act that solved the data request. + bytes cborBytes; // CBOR-encoded result to the data request, as resolved by the Witnet blockchain. + } + + /// Final query's result status from a requester's point of view. + enum ResultStatus { + Void, + Awaiting, + Ready, + Error, + AwaitingReady, + AwaitingError + } struct RadonSLA { /// @dev Number of witnessing nodes that will take part in the resolution of a data request within the Witnet blockchain: @@ -22,6 +61,55 @@ library WitnetV2 { uint64 witnessingWitReward; } + /// =============================================================================================================== + /// --- 'WitnetV2.Request' helper methods ------------------------------------------------------------------------- + + function packRequesterCallbackGasLimit(address requester, uint96 callbackGasLimit) internal pure returns (bytes32) { + return bytes32(uint(bytes32(bytes20(requester))) | callbackGasLimit); + } + + function unpackRequester(Request storage self) internal view returns (address) { + return address(bytes20(self.fromCallbackGas)); + } + + function unpackCallbackGasLimit(Request storage self) internal view returns (uint96) { + return uint96(uint(self.fromCallbackGas)); + } + + function unpackRequesterAndCallbackGasLimit(Request storage self) internal view returns (address, uint96) { + bytes32 _packed = self.fromCallbackGas; + return (address(bytes20(_packed)), uint96(uint(_packed))); + } + + + /// =============================================================================================================== + /// --- 'WitnetV2.Response' helper methods ------------------------------------------------------------------------ + + function packReporterEvmFinalityBlock(address reporter, uint256 evmFinalityBlock) internal pure returns (bytes32) { + return bytes32(uint(bytes32(bytes20(reporter))) << 96 | uint96(evmFinalityBlock)); + } + + function unpackWitnetReporter(Response storage self) internal view returns (address) { + return address(bytes20(self.fromFinality)); + } + + function unpackEvmFinalityBlock(Response storage self) internal view returns (uint256) { + return uint(uint96(uint(self.fromFinality))); + } + + function unpackEvmFinalityBlock(bytes32 fromFinality) internal pure returns (uint256) { + return uint(uint96(uint(fromFinality))); + } + + function unpackWitnetReporterAndEvmFinalityBlock(Response storage self) internal view returns (address, uint256) { + bytes32 _packed = self.fromFinality; + return (address(bytes20(_packed)), uint(uint96(uint(_packed)))); + } + + + /// =============================================================================================================== + /// --- 'WitnetV2.RadonSLA' helper methods ------------------------------------------------------------------------ + function equalOrGreaterThan(RadonSLA memory a, RadonSLA memory b) internal pure returns (bool) { @@ -73,6 +161,13 @@ library WitnetV2 { ); } + uint256 internal constant _WITNET_GENESIS_TIMESTAMP = 1602666045; + uint256 internal constant _WITNET_GENESIS_EPOCH_SECONDS = 45; + + uint256 internal constant _WITNET_2_0_EPOCH = 1234567; + uint256 internal constant _WITNET_2_0_EPOCH_SECONDS = 30; + uint256 internal constant _WITNET_2_0_TIMESTAMP = _WITNET_GENESIS_TIMESTAMP + _WITNET_2_0_EPOCH * _WITNET_GENESIS_EPOCH_SECONDS; + function timestampToWitnetEpoch(uint _timestamp) internal pure returns (uint) { if (_timestamp > _WITNET_2_0_TIMESTAMP ) { return ( From eb7c61b6e239cc99016a2683ec2a69750b86f56b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Tue, 28 Nov 2023 17:06:46 +0100 Subject: [PATCH 70/86] chore: IWitnetRequestBoard -> V2/IWitnetRequestBoard --- contracts/WitnetRequestBoard.sol | 4 ++-- contracts/interfaces/{ => V2}/IWitnetRequestBoard.sol | 2 +- contracts/interfaces/{ => V2}/IWitnetRequestBoardEvents.sol | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename contracts/interfaces/{ => V2}/IWitnetRequestBoard.sol (99%) rename contracts/interfaces/{ => V2}/IWitnetRequestBoardEvents.sol (96%) diff --git a/contracts/WitnetRequestBoard.sol b/contracts/WitnetRequestBoard.sol index fcb99ba96..372a3c02d 100644 --- a/contracts/WitnetRequestBoard.sol +++ b/contracts/WitnetRequestBoard.sol @@ -4,8 +4,8 @@ pragma solidity >=0.7.0 <0.9.0; import "./WitnetBytecodes.sol"; import "./WitnetRequestFactory.sol"; -import "./interfaces/IWitnetRequestBoard.sol"; -import "./interfaces/IWitnetRequestBoardEvents.sol"; +import "./interfaces/V2/IWitnetRequestBoard.sol"; +import "./interfaces/V2/IWitnetRequestBoardEvents.sol"; /// @title Witnet Request Board functionality base contract. /// @author The Witnet Foundation. diff --git a/contracts/interfaces/IWitnetRequestBoard.sol b/contracts/interfaces/V2/IWitnetRequestBoard.sol similarity index 99% rename from contracts/interfaces/IWitnetRequestBoard.sol rename to contracts/interfaces/V2/IWitnetRequestBoard.sol index 4a0894a05..b90bdc045 100644 --- a/contracts/interfaces/IWitnetRequestBoard.sol +++ b/contracts/interfaces/V2/IWitnetRequestBoard.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.7.0 <0.9.0; -import "../libs/WitnetV2.sol"; +import "../../libs/WitnetV2.sol"; interface IWitnetRequestBoard { diff --git a/contracts/interfaces/IWitnetRequestBoardEvents.sol b/contracts/interfaces/V2/IWitnetRequestBoardEvents.sol similarity index 96% rename from contracts/interfaces/IWitnetRequestBoardEvents.sol rename to contracts/interfaces/V2/IWitnetRequestBoardEvents.sol index 1c7ab7f2e..0dce1d9b0 100644 --- a/contracts/interfaces/IWitnetRequestBoardEvents.sol +++ b/contracts/interfaces/V2/IWitnetRequestBoardEvents.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.7.0 <0.9.0; -import "../libs/WitnetV2.sol"; +import "../../libs/WitnetV2.sol"; interface IWitnetRequestBoardEvents { From b50c8f6cf65a311bf84a19288707834a902b0942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Tue, 28 Nov 2023 17:07:16 +0100 Subject: [PATCH 71/86] chore: restoring Witnet.* v0.7 structs --- contracts/libs/Witnet.sol | 76 ++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 41 deletions(-) diff --git a/contracts/libs/Witnet.sol b/contracts/libs/Witnet.sol index 94fcf09ec..931e41ee3 100644 --- a/contracts/libs/Witnet.sol +++ b/contracts/libs/Witnet.sol @@ -11,41 +11,37 @@ library Witnet { using WitnetCBOR for WitnetCBOR.CBOR; using WitnetCBOR for WitnetCBOR.CBOR[]; - // /// Struct containing both request and response data related to every query posted to the Witnet Request Board - // struct Query { - // Request request; - // Response response; - // } + /// Struct containing both request and response data related to every query posted to the Witnet Request Board + struct Query { + Request request; + Response response; + address from; // Address from which the request was posted. + } - // /// Possible status of a Witnet query. - // enum QueryStatus { - // Unknown, - // Posted, - // Reported, - // Undeliverable, - // Finalized - // } + /// Possible status of a Witnet query. + enum QueryStatus { + Unknown, + Posted, + Reported, + Deleted + } - // /// Data kept in EVM-storage for every Request posted to the Witnet Request Board. - // struct Request { - // bytes32 fromCallbackGas; // Packed: contains requester address in most significant bytes20, - // // and max callback gas limit if a callback is required. - // bytes32 SLA; // Packed: Service-Level Aggreement parameters upon which the data request - // // will be solved by the Witnet blockchain. - // bytes32 RAD; // Verified hash of the actual data request to be solved by the Witnet blockchain. - // uint256 reserved1; // Reserved uint256 slot. - // uint256 evmReward; // EVM reward to be paid to the relayer of the Witnet resolution to the data request. - // bytes bytecode; // Raw bytecode of the data request to be solved by the Witnet blockchain (only if not yet verified). - // } + /// 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. + 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. - // struct Response { - // bytes32 fromFinality; // Packed: contains address from which the result to the data request was reported, and - // // the EVM block at which the provided result can be considered to be final. - // uint256 timestamp; // Timestamp at which data from data sources were retrieved by the Witnet blockchain. - // bytes32 tallyHash; // Hash of the Witnet commit/reveal act that solved the data request. - // bytes cborBytes; // CBOR-encoded result to the data request, as resolved by the Witnet blockchain. - // } + /// Data kept in EVM-storage containing Witnet-provided response metadata and result. + struct Response { + address reporter; // Address from which the result was reported. + uint256 timestamp; // Timestamp of the Witnet-provided result. + bytes32 drTxHash; // Hash of the Witnet transaction that solved the queried Data Request. + bytes cborBytes; // Witnet-provided result CBOR-bytes to the queried Data Request. + } /// Data struct containing the Witnet-provided result to a Data Request. struct Result { @@ -53,15 +49,13 @@ library Witnet { WitnetCBOR.CBOR value; // Resulting value, in CBOR-serialized bytes. } - // /// Final query's result status from a requester's point of view. - // enum ResultStatus { - // Void, - // Awaiting, - // Ready, - // Error, - // AwaitingReady, - // AwaitingError - // } + /// Final query's result status from a requester's point of view. + enum ResultStatus { + Void, + Awaiting, + Ready, + Error + } /// Data struct describing an error when trying to fetch a Witnet-provided result to a Data Request. struct ResultError { From 2d970fcfc46d77e6c6da7bfdd213b37fd5b20c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Tue, 28 Nov 2023 17:11:56 +0100 Subject: [PATCH 72/86] chore: IWitnetRequestBoardReporter -> V2/IWitnetRequestBoardReporter --- contracts/core/defaults/WitnetRequestBoardTrustableBase.sol | 2 +- contracts/interfaces/{ => V2}/IWitnetRequestBoardReporter.sol | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename contracts/interfaces/{ => V2}/IWitnetRequestBoardReporter.sol (100%) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index ccadccffe..6006d5dad 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -10,7 +10,7 @@ import "../../WitnetRequestFactory.sol"; import "../../data/WitnetRequestBoardDataACLs.sol"; import "../../interfaces/IWitnetRequest.sol"; import "../../interfaces/IWitnetRequestBoardAdminACLs.sol"; -import "../../interfaces/IWitnetRequestBoardReporter.sol"; +import "../../interfaces/V2/IWitnetRequestBoardReporter.sol"; import "../../interfaces/V2/IWitnetConsumer.sol"; import "../../libs/WitnetErrorsLib.sol"; import "../../patterns/Payable.sol"; diff --git a/contracts/interfaces/IWitnetRequestBoardReporter.sol b/contracts/interfaces/V2/IWitnetRequestBoardReporter.sol similarity index 100% rename from contracts/interfaces/IWitnetRequestBoardReporter.sol rename to contracts/interfaces/V2/IWitnetRequestBoardReporter.sol From ddab6cf9f79567d437318954891e292600c20113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Tue, 28 Nov 2023 17:17:26 +0100 Subject: [PATCH 73/86] feat: WRBTrustableBase.ddrTag() --- .../core/defaults/WitnetRequestBoardTrustableBase.sol | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index 6006d5dad..d224f2a55 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -37,7 +37,6 @@ abstract contract WitnetRequestBoardTrustableBase using WitnetV2 for WitnetV2.Response; bytes4 public immutable override specs = type(IWitnetRequestBoard).interfaceId; - bytes4 public immutable group = bytes4(keccak256(abi.encode(address(this), block.chainid))); WitnetRequestFactory immutable public override factory; WitnetBytecodes immutable public override registry; @@ -101,6 +100,10 @@ abstract contract WitnetRequestBoardTrustableBase ))); } + function ddrTag() virtual public view returns (bytes4) { + return bytes4(keccak256(abi.encode(address(this), block.chainid))); + } + // ================================================================================================================ // --- Yet to be implemented virtual methods ---------------------------------------------------------------------- @@ -771,7 +774,7 @@ abstract contract WitnetRequestBoardTrustableBase returns (uint256) { return uint(keccak256(abi.encode( - group, + ddrTag(), block.number, msg.sender, _queryRAD, From 565c3bccbe0f6a48d196057b1eefd3b085424135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Wed, 29 Nov 2023 11:51:19 +0100 Subject: [PATCH 74/86] refactor: WRB.ddrTag() -> WRB.channel() --- contracts/WitnetRequestBoard.sol | 1 + contracts/core/defaults/WitnetRequestBoardTrustableBase.sol | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/contracts/WitnetRequestBoard.sol b/contracts/WitnetRequestBoard.sol index 372a3c02d..93da562cd 100644 --- a/contracts/WitnetRequestBoard.sol +++ b/contracts/WitnetRequestBoard.sol @@ -17,6 +17,7 @@ abstract contract WitnetRequestBoard function class() virtual external view returns (string memory) { return type(WitnetRequestBoard).name; } + function channel() virtual external view returns (bytes4); function factory() virtual external view returns (WitnetRequestFactory); function registry() virtual external view returns (WitnetBytecodes); function specs() virtual external view returns (bytes4); diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index d224f2a55..073e357ae 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -100,7 +100,7 @@ abstract contract WitnetRequestBoardTrustableBase ))); } - function ddrTag() virtual public view returns (bytes4) { + function channel() virtual override public view returns (bytes4) { return bytes4(keccak256(abi.encode(address(this), block.chainid))); } @@ -774,7 +774,7 @@ abstract contract WitnetRequestBoardTrustableBase returns (uint256) { return uint(keccak256(abi.encode( - ddrTag(), + channel(), block.number, msg.sender, _queryRAD, From cd140243d7b7539ef08076d367a8ff04729dcc54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Wed, 29 Nov 2023 11:52:34 +0100 Subject: [PATCH 75/86] feat: add mocking contracts --- .../WitnetRequestBoardTrustableBase.sol | 25 ++++++++------ .../defaults/WitnetRequestFactoryDefault.sol | 1 - contracts/data/WitnetRequestBoardDataACLs.sol | 6 ++-- contracts/mocks/WitnetBytecodesMock.sol | 15 ++++++++ contracts/mocks/WitnetPriceFeedsMock.sol | 15 ++++++++ contracts/mocks/WitnetRequestBoardMock.sol | 34 +++++++++++++++++++ contracts/mocks/WitnetRequestFactoryMock.sol | 21 ++++++++++++ 7 files changed, 102 insertions(+), 15 deletions(-) create mode 100644 contracts/mocks/WitnetBytecodesMock.sol create mode 100644 contracts/mocks/WitnetPriceFeedsMock.sol create mode 100644 contracts/mocks/WitnetRequestBoardMock.sol create mode 100644 contracts/mocks/WitnetRequestFactoryMock.sol diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index 073e357ae..2f46da79e 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -37,9 +37,9 @@ abstract contract WitnetRequestBoardTrustableBase using WitnetV2 for WitnetV2.Response; bytes4 public immutable override specs = type(IWitnetRequestBoard).interfaceId; - - WitnetRequestFactory immutable public override factory; WitnetBytecodes immutable public override registry; + + WitnetRequestFactory immutable private __factory; modifier checkCallbackRecipient(address _addr, uint96 _callbackGasLimit) { require( @@ -76,8 +76,7 @@ abstract contract WitnetRequestBoardTrustableBase "io.witnet.proxiable.board" ) { - assert(address(_factory) != address(0) && address(_registry) != address(0)); - factory = _factory; + __factory = _factory; registry = _registry; } @@ -104,6 +103,10 @@ abstract contract WitnetRequestBoardTrustableBase return bytes4(keccak256(abi.encode(address(this), block.chainid))); } + function factory() virtual override public view returns (WitnetRequestFactory) { + return __factory; + } + // ================================================================================================================ // --- Yet to be implemented virtual methods ---------------------------------------------------------------------- @@ -158,16 +161,16 @@ abstract contract WitnetRequestBoardTrustableBase __storage().base = base(); require( - address(factory).code.length > 0, + address(__factory).code.length > 0, "WitnetRequestBoardTrustableBase: inexistent factory" ); require( - factory.specs() == type(IWitnetRequestFactory).interfaceId, + __factory.specs() == type(IWitnetRequestFactory).interfaceId, "WitnetRequestBoardTrustableBase: uncompliant factory" ); require( - address(factory.witnet()) == address(this) - && address(factory.registry()) == address(registry), + address(__factory.witnet()) == address(this) + && address(__factory.registry()) == address(registry), "WitnetRequestBoardTrustableBase: discordant factory" ); @@ -734,7 +737,7 @@ abstract contract WitnetRequestBoardTrustableBase /// Tells whether given address is included in the active reporters control list. /// @param _reporter The address to be checked. function isReporter(address _reporter) public view override returns (bool) { - return _acls().isReporter_[_reporter]; + return __acls().isReporter_[_reporter]; } /// Adds given addresses to the active reporters control list. @@ -760,7 +763,7 @@ abstract contract WitnetRequestBoardTrustableBase { for (uint ix = 0; ix < _exReporters.length; ix ++) { address _reporter = _exReporters[ix]; - _acls().isReporter_[_reporter] = false; + __acls().isReporter_[_reporter] = false; } emit ReportersUnset(_exReporters); } @@ -983,7 +986,7 @@ abstract contract WitnetRequestBoardTrustableBase { for (uint ix = 0; ix < _reporters.length; ix ++) { address _reporter = _reporters[ix]; - _acls().isReporter_[_reporter] = true; + __acls().isReporter_[_reporter] = true; } emit ReportersSet(_reporters); } diff --git a/contracts/core/defaults/WitnetRequestFactoryDefault.sol b/contracts/core/defaults/WitnetRequestFactoryDefault.sol index a3ef1b114..6bc54b6fb 100644 --- a/contracts/core/defaults/WitnetRequestFactoryDefault.sol +++ b/contracts/core/defaults/WitnetRequestFactoryDefault.sol @@ -60,7 +60,6 @@ contract WitnetRequestFactoryDefault "io.witnet.requests.factory" ) { - assert(address(_witnet) != address(0) && address(_registry) != address(0)); witnet = _witnet; registry = _registry; // let logic contract be used as a factory, while avoiding further initializations: diff --git a/contracts/data/WitnetRequestBoardDataACLs.sol b/contracts/data/WitnetRequestBoardDataACLs.sol index 1652d16f9..42ca19217 100644 --- a/contracts/data/WitnetRequestBoardDataACLs.sol +++ b/contracts/data/WitnetRequestBoardDataACLs.sol @@ -19,12 +19,12 @@ abstract contract WitnetRequestBoardDataACLs } constructor() { - _acls().isReporter_[msg.sender] = true; + __acls().isReporter_[msg.sender] = true; } modifier onlyReporters { require( - _acls().isReporter_[msg.sender], + __acls().isReporter_[msg.sender], "WitnetRequestBoard: unauthorized reporter" ); _; @@ -33,7 +33,7 @@ abstract contract WitnetRequestBoardDataACLs // ================================================================================================================ // --- Internal functions ----------------------------------------------------------------------------------------- - function _acls() internal pure returns (WitnetBoardACLs storage _struct) { + function __acls() internal pure returns (WitnetBoardACLs storage _struct) { assembly { _struct.slot := _WITNET_BOARD_ACLS_SLOTHASH } diff --git a/contracts/mocks/WitnetBytecodesMock.sol b/contracts/mocks/WitnetBytecodesMock.sol new file mode 100644 index 000000000..6b50c5260 --- /dev/null +++ b/contracts/mocks/WitnetBytecodesMock.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.7.0 <0.9.0; +pragma experimental ABIEncoderV2; + +import "../core/defaults/WitnetBytecodesDefault.sol"; + +contract WitnetBytecodesMock is WitnetBytecodesDefault { + constructor() + WitnetBytecodesDefault( + false, + bytes32("mocked") + ) + {} +} diff --git a/contracts/mocks/WitnetPriceFeedsMock.sol b/contracts/mocks/WitnetPriceFeedsMock.sol new file mode 100644 index 000000000..1656c0bb9 --- /dev/null +++ b/contracts/mocks/WitnetPriceFeedsMock.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.7.0 <0.9.0; +pragma experimental ABIEncoderV2; + +import "../apps/WitnetPriceFeeds.sol"; + +contract WitnetPriceFeedsMock is WitnetPriceFeeds { + constructor(WitnetRequestBoard _wrb) + WitnetPriceFeeds( + msg.sender, + _wrb + ) + {} +} diff --git a/contracts/mocks/WitnetRequestBoardMock.sol b/contracts/mocks/WitnetRequestBoardMock.sol new file mode 100644 index 000000000..a1cb85471 --- /dev/null +++ b/contracts/mocks/WitnetRequestBoardMock.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.7.0 <0.9.0; +pragma experimental ABIEncoderV2; + +import "./WitnetBytecodesMock.sol"; +import "../core/defaults/WitnetRequestBoardTrustableDefault.sol"; + +contract WitnetRequestBoardMock + is + WitnetRequestBoardTrustableDefault +{ + WitnetRequestFactory private __factory; + + constructor(WitnetBytecodesMock _registry) + WitnetRequestBoardTrustableDefault( + WitnetRequestFactory(address(0)), + WitnetBytecodes(address(_registry)), + false, + bytes32("mocked"), + 60000, 65000, 70000, 20000 + ) + { + __acls().isReporter_[msg.sender] = true; + } + + function factory() override public view returns (WitnetRequestFactory) { + return __factory; + } + + function setFactory(WitnetRequestFactory _factory) external onlyOwner { + __factory = _factory; + } +} \ No newline at end of file diff --git a/contracts/mocks/WitnetRequestFactoryMock.sol b/contracts/mocks/WitnetRequestFactoryMock.sol new file mode 100644 index 000000000..41679ed92 --- /dev/null +++ b/contracts/mocks/WitnetRequestFactoryMock.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.7.0 <0.9.0; +pragma experimental ABIEncoderV2; + +import "./WitnetRequestBoardMock.sol"; +import "../core/defaults/WitnetRequestFactoryDefault.sol"; + +contract WitnetRequestFactoryMock + is + WitnetRequestFactoryDefault +{ + constructor (WitnetRequestBoardMock _wrb) + WitnetRequestFactoryDefault( + WitnetRequestBoard(address(_wrb)), + WitnetBytecodes(_wrb.registry()), + false, + bytes32("mocked") + ) + {} +} \ No newline at end of file From b4f7b71a951a2d4983a0675d9fc1af9a6f379096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Wed, 29 Nov 2023 12:33:19 +0100 Subject: [PATCH 76/86] chore: refactor Witnet*Mock -> WitnetMocked* --- ...tBytecodesMock.sol => WitnetMockedBytecodes.sol} | 2 +- ...riceFeedsMock.sol => WitnetMockedPriceFeeds.sol} | 2 +- ...andomnessMock.sol => WitnetMockedRandomness.sol} | 10 +++++----- ...stBoardMock.sol => WitnetMockedRequestBoard.sol} | 13 ++++++++----- ...ctoryMock.sol => WitnetMockedRequestFactory.sol} | 6 +++--- 5 files changed, 18 insertions(+), 15 deletions(-) rename contracts/mocks/{WitnetBytecodesMock.sol => WitnetMockedBytecodes.sol} (82%) rename contracts/mocks/{WitnetPriceFeedsMock.sol => WitnetMockedPriceFeeds.sol} (83%) rename contracts/mocks/{WitnetRandomnessMock.sol => WitnetMockedRandomness.sol} (95%) rename contracts/mocks/{WitnetRequestBoardMock.sol => WitnetMockedRequestBoard.sol} (66%) rename contracts/mocks/{WitnetRequestFactoryMock.sol => WitnetMockedRequestFactory.sol} (76%) diff --git a/contracts/mocks/WitnetBytecodesMock.sol b/contracts/mocks/WitnetMockedBytecodes.sol similarity index 82% rename from contracts/mocks/WitnetBytecodesMock.sol rename to contracts/mocks/WitnetMockedBytecodes.sol index 6b50c5260..9c205fb39 100644 --- a/contracts/mocks/WitnetBytecodesMock.sol +++ b/contracts/mocks/WitnetMockedBytecodes.sol @@ -5,7 +5,7 @@ pragma experimental ABIEncoderV2; import "../core/defaults/WitnetBytecodesDefault.sol"; -contract WitnetBytecodesMock is WitnetBytecodesDefault { +contract WitnetMockedBytecodes is WitnetBytecodesDefault { constructor() WitnetBytecodesDefault( false, diff --git a/contracts/mocks/WitnetPriceFeedsMock.sol b/contracts/mocks/WitnetMockedPriceFeeds.sol similarity index 83% rename from contracts/mocks/WitnetPriceFeedsMock.sol rename to contracts/mocks/WitnetMockedPriceFeeds.sol index 1656c0bb9..d99eb1fd2 100644 --- a/contracts/mocks/WitnetPriceFeedsMock.sol +++ b/contracts/mocks/WitnetMockedPriceFeeds.sol @@ -5,7 +5,7 @@ pragma experimental ABIEncoderV2; import "../apps/WitnetPriceFeeds.sol"; -contract WitnetPriceFeedsMock is WitnetPriceFeeds { +contract WitnetMockedPriceFeeds is WitnetPriceFeeds { constructor(WitnetRequestBoard _wrb) WitnetPriceFeeds( msg.sender, diff --git a/contracts/mocks/WitnetRandomnessMock.sol b/contracts/mocks/WitnetMockedRandomness.sol similarity index 95% rename from contracts/mocks/WitnetRandomnessMock.sol rename to contracts/mocks/WitnetMockedRandomness.sol index 6e15db063..114a8b4be 100644 --- a/contracts/mocks/WitnetRandomnessMock.sol +++ b/contracts/mocks/WitnetMockedRandomness.sol @@ -11,7 +11,7 @@ import "../apps/WitnetRandomness.sol"; /// @dev CONTRACT ADDRESS PROVIDED BY THE WITNET FOUNDATION. /// @dev SEE: https://docs.witnet.io/smart-contracts/witnet-randomness-oracle/contract-addresses /// @author Witnet Foundation. -contract WitnetRandomnessMock +contract WitnetMockedRandomness is WitnetRandomness { @@ -19,7 +19,7 @@ contract WitnetRandomnessMock uint256 internal __mockRandomizeFee; uint256 internal __mockRandomizeLatestId; - /// Constructor: new WitnetRandomnessMock contract + /// Constructor: new WitnetMockedRandomness contract /// @param _mockRandomizeLatencyBlocks Mocked number of blocks in which a new randomness will be provided after `randomize()` /// @param _mockRandomizeFee Mocked randomize fee (will be constant no matter what tx gas price is provided). constructor ( @@ -81,8 +81,8 @@ contract WitnetRandomnessMock _block = getRandomnessNextBlock(_block); } uint256 _queryId = __randomize_[_block].witnetQueryId; - require(_queryId != 0, "WitnetRandomnessMock: not randomized"); - require(block.number >= _block + __mockRandomizeLatencyBlocks, "WitnetRandomnessMock: pending randomize"); + require(_queryId != 0, "WitnetMockedRandomness: not randomized"); + require(block.number >= _block + __mockRandomizeLatencyBlocks, "WitnetMockedRandomness: pending randomize"); return blockhash(_block); } @@ -115,7 +115,7 @@ contract WitnetRandomnessMock _usedFunds = __mockRandomizeFee; require( msg.value >= _usedFunds, - "WitnetRandomnessMock: insufficient reward" + "WitnetMockedRandomness: insufficient reward" ); // Post the Witnet Randomness request: uint _queryId = ++ __mockRandomizeLatestId; diff --git a/contracts/mocks/WitnetRequestBoardMock.sol b/contracts/mocks/WitnetMockedRequestBoard.sol similarity index 66% rename from contracts/mocks/WitnetRequestBoardMock.sol rename to contracts/mocks/WitnetMockedRequestBoard.sol index a1cb85471..5f5b1176d 100644 --- a/contracts/mocks/WitnetRequestBoardMock.sol +++ b/contracts/mocks/WitnetMockedRequestBoard.sol @@ -3,16 +3,19 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "./WitnetBytecodesMock.sol"; +import "./WitnetMockedBytecodes.sol"; +import "./WitnetMockedRequestFactory.sol"; import "../core/defaults/WitnetRequestBoardTrustableDefault.sol"; -contract WitnetRequestBoardMock +import "./WitnetMockedPriceFeeds.sol"; + +contract WitnetMockedRequestBoard is WitnetRequestBoardTrustableDefault { WitnetRequestFactory private __factory; - constructor(WitnetBytecodesMock _registry) + constructor(WitnetMockedBytecodes _registry) WitnetRequestBoardTrustableDefault( WitnetRequestFactory(address(0)), WitnetBytecodes(address(_registry)), @@ -28,7 +31,7 @@ contract WitnetRequestBoardMock return __factory; } - function setFactory(WitnetRequestFactory _factory) external onlyOwner { - __factory = _factory; + function setFactory(WitnetMockedRequestFactory _factory) external onlyOwner { + __factory = WitnetRequestFactory(address(_factory)); } } \ No newline at end of file diff --git a/contracts/mocks/WitnetRequestFactoryMock.sol b/contracts/mocks/WitnetMockedRequestFactory.sol similarity index 76% rename from contracts/mocks/WitnetRequestFactoryMock.sol rename to contracts/mocks/WitnetMockedRequestFactory.sol index 41679ed92..654b43d55 100644 --- a/contracts/mocks/WitnetRequestFactoryMock.sol +++ b/contracts/mocks/WitnetMockedRequestFactory.sol @@ -3,14 +3,14 @@ pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; -import "./WitnetRequestBoardMock.sol"; +import "./WitnetMockedRequestBoard.sol"; import "../core/defaults/WitnetRequestFactoryDefault.sol"; -contract WitnetRequestFactoryMock +contract WitnetMockedRequestFactory is WitnetRequestFactoryDefault { - constructor (WitnetRequestBoardMock _wrb) + constructor (WitnetMockedRequestBoard _wrb) WitnetRequestFactoryDefault( WitnetRequestBoard(address(_wrb)), WitnetBytecodes(_wrb.registry()), From 1ba0496626aa5fcc81ec0055ac32aec7be9ccae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Wed, 29 Nov 2023 12:36:55 +0100 Subject: [PATCH 77/86] chore: add disclaimer to mocked contracts --- contracts/mocks/WitnetMockedBytecodes.sol | 5 +++++ contracts/mocks/WitnetMockedPriceFeeds.sol | 5 +++++ contracts/mocks/WitnetMockedRandomness.sol | 9 ++++----- contracts/mocks/WitnetMockedRequestBoard.sol | 5 +++++ contracts/mocks/WitnetMockedRequestFactory.sol | 5 +++++ 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/contracts/mocks/WitnetMockedBytecodes.sol b/contracts/mocks/WitnetMockedBytecodes.sol index 9c205fb39..144738cbd 100644 --- a/contracts/mocks/WitnetMockedBytecodes.sol +++ b/contracts/mocks/WitnetMockedBytecodes.sol @@ -5,6 +5,11 @@ pragma experimental ABIEncoderV2; import "../core/defaults/WitnetBytecodesDefault.sol"; +/// @title Mocked implementation of `WitnetBytecodes`. +/// @dev TO BE USED ONLY ON DEVELOPMENT ENVIRONMENTS. +/// @dev ON SUPPORTED TESTNETS AND MAINNETS, PLEASE USE +/// @dev THE `WitnetBytecodes` CONTRACT ADDRESS PROVIDED +/// @dev BY THE WITNET FOUNDATION. contract WitnetMockedBytecodes is WitnetBytecodesDefault { constructor() WitnetBytecodesDefault( diff --git a/contracts/mocks/WitnetMockedPriceFeeds.sol b/contracts/mocks/WitnetMockedPriceFeeds.sol index d99eb1fd2..b16e883a0 100644 --- a/contracts/mocks/WitnetMockedPriceFeeds.sol +++ b/contracts/mocks/WitnetMockedPriceFeeds.sol @@ -5,6 +5,11 @@ pragma experimental ABIEncoderV2; import "../apps/WitnetPriceFeeds.sol"; +/// @title Mocked implementation of `WitnetPriceFeeds`. +/// @dev TO BE USED ONLY ON DEVELOPMENT ENVIRONMENTS. +/// @dev ON SUPPORTED TESTNETS AND MAINNETS, PLEASE USE +/// @dev THE `WitnetPriceFeeds` CONTRACT ADDRESS PROVIDED +/// @dev BY THE WITNET FOUNDATION. contract WitnetMockedPriceFeeds is WitnetPriceFeeds { constructor(WitnetRequestBoard _wrb) WitnetPriceFeeds( diff --git a/contracts/mocks/WitnetMockedRandomness.sol b/contracts/mocks/WitnetMockedRandomness.sol index 114a8b4be..e77d04c55 100644 --- a/contracts/mocks/WitnetMockedRandomness.sol +++ b/contracts/mocks/WitnetMockedRandomness.sol @@ -5,12 +5,11 @@ pragma experimental ABIEncoderV2; import "../apps/WitnetRandomness.sol"; -/// @title WitnetRandomness mock contract implementation. +/// @title Mocked implementation of `WitnetRandomness`. /// @dev TO BE USED ONLY ON DEVELOPMENT ENVIRONMENTS. -/// @dev ON SUPPORTED TESTNETS, PLEASE USE THE `WitnetRandomness` -/// @dev CONTRACT ADDRESS PROVIDED BY THE WITNET FOUNDATION. -/// @dev SEE: https://docs.witnet.io/smart-contracts/witnet-randomness-oracle/contract-addresses -/// @author Witnet Foundation. +/// @dev ON SUPPORTED TESTNETS AND MAINNETS, PLEASE USE +/// @dev THE `WitnetRandomness` CONTRACT ADDRESS PROVIDED +/// @dev BY THE WITNET FOUNDATION. contract WitnetMockedRandomness is WitnetRandomness diff --git a/contracts/mocks/WitnetMockedRequestBoard.sol b/contracts/mocks/WitnetMockedRequestBoard.sol index 5f5b1176d..f429060b6 100644 --- a/contracts/mocks/WitnetMockedRequestBoard.sol +++ b/contracts/mocks/WitnetMockedRequestBoard.sol @@ -9,6 +9,11 @@ import "../core/defaults/WitnetRequestBoardTrustableDefault.sol"; import "./WitnetMockedPriceFeeds.sol"; +/// @title Mocked implementation of `WitnetRequestBoard`. +/// @dev TO BE USED ONLY ON DEVELOPMENT ENVIRONMENTS. +/// @dev ON SUPPORTED TESTNETS AND MAINNETS, PLEASE USE +/// @dev THE `WitnetRequestBoard` CONTRACT ADDRESS PROVIDED +/// @dev BY THE WITNET FOUNDATION. contract WitnetMockedRequestBoard is WitnetRequestBoardTrustableDefault diff --git a/contracts/mocks/WitnetMockedRequestFactory.sol b/contracts/mocks/WitnetMockedRequestFactory.sol index 654b43d55..bfabbba44 100644 --- a/contracts/mocks/WitnetMockedRequestFactory.sol +++ b/contracts/mocks/WitnetMockedRequestFactory.sol @@ -6,6 +6,11 @@ pragma experimental ABIEncoderV2; import "./WitnetMockedRequestBoard.sol"; import "../core/defaults/WitnetRequestFactoryDefault.sol"; +/// @title Mocked implementation of `WitnetRequestFactory`. +/// @dev TO BE USED ONLY ON DEVELOPMENT ENVIRONMENTS. +/// @dev ON SUPPORTED TESTNETS AND MAINNETS, PLEASE USE +/// @dev THE `WitnetRequestFactory` CONTRACT ADDRESS PROVIDED +/// @dev BY THE WITNET FOUNDATION. contract WitnetMockedRequestFactory is WitnetRequestFactoryDefault From ea8613f52443e425d9ee8403ececbb42a4a57f76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 30 Nov 2023 14:31:44 +0100 Subject: [PATCH 78/86] feat: deprecate WitnetV2.RadonSLA.witnessingCollateralRatio --- contracts/apps/UsingWitnetRandomness.sol | 16 ++++---- contracts/apps/WitnetPriceFeeds.sol | 5 +-- contracts/apps/WitnetRandomness.sol | 7 ++-- .../WitnetRequestBoardTrustableBase.sol | 8 ++-- contracts/interfaces/V2/IWitnetConsumer.sol | 8 +--- contracts/libs/Witnet.sol | 3 +- contracts/libs/WitnetEncodingLib.sol | 4 +- contracts/libs/WitnetV2.sol | 41 +++++++------------ 8 files changed, 36 insertions(+), 56 deletions(-) diff --git a/contracts/apps/UsingWitnetRandomness.sol b/contracts/apps/UsingWitnetRandomness.sol index df034d3f0..ca7576ee9 100644 --- a/contracts/apps/UsingWitnetRandomness.sol +++ b/contracts/apps/UsingWitnetRandomness.sol @@ -18,11 +18,15 @@ abstract contract UsingWitnetRandomness bytes32 internal immutable __witnetRandomnessRadHash; bytes32 private __defaultRandomizePackedSLA; - constructor(WitnetRequestBoard _wrb, uint96 _randomizeCallbackGasLimit) + constructor( + WitnetRequestBoard _wrb, + uint96 _randomizeCallbackGasLimit, + WitnetV2.RadonSLA memory _defaultSLA + ) UsingWitnet(_wrb) WitnetConsumer(_randomizeCallbackGasLimit) { - // Build Witnet randomness request + // On-chain building of the Witnet Randomness Request: { WitnetRequestFactory _factory = witnet().factory(); WitnetBytecodes _registry = witnet().registry(); @@ -48,18 +52,14 @@ abstract contract UsingWitnetRandomness _retrievals, _aggregator, _tally, - 35 // CBOR overhead (3 bytes) + payload (32 bytes) + 32 // 256 bits of pure entropy ;-) )); __witnetRandomnessRadHash = WitnetRequest( _template.buildRequest(new string[][](_retrievals.length)) ).radHash(); } // Settle default randomize SLA: - __defaultRandomizePackedSLA = WitnetV2.RadonSLA({ - witnessingCommitteeSize: 7, - witnessingCollateralRatio: 10, - witnessingWitReward: 10 ** 9 - }).toBytes32(); + __defaultRandomizePackedSLA = _defaultSLA.toBytes32(); } function _defaultRandomizeSLA() internal view returns (WitnetV2.RadonSLA memory) { diff --git a/contracts/apps/WitnetPriceFeeds.sol b/contracts/apps/WitnetPriceFeeds.sol index 2ffcbffa5..7c6de97a6 100644 --- a/contracts/apps/WitnetPriceFeeds.sol +++ b/contracts/apps/WitnetPriceFeeds.sol @@ -46,9 +46,8 @@ contract WitnetPriceFeeds ); witnet = _wrb; __settleDefaultRadonSLA(WitnetV2.RadonSLA({ - witnessingCommitteeSize: 5, - witnessingCollateralRatio: 10, - witnessingWitReward: 10 ** 9 + witnessingCommitteeSize: 10, + witnessingWitTotalReward: 10 ** 9 })); } diff --git a/contracts/apps/WitnetRandomness.sol b/contracts/apps/WitnetRandomness.sol index cdb357d5d..593a2d9b8 100644 --- a/contracts/apps/WitnetRandomness.sol +++ b/contracts/apps/WitnetRandomness.sol @@ -70,7 +70,7 @@ contract WitnetRandomness _retrievals, _aggregator, _tally, - 35 // CBOR overhead (3 bytes) + payload (32 bytes) + 32 // 256 bits of pure entropy ;-) )); witnetRandomnessRequest = WitnetRequest(_template.buildRequest(new string[][](_retrievals.length))); __witnetRandomnessRadHash = witnetRandomnessRequest.radHash(); @@ -466,9 +466,8 @@ contract WitnetRandomness function __initializeWitnetRandomnessSLA() virtual internal { __settleWitnetRandomnessSLA(WitnetV2.RadonSLA({ - witnessingCommitteeSize: 5, - witnessingCollateralRatio: 10, - witnessingWitReward: 10 ** 9 + witnessingCommitteeSize: 10, + witnessingWitTotalReward: 10 ** 9 })); } diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index 2f46da79e..5819d6b2f 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -445,7 +445,7 @@ abstract contract WitnetRequestBoardTrustableBase ) virtual override external payable - checkReward(estimateBaseFee(_getGasPrice(), _queryRAD))//32))// _queryRAD)) + checkReward(estimateBaseFee(_getGasPrice(), _queryRAD)) checkSLA(_querySLA) returns (uint256 _witnetQueryId) { @@ -453,7 +453,7 @@ abstract contract WitnetRequestBoardTrustableBase // Let Web3 observers know that a new request has been posted emit WitnetQuery( _witnetQueryId, - _querySLA.totalWitnessingReward(), + _querySLA.witnessingWitTotalReward, _getMsgValue() ); } @@ -492,7 +492,7 @@ abstract contract WitnetRequestBoardTrustableBase ); emit WitnetQuery( _witnetQueryId, - _querySLA.totalWitnessingReward(), + _querySLA.witnessingWitTotalReward, _getMsgValue() ); } @@ -532,7 +532,7 @@ abstract contract WitnetRequestBoardTrustableBase __seekQueryRequest(_witnetQueryId).bytecode = _queryUnverifiedBytecode; emit WitnetQuery( _witnetQueryId, - _querySLA.totalWitnessingReward(), + _querySLA.witnessingWitTotalReward, _getMsgValue() ); } diff --git a/contracts/interfaces/V2/IWitnetConsumer.sol b/contracts/interfaces/V2/IWitnetConsumer.sol index 8fcc4ce62..6c46d1c1c 100644 --- a/contracts/interfaces/V2/IWitnetConsumer.sol +++ b/contracts/interfaces/V2/IWitnetConsumer.sol @@ -8,9 +8,7 @@ interface IWitnetConsumer { /// @notice Method to be called from the WitnetRequestBoard 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 WitnetRequestBoard being used - /// @dev by the WitnetConsumer contract. Within the implementation of this method, the WitnetConsumer - /// @dev can call to the WRB as to retrieve the Witnet tracking information (i.e. the `witnetDrTxHash` - /// @dev and `witnetDrCommitTxTimestamp`), or the finality status, of the result being reported. + /// @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. @@ -27,9 +25,7 @@ interface IWitnetConsumer { /// @notice Method to be called from the WitnetRequestBoard 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 WitnetRequestBoard being used - /// @dev by the WitnetConsumer contract. Within the implementation of this method, the WitnetConsumer - /// @dev can call to the WRB as to retrieve the Witnet tracking information (i.e. the `witnetDrTxHash` - /// @dev and `witnetDrCommitTxTimestamp`), or the finality status, of the result being reported. + /// @dev by the WitnetConsumer contract. /// @param witnetQueryId The unique identifier of the Witnet query being reported. /// @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. diff --git a/contracts/libs/Witnet.sol b/contracts/libs/Witnet.sol index 931e41ee3..5b2fcfec9 100644 --- a/contracts/libs/Witnet.sol +++ b/contracts/libs/Witnet.sol @@ -229,7 +229,6 @@ library Witnet { struct RadonReducer { RadonReducerOpcodes opcode; RadonFilter[] filters; - // bytes script; } /// Reducting functions currently supported on the Witnet blockchain. @@ -696,7 +695,7 @@ library Witnet { // }); // } - // function totalWitnessingReward(Witnet.RadonSLA memory sla) + // function witnessingWitTotalReward(Witnet.RadonSLA memory sla) // internal pure returns (uint64) // { // return sla.witnessReward * sla.numWitnesses; diff --git a/contracts/libs/WitnetEncodingLib.sol b/contracts/libs/WitnetEncodingLib.sol index ba679d55f..422d204eb 100644 --- a/contracts/libs/WitnetEncodingLib.sol +++ b/contracts/libs/WitnetEncodingLib.sol @@ -372,13 +372,13 @@ library WitnetEncodingLib { maxDataSize ); } - return maxDataSize; + return maxDataSize + 3; // TODO: determine CBOR-encoding length overhead } else if ( dataType == Witnet.RadonDataTypes.Integer || dataType == Witnet.RadonDataTypes.Float || dataType == Witnet.RadonDataTypes.Bool ) { - return 9; // TBD: size(dataType); + return 9; } else { revert UnsupportedRadonDataType( uint8(dataType), diff --git a/contracts/libs/WitnetV2.sol b/contracts/libs/WitnetV2.sol index 0cb3454ef..13e0f1285 100644 --- a/contracts/libs/WitnetV2.sol +++ b/contracts/libs/WitnetV2.sol @@ -53,12 +53,13 @@ library WitnetV2 { } struct RadonSLA { - /// @dev Number of witnessing nodes that will take part in the resolution of a data request within the Witnet blockchain: + /// @dev Number of witnessing nodes that will take part in the resolution + /// @dev of a data request within the Witnet blockchain: uint8 witnessingCommitteeSize; - /// @dev Collateral-to-reward ratio that witnessing nodes will have to commit with when taking part in a data request resolution. - uint8 witnessingCollateralRatio; - /// @dev Minimum amount of $nanoWIT that all Witnet nodes participating in the resolution of a data request will receive as a reward: - uint64 witnessingWitReward; + + /// @dev Total reward in $nanoWIT that will be equally distributed to all nodes + /// @dev involved in the resolution of a data request in the Witnet blockchain: + uint64 witnessingWitTotalReward; } /// =============================================================================================================== @@ -113,26 +114,22 @@ library WitnetV2 { function equalOrGreaterThan(RadonSLA memory a, RadonSLA memory b) internal pure returns (bool) { - return ( - a.witnessingCommitteeSize * a.witnessingCollateralRatio * a.witnessingWitReward - >= b.witnessingCommitteeSize * b.witnessingCollateralRatio * b.witnessingWitReward - ); + return (a.witnessingCommitteeSize >= b.witnessingCommitteeSize); } function isValid(RadonSLA calldata sla) internal pure returns (bool) { return ( - sla.witnessingWitReward > 0 + sla.witnessingWitTotalReward > 0 && sla.witnessingCommitteeSize > 0 && sla.witnessingCommitteeSize <= 127 - && sla.witnessingCollateralRatio > 0 && sla.witnessingCollateralRatio <= 127 ); } function toBytes32(RadonSLA memory sla) internal pure returns (bytes32) { return bytes32( uint(sla.witnessingCommitteeSize) << 248 - | uint(sla.witnessingCollateralRatio) << 240 + // | uint(sla.witnessingCollateralRatio) << 240 // | uint(sla.witnessingNotBeforeTimestamp) << 64 - | uint(sla.witnessingWitReward) + | uint(sla.witnessingWitTotalReward) ); } @@ -141,24 +138,14 @@ library WitnetV2 { { return RadonSLA({ witnessingCommitteeSize: uint8(uint(_packed) >> 248), - witnessingCollateralRatio: uint8(uint(_packed) >> 240), + // witnessingCollateralRatio: uint8(uint(_packed) >> 240), // witnessingNotBeforeTimestamp: uint64(uint(_packed) >> 64), - witnessingWitReward: uint64(uint(_packed)) + witnessingWitTotalReward: uint64(uint(_packed)) }); } - function totalWitnessingReward(WitnetV2.RadonSLA calldata sla) internal pure returns (uint64) { - return ( - (3 + sla.witnessingCommitteeSize) - * sla.witnessingWitReward - ); - } - - function totalWitnessingReward(bytes32 _packed) internal pure returns (uint64) { - return ( - (3 + (uint8(uint(_packed) << 248))) // 3 + witnessingCommitteSize - * uint64(uint(_packed)) // witnessingWitReward - ); + function witnessingWitTotalReward(bytes32 _packed) internal pure returns (uint64) { + return uint64(uint(_packed)); } uint256 internal constant _WITNET_GENESIS_TIMESTAMP = 1602666045; From ff0e351fb1b4bdd8c6a5c78b172ce46adcfdfdb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 30 Nov 2023 14:47:43 +0100 Subject: [PATCH 79/86] chore: refactor UsingWitnetRandomness internal methods --- contracts/apps/UsingWitnetRandomness.sol | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/contracts/apps/UsingWitnetRandomness.sol b/contracts/apps/UsingWitnetRandomness.sol index ca7576ee9..79908f1e7 100644 --- a/contracts/apps/UsingWitnetRandomness.sol +++ b/contracts/apps/UsingWitnetRandomness.sol @@ -62,15 +62,15 @@ abstract contract UsingWitnetRandomness __defaultRandomizePackedSLA = _defaultSLA.toBytes32(); } - function _defaultRandomizeSLA() internal view returns (WitnetV2.RadonSLA memory) { + function _witnetDefaultSLA() virtual internal view returns (WitnetV2.RadonSLA memory) { return __defaultRandomizePackedSLA.toRadonSLA(); } - function _estimateRandomizeBaseFee() internal view returns (uint256) { - return _witnetEstimateBaseFee(35); + function _witnetEstimateRandomizeBaseFee() internal view returns (uint256) { + return _witnetEstimateBaseFee(32); } - function _randomUniform(uint32 _range, uint256 _nonce, bytes32 _seed) internal pure returns (uint32) { + function _witnetRandomUniformUint32(uint32 _range, uint256 _nonce, bytes32 _seed) internal pure returns (uint32) { uint256 _number = uint256( keccak256( abi.encode(_seed, _nonce) @@ -79,19 +79,15 @@ abstract contract UsingWitnetRandomness return uint32((_number * _range) >> 224); } - function _readRandomnessFromResultValue(WitnetCBOR.CBOR calldata cborValue) internal pure returns (bytes32) { - return cborValue.readBytes().toBytes32(); - } - - function __randomize(uint256 _witnetEvmReward) virtual internal returns (uint256) { + function __witnetRandomize(uint256 _witnetEvmReward) virtual internal returns (uint256) { return __witnetRequestData( _witnetEvmReward, - _defaultRandomizeSLA(), + _witnetDefaultSLA(), __witnetRandomnessRadHash ); } - function __randomize( + function __witnetRandomize( uint256 _witnetEvmReward, WitnetV2.RadonSLA calldata _witnetQuerySLA ) @@ -105,7 +101,11 @@ abstract contract UsingWitnetRandomness ); } - function __settleRandomizeDefaultSLA(WitnetV2.RadonSLA calldata sla) virtual internal { + function _witnetReadRandomizeFromResultValue(WitnetCBOR.CBOR calldata cborValue) internal pure returns (bytes32) { + return cborValue.readBytes().toBytes32(); + } + + function __witnetSettleDefaultSLA(WitnetV2.RadonSLA calldata sla) virtual internal { __defaultRandomizePackedSLA = sla.toBytes32(); } } \ No newline at end of file From b8e74c830bc6a0aa83103a112ad1c13fb8be5944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 30 Nov 2023 18:01:16 +0100 Subject: [PATCH 80/86] chore: refactor UsingWitnet internal methods --- contracts/apps/UsingWitnet.sol | 24 +++++++++++++ contracts/apps/UsingWitnetRandomness.sol | 11 +----- contracts/apps/UsingWitnetRequest.sol | 15 +++++++- contracts/apps/UsingWitnetRequestTemplate.sol | 18 +++++++++- contracts/apps/WitnetRequestConsumer.sol | 8 +++-- .../apps/WitnetRequestTemplateConsumer.sol | 36 +++++++++++++++++-- 6 files changed, 95 insertions(+), 17 deletions(-) diff --git a/contracts/apps/UsingWitnet.sol b/contracts/apps/UsingWitnet.sol index f19147db5..928f5c240 100644 --- a/contracts/apps/UsingWitnet.sol +++ b/contracts/apps/UsingWitnet.sol @@ -13,6 +13,7 @@ abstract contract UsingWitnet IWitnetRequestBoardEvents { WitnetRequestBoard internal immutable __witnet; + bytes32 private __witnetDefaultPackedSLA; /// @dev Include an address to specify the WitnetRequestBoard entry point address. /// @param _wrb The WitnetRequestBoard entry point address. @@ -22,6 +23,10 @@ abstract contract UsingWitnet "UsingWitnet: uncompliant WitnetRequestBoard" ); __witnet = _wrb; + __witnetDefaultPackedSLA = WitnetV2.toBytes32(WitnetV2.RadonSLA({ + witnessingCommitteeSize: 10, + witnessingWitTotalReward: 10 ** 9 + })); } /// @dev Provides a convenient way for client contracts extending this to block the execution of the main logic of the @@ -80,6 +85,10 @@ abstract contract UsingWitnet return __witnet.getQueryResultError(_witnetQueryId); } + function _witnetDefaultSLA() virtual internal view returns (WitnetV2.RadonSLA memory) { + return WitnetV2.toRadonSLA(__witnetDefaultPackedSLA); + } + function __witnetRequestData( uint256 _witnetEvmReward, WitnetV2.RadonSLA memory _witnetQuerySLA, @@ -92,4 +101,19 @@ abstract contract UsingWitnet _witnetQuerySLA ); } + + function __witnetRequestData( + uint256 _witnetEvmReward, + bytes32 _witnetRadHash + ) + virtual internal returns (uint256) + { + return __witnet.postRequest{value: _witnetEvmReward}( + _witnetRadHash, + _witnetDefaultSLA() + ); + } + function __witnetSetDefaultSLA(WitnetV2.RadonSLA memory _defaultSLA) virtual internal { + __witnetDefaultPackedSLA = WitnetV2.toBytes32(_defaultSLA); + } } diff --git a/contracts/apps/UsingWitnetRandomness.sol b/contracts/apps/UsingWitnetRandomness.sol index 79908f1e7..d7b3c9a03 100644 --- a/contracts/apps/UsingWitnetRandomness.sol +++ b/contracts/apps/UsingWitnetRandomness.sol @@ -16,7 +16,6 @@ abstract contract UsingWitnetRandomness using WitnetV2 for WitnetV2.RadonSLA; bytes32 internal immutable __witnetRandomnessRadHash; - bytes32 private __defaultRandomizePackedSLA; constructor( WitnetRequestBoard _wrb, @@ -59,11 +58,7 @@ abstract contract UsingWitnetRandomness ).radHash(); } // Settle default randomize SLA: - __defaultRandomizePackedSLA = _defaultSLA.toBytes32(); - } - - function _witnetDefaultSLA() virtual internal view returns (WitnetV2.RadonSLA memory) { - return __defaultRandomizePackedSLA.toRadonSLA(); + __witnetSetDefaultSLA(_defaultSLA); } function _witnetEstimateRandomizeBaseFee() internal view returns (uint256) { @@ -104,8 +99,4 @@ abstract contract UsingWitnetRandomness function _witnetReadRandomizeFromResultValue(WitnetCBOR.CBOR calldata cborValue) internal pure returns (bytes32) { return cborValue.readBytes().toBytes32(); } - - function __witnetSettleDefaultSLA(WitnetV2.RadonSLA calldata sla) virtual internal { - __defaultRandomizePackedSLA = sla.toBytes32(); - } } \ No newline at end of file diff --git a/contracts/apps/UsingWitnetRequest.sol b/contracts/apps/UsingWitnetRequest.sol index 3e75ca492..3d29baca1 100644 --- a/contracts/apps/UsingWitnetRequest.sol +++ b/contracts/apps/UsingWitnetRequest.sol @@ -12,7 +12,10 @@ abstract contract UsingWitnetRequest bytes32 immutable internal __witnetRequestRadHash; uint16 immutable internal __witnetResultMaxSize; - constructor (WitnetRequest _witnetRequest) + constructor ( + WitnetRequest _witnetRequest, + WitnetV2.RadonSLA memory _defaultSLA + ) UsingWitnet(_witnetRequest.witnet()) { require( @@ -22,6 +25,7 @@ abstract contract UsingWitnetRequest dataRequest = _witnetRequest; __witnetResultMaxSize = _witnetRequest.resultDataMaxSize(); __witnetRequestRadHash = _witnetRequest.radHash(); + __witnetSetDefaultSLA(_defaultSLA); } function _witnetEstimateBaseFee() @@ -47,4 +51,13 @@ abstract contract UsingWitnetRequest ); } + function __witnetRequestData(uint256 _witnetEvmReward) + virtual internal returns (uint256) + { + return __witnetRequestData( + _witnetEvmReward, + _witnetDefaultSLA(), + __witnetRequestRadHash + ); + } } \ No newline at end of file diff --git a/contracts/apps/UsingWitnetRequestTemplate.sol b/contracts/apps/UsingWitnetRequestTemplate.sol index c95d591da..17af88bbc 100644 --- a/contracts/apps/UsingWitnetRequestTemplate.sol +++ b/contracts/apps/UsingWitnetRequestTemplate.sol @@ -11,7 +11,10 @@ abstract contract UsingWitnetRequestTemplate uint16 immutable internal __witnetResultMaxSize; - constructor (WitnetRequestTemplate _requestTemplate) + constructor ( + WitnetRequestTemplate _requestTemplate, + WitnetV2.RadonSLA memory _defaultSLA + ) UsingWitnet(_requestTemplate.witnet()) { require( @@ -20,6 +23,7 @@ abstract contract UsingWitnetRequestTemplate ); dataRequestTemplate = _requestTemplate; __witnetResultMaxSize = _requestTemplate.resultDataMaxSize(); + __witnetSetDefaultSLA(_defaultSLA); } function _witnetBuildRadHash(string[][] memory _witnetRequestArgs) @@ -58,4 +62,16 @@ abstract contract UsingWitnetRequestTemplate ); } + function __witnetRequestData( + uint256 _witnetEvmReward, + string[][] memory _witnetRequestArgs + ) + virtual internal returns (uint256) + { + return __witnetRequestData( + _witnetEvmReward, + _witnetBuildRadHash(_witnetRequestArgs) + ); + } + } \ No newline at end of file diff --git a/contracts/apps/WitnetRequestConsumer.sol b/contracts/apps/WitnetRequestConsumer.sol index e8f4e0ec5..4b9ca68c7 100644 --- a/contracts/apps/WitnetRequestConsumer.sol +++ b/contracts/apps/WitnetRequestConsumer.sol @@ -12,8 +12,12 @@ abstract contract WitnetRequestConsumer using WitnetCBOR for WitnetCBOR.CBOR; using WitnetCBOR for WitnetCBOR.CBOR[]; - constructor(WitnetRequest _witnetRequest, uint96 _callbackGasLimit) - UsingWitnetRequest(_witnetRequest) + constructor( + WitnetRequest _witnetRequest, + uint96 _callbackGasLimit, + WitnetV2.RadonSLA memory _defaultSLA + ) + UsingWitnetRequest(_witnetRequest, _defaultSLA) WitnetConsumer(_callbackGasLimit) { require( diff --git a/contracts/apps/WitnetRequestTemplateConsumer.sol b/contracts/apps/WitnetRequestTemplateConsumer.sol index 7adad22c5..01195b6fa 100644 --- a/contracts/apps/WitnetRequestTemplateConsumer.sol +++ b/contracts/apps/WitnetRequestTemplateConsumer.sol @@ -12,8 +12,12 @@ abstract contract WitnetRequestTemplateConsumer using WitnetCBOR for WitnetCBOR.CBOR; using WitnetCBOR for WitnetCBOR.CBOR[]; - constructor(WitnetRequestTemplate _requestTemplate, uint96 _callbackGasLimit) - UsingWitnetRequestTemplate(_requestTemplate) + constructor( + WitnetRequestTemplate _requestTemplate, + uint96 _callbackGasLimit, + WitnetV2.RadonSLA memory _defaultSLA + ) + UsingWitnetRequestTemplate(_requestTemplate, _defaultSLA) WitnetConsumer(_callbackGasLimit) { require( @@ -55,6 +59,20 @@ abstract contract WitnetRequestTemplateConsumer ); } + function __witnetRequestData( + uint256 _witnetEvmReward, + bytes32 _witnetRadHash + ) + virtual override internal + returns (uint256) + { + return WitnetConsumer.__witnetRequestData( + _witnetEvmReward, + _witnetDefaultSLA(), + _witnetRadHash + ); + } + function __witnetRequestData( uint256 _witnetEvmReward, WitnetV2.RadonSLA memory _witnetQuerySLA, @@ -70,6 +88,18 @@ abstract contract WitnetRequestTemplateConsumer ); } - + function __witnetRequestData( + uint256 _witnetEvmReward, + string[][] memory _witnetRequestArgs + ) + virtual override internal + returns (uint256) + { + return WitnetConsumer.__witnetRequestData( + _witnetEvmReward, + _witnetDefaultSLA(), + _witnetBuildRadHash(_witnetRequestArgs) + ); + } } From 0d9fc0c979e1e2d8d7c7db95b4ef3028385cbe9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 1 Dec 2023 10:15:05 +0100 Subject: [PATCH 81/86] feat: UsingWitnet._witnetBaseFeeOverheadPercentage() --- contracts/apps/UsingWitnet.sol | 34 +++++++++++--- contracts/apps/UsingWitnetRandomness.sol | 14 ++++-- contracts/apps/UsingWitnetRequest.sol | 12 ++--- contracts/apps/UsingWitnetRequestTemplate.sol | 22 +++++----- contracts/apps/WitnetConsumer.sol | 44 ++++++++++++------- contracts/apps/WitnetRequestConsumer.sol | 27 ++++++------ .../apps/WitnetRequestTemplateConsumer.sol | 28 ++++++------ contracts/interfaces/V2/IWitnetConsumer.sol | 1 - 8 files changed, 111 insertions(+), 71 deletions(-) diff --git a/contracts/apps/UsingWitnet.sol b/contracts/apps/UsingWitnet.sol index 928f5c240..c02f93c35 100644 --- a/contracts/apps/UsingWitnet.sol +++ b/contracts/apps/UsingWitnet.sol @@ -12,11 +12,20 @@ abstract contract UsingWitnet is IWitnetRequestBoardEvents { + /// @dev Immutable reference to the Witnet Request Board contract. WitnetRequestBoard internal immutable __witnet; + + /// @dev Default Security-Level Agreement parameters to be fulfilled by the Witnet blockchain + /// @dev when solving a data request. bytes32 private __witnetDefaultPackedSLA; - /// @dev Include an address to specify the WitnetRequestBoard entry point address. - /// @param _wrb The WitnetRequestBoard entry point address. + /// @dev Percentage over base fee to pay on every data request, + /// @dev as to deal with volatility of evmGasPrice and evmWitPrice during the live time of + /// @dev a data request (since being posted until a result gets reported back), at both the EVM and + /// @dev the Witnet blockchain levels, respectivelly. + uint16 private __witnetBaseFeeOverheadPercentage; + + /// @param _wrb Address of the WitnetRequestBoard contract. constructor(WitnetRequestBoard _wrb) { require( _wrb.specs() == type(IWitnetRequestBoard).interfaceId, @@ -24,9 +33,11 @@ abstract contract UsingWitnet ); __witnet = _wrb; __witnetDefaultPackedSLA = WitnetV2.toBytes32(WitnetV2.RadonSLA({ - witnessingCommitteeSize: 10, - witnessingWitTotalReward: 10 ** 9 + witnessingCommitteeSize: 10, // up to 127 + witnessingWitTotalReward: 10 ** 9 // 1.0 $WIT })); + + __witnetBaseFeeOverheadPercentage = 10; // defaults to 10% } /// @dev Provides a convenient way for client contracts extending this to block the execution of the main logic of the @@ -53,11 +64,14 @@ abstract contract UsingWitnet /// @notice Estimate the minimum reward required for posting a data request, using `tx.gasprice` as a reference. /// @dev Underestimates if the size of returned data is greater than `_resultMaxSize`. /// @param _resultMaxSize Maximum expected size of returned data (in bytes). - function _witnetEstimateBaseFee(uint16 _resultMaxSize) + function _witnetEstimateEvmReward(uint16 _resultMaxSize) virtual internal view returns (uint256) { - return __witnet.estimateBaseFee(tx.gasprice, _resultMaxSize); + return ( + (100 + _witnetBaseFeeOverheadPercentage()) + * __witnet.estimateBaseFee(tx.gasprice, _resultMaxSize) + ) / 100; } function _witnetCheckQueryResultAuditTrail(uint256 _witnetQueryId) @@ -89,6 +103,10 @@ abstract contract UsingWitnet return WitnetV2.toRadonSLA(__witnetDefaultPackedSLA); } + function _witnetBaseFeeOverheadPercentage() virtual internal view returns (uint16) { + return __witnetBaseFeeOverheadPercentage; + } + function __witnetRequestData( uint256 _witnetEvmReward, WitnetV2.RadonSLA memory _witnetQuerySLA, @@ -116,4 +134,8 @@ abstract contract UsingWitnet function __witnetSetDefaultSLA(WitnetV2.RadonSLA memory _defaultSLA) virtual internal { __witnetDefaultPackedSLA = WitnetV2.toBytes32(_defaultSLA); } + + function __witnetSetBaseFeeOverheadPercentage(uint16 _baseFeeOverheadPercentage) virtual internal { + __witnetBaseFeeOverheadPercentage = _baseFeeOverheadPercentage; + } } diff --git a/contracts/apps/UsingWitnetRandomness.sol b/contracts/apps/UsingWitnetRandomness.sol index d7b3c9a03..2fbeb323b 100644 --- a/contracts/apps/UsingWitnetRandomness.sol +++ b/contracts/apps/UsingWitnetRandomness.sol @@ -17,13 +17,18 @@ abstract contract UsingWitnetRandomness bytes32 internal immutable __witnetRandomnessRadHash; + /// @param _wrb Address of the WitnetRequestBoard contract. + /// @param _baseFeeOverheadPercentage Percentage over base fee to pay as on every data request. + /// @param _callbackGasLimit Maximum gas to be spent by the IWitnetConsumer's callback methods. + /// @param _defaultSLA Default Security-Level Agreement parameters to be fulfilled by the Witnet blockchain. constructor( WitnetRequestBoard _wrb, - uint96 _randomizeCallbackGasLimit, + uint16 _baseFeeOverheadPercentage, + uint96 _callbackGasLimit, WitnetV2.RadonSLA memory _defaultSLA ) UsingWitnet(_wrb) - WitnetConsumer(_randomizeCallbackGasLimit) + WitnetConsumer(_callbackGasLimit) { // On-chain building of the Witnet Randomness Request: { @@ -59,10 +64,11 @@ abstract contract UsingWitnetRandomness } // Settle default randomize SLA: __witnetSetDefaultSLA(_defaultSLA); + __witnetSetBaseFeeOverheadPercentage(_baseFeeOverheadPercentage); } - function _witnetEstimateRandomizeBaseFee() internal view returns (uint256) { - return _witnetEstimateBaseFee(32); + function _witnetEstimateEvmReward() virtual override internal view returns (uint256) { + return _witnetEstimateEvmReward(32); } function _witnetRandomUniformUint32(uint32 _range, uint256 _nonce, bytes32 _seed) internal pure returns (uint32) { diff --git a/contracts/apps/UsingWitnetRequest.sol b/contracts/apps/UsingWitnetRequest.sol index 3d29baca1..464c28333 100644 --- a/contracts/apps/UsingWitnetRequest.sol +++ b/contracts/apps/UsingWitnetRequest.sol @@ -12,8 +12,12 @@ abstract contract UsingWitnetRequest bytes32 immutable internal __witnetRequestRadHash; uint16 immutable internal __witnetResultMaxSize; + /// @param _witnetRequest Address of the WitnetRequest contract containing the actual data request. + /// @param _baseFeeOverheadPercentage Percentage over base fee to pay as on every data request. + /// @param _defaultSLA Default Security-Level Agreement parameters to be fulfilled by the Witnet blockchain. constructor ( WitnetRequest _witnetRequest, + uint16 _baseFeeOverheadPercentage, WitnetV2.RadonSLA memory _defaultSLA ) UsingWitnet(_witnetRequest.witnet()) @@ -26,16 +30,14 @@ abstract contract UsingWitnetRequest __witnetResultMaxSize = _witnetRequest.resultDataMaxSize(); __witnetRequestRadHash = _witnetRequest.radHash(); __witnetSetDefaultSLA(_defaultSLA); + __witnetSetBaseFeeOverheadPercentage(_baseFeeOverheadPercentage); } - function _witnetEstimateBaseFee() + function _witnetEstimateEvmReward() virtual internal view returns (uint256) { - return __witnet.estimateBaseFee( - tx.gasprice, - __witnetResultMaxSize - ); + return _witnetEstimateEvmReward(__witnetResultMaxSize); } function __witnetRequestData( diff --git a/contracts/apps/UsingWitnetRequestTemplate.sol b/contracts/apps/UsingWitnetRequestTemplate.sol index 17af88bbc..11efa8497 100644 --- a/contracts/apps/UsingWitnetRequestTemplate.sol +++ b/contracts/apps/UsingWitnetRequestTemplate.sol @@ -11,19 +11,24 @@ abstract contract UsingWitnetRequestTemplate uint16 immutable internal __witnetResultMaxSize; + /// @param _witnetRequestTemplate Address of the WitnetRequestTemplate from which actual data requests will get built. + /// @param _baseFeeOverheadPercentage Percentage over base fee to pay as on every data request. + /// @param _defaultSLA Default Security-Level Agreement parameters to be fulfilled by the Witnet blockchain. constructor ( - WitnetRequestTemplate _requestTemplate, + WitnetRequestTemplate _witnetRequestTemplate, + uint16 _baseFeeOverheadPercentage, WitnetV2.RadonSLA memory _defaultSLA ) - UsingWitnet(_requestTemplate.witnet()) + UsingWitnet(_witnetRequestTemplate.witnet()) { require( - _requestTemplate.specs() == type(WitnetRequestTemplate).interfaceId, + _witnetRequestTemplate.specs() == type(WitnetRequestTemplate).interfaceId, "UsingWitnetRequestTemplate: uncompliant WitnetRequestTemplate" ); - dataRequestTemplate = _requestTemplate; - __witnetResultMaxSize = _requestTemplate.resultDataMaxSize(); + dataRequestTemplate = _witnetRequestTemplate; + __witnetResultMaxSize = _witnetRequestTemplate.resultDataMaxSize(); __witnetSetDefaultSLA(_defaultSLA); + __witnetSetBaseFeeOverheadPercentage(_baseFeeOverheadPercentage); } function _witnetBuildRadHash(string[][] memory _witnetRequestArgs) @@ -38,14 +43,11 @@ abstract contract UsingWitnetRequestTemplate return WitnetRequest(dataRequestTemplate.buildRequest(_witnetRequestArgs)); } - function _witnetEstimateBaseFee() + function _witnetEstimateEvmReward() virtual internal view returns (uint256) { - return __witnet.estimateBaseFee( - tx.gasprice, - __witnetResultMaxSize - ); + return _witnetEstimateEvmReward(__witnetResultMaxSize); } function __witnetRequestData( diff --git a/contracts/apps/WitnetConsumer.sol b/contracts/apps/WitnetConsumer.sol index 3a460dc29..92befc63c 100644 --- a/contracts/apps/WitnetConsumer.sol +++ b/contracts/apps/WitnetConsumer.sol @@ -8,16 +8,18 @@ abstract contract WitnetConsumer is IWitnetConsumer, UsingWitnet -{ - uint96 private immutable __witnetReportCallbackGasLimit; +{ + /// @dev Maximum gas to be spent by the IWitnetConsumer's callback methods. + uint96 private immutable __witnetCallbackGasLimit; modifier onlyFromWitnet { require(msg.sender == address(__witnet), "WitnetConsumer: unauthorized"); _; } - constructor (uint96 _maxCallbackGas) { - __witnetReportCallbackGasLimit = _maxCallbackGas; + /// @param _callbackGasLimit Maximum gas to be spent by the IWitnetConsumer's callback methods. + constructor (uint96 _callbackGasLimit) { + __witnetCallbackGasLimit = _callbackGasLimit; } @@ -32,31 +34,41 @@ abstract contract WitnetConsumer /// =============================================================================================================== /// --- WitnetConsumer virtual methods ---------------------------------------------------------------------------- - function _witnetEstimateBaseFee(uint16) + function _witnetCallbackGasLimit() + virtual internal view + returns (uint96) + { + return __witnetCallbackGasLimit; + } + + function _witnetEstimateEvmReward() virtual internal view returns (uint256) { + return ( + (100 + _witnetBaseFeeOverheadPercentage()) + * __witnet.estimateBaseFeeWithCallback( + tx.gasprice, + _witnetCallbackGasLimit() + ) + ) / 100; + } + + function _witnetEstimateEvmReward(uint16) virtual override internal view returns (uint256) { - return _witnetEstimateBaseFeeWithCallback(_witnetReportCallbackGasLimit()); + return _witnetEstimateEvmReward(); } /// @notice Estimate the minimum reward required for posting a data request, using `tx.gasprice` as a reference. /// @dev Underestimates if the size of returned data is greater than `_resultMaxSize`. /// @param _callbackGasLimit Maximum gas to be spent when reporting the data request result. - function _witnetEstimateBaseFeeWithCallback(uint96 _callbackGasLimit) + function _witnetEstimateEvmRewardWithCallback(uint96 _callbackGasLimit) virtual internal view returns (uint256) { return __witnet.estimateBaseFeeWithCallback(tx.gasprice, _callbackGasLimit); } - function _witnetReportCallbackGasLimit() - virtual internal view - returns (uint96) - { - return __witnetReportCallbackGasLimit; - } - function __witnetRequestData( uint256 _witnetEvmReward, WitnetV2.RadonSLA memory _witnetQuerySLA, @@ -68,7 +80,7 @@ abstract contract WitnetConsumer return __witnet.postRequestWithCallback{value: _witnetEvmReward}( _witnetRadHash, _witnetQuerySLA, - __witnetReportCallbackGasLimit + __witnetCallbackGasLimit ); } @@ -82,7 +94,7 @@ abstract contract WitnetConsumer return __witnet.postRequestWithCallback{value: _witnetEvmReward}( _witnetRequestBytecode, _witnetQuerySLA, - __witnetReportCallbackGasLimit + __witnetCallbackGasLimit ); } diff --git a/contracts/apps/WitnetRequestConsumer.sol b/contracts/apps/WitnetRequestConsumer.sol index 4b9ca68c7..6e34e2932 100644 --- a/contracts/apps/WitnetRequestConsumer.sol +++ b/contracts/apps/WitnetRequestConsumer.sol @@ -11,36 +11,35 @@ abstract contract WitnetRequestConsumer { using WitnetCBOR for WitnetCBOR.CBOR; using WitnetCBOR for WitnetCBOR.CBOR[]; - + + /// @param _witnetRequest Address of the WitnetRequest contract containing the actual data request. + /// @param _baseFeeOverheadPercentage Percentage over base fee to pay as on every data request. + /// @param _callbackGasLimit Maximum gas to be spent by the IWitnetConsumer's callback methods. + /// @param _defaultSLA Default Security-Level Agreement parameters to be fulfilled by the Witnet blockchain. constructor( WitnetRequest _witnetRequest, + uint16 _baseFeeOverheadPercentage, uint96 _callbackGasLimit, WitnetV2.RadonSLA memory _defaultSLA ) - UsingWitnetRequest(_witnetRequest, _defaultSLA) + UsingWitnetRequest(_witnetRequest, _baseFeeOverheadPercentage, _defaultSLA) WitnetConsumer(_callbackGasLimit) - { - require( - _witnetEstimateBaseFeeWithCallback(_callbackGasLimit) - > UsingWitnetRequest._witnetEstimateBaseFee(), - "WitnetRequestConsumer: insufficient callback gas limit" - ); - } + {} - function _witnetEstimateBaseFee() - virtual override + function _witnetEstimateEvmReward() + virtual override(UsingWitnetRequest, WitnetConsumer) internal view returns (uint256) { - return WitnetConsumer._witnetEstimateBaseFee(__witnetResultMaxSize); + return WitnetConsumer._witnetEstimateEvmReward(); } - function _witnetEstimateBaseFee(uint16 _resultMaxSize) + function _witnetEstimateEvmReward(uint16) virtual override(UsingWitnet, WitnetConsumer) internal view returns (uint256) { - return WitnetConsumer._witnetEstimateBaseFee(_resultMaxSize); + return WitnetConsumer._witnetEstimateEvmReward(); } function __witnetRequestData( diff --git a/contracts/apps/WitnetRequestTemplateConsumer.sol b/contracts/apps/WitnetRequestTemplateConsumer.sol index 01195b6fa..71d20eaa9 100644 --- a/contracts/apps/WitnetRequestTemplateConsumer.sol +++ b/contracts/apps/WitnetRequestTemplateConsumer.sol @@ -12,36 +12,34 @@ abstract contract WitnetRequestTemplateConsumer using WitnetCBOR for WitnetCBOR.CBOR; using WitnetCBOR for WitnetCBOR.CBOR[]; + /// @param _witnetRequestTemplate Address of the WitnetRequestTemplate from which actual data requests will get built. + /// @param _baseFeeOverheadPercentage Percentage over base fee to pay as on every data request. + /// @param _callbackGasLimit Maximum gas to be spent by the IWitnetConsumer's callback methods. + /// @param _defaultSLA Default Security-Level Agreement parameters to be fulfilled by the Witnet blockchain. constructor( - WitnetRequestTemplate _requestTemplate, + WitnetRequestTemplate _witnetRequestTemplate, + uint16 _baseFeeOverheadPercentage, uint96 _callbackGasLimit, WitnetV2.RadonSLA memory _defaultSLA ) - UsingWitnetRequestTemplate(_requestTemplate, _defaultSLA) + UsingWitnetRequestTemplate(_witnetRequestTemplate, _baseFeeOverheadPercentage, _defaultSLA) WitnetConsumer(_callbackGasLimit) - { - require( - _witnetEstimateBaseFeeWithCallback(_callbackGasLimit) - > UsingWitnetRequestTemplate._witnetEstimateBaseFee(), - "WitnetRequestTemplateConsumer: insufficient callback gas limit" - ); - - } + {} - function _witnetEstimateBaseFee() - virtual override + function _witnetEstimateEvmReward() + virtual override(UsingWitnetRequestTemplate, WitnetConsumer) internal view returns (uint256) { - return WitnetConsumer._witnetEstimateBaseFee(__witnetResultMaxSize); + return WitnetConsumer._witnetEstimateEvmReward(__witnetResultMaxSize); } - function _witnetEstimateBaseFee(uint16 _resultMaxSize) + function _witnetEstimateEvmReward(uint16) virtual override(UsingWitnet, WitnetConsumer) internal view returns (uint256) { - return WitnetConsumer._witnetEstimateBaseFee(_resultMaxSize); + return WitnetConsumer._witnetEstimateEvmReward(); } function __witnetRequestData( diff --git a/contracts/interfaces/V2/IWitnetConsumer.sol b/contracts/interfaces/V2/IWitnetConsumer.sol index 6c46d1c1c..bc191d06a 100644 --- a/contracts/interfaces/V2/IWitnetConsumer.sol +++ b/contracts/interfaces/V2/IWitnetConsumer.sol @@ -27,7 +27,6 @@ interface IWitnetConsumer { /// @dev It should revert if called from any other address different to the WitnetRequestBoard being used /// @dev by the WitnetConsumer contract. /// @param witnetQueryId The unique identifier of the Witnet query being reported. - /// @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. From 71e7973ea444047c6990602614241706aa119499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 1 Dec 2023 10:54:20 +0100 Subject: [PATCH 82/86] refactor: IWRB.estimateQueryEarnings -> IWRBReporter.estimateQueryEarnings --- .../WitnetRequestBoardTrustableBase.sol | 46 ++++++++----------- .../interfaces/V2/IWitnetRequestBoard.sol | 8 +--- .../V2/IWitnetRequestBoardReporter.sol | 6 +++ 3 files changed, 27 insertions(+), 33 deletions(-) diff --git a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol index 5819d6b2f..f8056eb5e 100644 --- a/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol +++ b/contracts/core/defaults/WitnetRequestBoardTrustableBase.sol @@ -213,32 +213,6 @@ abstract contract WitnetRequestBoardTrustableBase _resultMaxSize ); } - - /// @notice Estimates the actual earnings (or loss), in WEI, that a reporter would get by reporting result to given query, - /// @notice based on the gas price of the calling transaction. Data requesters should consider upgrading the reward on - /// @notice queries providing no actual earnings. - /// @dev Fails if the query does not exist, or if deleted. - function estimateQueryEarnings(uint256 _witnetQueryId, uint256 _gasPrice) - virtual override - external view - returns (int256 _earnings) - { - WitnetV2.Request storage __request = __seekQueryRequest(_witnetQueryId); - - _earnings = int(__request.evmReward); - uint96 _callbackGasLimit = __request.unpackCallbackGasLimit(); - if (_callbackGasLimit > 0) { - _earnings -= int(estimateBaseFeeWithCallback( - _gasPrice, - _callbackGasLimit - )); - } else { - _earnings -= int(estimateBaseFee( - _gasPrice, - __request.RAD - )); - } - } /// Retrieves copy of all response data related to a previously posted request, removing the whole query from storage. /// @dev Fails if the `_witnetQueryId` is not in 'Reported' status, or called from an address different to @@ -554,6 +528,26 @@ abstract contract WitnetRequestBoardTrustableBase // ================================================================================================================ // --- Full implementation of IWitnetRequestBoardReporter --------------------------------------------------------- + /// @notice Estimates the actual earnings (or loss), in WEI, that a reporter would get by reporting result to given query, + /// @notice based on the gas price of the calling transaction. Data requesters should consider upgrading the reward on + /// @notice queries providing no actual earnings. + /// @dev Fails if the query does not exist, or if deleted. + function estimateQueryEarnings(uint256[] calldata _witnetQueryIds, uint256 _gasPrice) + virtual override + external view + returns (int256 _earnings) + { + uint256 _expenses; uint256 _revenues; + for (uint _ix = 0; _ix < _witnetQueryIds.length; _ix ++) { + if (_statusOf(_witnetQueryIds[_ix]) == WitnetV2.QueryStatus.Posted) { + WitnetV2.Request storage __request = __seekQueryRequest(_witnetQueryIds[_ix]); + _revenues += __request.evmReward; + _expenses += _gasPrice * __request.unpackCallbackGasLimit(); + } + } + return int256(_revenues) - int256(_expenses); + } + /// Reports the Witnet-provable result to a previously posted request. /// @dev Will assume `block.timestamp` as the timestamp at which the request was solved. /// @dev Fails if: diff --git a/contracts/interfaces/V2/IWitnetRequestBoard.sol b/contracts/interfaces/V2/IWitnetRequestBoard.sol index b90bdc045..aa4ec2d16 100644 --- a/contracts/interfaces/V2/IWitnetRequestBoard.sol +++ b/contracts/interfaces/V2/IWitnetRequestBoard.sol @@ -21,13 +21,7 @@ interface IWitnetRequestBoard { /// @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, uint96 callbackGasLimit) external view returns (uint256); - - /// @notice Estimates the actual earnings (or loss), in WEI, that a reporter would get by reporting result to given query, - /// @notice based on the gas price of the calling transaction. Data requesters should consider upgrading the reward on - /// @notice queries providing no actual earnings. - /// @dev Fails if the query does not exist, or if deleted. - function estimateQueryEarnings(uint256 queryId, uint256 gasPrice) external view returns (int256); - + /// @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 diff --git a/contracts/interfaces/V2/IWitnetRequestBoardReporter.sol b/contracts/interfaces/V2/IWitnetRequestBoardReporter.sol index ede92a211..3be90abd4 100644 --- a/contracts/interfaces/V2/IWitnetRequestBoardReporter.sol +++ b/contracts/interfaces/V2/IWitnetRequestBoardReporter.sol @@ -6,6 +6,12 @@ pragma solidity >=0.7.0 <0.9.0; /// @author The Witnet Foundation. interface IWitnetRequestBoardReporter { + /// @notice Estimates the actual earnings (or loss), in WEI, that a reporter would get by reporting result to given query, + /// @notice based on the gas price of the calling transaction. Data requesters should consider upgrading the reward on + /// @notice queries providing no actual earnings. + /// @dev Fails if the query does not exist, or if deleted. + function estimateQueryEarnings(uint256[] calldata queryIds, uint256 gasPrice) external view returns (int256); + /// @notice Reports the Witnet-provided result to a previously posted request. /// @dev Will assume `block.timestamp` as the timestamp at which the request was solved. /// @dev Fails if: From 935395d4d3600c016fe6215ec6b1c806c989b696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 1 Dec 2023 11:47:54 +0100 Subject: [PATCH 83/86] refactor: remove posting logic from UsingWitnet & WitnetConsumer --- contracts/apps/UsingWitnet.sol | 24 -------- contracts/apps/UsingWitnetRandomness.sol | 25 ++++---- contracts/apps/UsingWitnetRequest.sol | 25 ++++---- contracts/apps/UsingWitnetRequestTemplate.sol | 19 +++--- contracts/apps/WitnetConsumer.sol | 38 +++--------- contracts/apps/WitnetRandomness.sol | 7 +-- contracts/apps/WitnetRequestConsumer.sol | 29 ---------- .../apps/WitnetRequestTemplateConsumer.sol | 58 ------------------- 8 files changed, 37 insertions(+), 188 deletions(-) diff --git a/contracts/apps/UsingWitnet.sol b/contracts/apps/UsingWitnet.sol index c02f93c35..f267a67f8 100644 --- a/contracts/apps/UsingWitnet.sol +++ b/contracts/apps/UsingWitnet.sol @@ -107,30 +107,6 @@ abstract contract UsingWitnet return __witnetBaseFeeOverheadPercentage; } - function __witnetRequestData( - uint256 _witnetEvmReward, - WitnetV2.RadonSLA memory _witnetQuerySLA, - bytes32 _witnetRadHash - ) - virtual internal returns (uint256) - { - return __witnet.postRequest{value: _witnetEvmReward}( - _witnetRadHash, - _witnetQuerySLA - ); - } - - function __witnetRequestData( - uint256 _witnetEvmReward, - bytes32 _witnetRadHash - ) - virtual internal returns (uint256) - { - return __witnet.postRequest{value: _witnetEvmReward}( - _witnetRadHash, - _witnetDefaultSLA() - ); - } function __witnetSetDefaultSLA(WitnetV2.RadonSLA memory _defaultSLA) virtual internal { __witnetDefaultPackedSLA = WitnetV2.toBytes32(_defaultSLA); } diff --git a/contracts/apps/UsingWitnetRandomness.sol b/contracts/apps/UsingWitnetRandomness.sol index 2fbeb323b..fa62d6f45 100644 --- a/contracts/apps/UsingWitnetRandomness.sol +++ b/contracts/apps/UsingWitnetRandomness.sol @@ -80,29 +80,24 @@ abstract contract UsingWitnetRandomness return uint32((_number * _range) >> 224); } + function _witnetReadRandomizeFromResultValue(WitnetCBOR.CBOR calldata cborValue) internal pure returns (bytes32) { + return cborValue.readBytes().toBytes32(); + } + function __witnetRandomize(uint256 _witnetEvmReward) virtual internal returns (uint256) { - return __witnetRequestData( - _witnetEvmReward, - _witnetDefaultSLA(), - __witnetRandomnessRadHash - ); + return __witnetRandomize(_witnetEvmReward, _witnetDefaultSLA()); } function __witnetRandomize( uint256 _witnetEvmReward, - WitnetV2.RadonSLA calldata _witnetQuerySLA + WitnetV2.RadonSLA memory _witnetQuerySLA ) virtual internal returns (uint256 _randomizeId) { - return __witnetRequestData( - _witnetEvmReward, - _witnetQuerySLA, - __witnetRandomnessRadHash + return __witnet.postRequest{value: _witnetEvmReward}( + __witnetRandomnessRadHash, + _witnetQuerySLA ); } - - function _witnetReadRandomizeFromResultValue(WitnetCBOR.CBOR calldata cborValue) internal pure returns (bytes32) { - return cborValue.readBytes().toBytes32(); - } -} \ No newline at end of file +} diff --git a/contracts/apps/UsingWitnetRequest.sol b/contracts/apps/UsingWitnetRequest.sol index 464c28333..fa5cbec20 100644 --- a/contracts/apps/UsingWitnetRequest.sol +++ b/contracts/apps/UsingWitnetRequest.sol @@ -40,26 +40,21 @@ abstract contract UsingWitnetRequest return _witnetEstimateEvmReward(__witnetResultMaxSize); } - function __witnetRequestData( - uint256 _witnetEvmReward, - WitnetV2.RadonSLA memory _witnetQuerySLA - ) + function __witnetRequestData(uint256 _witnetEvmReward) virtual internal returns (uint256) { - return __witnetRequestData( - _witnetEvmReward, - _witnetQuerySLA, - __witnetRequestRadHash - ); + return __witnetRequestData(_witnetEvmReward, _witnetDefaultSLA()); } - function __witnetRequestData(uint256 _witnetEvmReward) + function __witnetRequestData( + uint256 _witnetEvmReward, + WitnetV2.RadonSLA memory _witnetQuerySLA + ) virtual internal returns (uint256) { - return __witnetRequestData( - _witnetEvmReward, - _witnetDefaultSLA(), - __witnetRequestRadHash + return __witnet.postRequest{value: _witnetEvmReward}( + __witnetRequestRadHash, + _witnetQuerySLA ); } -} \ No newline at end of file +} diff --git a/contracts/apps/UsingWitnetRequestTemplate.sol b/contracts/apps/UsingWitnetRequestTemplate.sol index 11efa8497..d3ad0a172 100644 --- a/contracts/apps/UsingWitnetRequestTemplate.sol +++ b/contracts/apps/UsingWitnetRequestTemplate.sol @@ -52,28 +52,23 @@ abstract contract UsingWitnetRequestTemplate function __witnetRequestData( uint256 _witnetEvmReward, - WitnetV2.RadonSLA memory _witnetQuerySLA, string[][] memory _witnetRequestArgs ) virtual internal returns (uint256) { - return __witnetRequestData( - _witnetEvmReward, - _witnetQuerySLA, - _witnetBuildRadHash(_witnetRequestArgs) - ); + return __witnetRequestData(_witnetEvmReward, _witnetRequestArgs, _witnetDefaultSLA()); } function __witnetRequestData( uint256 _witnetEvmReward, - string[][] memory _witnetRequestArgs + string[][] memory _witnetRequestArgs, + WitnetV2.RadonSLA memory _witnetQuerySLA ) virtual internal returns (uint256) { - return __witnetRequestData( - _witnetEvmReward, - _witnetBuildRadHash(_witnetRequestArgs) + return __witnet.postRequest{value: _witnetEvmReward}( + _witnetBuildRadHash(_witnetRequestArgs), + _witnetQuerySLA ); } - -} \ No newline at end of file +} diff --git a/contracts/apps/WitnetConsumer.sol b/contracts/apps/WitnetConsumer.sol index 92befc63c..c0029b640 100644 --- a/contracts/apps/WitnetConsumer.sol +++ b/contracts/apps/WitnetConsumer.sol @@ -66,36 +66,12 @@ abstract contract WitnetConsumer virtual internal view returns (uint256) { - return __witnet.estimateBaseFeeWithCallback(tx.gasprice, _callbackGasLimit); - } - - function __witnetRequestData( - uint256 _witnetEvmReward, - WitnetV2.RadonSLA memory _witnetQuerySLA, - bytes32 _witnetRadHash - ) - virtual override internal - returns (uint256) - { - return __witnet.postRequestWithCallback{value: _witnetEvmReward}( - _witnetRadHash, - _witnetQuerySLA, - __witnetCallbackGasLimit - ); - } - - function __witnetRequestData( - uint256 _witnetEvmReward, - WitnetV2.RadonSLA memory _witnetQuerySLA, - bytes calldata _witnetRequestBytecode - ) - virtual internal returns (uint256) - { - return __witnet.postRequestWithCallback{value: _witnetEvmReward}( - _witnetRequestBytecode, - _witnetQuerySLA, - __witnetCallbackGasLimit - ); + return ( + (100 + _witnetBaseFeeOverheadPercentage()) + * __witnet.estimateBaseFeeWithCallback( + tx.gasprice, + _callbackGasLimit + ) + ) / 100; } - } diff --git a/contracts/apps/WitnetRandomness.sol b/contracts/apps/WitnetRandomness.sol index 593a2d9b8..7947ef024 100644 --- a/contracts/apps/WitnetRandomness.sol +++ b/contracts/apps/WitnetRandomness.sol @@ -327,10 +327,9 @@ contract WitnetRandomness { if (latestRandomizeBlock < block.number) { // Post the Witnet Randomness request: - uint _queryId = __witnetRequestData( - msg.value, - __witnetRandomnessPackedSLA.toRadonSLA(), - __witnetRandomnessRadHash + uint _queryId = __witnet.postRequest{value: msg.value}( + __witnetRandomnessRadHash, + __witnetRandomnessPackedSLA.toRadonSLA() ); // Keep Randomize data in storage: RandomizeData storage __data = __randomize_[block.number]; diff --git a/contracts/apps/WitnetRequestConsumer.sol b/contracts/apps/WitnetRequestConsumer.sol index 6e34e2932..e93b66dfb 100644 --- a/contracts/apps/WitnetRequestConsumer.sol +++ b/contracts/apps/WitnetRequestConsumer.sol @@ -42,33 +42,4 @@ abstract contract WitnetRequestConsumer return WitnetConsumer._witnetEstimateEvmReward(); } - function __witnetRequestData( - uint256 _witnetEvmReward, - WitnetV2.RadonSLA memory _witnetQuerySLA, - bytes32 _witnetRadHash - ) - virtual override(UsingWitnet, WitnetConsumer) internal - returns (uint256) - { - return WitnetConsumer.__witnetRequestData( - _witnetEvmReward, - _witnetQuerySLA, - _witnetRadHash - ); - } - - function __witnetRequestData( - uint256 _witnetEvmReward, - WitnetV2.RadonSLA memory _witnetQuerySLA - ) - virtual override internal - returns (uint256) - { - return WitnetConsumer.__witnetRequestData( - _witnetEvmReward, - _witnetQuerySLA, - __witnetRequestRadHash - ); - } - } diff --git a/contracts/apps/WitnetRequestTemplateConsumer.sol b/contracts/apps/WitnetRequestTemplateConsumer.sol index 71d20eaa9..dc00a9c11 100644 --- a/contracts/apps/WitnetRequestTemplateConsumer.sol +++ b/contracts/apps/WitnetRequestTemplateConsumer.sol @@ -42,62 +42,4 @@ abstract contract WitnetRequestTemplateConsumer return WitnetConsumer._witnetEstimateEvmReward(); } - function __witnetRequestData( - uint256 _witnetEvmReward, - WitnetV2.RadonSLA memory _witnetQuerySLA, - bytes32 _witnetRadHash - ) - virtual override(UsingWitnet, WitnetConsumer) internal - returns (uint256) - { - return WitnetConsumer.__witnetRequestData( - _witnetEvmReward, - _witnetQuerySLA, - _witnetRadHash - ); - } - - function __witnetRequestData( - uint256 _witnetEvmReward, - bytes32 _witnetRadHash - ) - virtual override internal - returns (uint256) - { - return WitnetConsumer.__witnetRequestData( - _witnetEvmReward, - _witnetDefaultSLA(), - _witnetRadHash - ); - } - - function __witnetRequestData( - uint256 _witnetEvmReward, - WitnetV2.RadonSLA memory _witnetQuerySLA, - string[][] memory _witnetRequestArgs - ) - virtual override internal - returns (uint256) - { - return WitnetConsumer.__witnetRequestData( - _witnetEvmReward, - _witnetQuerySLA, - _witnetBuildRadHash(_witnetRequestArgs) - ); - } - - function __witnetRequestData( - uint256 _witnetEvmReward, - string[][] memory _witnetRequestArgs - ) - virtual override internal - returns (uint256) - { - return WitnetConsumer.__witnetRequestData( - _witnetEvmReward, - _witnetDefaultSLA(), - _witnetBuildRadHash(_witnetRequestArgs) - ); - } - } From 1099a665826f3035a54edac557ee3dfd3a5c3e87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Tue, 12 Dec 2023 19:12:10 +0100 Subject: [PATCH 84/86] feat(libs): add support to new radon operators BytesAsInteger, BytesLength, BytesSlice, BytesStringify, IntegerToBytes, StringAsBytes --- contracts/libs/WitnetEncodingLib.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/libs/WitnetEncodingLib.sol b/contracts/libs/WitnetEncodingLib.sol index 422d204eb..968a7e854 100644 --- a/contracts/libs/WitnetEncodingLib.sol +++ b/contracts/libs/WitnetEncodingLib.sol @@ -13,15 +13,15 @@ library WitnetEncodingLib { using WitnetCBOR for WitnetCBOR.CBOR[]; bytes internal constant WITNET_RADON_OPCODES_RESULT_TYPES = - hex"10ffffffffffffffffffffffffffffff040100010203050406071311ff01ffff07ff02ffffffffffffffffffffffffff0703ffffffffffffffffffffffffffff0405070202ff04040404ffffffffffff05070402040205050505ff04ff04ffffff010203050406070101ffffffffffff02ff050404000106060707070701ffff"; + hex"10ffffffffffffffffffffffffffffff040100010203050406071311ff01ffff07ff02ffffffffffffffffffffffffff070304ff04ffffffffffffff03ffffff0405070202ff0404040403ffffffffff05070402040205050505ff04ff04ffffff010203050406070101ffffffffffff0203050404000106060707070701ffff"; // 10ffffffffffffffffffffffffffffff // 040100001203050406070100ff01ffff // 07ff02ffffffffffffffffffffffffff - // 0703ffffffffffffffffffffffffffff - // 0405070202ff04040404ffffffffffff + // 070304ff04ffffffffffffff03ffffff + // 0405070202ff0404040403ffffffffff // 05070402040205050505ff04ff04ffff // ff010203050406070101ffffffffffff - // 02ff050404000106060707070701ffff + // 0203050404000106060707070701ffff error UnsupportedDataRequestMethod(uint8 method, string schema, string body, string[2][] headers); error UnsupportedRadonDataType(uint8 datatype, uint256 maxlength); From 153f486b302d77ea2d0e236088d9224af85db519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 12 Jan 2024 14:59:27 +0100 Subject: [PATCH 85/86] feat(libs): add support to new radon operators ArrayPick, MapAlter, MapPick, MapStringify --- contracts/libs/WitnetEncodingLib.sol | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/libs/WitnetEncodingLib.sol b/contracts/libs/WitnetEncodingLib.sol index 968a7e854..36065dc3b 100644 --- a/contracts/libs/WitnetEncodingLib.sol +++ b/contracts/libs/WitnetEncodingLib.sol @@ -13,14 +13,14 @@ library WitnetEncodingLib { using WitnetCBOR for WitnetCBOR.CBOR[]; bytes internal constant WITNET_RADON_OPCODES_RESULT_TYPES = - hex"10ffffffffffffffffffffffffffffff040100010203050406071311ff01ffff07ff02ffffffffffffffffffffffffff070304ff04ffffffffffffff03ffffff0405070202ff0404040403ffffffffff05070402040205050505ff04ff04ffffff010203050406070101ffffffffffff0203050404000106060707070701ffff"; + hex"10ffffffffffffffffffffffffffffff040100010203050406071311ff0101ff07ff02ffffffffffffffffffffffffff070304ff04ffffffffffffff03ffffff0405070202ff0404040403ffffffffff05070402040205050505ff04ff04ffff07010203050406070101ff06ffff06ff0203050404000106060707070701ffff"; // 10ffffffffffffffffffffffffffffff - // 040100001203050406070100ff01ffff + // 040100001203050406070100ff0101ff // 07ff02ffffffffffffffffffffffffff // 070304ff04ffffffffffffff03ffffff // 0405070202ff0404040403ffffffffff // 05070402040205050505ff04ff04ffff - // ff010203050406070101ffffffffffff + // 07010203050406070101ff06ffff06ff // 0203050404000106060707070701ffff error UnsupportedDataRequestMethod(uint8 method, string schema, string body, string[2][] headers); @@ -34,7 +34,7 @@ library WitnetEncodingLib { error UnsupportedRadonTallyScript(bytes32 hash); /// =============================================================================================================== - /// --- WitnetLib internal methods -------------------------------------------------------------------------------- + /// --- WitnetEncodingLib internal methods -------------------------------------------------------------------------------- function size(Witnet.RadonDataTypes _type) internal pure returns (uint16) { if (_type == Witnet.RadonDataTypes.Integer @@ -51,7 +51,7 @@ library WitnetEncodingLib { /// =============================================================================================================== - /// --- WitnetLib public methods (if used library will have to linked to calling contracts) ----------------------- + /// --- WitnetEncodingLib public methods (if used library will have to linked to calling contracts) ----------------------- /// @notice Encode bytes array into given major type (UTF-8 not yet supported) /// @param buf Bytes array @@ -474,7 +474,7 @@ library WitnetEncodingLib { /// =============================================================================================================== - /// --- WitnetLib private methods --------------------------------------------------------------------------------- + /// --- WitnetEncodingLib private methods --------------------------------------------------------------------------------- function _replaceCborWildcards( WitnetCBOR.CBOR memory self, From bc0bd9276bb2ea1a98af34db212982d3617d3f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 12 Jan 2024 15:01:35 +0100 Subject: [PATCH 86/86] chore: fmt! --- migrations/scripts/1_deployer.js | 40 ++--- migrations/scripts/2_libs.js | 89 ++++++----- migrations/scripts/3_core.js | 258 +++++++++++++++++-------------- migrations/scripts/4_proxies.js | 238 ++++++++++++++-------------- migrations/scripts/5_apps.js | 216 ++++++++++++++------------ migrations/witnet.settings.js | 94 +++++------ scripts/eth-create2.js | 19 ++- scripts/eth-create3.js | 21 ++- scripts/utils/index.js | 2 +- scripts/utils/traceTx.js | 2 +- scripts/vanity2gen.js | 1 - scripts/vanity3gen.js | 2 +- 12 files changed, 506 insertions(+), 476 deletions(-) diff --git a/migrations/scripts/1_deployer.js b/migrations/scripts/1_deployer.js index 66bc77d3c..a3382c969 100644 --- a/migrations/scripts/1_deployer.js +++ b/migrations/scripts/1_deployer.js @@ -4,27 +4,27 @@ const utils = require("../../scripts/utils") const WitnetDeployer = artifacts.require("WitnetDeployer") module.exports = async function (deployer, network, [, from,, master]) { - const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" - const ecosystem = utils.getRealmNetworkFromArgs()[0] - network = network.split("-")[0] + const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const ecosystem = utils.getRealmNetworkFromArgs()[0] + network = network.split("-")[0] - if (!addresses[ecosystem]) addresses[ecosystem] = {} - if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} + if (!addresses[ecosystem]) addresses[ecosystem] = {} + if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} - let factory - if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetDeployer)) { - await deployer.deploy(WitnetDeployer, { from: master }) - factory = await WitnetDeployer.deployed() - addresses[ecosystem][network].WitnetDeployer = factory.address - } else { - factory = await WitnetDeployer.at(addresses[ecosystem][network].WitnetDeployer) - WitnetDeployer.address = factory.address - utils.traceHeader("Skipped 'WitnetDeployer'") - console.info(" > Contract address:", factory.address) - console.info() - } + let factory + if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetDeployer)) { + await deployer.deploy(WitnetDeployer, { from: master }) + factory = await WitnetDeployer.deployed() + addresses[ecosystem][network].WitnetDeployer = factory.address + } else { + factory = await WitnetDeployer.at(addresses[ecosystem][network].WitnetDeployer) + WitnetDeployer.address = factory.address + utils.traceHeader("Skipped 'WitnetDeployer'") + console.info(" > Contract address:", factory.address) + console.info() + } - if (!isDryRun) { - utils.saveAddresses(addresses) - } + if (!isDryRun) { + utils.saveAddresses(addresses) + } } diff --git a/migrations/scripts/2_libs.js b/migrations/scripts/2_libs.js index edaf95995..451663e57 100644 --- a/migrations/scripts/2_libs.js +++ b/migrations/scripts/2_libs.js @@ -6,53 +6,52 @@ const utils = require("../../scripts/utils") const WitnetDeployer = artifacts.require("WitnetDeployer") module.exports = async function (_, network, [, from]) { - const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" - const ecosystem = utils.getRealmNetworkFromArgs()[0] - network = network.split("-")[0] + const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const ecosystem = utils.getRealmNetworkFromArgs()[0] + network = network.split("-")[0] - const addresses = require("../witnet.addresses") - if (!addresses[ecosystem]) addresses[ecosystem] = {} - if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} + const addresses = require("../witnet.addresses") + if (!addresses[ecosystem]) addresses[ecosystem] = {} + if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} - const targets = merge( - settings.artifacts.default, - settings.artifacts[ecosystem], - settings.artifacts[network] - ) - const libs = [ - targets.WitnetErrorsLib, - targets.WitnetEncodingLib, - targets.WitnetPriceFeedsLib, - ] + const targets = merge( + settings.artifacts.default, + settings.artifacts[ecosystem], + settings.artifacts[network] + ) + const libs = [ + targets.WitnetErrorsLib, + targets.WitnetEncodingLib, + targets.WitnetPriceFeedsLib, + ] - const deployer = await WitnetDeployer.deployed() - for (index in libs) { - const key = libs[index] - const artifact = artifacts.require(key) - if (utils.isNullAddress(addresses[ecosystem][network][key])) { - utils.traceHeader(`Deploying '${key}'...`) - const libInitCode = artifact.toJSON().bytecode - const libAddr = await deployer.determineAddr.call(libInitCode, "0x0", { from }) - console.info(" ", "> account: ", from) - console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), 'ether'), "ETH") - const tx = await deployer.deploy(libInitCode, "0x0", { from }) - utils.traceTx(tx) - if ((await web3.eth.getCode(libAddr)).length > 3) { - addresses[ecosystem][network][key] = libAddr - } else { - console.info(`Error: Library was not deployed on expected address: ${libAddr}`) - process.exit(1) - } - } else { - utils.traceHeader(`Skipped '${key}'`) - } - artifact.address = addresses[ecosystem][network][key] - console.info(" ", "> library address: ", artifact.address) - console.info(" ", "> library codehash: ", web3.utils.soliditySha3(await web3.eth.getCode(artifact.address))) - console.info() - if (!isDryRun) { - utils.saveAddresses(addresses) - } + const deployer = await WitnetDeployer.deployed() + for (index in libs) { + const key = libs[index] + const artifact = artifacts.require(key) + if (utils.isNullAddress(addresses[ecosystem][network][key])) { + utils.traceHeader(`Deploying '${key}'...`) + const libInitCode = artifact.toJSON().bytecode + const libAddr = await deployer.determineAddr.call(libInitCode, "0x0", { from }) + console.info(" ", "> account: ", from) + console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), "ether"), "ETH") + const tx = await deployer.deploy(libInitCode, "0x0", { from }) + utils.traceTx(tx) + if ((await web3.eth.getCode(libAddr)).length > 3) { + addresses[ecosystem][network][key] = libAddr + } else { + console.info(`Error: Library was not deployed on expected address: ${libAddr}`) + process.exit(1) + } + } else { + utils.traceHeader(`Skipped '${key}'`) } - + artifact.address = addresses[ecosystem][network][key] + console.info(" ", "> library address: ", artifact.address) + console.info(" ", "> library codehash: ", web3.utils.soliditySha3(await web3.eth.getCode(artifact.address))) + console.info() + if (!isDryRun) { + utils.saveAddresses(addresses) + } + } } diff --git a/migrations/scripts/3_core.js b/migrations/scripts/3_core.js index 887ae59af..cf999f89b 100644 --- a/migrations/scripts/3_core.js +++ b/migrations/scripts/3_core.js @@ -5,142 +5,160 @@ const addresses = require("../witnet.addresses") const settings = require("../witnet.settings") const utils = require("../../scripts/utils") const version = `${ - require("../../package").version - }-${ - require("child_process").execSync("git rev-parse HEAD").toString().trim().substring(0, 7) - }` + require("../../package").version +}-${ + require("child_process").execSync("git rev-parse HEAD").toString().trim().substring(0, 7) +}` const WitnetDeployer = artifacts.require("WitnetDeployer") module.exports = async function (_, network, [, from]) { - const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" - const ecosystem = utils.getRealmNetworkFromArgs()[0] - network = network.split("-")[0] + const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const ecosystem = utils.getRealmNetworkFromArgs()[0] + network = network.split("-")[0] - if (!addresses[ecosystem]) addresses[ecosystem] = {} - if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} + if (!addresses[ecosystem]) addresses[ecosystem] = {} + if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} - const specs = merge( - settings.specs.default, - settings.specs[ecosystem], - settings.specs[network], - ) - const targets = merge( - settings.artifacts.default, - settings.artifacts[ecosystem], - settings.artifacts[network] - ) + const specs = merge( + settings.specs.default, + settings.specs[ecosystem], + settings.specs[network], + ) + const targets = merge( + settings.artifacts.default, + settings.artifacts[ecosystem], + settings.artifacts[network] + ) - // Deploy/upgrade WitnetBytecodes target implementation, if required - { - await deploy({ - from, ecosystem, network, targets, - key: targets.WitnetBytecodes, - libs: specs.WitnetBytecodes.libs, - immutables: specs.WitnetBytecodes.immutables, - intrinsics: { types: [ 'bool', 'bytes32' ], values: [ - /* _upgradable */ true, - /* _versionTag */ utils.fromAscii(version) - ]}, - }); - if (!isDryRun) { - utils.saveAddresses(addresses); - } + // Deploy/upgrade WitnetBytecodes target implementation, if required + { + await deploy({ + from, + ecosystem, + network, + targets, + key: targets.WitnetBytecodes, + libs: specs.WitnetBytecodes.libs, + immutables: specs.WitnetBytecodes.immutables, + intrinsics: { + types: ["bool", "bytes32"], + values: [ + /* _upgradable */ true, + /* _versionTag */ utils.fromAscii(version), + ], + }, + }) + if (!isDryRun) { + utils.saveAddresses(addresses) } - // Deploy/upgrade WitnetRequestFactory target implementation, if required - { - await deploy({ - from, ecosystem, network, targets, - key: targets.WitnetRequestFactory, - libs: specs.WitnetRequestFactory.libs, - immutables: specs.WitnetRequestFactory.immutables, - intrinsics: { types: [ 'address', 'address', 'bool', 'bytes32' ], values: [ - /* _witnet */ await determineProxyAddr(from, specs.WitnetRequestBoard?.vanity || 3), - /* _registry */ await determineProxyAddr(from, specs.WitnetBytecodes?.vanity || 1), - /* _upgradable */ true, - /* _versionTag */ utils.fromAscii(version), - ]}, - }); - if (!isDryRun) { - utils.saveAddresses(addresses); - } + } + // Deploy/upgrade WitnetRequestFactory target implementation, if required + { + await deploy({ + from, + ecosystem, + network, + targets, + key: targets.WitnetRequestFactory, + libs: specs.WitnetRequestFactory.libs, + immutables: specs.WitnetRequestFactory.immutables, + intrinsics: { + types: ["address", "address", "bool", "bytes32"], + values: [ + /* _witnet */ await determineProxyAddr(from, specs.WitnetRequestBoard?.vanity || 3), + /* _registry */ await determineProxyAddr(from, specs.WitnetBytecodes?.vanity || 1), + /* _upgradable */ true, + /* _versionTag */ utils.fromAscii(version), + ], + }, + }) + if (!isDryRun) { + utils.saveAddresses(addresses) } - // Deploy/upgrade WitnetRequestBoard target implementation, if required - { - await deploy({ - from, ecosystem, network, targets, - key: targets.WitnetRequestBoard, - libs: specs.WitnetRequestBoard.libs, - immutables: specs.WitnetRequestBoard.immutables, - intrinsics: { types: [ 'address', 'address', 'bool', 'bytes32' ], values: [ - /* _factory */ await determineProxyAddr(from, specs.WitnetRequestFactory?.vanity || 2), - /* _registry */ await determineProxyAddr(from, specs.WitnetBytecodes?.vanity || 1), - /* _upgradable */ true, - /* _versionTag */ utils.fromAscii(version), - ]}, - }); - if (!isDryRun) { - utils.saveAddresses(addresses); - } + } + // Deploy/upgrade WitnetRequestBoard target implementation, if required + { + await deploy({ + from, + ecosystem, + network, + targets, + key: targets.WitnetRequestBoard, + libs: specs.WitnetRequestBoard.libs, + immutables: specs.WitnetRequestBoard.immutables, + intrinsics: { + types: ["address", "address", "bool", "bytes32"], + values: [ + /* _factory */ await determineProxyAddr(from, specs.WitnetRequestFactory?.vanity || 2), + /* _registry */ await determineProxyAddr(from, specs.WitnetBytecodes?.vanity || 1), + /* _upgradable */ true, + /* _versionTag */ utils.fromAscii(version), + ], + }, + }) + if (!isDryRun) { + utils.saveAddresses(addresses) } + } } -async function deploy(specs) { - const { from, ecosystem, network, key, libs, intrinsics, immutables, targets } = specs; - const contract = artifacts.require(key) - if (utils.isNullAddress(addresses[ecosystem][network][key])) { - utils.traceHeader(`Deploying '${key}'...`) - console.info(" ", "> account: ", from) - console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), 'ether'), "ETH") - const deployer = await WitnetDeployer.deployed() - let { types, values } = intrinsics - if (immutables?.types) types = [ ...types, ...immutables.types ] - if (immutables?.values) values = [ ...values, ...immutables.values ] - const constructorArgs = web3.eth.abi.encodeParameters(types, values) - if (constructorArgs.length > 2) { - console.info(" ", "> constructor types:", types) - console.info(" ", "> constructor args: ", constructorArgs.slice(2)) - } - const coreBytecode = link(contract.toJSON().bytecode, libs, targets) - if (coreBytecode.indexOf("__") > -1) { - console.info(bytecode) - console.info("Error: Cannot deploy due to some missing libs") - process.exit(1) - } - const coreInitCode = coreBytecode + constructorArgs.slice(2) - const coreAddr = await deployer.determineAddr.call(coreInitCode, "0x0", { from }) - const tx = await deployer.deploy(coreInitCode, "0x0", { from }) - utils.traceTx(tx) - if ((await web3.eth.getCode(coreAddr)).length > 3) { - addresses[ecosystem][network][key] = coreAddr - } else { - console.info(`Error: Contract was not deployed on expected address: ${coreAddr}`) - process.exit(1) - } +async function deploy (specs) { + const { from, ecosystem, network, key, libs, intrinsics, immutables, targets } = specs + const contract = artifacts.require(key) + if (utils.isNullAddress(addresses[ecosystem][network][key])) { + utils.traceHeader(`Deploying '${key}'...`) + console.info(" ", "> account: ", from) + console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), "ether"), "ETH") + const deployer = await WitnetDeployer.deployed() + let { types, values } = intrinsics + if (immutables?.types) types = [...types, ...immutables.types] + if (immutables?.values) values = [...values, ...immutables.values] + const constructorArgs = web3.eth.abi.encodeParameters(types, values) + if (constructorArgs.length > 2) { + console.info(" ", "> constructor types:", types) + console.info(" ", "> constructor args: ", constructorArgs.slice(2)) + } + const coreBytecode = link(contract.toJSON().bytecode, libs, targets) + if (coreBytecode.indexOf("__") > -1) { + console.info(bytecode) + console.info("Error: Cannot deploy due to some missing libs") + process.exit(1) + } + const coreInitCode = coreBytecode + constructorArgs.slice(2) + const coreAddr = await deployer.determineAddr.call(coreInitCode, "0x0", { from }) + const tx = await deployer.deploy(coreInitCode, "0x0", { from }) + utils.traceTx(tx) + if ((await web3.eth.getCode(coreAddr)).length > 3) { + addresses[ecosystem][network][key] = coreAddr } else { - utils.traceHeader(`Skipped '${key}'`) + console.info(`Error: Contract was not deployed on expected address: ${coreAddr}`) + process.exit(1) } - contract.address = addresses[ecosystem][network][key] - console.info(" ", "> contract address: ", contract.address) - console.info(" ", "> contract codehash:", web3.utils.soliditySha3(await web3.eth.getCode(contract.address))) - console.info() - return contract + } else { + utils.traceHeader(`Skipped '${key}'`) + } + contract.address = addresses[ecosystem][network][key] + console.info(" ", "> contract address: ", contract.address) + console.info(" ", "> contract codehash:", web3.utils.soliditySha3(await web3.eth.getCode(contract.address))) + console.info() + return contract } -async function determineProxyAddr(from, nonce) { - const salt = nonce ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(nonce), 32).toString("hex") : "0x0" - const deployer = await WitnetDeployer.deployed() - return await deployer.determineProxyAddr.call(salt, { from }) +async function determineProxyAddr (from, nonce) { + const salt = nonce ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(nonce), 32).toString("hex") : "0x0" + const deployer = await WitnetDeployer.deployed() + return await deployer.determineProxyAddr.call(salt, { from }) } -function link(bytecode, libs, targets) { - if (libs && Array.isArray(libs) && libs.length > 0) { - for (index in libs) { - const key = targets[libs[index]] - const lib = artifacts.require(key) - bytecode = bytecode.replaceAll(`__${key}${"_".repeat(38-key.length)}`, lib.address.slice(2)) - console.info(" ", `> linked library: ${key} => ${lib.address}`) - } +function link (bytecode, libs, targets) { + if (libs && Array.isArray(libs) && libs.length > 0) { + for (index in libs) { + const key = targets[libs[index]] + const lib = artifacts.require(key) + bytecode = bytecode.replaceAll(`__${key}${"_".repeat(38 - key.length)}`, lib.address.slice(2)) + console.info(" ", `> linked library: ${key} => ${lib.address}`) } - return bytecode -} \ No newline at end of file + } + return bytecode +} diff --git a/migrations/scripts/4_proxies.js b/migrations/scripts/4_proxies.js index e5fbcf5d7..08f104d1a 100644 --- a/migrations/scripts/4_proxies.js +++ b/migrations/scripts/4_proxies.js @@ -9,137 +9,141 @@ const WitnetDeployer = artifacts.require("WitnetDeployer") const WitnetProxy = artifacts.require("WitnetProxy") module.exports = async function (_, network, [, from, reporter]) { - const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" - const ecosystem = utils.getRealmNetworkFromArgs()[0] - network = network.split("-")[0] + const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const ecosystem = utils.getRealmNetworkFromArgs()[0] + network = network.split("-")[0] - if (!addresses[ecosystem]) addresses[ecosystem] = {} - if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} + if (!addresses[ecosystem]) addresses[ecosystem] = {} + if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} - const targets = merge( - settings.artifacts.default, - settings.artifacts[ecosystem], - settings.artifacts[network] - ) - const specs = merge( - settings.specs.default, - settings.specs[ecosystem], - settings.specs[network], - ) - const singletons = [ - "WitnetBytecodes", - "WitnetRequestFactory", - "WitnetRequestBoard", - ] + const targets = merge( + settings.artifacts.default, + settings.artifacts[ecosystem], + settings.artifacts[network] + ) + const specs = merge( + settings.specs.default, + settings.specs[ecosystem], + settings.specs[network], + ) + const singletons = [ + "WitnetBytecodes", + "WitnetRequestFactory", + "WitnetRequestBoard", + ] - specs["WitnetRequestBoard"].mutables = merge({ - types: [ 'address[]', ], - values: [ [ reporter, ], ], - }, specs["WitnetRequestBoard"].mutables - ) + specs.WitnetRequestBoard.mutables = merge({ + types: ["address[]"], + values: [[reporter]], + }, specs.WitnetRequestBoard.mutables + ) - // Deploy/upgrade singleton proxies, if required - for (index in singletons) { - await deploy({ - from, ecosystem, network, specs, targets, - key: singletons[index], - }); - if (!isDryRun) { - utils.saveAddresses(addresses); - } + // Deploy/upgrade singleton proxies, if required + for (index in singletons) { + await deploy({ + from, + ecosystem, + network, + specs, + targets, + key: singletons[index], + }) + if (!isDryRun) { + utils.saveAddresses(addresses) } + } } -async function deploy(target) { - const { from, ecosystem, network, key, specs, targets } = target; - - const mutables = specs[key].mutables - const proxy = artifacts.require(key) - const proxy_salt = specs[key].vanity ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(specs[key].vanity), 32).toString("hex") : "0x0" - - if (utils.isNullAddress(addresses[ecosystem][network][key])) { - utils.traceHeader(`Deploying '${key}'...`) - console.info(" ", "> account: ", from) - console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), 'ether'), "ETH") - const deployer = await WitnetDeployer.deployed() - const impl = await artifacts.require(targets[key]).deployed() - const proxyAddr = await deployer.determineProxyAddr.call(proxy_salt, { from }) - if ((await web3.eth.getCode(proxyAddr)).length < 3) { - const initdata = mutables ? web3.eth.abi.encodeParameters(mutables.types, mutables.values) : "0x" - if (initdata.length > 2) { - console.info(" ", "> initialize types: ", mutables.types) - console.info(" ", "> initialize params:", mutables.values) - } - const tx = await deployer.proxify(proxy_salt, impl.address, initdata, { from }) - utils.traceTx(tx) - // save/overwrite exportable abi file - utils.saveJsonAbi(key, proxy.abi) - } else { - try { - const oldImplAddr = await getProxyImplementation(from, proxyAddr) - const oldImpl = await artifacts.require(targets[key]).at(oldImplAddr) - const oldClass = await oldImpl.class.call({ from }) - const newClass = await impl.class.call({ from }) - if (oldClass !== newClass) { - console.info(`Error: proxy address already taken (\"${oldClass}\" != \"${newClass}\")`) - process.exit(1) - } else { - console.info(" ", `> recovered proxy address on class \"${oldClass}\" ;-)`) - } - } catch (ex) { - console.info("Error: cannot check proxy recoverability:", ex) - } - } - if ((await web3.eth.getCode(proxyAddr)).length > 3) { - addresses[ecosystem][network][key] = proxyAddr +async function deploy (target) { + const { from, ecosystem, network, key, specs, targets } = target + + const mutables = specs[key].mutables + const proxy = artifacts.require(key) + const proxy_salt = specs[key].vanity ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(specs[key].vanity), 32).toString("hex") : "0x0" + + if (utils.isNullAddress(addresses[ecosystem][network][key])) { + utils.traceHeader(`Deploying '${key}'...`) + console.info(" ", "> account: ", from) + console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), "ether"), "ETH") + const deployer = await WitnetDeployer.deployed() + const impl = await artifacts.require(targets[key]).deployed() + const proxyAddr = await deployer.determineProxyAddr.call(proxy_salt, { from }) + if ((await web3.eth.getCode(proxyAddr)).length < 3) { + const initdata = mutables ? web3.eth.abi.encodeParameters(mutables.types, mutables.values) : "0x" + if (initdata.length > 2) { + console.info(" ", "> initialize types: ", mutables.types) + console.info(" ", "> initialize params:", mutables.values) + } + const tx = await deployer.proxify(proxy_salt, impl.address, initdata, { from }) + utils.traceTx(tx) + // save/overwrite exportable abi file + utils.saveJsonAbi(key, proxy.abi) + } else { + try { + const oldImplAddr = await getProxyImplementation(from, proxyAddr) + const oldImpl = await artifacts.require(targets[key]).at(oldImplAddr) + const oldClass = await oldImpl.class.call({ from }) + const newClass = await impl.class.call({ from }) + if (oldClass !== newClass) { + console.info(`Error: proxy address already taken (\"${oldClass}\" != \"${newClass}\")`) + process.exit(1) } else { - console.info(`Error: Contract was not deployed on expected address: ${proxyAddr}`) - process.exit(1) + console.info(" ", `> recovered proxy address on class \"${oldClass}\" ;-)`) } + } catch (ex) { + console.info("Error: cannot check proxy recoverability:", ex) + } + } + if ((await web3.eth.getCode(proxyAddr)).length > 3) { + addresses[ecosystem][network][key] = proxyAddr } else { - const oldAddr = await getProxyImplementation(from, addresses[ecosystem][network][key]) - const oldImpl = await artifacts.require(targets[key]).at(oldAddr) - const newImpl = await artifacts.require(targets[key]).deployed() - if (oldAddr !== newImpl.address) { - utils.traceHeader(`Upgrading '${key}'...`) - const oldVersion = await oldImpl.version.call({ from }) - const newVersion = await newImpl.version.call({ from }) - if( - process.argv.length >= 3 && process.argv[2].includes("--upgrade-all") || ["y", "yes"].includes( - (await utils.prompt(` > From v${oldVersion} to v${newVersion} ? [y / N]`)).toLowerCase().trim() - ) - ) { - const initdata = mutables ? web3.eth.abi.encodeParameters(mutables.types, mutables.values) : "0x" - if (initdata.length > 2) { - console.info(" ", "> initialize types: ", mutables.types) - console.info(" ", "> initialize params:", mutables.values) - } - const tx = await upgradeProxyTo(from, proxy, newImpl.address, initdata) - utils.traceTx(tx) - // save/overwrite exportable abi file - utils.saveJsonAbi(key, proxy.abi) - } - } else { - utils.traceHeader(`Skipped '${key}'`) + console.info(`Error: Contract was not deployed on expected address: ${proxyAddr}`) + process.exit(1) + } + } else { + const oldAddr = await getProxyImplementation(from, addresses[ecosystem][network][key]) + const oldImpl = await artifacts.require(targets[key]).at(oldAddr) + const newImpl = await artifacts.require(targets[key]).deployed() + if (oldAddr !== newImpl.address) { + utils.traceHeader(`Upgrading '${key}'...`) + const oldVersion = await oldImpl.version.call({ from }) + const newVersion = await newImpl.version.call({ from }) + if ( + process.argv.length >= 3 && process.argv[2].includes("--upgrade-all") || ["y", "yes"].includes( + (await utils.prompt(` > From v${oldVersion} to v${newVersion} ? [y / N]`)).toLowerCase().trim() + ) + ) { + const initdata = mutables ? web3.eth.abi.encodeParameters(mutables.types, mutables.values) : "0x" + if (initdata.length > 2) { + console.info(" ", "> initialize types: ", mutables.types) + console.info(" ", "> initialize params:", mutables.values) } + const tx = await upgradeProxyTo(from, proxy, newImpl.address, initdata) + utils.traceTx(tx) + // save/overwrite exportable abi file + utils.saveJsonAbi(key, proxy.abi) + } + } else { + utils.traceHeader(`Skipped '${key}'`) } - proxy.address = addresses[ecosystem][network][key] - const impl = await artifacts.require(targets[key]).at(proxy.address) - console.info(" ", "> proxy address: ", impl.address) - console.info(" ", "> proxy codehash: ", web3.utils.soliditySha3(await web3.eth.getCode(impl.address))) - console.info(" ", "> proxy operator: ", await impl.owner.call()) - console.info(" ", "> impl. address: ", await getProxyImplementation(from, proxy.address)) - console.info(" ", "> impl. version: ", await impl.version.call()) - console.info() - return proxy + } + proxy.address = addresses[ecosystem][network][key] + const impl = await artifacts.require(targets[key]).at(proxy.address) + console.info(" ", "> proxy address: ", impl.address) + console.info(" ", "> proxy codehash: ", web3.utils.soliditySha3(await web3.eth.getCode(impl.address))) + console.info(" ", "> proxy operator: ", await impl.owner.call()) + console.info(" ", "> impl. address: ", await getProxyImplementation(from, proxy.address)) + console.info(" ", "> impl. version: ", await impl.version.call()) + console.info() + return proxy } -async function getProxyImplementation(from, proxyAddr) { - proxy = await WitnetProxy.at(proxyAddr) - return await proxy.implementation.call({ from }) +async function getProxyImplementation (from, proxyAddr) { + proxy = await WitnetProxy.at(proxyAddr) + return await proxy.implementation.call({ from }) } -async function upgradeProxyTo(from, proxy, implAddr, initData) { - proxy = await WitnetProxy.at(proxy.address) - return await proxy.upgradeTo(implAddr, initData, { from }) +async function upgradeProxyTo (from, proxy, implAddr, initData) { + proxy = await WitnetProxy.at(proxy.address) + return await proxy.upgradeTo(implAddr, initData, { from }) } diff --git a/migrations/scripts/5_apps.js b/migrations/scripts/5_apps.js index 3692fa4b5..3080cc8ab 100644 --- a/migrations/scripts/5_apps.js +++ b/migrations/scripts/5_apps.js @@ -8,117 +8,129 @@ const utils = require("../../scripts/utils") const WitnetDeployer = artifacts.require("WitnetDeployer") module.exports = async function (_, network, [,,, from]) { - const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" - const ecosystem = utils.getRealmNetworkFromArgs()[0] - network = network.split("-")[0] + const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const ecosystem = utils.getRealmNetworkFromArgs()[0] + network = network.split("-")[0] - if (!addresses[ecosystem]) addresses[ecosystem] = {} - if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} + if (!addresses[ecosystem]) addresses[ecosystem] = {} + if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} - const specs = merge( - settings.specs.default, - settings.specs[ecosystem], - settings.specs[network], - ) - const targets = merge( - settings.artifacts.default, - settings.artifacts[ecosystem], - settings.artifacts[network] - ) + const specs = merge( + settings.specs.default, + settings.specs[ecosystem], + settings.specs[network], + ) + const targets = merge( + settings.artifacts.default, + settings.artifacts[ecosystem], + settings.artifacts[network] + ) - // Deploy the WitnetPriceFeeds oracle, if required - { - await deploy({ - from, ecosystem, network, targets, - key: targets.WitnetPriceFeeds, - libs: specs.WitnetPriceFeeds.libs, - vanity: specs.WitnetPriceFeeds?.vanity || 0, - immutables: specs.WitnetPriceFeeds.immutables, - intrinsics: { types: [ 'address', 'address' ], values: [ - /* _operator */ from, - /* _wrb */ await determineProxyAddr(from, specs.WitnetRequestBoard?.vanity || 3), - ]}, - }); - if (!isDryRun) utils.saveAddresses(addresses); - } - // Deploy the WitnetRandomness oracle, if required - { - await deploy({ - from, ecosystem, network, targets, - key: targets.WitnetRandomness, - libs: specs.WitnetRandomness?.libs, - vanity: specs.WitnetRandomness?.vanity || 0, - immutables: specs.WitnetRandomness?.immutables, - intrinsics: { types: [ 'address', 'address' ], values: [ - /* _operator */ from, - /* _wrb */ await determineProxyAddr(from, specs.WitnetRequestBoard?.vanity || 3), - ]}, - }); - if (!isDryRun) utils.saveAddresses(addresses); - } + // Deploy the WitnetPriceFeeds oracle, if required + { + await deploy({ + from, + ecosystem, + network, + targets, + key: targets.WitnetPriceFeeds, + libs: specs.WitnetPriceFeeds.libs, + vanity: specs.WitnetPriceFeeds?.vanity || 0, + immutables: specs.WitnetPriceFeeds.immutables, + intrinsics: { + types: ["address", "address"], + values: [ + /* _operator */ from, + /* _wrb */ await determineProxyAddr(from, specs.WitnetRequestBoard?.vanity || 3), + ], + }, + }) + if (!isDryRun) utils.saveAddresses(addresses) + } + // Deploy the WitnetRandomness oracle, if required + { + await deploy({ + from, + ecosystem, + network, + targets, + key: targets.WitnetRandomness, + libs: specs.WitnetRandomness?.libs, + vanity: specs.WitnetRandomness?.vanity || 0, + immutables: specs.WitnetRandomness?.immutables, + intrinsics: { + types: ["address", "address"], + values: [ + /* _operator */ from, + /* _wrb */ await determineProxyAddr(from, specs.WitnetRequestBoard?.vanity || 3), + ], + }, + }) + if (!isDryRun) utils.saveAddresses(addresses) + } } -async function deploy(specs) { - const { from, ecosystem, network, key, libs, intrinsics, immutables, targets, vanity } = specs; - const artifact = artifacts.require(key) - const salt = vanity ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(vanity), 32).toString("hex") : "0x0" - if (utils.isNullAddress(addresses[ecosystem][network][key])) { - utils.traceHeader(`Deploying '${key}'...`) - const deployer = await WitnetDeployer.deployed() - let { types, values } = intrinsics - if (immutables?.types) types = [ ...types, ...immutables.types ] - if (immutables?.values) values = [ ...values, ...immutables.values ] - const constructorArgs = web3.eth.abi.encodeParameters(types, values) - if (constructorArgs.length > 2) { - console.info(" ", "> constructor types:", types) - console.info(" ", "> constructor args: ", constructorArgs.slice(2)) - } - const coreBytecode = link(artifact.toJSON().bytecode, libs, targets) - if (coreBytecode.indexOf("__") > -1) { - console.info(bytecode) - console.info("Cannot deploy due to some missing libs") - process.exit(1) - } - const dappInitCode = coreBytecode + constructorArgs.slice(2) - const dappAddr = await deployer.determineAddr.call(dappInitCode, salt, { from }) - console.info(" ", "> account: ", from) - console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), 'ether'), "ETH") - const tx = await deployer.deploy(dappInitCode, salt, { from }) - utils.traceTx(tx) - if ((await web3.eth.getCode(dappAddr)).length > 3) { - addresses[ecosystem][network][key] = dappAddr - // save/overwrite exportable abi file - utils.saveJsonAbi(key, artifact.abi) - } else { - console.info(`Contract was not deployed on expected address: ${dappAddr}`) - console.log(tx.receipt) - process.exit(1) - } +async function deploy (specs) { + const { from, ecosystem, network, key, libs, intrinsics, immutables, targets, vanity } = specs + const artifact = artifacts.require(key) + const salt = vanity ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(vanity), 32).toString("hex") : "0x0" + if (utils.isNullAddress(addresses[ecosystem][network][key])) { + utils.traceHeader(`Deploying '${key}'...`) + const deployer = await WitnetDeployer.deployed() + let { types, values } = intrinsics + if (immutables?.types) types = [...types, ...immutables.types] + if (immutables?.values) values = [...values, ...immutables.values] + const constructorArgs = web3.eth.abi.encodeParameters(types, values) + if (constructorArgs.length > 2) { + console.info(" ", "> constructor types:", types) + console.info(" ", "> constructor args: ", constructorArgs.slice(2)) + } + const coreBytecode = link(artifact.toJSON().bytecode, libs, targets) + if (coreBytecode.indexOf("__") > -1) { + console.info(bytecode) + console.info("Cannot deploy due to some missing libs") + process.exit(1) + } + const dappInitCode = coreBytecode + constructorArgs.slice(2) + const dappAddr = await deployer.determineAddr.call(dappInitCode, salt, { from }) + console.info(" ", "> account: ", from) + console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), "ether"), "ETH") + const tx = await deployer.deploy(dappInitCode, salt, { from }) + utils.traceTx(tx) + if ((await web3.eth.getCode(dappAddr)).length > 3) { + addresses[ecosystem][network][key] = dappAddr + // save/overwrite exportable abi file + utils.saveJsonAbi(key, artifact.abi) } else { - utils.traceHeader(`Skipped '${key}'`) + console.info(`Contract was not deployed on expected address: ${dappAddr}`) + console.log(tx.receipt) + process.exit(1) } - artifact.address = addresses[ecosystem][network][key] - console.info(" ", "> contract address: ", artifact.address) - console.info(" ", "> contract codehash:", web3.utils.soliditySha3(await web3.eth.getCode(artifact.address))) - console.info() - return artifact + } else { + utils.traceHeader(`Skipped '${key}'`) + } + artifact.address = addresses[ecosystem][network][key] + console.info(" ", "> contract address: ", artifact.address) + console.info(" ", "> contract codehash:", web3.utils.soliditySha3(await web3.eth.getCode(artifact.address))) + console.info() + return artifact } -async function determineProxyAddr(from, nonce) { - const salt = nonce ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(nonce), 32).toString("hex") : "0x0" - const deployer = await WitnetDeployer.deployed() - const addr = await deployer.determineProxyAddr.call(salt, { from }) - return addr +async function determineProxyAddr (from, nonce) { + const salt = nonce ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(nonce), 32).toString("hex") : "0x0" + const deployer = await WitnetDeployer.deployed() + const addr = await deployer.determineProxyAddr.call(salt, { from }) + return addr } -function link(bytecode, libs, targets) { - if (libs && Array.isArray(libs) && libs.length > 0) { - for (index in libs) { - const key = targets[libs[index]] - const lib = artifacts.require(key) - bytecode = bytecode.replaceAll(`__${key}${"_".repeat(38-key.length)}`, lib.address.slice(2)) - console.info(" ", `> linked library: ${key} => ${lib.address}`) - } +function link (bytecode, libs, targets) { + if (libs && Array.isArray(libs) && libs.length > 0) { + for (index in libs) { + const key = targets[libs[index]] + const lib = artifacts.require(key) + bytecode = bytecode.replaceAll(`__${key}${"_".repeat(38 - key.length)}`, lib.address.slice(2)) + console.info(" ", `> linked library: ${key} => ${lib.address}`) } - return bytecode -} \ No newline at end of file + } + return bytecode +} diff --git a/migrations/witnet.settings.js b/migrations/witnet.settings.js index 80bcc6faf..5081d57d8 100644 --- a/migrations/witnet.settings.js +++ b/migrations/witnet.settings.js @@ -659,7 +659,7 @@ module.exports = { specs: { default: { WitnetBytecodes: { - libs: [ "WitnetEncodingLib", ], + libs: ["WitnetEncodingLib"], vanity: 172582, }, WitnetRandomness: { @@ -667,31 +667,31 @@ module.exports = { }, WitnetRequestBoard: { immutables: { - types: [ 'uint256', 'uint256', 'uint256', 'uint256', ], + types: ["uint256", "uint256", "uint256", "uint256"], values: [ - /* _reportResultGasBase */ 58282, - /* _reportResultWithCallbackGasBase */ 65273, - /* _reportResultWithCallbackRevertGasBase */ 69546, - /* _sstoreFromZeroGas */ 20000, - ] + /* _reportResultGasBase */ 58282, + /* _reportResultWithCallbackGasBase */ 65273, + /* _reportResultWithCallbackRevertGasBase */ 69546, + /* _sstoreFromZeroGas */ 20000, + ], }, - libs: [ "WitnetErrorsLib", ], + libs: ["WitnetErrorsLib"], vanity: 899032812, // => 0x000071F0c823bD30D2Bf4CD1E829Eba5A6070000 }, WitnetRequestFactory: { vanity: 178848, }, WitnetPriceFeeds: { - libs: [ "WitnetPriceFeedsLib", ], + libs: ["WitnetPriceFeedsLib"], vanity: 5, - } + }, }, avalanche: { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 155000, - ] + /* _reportResultGasBase */ 155000, + ], }, }, }, @@ -699,8 +699,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 114000, - ] + /* _reportResultGasBase */ 114000, + ], }, }, }, @@ -708,8 +708,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 78500, - ] + /* _reportResultGasBase */ 78500, + ], }, }, }, @@ -717,8 +717,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 225000, - ] + /* _reportResultGasBase */ 225000, + ], }, }, }, @@ -726,8 +726,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 225000, - ] + /* _reportResultGasBase */ 225000, + ], }, }, }, @@ -735,8 +735,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 137500, - ] + /* _reportResultGasBase */ 137500, + ], }, }, }, @@ -744,8 +744,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 85000, - ] + /* _reportResultGasBase */ 85000, + ], }, }, }, @@ -753,8 +753,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 530000, - ] + /* _reportResultGasBase */ 530000, + ], }, }, }, @@ -762,8 +762,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 85000, - ] + /* _reportResultGasBase */ 85000, + ], }, }, }, @@ -771,8 +771,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 92500, - ] + /* _reportResultGasBase */ 92500, + ], }, }, }, @@ -780,8 +780,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 105000, - ] + /* _reportResultGasBase */ 105000, + ], }, }, }, @@ -789,8 +789,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 85000, - ] + /* _reportResultGasBase */ 85000, + ], }, }, }, @@ -798,8 +798,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 134800, - ] + /* _reportResultGasBase */ 134800, + ], }, }, }, @@ -807,8 +807,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 115000, - ] + /* _reportResultGasBase */ 115000, + ], }, }, }, @@ -816,8 +816,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 145000, - ] + /* _reportResultGasBase */ 145000, + ], }, }, }, @@ -825,8 +825,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 135000, - ] + /* _reportResultGasBase */ 135000, + ], }, }, }, @@ -834,8 +834,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ "0x3100A1CAC7EF19DC", - ] + /* _reportResultGasBase */ "0x3100A1CAC7EF19DC", + ], }, }, }, @@ -843,10 +843,10 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 83949, - ] + /* _reportResultGasBase */ 83949, + ], }, }, }, }, -} \ No newline at end of file +} diff --git a/scripts/eth-create2.js b/scripts/eth-create2.js index 52a0f84c3..5a364f00e 100644 --- a/scripts/eth-create2.js +++ b/scripts/eth-create2.js @@ -1,6 +1,6 @@ -const assert = require('nanoassert') -const { utils } = require('eth-helpers') -const keccak = require('sha3-wasm').keccak256 +const assert = require("nanoassert") +const { utils } = require("eth-helpers") +const keccak = require("sha3-wasm").keccak256 const prefix = Buffer.from([0xff]) @@ -16,13 +16,13 @@ const prefix = Buffer.from([0xff]) * `eth-checksum` or similar modules */ module.exports = function create2 (address, salt, initCode) { - if (typeof address === 'string') address = utils.parse.address(address) - if (typeof salt === 'string') salt = utils.parse.uint256(salt) - if (typeof initCode === 'string') initCode = utils.parse.bytes(initCode) + if (typeof address === "string") address = utils.parse.address(address) + if (typeof salt === "string") salt = utils.parse.uint256(salt) + if (typeof initCode === "string") initCode = utils.parse.bytes(initCode) - assert(address.byteLength === 20, 'address must be 20 bytes') - assert(salt.byteLength === 32, 'salt must be 32 bytes') - assert(initCode.byteLength != null, 'initCode must be Buffer') + assert(address.byteLength === 20, "address must be 20 bytes") + assert(salt.byteLength === 32, "salt must be 32 bytes") + assert(initCode.byteLength != null, "initCode must be Buffer") const codeHash = keccak().update(initCode).digest() @@ -34,4 +34,3 @@ module.exports = function create2 (address, salt, initCode) { .digest() .slice(-20)) } - diff --git a/scripts/eth-create3.js b/scripts/eth-create3.js index 2f5347d48..613e8de59 100644 --- a/scripts/eth-create3.js +++ b/scripts/eth-create3.js @@ -1,6 +1,6 @@ -const assert = require('nanoassert') -const { utils } = require('eth-helpers') -const keccak = require('sha3-wasm').keccak256 +const assert = require("nanoassert") +const { utils } = require("eth-helpers") +const keccak = require("sha3-wasm").keccak256 const factoryPrefix = Buffer.from([0xff]) @@ -15,11 +15,11 @@ const factoryPrefix = Buffer.from([0xff]) * `eth-checksum` or similar modules */ module.exports = function create3 (address, salt) { - if (typeof address === 'string') address = utils.parse.address(address) - if (typeof salt === 'string') salt = utils.parse.uint256(salt) + if (typeof address === "string") address = utils.parse.address(address) + if (typeof salt === "string") salt = utils.parse.uint256(salt) - assert(address.byteLength === 20, 'address must be 20 bytes') - assert(salt.byteLength === 32, 'salt must be 32 bytes') + assert(address.byteLength === 20, "address must be 20 bytes") + assert(salt.byteLength === 32, "salt must be 32 bytes") const factoryHash = utils.parse.uint256("0x21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f") const factoryAddr = keccak() @@ -29,8 +29,8 @@ module.exports = function create3 (address, salt) { .update(factoryHash) .digest() .slice(-20) - ; - assert(factoryAddr.byteLength === 20, 'address must be 20 bytes') + + assert(factoryAddr.byteLength === 20, "address must be 20 bytes") return utils.format.address(keccak() .update(Buffer.from([0xd6, 0x94])) @@ -38,6 +38,5 @@ module.exports = function create3 (address, salt) { .update(Buffer.from([0x01])) .digest() .slice(-20) - ) + ) } - diff --git a/scripts/utils/index.js b/scripts/utils/index.js index 6d9190a6b..1cce66d5b 100644 --- a/scripts/utils/index.js +++ b/scripts/utils/index.js @@ -121,7 +121,7 @@ function saveAddresses (addrs) { function saveJsonAbi (key, abi) { const version = require("../../package.json").version - const latest_fn = `./migrations/abis/${key}.json`; + const latest_fn = `./migrations/abis/${key}.json` const version_fn = `./migrations/abis/${key}-${version}.json` let latest_abi = [] if (fs.existsSync(latest_fn)) { diff --git a/scripts/utils/traceTx.js b/scripts/utils/traceTx.js index 4c36b7223..28134518a 100644 --- a/scripts/utils/traceTx.js +++ b/scripts/utils/traceTx.js @@ -4,5 +4,5 @@ module.exports = function (tx) { console.info(" ", "> transaction hash: ", tx.receipt.transactionHash) console.info(" ", "> gas used: ", tx.receipt.gasUsed.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")) console.info(" ", "> gas price: ", tx.receipt.effectiveGasPrice / 10 ** 9, "gwei") - console.info(" ", "> total cost: ", web3.utils.fromWei(BigInt(tx.receipt.gasUsed * tx.receipt.effectiveGasPrice).toString(), 'ether'), "ETH") + console.info(" ", "> total cost: ", web3.utils.fromWei(BigInt(tx.receipt.gasUsed * tx.receipt.effectiveGasPrice).toString(), "ether"), "ETH") } diff --git a/scripts/vanity2gen.js b/scripts/vanity2gen.js index 8a8354137..0ce0ee900 100644 --- a/scripts/vanity2gen.js +++ b/scripts/vanity2gen.js @@ -80,4 +80,3 @@ module.exports = async function () { offset++ } } - diff --git a/scripts/vanity3gen.js b/scripts/vanity3gen.js index 6452d3b81..3e1721686 100644 --- a/scripts/vanity3gen.js +++ b/scripts/vanity3gen.js @@ -14,7 +14,7 @@ module.exports = async function () { let network = "default" let prefix = "0x00" let suffix = "0x00" - let hexArgs = "" + const hexArgs = "" process.argv.map((argv, index, args) => { if (argv === "--offset") { offset = parseInt(args[index + 1])