From 985ebb63b95b194a0a256635655ded4a88edd524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 15 Mar 2024 13:39:16 +0100 Subject: [PATCH 01/35] feat: IWitnetFeedAdmin.baseFeeOverheadPercentage() --- contracts/core/defaults/WitnetPriceFeedsDefault.sol | 8 ++++++++ contracts/interfaces/IWitnetFeedsAdmin.sol | 1 + 2 files changed, 9 insertions(+) diff --git a/contracts/core/defaults/WitnetPriceFeedsDefault.sol b/contracts/core/defaults/WitnetPriceFeedsDefault.sol index 35433fac..503697bb 100644 --- a/contracts/core/defaults/WitnetPriceFeedsDefault.sol +++ b/contracts/core/defaults/WitnetPriceFeedsDefault.sol @@ -332,6 +332,14 @@ contract WitnetPriceFeedsDefault Ownable2Step.acceptOwnership(); } + function baseFeeOverheadPercentage() + virtual override + external view + returns (uint16) + { + return __baseFeeOverheadPercentage; + } + function pendingOwner() virtual override (IWitnetFeedsAdmin, Ownable2Step) public view diff --git a/contracts/interfaces/IWitnetFeedsAdmin.sol b/contracts/interfaces/IWitnetFeedsAdmin.sol index 990f2fbf..bc4c8107 100644 --- a/contracts/interfaces/IWitnetFeedsAdmin.sol +++ b/contracts/interfaces/IWitnetFeedsAdmin.sol @@ -7,6 +7,7 @@ import "../WitnetRequest.sol"; interface IWitnetFeedsAdmin { function acceptOwnership() external; + function baseFeeOverheadPercentage() external view returns (uint16); function deleteFeed(string calldata caption) external; function deleteFeeds() external; function owner() external view returns (address); From b4a20a99a0ad6d3ef372ca845ee4ad0d73acddda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 15 Mar 2024 13:41:41 +0100 Subject: [PATCH 02/35] refactor: UsingWitnetRandomness -> WitnetRandomnessConsumer --- contracts/apps/UsingWitnet.sol | 12 +---- contracts/apps/UsingWitnetRequest.sol | 2 +- contracts/apps/UsingWitnetRequestTemplate.sol | 2 +- contracts/apps/WitnetConsumer.sol | 4 +- ...mness.sol => WitnetRandomnessConsumer.sol} | 17 +++---- contracts/libs/Witnet.sol | 48 +------------------ contracts/libs/WitnetEncodingLib.sol | 2 +- 7 files changed, 15 insertions(+), 72 deletions(-) rename contracts/apps/{UsingWitnetRandomness.sol => WitnetRandomnessConsumer.sol} (84%) diff --git a/contracts/apps/UsingWitnet.sol b/contracts/apps/UsingWitnet.sol index 7f829491..0c1a21cb 100644 --- a/contracts/apps/UsingWitnet.sol +++ b/contracts/apps/UsingWitnet.sol @@ -23,7 +23,7 @@ abstract contract UsingWitnet /// @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; + uint16 internal __witnetBaseFeeOverheadPercentage; /// @param _wrb Address of the WitnetOracle contract. constructor(WitnetOracle _wrb) { @@ -71,7 +71,7 @@ abstract contract UsingWitnet returns (uint256) { return ( - (100 + _witnetBaseFeeOverheadPercentage()) + (100 + __witnetBaseFeeOverheadPercentage) * __witnet.estimateBaseFee(tx.gasprice, _resultMaxSize) ) / 100; } @@ -89,12 +89,4 @@ abstract contract UsingWitnet { return __witnet.getQueryResultError(_witnetQueryId); } - - function _witnetBaseFeeOverheadPercentage() virtual internal view returns (uint16) { - return __witnetBaseFeeOverheadPercentage; - } - - function __witnetSetBaseFeeOverheadPercentage(uint16 _baseFeeOverheadPercentage) virtual internal { - __witnetBaseFeeOverheadPercentage = _baseFeeOverheadPercentage; - } } diff --git a/contracts/apps/UsingWitnetRequest.sol b/contracts/apps/UsingWitnetRequest.sol index 70a2c20e..cf8541f0 100644 --- a/contracts/apps/UsingWitnetRequest.sol +++ b/contracts/apps/UsingWitnetRequest.sol @@ -27,7 +27,7 @@ abstract contract UsingWitnetRequest dataRequest = _witnetRequest; __witnetQueryResultMaxSize = _witnetRequest.resultDataMaxSize(); __witnetRequestRadHash = _witnetRequest.radHash(); - __witnetSetBaseFeeOverheadPercentage(_baseFeeOverheadPercentage); + __witnetBaseFeeOverheadPercentage = _baseFeeOverheadPercentage; } function _witnetEstimateEvmReward() diff --git a/contracts/apps/UsingWitnetRequestTemplate.sol b/contracts/apps/UsingWitnetRequestTemplate.sol index 5785e8e3..1823bdce 100644 --- a/contracts/apps/UsingWitnetRequestTemplate.sol +++ b/contracts/apps/UsingWitnetRequestTemplate.sol @@ -25,7 +25,7 @@ abstract contract UsingWitnetRequestTemplate ); dataRequestTemplate = _witnetRequestTemplate; __witnetQueryResultMaxSize = _witnetRequestTemplate.resultDataMaxSize(); - __witnetSetBaseFeeOverheadPercentage(_baseFeeOverheadPercentage); + __witnetBaseFeeOverheadPercentage = _baseFeeOverheadPercentage; } function _witnetBuildRadHash(string[][] memory _witnetRequestArgs) diff --git a/contracts/apps/WitnetConsumer.sol b/contracts/apps/WitnetConsumer.sol index 60c8b30c..fecb4aad 100644 --- a/contracts/apps/WitnetConsumer.sol +++ b/contracts/apps/WitnetConsumer.sol @@ -43,7 +43,7 @@ abstract contract WitnetConsumer function _witnetEstimateEvmReward() virtual internal view returns (uint256) { return ( - (100 + _witnetBaseFeeOverheadPercentage()) + (100 + __witnetBaseFeeOverheadPercentage) * __witnet.estimateBaseFeeWithCallback( tx.gasprice, _witnetCallbackGasLimit() @@ -67,7 +67,7 @@ abstract contract WitnetConsumer returns (uint256) { return ( - (100 + _witnetBaseFeeOverheadPercentage()) + (100 + __witnetBaseFeeOverheadPercentage) * __witnet.estimateBaseFeeWithCallback( tx.gasprice, _callbackGasLimit diff --git a/contracts/apps/UsingWitnetRandomness.sol b/contracts/apps/WitnetRandomnessConsumer.sol similarity index 84% rename from contracts/apps/UsingWitnetRandomness.sol rename to contracts/apps/WitnetRandomnessConsumer.sol index 61e20d0b..fe23b851 100644 --- a/contracts/apps/UsingWitnetRandomness.sol +++ b/contracts/apps/WitnetRandomnessConsumer.sol @@ -6,7 +6,7 @@ pragma experimental ABIEncoderV2; import "./WitnetConsumer.sol"; import "../WitnetRequest.sol"; -abstract contract UsingWitnetRandomness +abstract contract WitnetRandomnessConsumer is WitnetConsumer { @@ -30,12 +30,11 @@ abstract contract UsingWitnetRandomness { // On-chain building of the Witnet Randomness Request: { - WitnetRequestFactory _factory = witnet().factory(); WitnetRequestBytecodes _registry = witnet().registry(); // Build own Witnet Randomness Request: bytes32[] memory _retrievals = new bytes32[](1); _retrievals[0] = _registry.verifyRadonRetrieval( - Witnet.RadonDataRequestMethods.Rng, + Witnet.RadonDataRequestMethods.RNG, "", // no url "", // no body new string[2][](0), // no headers @@ -50,17 +49,15 @@ abstract contract UsingWitnetRandomness opcode: Witnet.RadonReducerOpcodes.ConcatenateAndHash, filters: _filters // no filters })); - WitnetRequestTemplate _template = WitnetRequestTemplate(_factory.buildRequestTemplate( + __witnetRandomnessRadHash = _registry.verifyRadonRequest( _retrievals, _aggregator, _tally, - 32 // 256 bits of pure entropy ;-) - )); - __witnetRandomnessRadHash = WitnetRequest( - _template.buildRequest(new string[][](_retrievals.length)) - ).radHash(); + 32, // 256 bits of pure entropy ;-) + new string[][](_retrievals.length) + ); } - __witnetSetBaseFeeOverheadPercentage(_baseFeeOverheadPercentage); + __witnetBaseFeeOverheadPercentage = _baseFeeOverheadPercentage; } function _witnetEstimateEvmReward() virtual override internal view returns (uint256) { diff --git a/contracts/libs/Witnet.sol b/contracts/libs/Witnet.sol index 8fabc32a..a31618bc 100644 --- a/contracts/libs/Witnet.sol +++ b/contracts/libs/Witnet.sol @@ -280,7 +280,7 @@ library Witnet { enum RadonDataRequestMethods { /* 0 */ Unknown, /* 1 */ HttpGet, - /* 2 */ Rng, + /* 2 */ RNG, /* 3 */ HttpPost, /* 4 */ HttpHead } @@ -537,53 +537,7 @@ library Witnet { 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 ---------------------------------------------------------------------------- diff --git a/contracts/libs/WitnetEncodingLib.sol b/contracts/libs/WitnetEncodingLib.sol index b05156d8..6967464b 100644 --- a/contracts/libs/WitnetEncodingLib.sol +++ b/contracts/libs/WitnetEncodingLib.sol @@ -333,7 +333,7 @@ library WitnetEncodingLib { || method == Witnet.RadonDataRequestMethods.HttpPost || method == Witnet.RadonDataRequestMethods.HttpHead ) - || method == Witnet.RadonDataRequestMethods.Rng + || method == Witnet.RadonDataRequestMethods.RNG && bytes(url).length == 0 && headers.length == 0 && script.length >= 1 From c5c51e4c84fd72579eea0f1fd8822b49f009d7ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 15 Mar 2024 13:48:39 +0100 Subject: [PATCH 03/35] feat: WitnetRandomness v2.0 --- contracts/WitnetRandomness.sol | 13 + contracts/apps/WitnetRandomnessV20.sol | 501 ++++++++++++++++++ contracts/interfaces/IWitnetRandomness.sol | 107 ++++ .../interfaces/IWitnetRandomnessAdmin.sol | 15 + contracts/libs/WitnetV2.sol | 22 + migrations/scripts/3_core.js | 16 +- migrations/scripts/5_apps.js | 117 ++++ settings/artifacts.js | 1 + settings/specs.js | 3 + test/witnet_bytecodes.test.js | 2 +- 10 files changed, 792 insertions(+), 5 deletions(-) create mode 100644 contracts/WitnetRandomness.sol create mode 100644 contracts/apps/WitnetRandomnessV20.sol create mode 100644 contracts/interfaces/IWitnetRandomness.sol create mode 100644 contracts/interfaces/IWitnetRandomnessAdmin.sol create mode 100644 migrations/scripts/5_apps.js diff --git a/contracts/WitnetRandomness.sol b/contracts/WitnetRandomness.sol new file mode 100644 index 00000000..ac1dc3fc --- /dev/null +++ b/contracts/WitnetRandomness.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.8.0 <0.9.0; + +import "./interfaces/IWitnetRandomness.sol"; + +abstract contract WitnetRandomness + is + IWitnetRandomness +{ + function class() virtual external view returns (string memory); + function specs() virtual external view returns (bytes4); +} \ No newline at end of file diff --git a/contracts/apps/WitnetRandomnessV20.sol b/contracts/apps/WitnetRandomnessV20.sol new file mode 100644 index 00000000..fa81b2a9 --- /dev/null +++ b/contracts/apps/WitnetRandomnessV20.sol @@ -0,0 +1,501 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.8.0 <0.9.0; + +import "../WitnetRandomness.sol"; +import "../apps/UsingWitnet.sol"; +import "../interfaces/IWitnetRandomnessAdmin.sol"; +import "../patterns/Ownable2Step.sol"; + +/// @title WitnetRandomnessV20: Unmalleable and provably-fair randomness generation based on the Witnet Oracle. +/// @author The Witnet Foundation. +contract WitnetRandomnessV20 + is + Ownable2Step, + UsingWitnet, + WitnetRandomness, + IWitnetRandomnessAdmin +{ + using Witnet for bytes; + using Witnet for Witnet.Result; + using WitnetV2 for WitnetV2.RadonSLA; + + struct Randomize { + uint256 witnetQueryId; + uint256 prevBlock; + uint256 nextBlock; + } + + struct Storage { + uint256 lastRandomizeBlock; + mapping (uint256 => Randomize) randomize_; + } + + /// @notice Unique identifier of the RNG data request used on the Witnet Oracle blockchain for solving randomness. + /// @dev Can be used to track all randomness requests solved on the Witnet Oracle blockchain. + bytes32 immutable public override witnetRadHash; + + constructor(WitnetOracle _witnet) + Ownable(address(msg.sender)) + UsingWitnet(_witnet) + { + require( + address(_witnet) == address(0) + || _witnet.specs() == type(IWitnetOracle).interfaceId, + "WitnetRandomnessV2: uncompliant WitnetOracle" + ); + WitnetRequestBytecodes _registry = witnet().registry(); + { + // Build own Witnet Randomness Request: + bytes32[] memory _retrievals = new bytes32[](1); + _retrievals[0] = _registry.verifyRadonRetrieval( + Witnet.RadonDataRequestMethods.RNG, + "", // no request url + "", // no request body + new string[2][](0), // no request headers + hex"80" // no request Radon 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 + })); + witnetRadHash = _registry.verifyRadonRequest( + _retrievals, + _aggregator, + _tally, + 32, // 256 bits of pure entropy ;-) + new string[][](_retrievals.length) + ); + } + } + + receive() virtual external payable { + revert(string(abi.encodePacked( + class(), + ": no transfers accepted" + ))); + } + + fallback() virtual external payable { + revert(string(abi.encodePacked( + class(), + ": 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))) + ))); + } + + function class() virtual override public pure returns (string memory) { + return type(WitnetRandomnessV20).name; + } + + function specs() virtual override external pure returns (bytes4) { + return type(WitnetRandomness).interfaceId; + } + + function witnet() override (IWitnetRandomness, UsingWitnet) + public view returns (WitnetOracle) + { + return UsingWitnet.witnet(); + } + + + /// =============================================================================================================== + /// --- '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. + function estimateRandomizeFee(uint256 _evmGasPrice) + public view + virtual override + returns (uint256) + { + return ( + (100 + __witnetBaseFeeOverheadPercentage) + * __witnet.estimateBaseFee(_evmGasPrice, 32) + ) / 100; + } + + /// @notice Retrieves the randomness value generated by the Witnet Oracle blockchain in response to the + /// @notice first non-errored randomize request solved after the given block number. + /// @dev Reverts if: + /// @dev i. no `randomize()` was requested on neither the given block, nor afterwards. + /// @dev ii. the first non-errored `randomize()` request found on or after the given block is not solved yet. + /// @dev iii. all `randomize()` requests that took place on or after the given block were solved with errors. + /// @param _blockNumber Block number from which the search will start + function fetchRandomnessAfter(uint256 _blockNumber) + public view + virtual override + returns (bytes32) + { + Randomize storage __randomize = __storage().randomize_[_blockNumber]; + + if (__randomize.witnetQueryId == 0) { + _blockNumber = getRandomizeNextBlock(_blockNumber); + } + + uint256 _witnetQueryId = __randomize.witnetQueryId; + require( + _witnetQueryId != 0, + "WitnetRandomness: not randomized" + ); + + WitnetV2.ResponseStatus _status = __witnet.getQueryResponseStatus(_witnetQueryId); + if (_status == WitnetV2.ResponseStatus.Ready) { + return (__witnet.getQueryResponse(_witnetQueryId) + .resultCborBytes + .toWitnetResult() + .asBytes32() + ); + } else if (_status == WitnetV2.ResponseStatus.Error) { + uint256 _nextRandomizeBlock = __randomize.nextBlock; + require( + _nextRandomizeBlock != 0, + "WitnetRandomness: faulty randomize" + ); + return fetchRandomnessAfter(_nextRandomizeBlock); + + } else { + revert("WitnetRandomness: pending randomize"); + } + } + + /// @notice Retrieves the unique hash and timestamp of the witnessing commit/reveal act that took + /// @notice place in the Witnet Oracle blockchain in response to the first non-errored randomize request + /// @notice solved after the given block number. + /// @dev Reverts if: + /// @dev i. no `randomize()` was requested on neither the given block, nor afterwards. + /// @dev ii. the first non-errored `randomize()` request found on or after the given block is not solved yet. + /// @dev iii. all `randomize()` requests that took place on or after the given block were solved with errors. + /// @param _blockNumber Block number from which the search will start. + /// @return _witnetResultTimestamp Timestamp at which the randomness value was generated by the Witnet blockchain. + /// @return _witnetResultTallyHash Hash of the witnessing commit/reveal act that took place on the Witnet blockchain. + /// @return _witnetResultFinalityBlock EVM block number from which the provided randomness can be considered to be final. + function fetchRandomnessAfterProof(uint256 _blockNumber) + virtual override + public view + returns ( + uint64 _witnetResultTimestamp, + bytes32 _witnetResultTallyHash, + uint256 _witnetResultFinalityBlock + ) + { + Randomize storage __randomize = __storage().randomize_[_blockNumber]; + + if (__randomize.witnetQueryId == 0) { + _blockNumber = getRandomizeNextBlock(_blockNumber); + } + + uint256 _witnetQueryId = __randomize.witnetQueryId; + require( + _witnetQueryId != 0, + "WitnetRandomness: not randomized" + ); + + WitnetV2.ResponseStatus _status = __witnet.getQueryResponseStatus(_witnetQueryId); + if (_status == WitnetV2.ResponseStatus.Ready) { + WitnetV2.Response memory _witnetQueryResponse = __witnet.getQueryResponse(_witnetQueryId); + _witnetResultTimestamp = _witnetQueryResponse.resultTimestamp; + _witnetResultTallyHash = _witnetQueryResponse.resultTallyHash; + _witnetResultFinalityBlock = _witnetQueryResponse.finality; + + } else if (_status == WitnetV2.ResponseStatus.Error) { + uint256 _nextRandomizeBlock = __randomize.nextBlock; + require( + _nextRandomizeBlock != 0, + "WitnetRandomness: faulty randomize" + ); + return fetchRandomnessAfterProof(_nextRandomizeBlock); + + } else { + revert("WitnetRandomness: pending randomize"); + } + } + + /// @notice Returns last block number on which a randomize was requested. + function getLastRandomizeBlock() + virtual override + external view + returns (uint256) + { + return __storage().lastRandomizeBlock; + } + + /// @notice Retrieves metadata related to the randomize request that got posted to the + /// @notice Witnet Oracle contract on the given block number. + /// @dev Returns zero values if no randomize request was actually posted on the given block. + /// @return _witnetQueryId Identifier of the underlying Witnet query created on the given block number. + /// @return _prevRandomizeBlock Block number in which a randomize request got posted just before this one. 0 if none. + /// @return _nextRandomizeBlock Block number in which a randomize request got posted just after this one, 0 if none. + function getRandomizeData(uint256 _blockNumber) + external view + virtual override + returns ( + uint256 _witnetQueryId, + uint256 _prevRandomizeBlock, + uint256 _nextRandomizeBlock + ) + { + Randomize storage __randomize = __storage().randomize_[_blockNumber]; + _witnetQueryId = __randomize.witnetQueryId; + _prevRandomizeBlock = __randomize.prevBlock; + _nextRandomizeBlock = __randomize.nextBlock; + } + + /// @notice Returns the number of the next block in which a randomize request was posted after the given one. + /// @param _blockNumber Block number from which the search will start. + /// @return Number of the first block found after the given one, or `0` otherwise. + function getRandomizeNextBlock(uint256 _blockNumber) + public view + virtual override + returns (uint256) + { + return ((__storage().randomize_[_blockNumber].witnetQueryId != 0) + ? __storage().randomize_[_blockNumber].nextBlock + // start search from the latest block + : _searchNextBlock(_blockNumber, __storage().lastRandomizeBlock) + ); + } + + /// @notice Returns the number of the previous block in which a randomize request was posted before the given one. + /// @param _blockNumber Block number from which the search will start. Cannot be zero. + /// @return First block found before the given one, or `0` otherwise. + function getRandomizePrevBlock(uint256 _blockNumber) + public view + virtual override + returns (uint256) + { + assert(_blockNumber > 0); + uint256 _latest = __storage().lastRandomizeBlock; + return ((_blockNumber > _latest) + ? _latest + // start search from the latest block + : _searchPrevBlock(_blockNumber, __storage().randomize_[_latest].prevBlock) + ); + } + + /// @notice Returns status of the first non-errored randomize request posted on or after the given block number. + /// @dev Possible values: + /// @dev - 0 -> Void: no randomize request was actually posted on or after the given block number. + /// @dev - 1 -> Awaiting: a randomize request was found but it's not yet solved by the Witnet blockchain. + /// @dev - 2 -> Ready: a successfull randomize value was reported and ready to be read. + /// @dev - 3 -> Error: all randomize requests after the given block were solved with errors. + /// @dev - 4 -> Finalizing: a randomize resolution has been reported from the Witnet blockchain, but it's not yet final. + function getRandomizeStatus(uint256 _blockNumber) + virtual override + public view + returns (WitnetV2.ResponseStatus) + { + if (__storage().randomize_[_blockNumber].witnetQueryId == 0) { + _blockNumber = getRandomizeNextBlock(_blockNumber); + } + uint256 _witnetQueryId = __storage().randomize_[_blockNumber].witnetQueryId; + if (_witnetQueryId == 0) { + return WitnetV2.ResponseStatus.Void; + + } else { + WitnetV2.ResponseStatus _status = __witnet.getQueryResponseStatus(_witnetQueryId); + if (_status == WitnetV2.ResponseStatus.Error) { + uint256 _nextRandomizeBlock = __storage().randomize_[_blockNumber].nextBlock; + if (_nextRandomizeBlock != 0) { + return getRandomizeStatus(_nextRandomizeBlock); + } else { + return WitnetV2.ResponseStatus.Error; + } + } else { + return _status; + } + } + } + + /// @notice Returns `true` only if a successfull resolution from the Witnet blockchain is found for the first + /// @notice non-errored randomize request posted on or after the given block number. + function isRandomized(uint256 _blockNumber) + public view + virtual override + returns (bool) + { + return ( + getRandomizeStatus(_blockNumber) == WitnetV2.ResponseStatus.Ready + ); + } + + /// @notice Generates a pseudo-random number uniformly distributed within the range [0 .. _range), by using + /// @notice the given `nonce` and the randomness returned by `getRandomnessAfter(blockNumber)`. + /// @dev Fails under same conditions as `getRandomnessAfter(uint256)` does. + /// @param _range Range within which the uniformly-distributed random number will be generated. + /// @param _nonce Nonce value enabling multiple random numbers from the same randomness value. + /// @param _blockNumber Block number from which the search for the first randomize request solved aftewards will start. + function random(uint32 _range, uint256 _nonce, uint256 _blockNumber) + external view + virtual override + returns (uint32) + { + return WitnetV2.randomUint32( + _range, + _nonce, + keccak256( + abi.encode( + msg.sender, + _blockNumber, + fetchRandomnessAfter(_blockNumber) + ) + ) + ); + } + + /// @notice Requests the Witnet oracle to generate an EVM-agnostic and trustless source of randomness. + /// @dev Only one randomness request per block will be actually posted to the Witnet Oracle. + /// @dev Only consumes the exact randomize fare as required for the `tx.gasprice`. Remaining funds will + /// @dev be transfered back to `msg.sender`. + /// @return _witnetEvmReward Funds actually paid as randomize fee. + function randomize() + external payable + virtual override + returns (uint256 _witnetEvmReward) + { + if (__storage().lastRandomizeBlock < block.number) { + _witnetEvmReward = estimateRandomizeFee(tx.gasprice); + require( + msg.value >= _witnetEvmReward, + "WitnetRandomness: insufficient reward" + ); + // Post the Witnet Randomness request: + uint _witnetQueryId = __witnet.postRequest{ + value: _witnetEvmReward + }( + witnetRadHash, + __witnetDefaultSLA + ); + // Keep Randomize data in storage: + Randomize storage __randomize = __storage().randomize_[block.number]; + __randomize.witnetQueryId = _witnetQueryId; + // Update block links: + uint256 _prevBlock = __storage().lastRandomizeBlock; + __randomize.prevBlock = _prevBlock; + __storage().randomize_[_prevBlock].nextBlock = block.number; + __storage().lastRandomizeBlock = block.number; + // Throw event: + emit Randomizing( + block.number, + _witnetQueryId, + _witnetEvmReward + ); + } + // Transfer back unused funds: + if (_witnetEvmReward < msg.value) { + payable(msg.sender).transfer(msg.value - _witnetEvmReward); + } + } + + /// @notice Returns the SLA parameters required for the Witnet Oracle blockchain to fulfill + /// @notice when solving randomness requests: + /// @notice - number of witnessing nodes contributing to randomness generation + /// @notice - reward in $nanoWIT received by every contributing node in the Witnet blockchain + function witnetQuerySLA() + virtual override + external view + returns (WitnetV2.RadonSLA memory) + { + return __witnetDefaultSLA; + } + + + /// =============================================================================================================== + /// --- 'IWitnetRandomnessAdmin' implementation ------------------------------------------------------------------- + + function acceptOwnership() + virtual override (IWitnetRandomnessAdmin, Ownable2Step) + public + { + Ownable2Step.acceptOwnership(); + } + + function baseFeeOverheadPercentage() + virtual override + external view + returns (uint16) + { + return __witnetBaseFeeOverheadPercentage; + } + + function owner() + virtual override (IWitnetRandomnessAdmin, Ownable) + public view + returns (address) + { + return Ownable.owner(); + } + + function pendingOwner() + virtual override (IWitnetRandomnessAdmin, Ownable2Step) + public view + returns (address) + { + return Ownable2Step.pendingOwner(); + } + + function transferOwnership(address _newOwner) + virtual override (IWitnetRandomnessAdmin, Ownable2Step) + public + onlyOwner + { + Ownable.transferOwnership(_newOwner); + } + + function settleBaseFeeOverheadPercentage(uint16 _baseFeeOverheadPercentage) + virtual override + external + onlyOwner + { + __witnetBaseFeeOverheadPercentage = _baseFeeOverheadPercentage; + } + + function settleWitnetQuerySLA(WitnetV2.RadonSLA calldata _witnetQuerySLA) + virtual override + external + onlyOwner + { + require( + _witnetQuerySLA.isValid(), + "WitnetRandomness: invalid SLA" + ); + __witnetDefaultSLA = _witnetQuerySLA; + } + + + // ================================================================================================================ + // --- Internal methods ------------------------------------------------------------------------------------------- + + /// @dev Recursively searches for the number of the first block after the given one in which a Witnet + /// @dev randomness request was posted. Returns 0 if none found. + function _searchNextBlock(uint256 _target, uint256 _latest) internal view returns (uint256) { + return ((_target >= _latest) + ? __storage().randomize_[_latest].nextBlock + : _searchNextBlock(_target, __storage().randomize_[_latest].prevBlock) + ); + } + + /// @dev Recursively searches for the number of the first block before the given one in which a Witnet + /// @dev randomness request was posted. Returns 0 if none found. + function _searchPrevBlock(uint256 _target, uint256 _latest) internal view returns (uint256) { + return ((_target > _latest) + ? _latest + : _searchPrevBlock(_target, __storage().randomize_[_latest].prevBlock) + ); + } + + function __storage() internal pure returns (Storage storage _ptr) { + bytes32 _slothash = keccak256(bytes("io.witnet.apps.randomness.v20")); + assembly { + _ptr.slot := _slothash + } + } +} diff --git a/contracts/interfaces/IWitnetRandomness.sol b/contracts/interfaces/IWitnetRandomness.sol new file mode 100644 index 00000000..5db5783f --- /dev/null +++ b/contracts/interfaces/IWitnetRandomness.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.7.0 <0.9.0; + +import "../WitnetOracle.sol"; + +/// @title The Witnet Randomness generator interface. +/// @author Witnet Foundation. +interface IWitnetRandomness { + + event Randomizing(uint256 blockNumber, uint256 witnetQueryId, uint256 witnetEvmReward); + + /// @notice Returns amount of wei required to be paid as a fee when requesting randomization with a + /// transaction gas price as the one given. + function estimateRandomizeFee(uint256 evmGasPrice) external view returns (uint256); + + /// @notice Retrieves the randomness value generated by the Witnet Oracle blockchain in response to the + /// @notice first non-errored randomize request solved after the given block number. + /// @dev Reverts if: + /// @dev i. no `randomize()` was requested on neither the given block, nor afterwards. + /// @dev ii. the first non-errored `randomize()` request found on or after the given block is not solved yet. + /// @dev iii. all `randomize()` requests that took place on or after the given block were solved with errors. + /// @param blockNumber Block number from which the search will start. + function fetchRandomnessAfter(uint256 blockNumber) external view returns (bytes32); + + /// @notice Retrieves the unique hash and timestamp of the witnessing commit/reveal act that took + /// @notice place in the Witnet Oracle blockchain in response to the first non-errored randomize request + /// @notice solved after the given block number. + /// @dev Reverts if: + /// @dev i. no `randomize()` was requested on neither the given block, nor afterwards. + /// @dev ii. the first non-errored `randomize()` request found on or after the given block is not solved yet. + /// @dev iii. all `randomize()` requests that took place on or after the given block were solved with errors. + /// @param blockNumber Block number from which the search will start. + /// @return witnetResultTimestamp Timestamp at which the randomness value was generated by the Witnet blockchain. + /// @return witnetResultTallyHash Hash of the witnessing commit/reveal act that took place on the Witnet blockchain. + /// @return witnetEvmFinalityBlock EVM block number from which the provided randomness can be considered to be final. + function fetchRandomnessAfterProof(uint256 blockNumber) external view returns ( + uint64 witnetResultTimestamp, + bytes32 witnetResultTallyHash, + uint256 witnetEvmFinalityBlock + ); + + /// @notice Returns last block number on which a randomize was requested. + function getLastRandomizeBlock() external view returns (uint256); + + /// @notice Retrieves metadata related to the randomize request that got posted to the + /// @notice Witnet Oracle contract on the given block number. + /// @dev Returns zero values if no randomize request was actually posted on the given block. + /// @return witnetQueryId Identifier of the underlying Witnet query created on the given block number. + /// @return prevRandomizeBlock Block number in which a randomize request got posted just before this one. 0 if none. + /// @return nextRandomizeBlock Block number in which a randomize request got posted just after this one, 0 if none. + function getRandomizeData(uint256 blockNumber) external view returns ( + uint256 witnetQueryId, + uint256 prevRandomizeBlock, + uint256 nextRandomizeBlock + ); + + /// @notice Returns the number of the next block in which a randomize request was posted after the given one. + /// @param blockNumber Block number from which the search will start. + /// @return Number of the first block found after the given one, or `0` otherwise. + function getRandomizeNextBlock(uint256 blockNumber) external view returns (uint256); + + /// @notice Returns the number of the previous block in which a randomize request was posted before the given one. + /// @param blockNumber Block number from which the search will start. + /// @return First block found before the given one, or `0` otherwise. + function getRandomizePrevBlock(uint256 blockNumber) external view returns (uint256); + + /// @notice Gets current status of the first non-errored randomize request posted on or after the given block number. + /// @dev Possible values: + /// @dev - 0 -> Void: no randomize request was actually posted on or after the given block number. + /// @dev - 1 -> Awaiting: a randomize request was found but it's not yet solved by the Witnet blockchain. + /// @dev - 2 -> Ready: a successfull randomize value was reported and ready to be read. + /// @dev - 3 -> Error: all randomize resolutions after the given block were solved with errors. + /// @dev - 4 -> Finalizing: a randomize resolution has been reported from the Witnet blockchain, but it's not yet final. + function getRandomizeStatus(uint256 blockNumber) external view returns (WitnetV2.ResponseStatus); + + /// @notice Returns `true` only if a successfull resolution from the Witnet blockchain is found for the first + /// @notice non-errored randomize request posted on or after the given block number. + function isRandomized(uint256 blockNumber) external view returns (bool); + + /// @notice Generates a pseudo-random number uniformly distributed within the range [0 .. _range), by using + /// @notice the given `nonce` and the randomness returned by `getRandomnessAfter(blockNumber)`. + /// @dev Fails under same conditions as `getRandomnessAfter(uint256)` does. + /// @param range Range within which the uniformly-distributed random number will be generated. + /// @param nonce Nonce value enabling multiple random numbers from the same randomness value. + /// @param blockNumber Block number from which the search for the first randomize request solved aftewards will start. + function random(uint32 range, uint256 nonce, uint256 blockNumber) external view returns (uint32); + + /// @notice Requests the Witnet oracle to generate an EVM-agnostic and trustless source of randomness. + /// @dev Only one randomness request per block will be actually posted to the Witnet Oracle. + /// @dev Only consumes the exact randomize fare as expected for the `tx.gasprice`. Remaining funds will + /// @dev be transfered back to `msg.sender`. + /// @return Funds actually paid as randomize fee. + function randomize() external payable returns (uint256); + + /// @notice Returns address of the Witnet Oracle bridging contract being used for solving randomness requests. + function witnet() external view returns (WitnetOracle); + + /// @notice Returns the SLA parameters required for the Witnet Oracle blockchain to fulfill + /// @notice when solving randomness requests: + /// @notice - number of witnessing nodes contributing to randomness generation + /// @notice - reward in $nanoWIT received per witnessing node in the Witnet blockchain + function witnetQuerySLA() external view returns (WitnetV2.RadonSLA memory); + + /// @notice Returns address of the Witnet-compliant data request being used for solving randomness. + function witnetRadHash() external view returns (bytes32); +} diff --git a/contracts/interfaces/IWitnetRandomnessAdmin.sol b/contracts/interfaces/IWitnetRandomnessAdmin.sol new file mode 100644 index 00000000..51999352 --- /dev/null +++ b/contracts/interfaces/IWitnetRandomnessAdmin.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.8.0 <0.9.0; + +import "../libs/WitnetV2.sol"; + +interface IWitnetRandomnessAdmin { + function acceptOwnership() external; + function baseFeeOverheadPercentage() external view returns (uint16); + function owner() external view returns (address); + function pendingOwner() external returns (address); + function transferOwnership(address) external; + function settleBaseFeeOverheadPercentage(uint16) external; + function settleWitnetQuerySLA(WitnetV2.RadonSLA calldata) external; +} \ No newline at end of file diff --git a/contracts/libs/WitnetV2.sol b/contracts/libs/WitnetV2.sol index 681ddba9..1d7cf08c 100644 --- a/contracts/libs/WitnetV2.sol +++ b/contracts/libs/WitnetV2.sol @@ -90,6 +90,28 @@ library WitnetV2 { return self.witnessingFeeNanoWit * (self.committeeSize + 3); } + + /// =============================================================================================================== + /// --- P-RNG generators ------------------------------------------------------------------------------------------ + + /// Generates a pseudo-random uint32 number uniformly distributed within the range `[0 .. range)`, based on + /// the given `nonce` and `seed` values. + function randomUint32(uint32 range, uint256 nonce, bytes32 seed) + internal pure + returns (uint32) + { + uint256 _number = uint256( + keccak256( + abi.encode(seed, nonce) + ) + ) & uint256(2 ** 224 - 1); + return uint32((_number * range) >> 224); + } + + + /// =============================================================================================================== + /// --- Witnet protocol v2.0 helper methods ----------------------------------------------------------------------- + uint256 internal constant _WITNET_GENESIS_TIMESTAMP = 1602666045; uint256 internal constant _WITNET_GENESIS_EPOCH_SECONDS = 45; diff --git a/migrations/scripts/3_core.js b/migrations/scripts/3_core.js index b2d001c7..c8605747 100644 --- a/migrations/scripts/3_core.js +++ b/migrations/scripts/3_core.js @@ -13,7 +13,9 @@ module.exports = async function (_, network, [, from]) { const specs = settings.getSpecs(network) const targets = settings.getArtifacts(network) - // Deploy/upgrade WitnetRequestBytecodes target implementation, if required + // ========================================================================== + // --- WitnetRequestBytecodes core implementation --------------------------- + await deploy({ network, targets, @@ -30,7 +32,9 @@ module.exports = async function (_, network, [, from]) { }, }) - // Deploy/upgrade WitnetRequestFactory target implementation, if required + // ========================================================================== + // --- WitnetRequestFactory core implementation ----------------------------- + await deploy({ network, targets, @@ -49,7 +53,9 @@ module.exports = async function (_, network, [, from]) { }, }) - // Deploy/upgrade WitnetOracle target implementation, if required + // ========================================================================== + // --- WitnetOracle core implementation --------------------------------- + await deploy({ network, targets, @@ -68,7 +74,9 @@ module.exports = async function (_, network, [, from]) { }, }) - // Deploy/upgrade WitnetPriceFeeds target implementation, if required + // ========================================================================== + // --- WitnetPriceFeeds core implementation --------------------------------- + await deploy({ network, targets, diff --git a/migrations/scripts/5_apps.js b/migrations/scripts/5_apps.js new file mode 100644 index 00000000..609b64ad --- /dev/null +++ b/migrations/scripts/5_apps.js @@ -0,0 +1,117 @@ +const ethUtils = require("ethereumjs-util") +const settings = require("../../settings") +const utils = require("../../src/utils") + +const WitnetDeployer = artifacts.require("WitnetDeployer") + +module.exports = async function (_, network, [, from]) { + const specs = settings.getSpecs(network) + const targets = settings.getArtifacts(network) + + // Community appliances built on top of the Witnet Oracle are meant to be immutable, + // and therefore not upgradable. Appliances can only be deployed + // once all core Witnet Oracle artifacts get deployed and initialized. + + // ========================================================================== + // --- WitnetRandomnessV20 -------------------------------------------------- + + await deploy({ + network, + targets, + from: utils.isDryRun(network) ? from : specs.WitnetRandomness.from || from, + key: targets.WitnetRandomness, + libs: specs.WitnetRandomness?.libs, + immutables: specs.WitnetRandomness?.immutables, + intrinsics: { + types: ["address"], + values: [ + /* _witnet */ await determineProxyAddr(from, specs.WitnetOracle?.vanity || 3), + ], + }, + }) +} + +async function deploy (specs) { + const { from, key, libs, intrinsics, immutables, network, targets } = specs + + const addresses = await utils.readJsonFromFile("./migrations/addresses.json") + if (!addresses[network]) addresses[network] = {} + + const selection = utils.getWitnetArtifactsFromArgs() + + const contract = artifacts.require(key) + if ( + utils.isNullAddress(addresses[network][key]) || + (await web3.eth.getCode(addresses[network][key])).length < 3 || + selection.includes(key) || + (libs && selection.filter(item => libs.includes(item)).length > 0) + ) { + 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:", JSON.stringify(types)) + console.info(" ", "> constructor args: ", constructorArgs.slice(2)) + } + const coreBytecode = link(contract.toJSON().bytecode, libs, targets) + if (coreBytecode.indexOf("__") > -1) { + console.info(coreBytecode) + 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[network][key] = coreAddr + } else { + console.info(`Error: Contract was not deployed on expected address: ${coreAddr}`) + process.exit(1) + } + // save addresses file if required + if (!utils.isDryRun(network)) { + await utils.overwriteJsonFile("./migrations/addresses.json", addresses) + const args = await utils.readJsonFromFile("./migrations/constructorArgs.json") + if (!args[network]) args[network] = {} + args[network][key] = constructorArgs.slice(2) + await utils.overwriteJsonFile("./migrations/constructorArgs.json", args) + } + } else { + utils.traceHeader(`Skipped '${key}'`) + } + contract.address = addresses[network][key] + for (const index in libs) { + const libname = libs[index] + const lib = artifacts.require(libname) + contract.link(lib) + console.info(" ", "> external library: ", `${libname}@${lib.address}`) + }; + 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 (const 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 +} diff --git a/settings/artifacts.js b/settings/artifacts.js index eef7d170..45ccc11f 100644 --- a/settings/artifacts.js +++ b/settings/artifacts.js @@ -2,6 +2,7 @@ module.exports = { default: { WitnetOracle: "WitnetOracleTrustableDefault", WitnetPriceFeeds: "WitnetPriceFeedsDefault", + WitnetRandomness: "WitnetRandomnessV20", WitnetRequestBytecodes: "WitnetRequestBytecodesDefault", WitnetRequestFactory: "WitnetRequestFactoryDefault", WitnetEncodingLib: "WitnetEncodingLib", diff --git a/settings/specs.js b/settings/specs.js index 95163c99..fd106e11 100644 --- a/settings/specs.js +++ b/settings/specs.js @@ -18,6 +18,9 @@ module.exports = { libs: ["WitnetPriceFeedsLib"], vanity: 1865150170, // 0x1111AbA2164AcdC6D291b08DfB374280035E1111 }, + WitnetRandomness: { + from: "0xF121b71715E71DDeD592F1125a06D4ED06F0694D", + }, WitnetRequestBytecodes: { libs: ["WitnetEncodingLib"], vanity: 6765579443, // 0x000B61Fe075F545fd37767f40391658275900000 diff --git a/test/witnet_bytecodes.test.js b/test/witnet_bytecodes.test.js index 825fc3b7..b1f21438 100644 --- a/test/witnet_bytecodes.test.js +++ b/test/witnet_bytecodes.test.js @@ -106,7 +106,7 @@ contract("WitnetRequestBytecodes", (accounts) => { let btcUsdPriceFeedHash context("verifyRadonRetrieval(..)", async () => { - context("WitnetV2.RadonDataRequestMethods.Rng", async () => { + context("WitnetV2.RadonDataRequestMethods.RNG", async () => { it("emits appropiate single event when verifying randomness data source for the first time", async () => { const tx = await bytecodes.verifyRadonRetrieval( 2, // requestMethod From dcee363d0d989622e56115217d132f02c4ba327b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 15 Mar 2024 13:56:03 +0100 Subject: [PATCH 04/35] chore: update README --- README.md | 49 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 21ffe194..01aca983 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # witnet-solidity-bridge -Open repository containing the smart contracts composing the **Witnet Solidity Bridge** framework. This framework enables Solidity developers and smart contracts operating in a long range of EVM-compatible chains to interact with the [Witnet Oracle Blockchain](https://witnet.io) for retrieving and aggregating offchain public data, and randomness. +Solidity source code of the smart contracts composing the **Witnet EVM Bridge** framework. This framework enables smart contracts operating in a long range of EVM-compatible chains to interact with the [Witnet Oracle Blockchain](https://witnet.io) for retrieving and aggregating offchain public data, or as an entropy source for randomness generation. ## Install the package `$ pnpm install` -## Deploy the whole WSB framework on a new chain +## Deploying the Witnet EVM Bridge on a new chain ### Pre-assessment @@ -29,7 +29,7 @@ Should any artifact require customized contract implementations: `$ pnpm run migrate :` -## Upgrade WSB components on an existing chain +## Upgrding the Witnet EVM Bridge on an existing chain When modifying the existing source code, or the contents of `settings/artifacts` or `settings/specs`, you may need to upgrade some of the artifacts on certain networks. Just add the `--artifacts` parameter and a comma-separated list of the artifacts you need to upgrade. For instance: @@ -44,8 +44,43 @@ Reasons for an upgrade to fail: - You're attempting to upgrade a contract with the same implementation logic as it currently has. - The parameters passed to the upgrade call, as specified in `settings/specs` are not accepted for some reason (see actual revert message for further info). -## Exported assets - -- [Deployed addresses.]("./migrations/addresses.json") -- [Supported chains.]("./settings/networks/index.js") +## Package exported modules + +### `require("witnet-solidity-bridge")` +Javacript methods and resources: + +- List of supported EVM ecosystems: + - `supportedEcosystems()` +- List of supported EVM chains: + - `supportedNetworks()` +- WEB addresses at a given chain: + - `getAddresses(network)` +- WEB artifacts: + - `assets.WitnetOracle` + - `assets.WitnetPriceFeeds` + - `assets.WitnetPriceRouteSolver` + - `assets.WitnetRequest` + - `assets.WitnetRequestBytecodes` + - `assets.WitnetRequestFactory` + - `assets.WitnetRequestTemplate` + - `assets.WitnetUpgrableBase` + +### `require("witnet-solidity-bridge/utils")` + +Javascript utils methods: + +- `fromAscii(str)` +- `getRealmNetworkFromArgs()` +- `getRealmNetworkFromString()` +- `getWitnetArtifactsFromArgs()` +- `getWitnetRequestMethodString(method)` +- `isDryRun(network)` +- `isNullAddress(addr)` +- `padLeft(str, char, size)` +- `prompt(text)` +- `readJsonFromFile(filename)` +- `overwriteJsonFile(filname, extra)` +- `traceHeader(header)` +- `traceTx(tx)` +- `traceVerify(network, verifyArgs)` From 2d4461f98f27a4deb7564721cbe7820a65596ead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 15 Mar 2024 17:49:32 +0100 Subject: [PATCH 05/35] chore: deploy/verify scripts for randomness appliance --- migrations/scripts/5_apps.js | 30 +++++++++++++++--------------- scripts/vanity2gen.js | 15 ++++++++++----- scripts/verify-apps.js | 27 +++++++++++++++++++++++++++ scripts/verify-core.js | 2 +- scripts/verify-impls.js | 2 +- scripts/verify-libs.js | 2 +- src/index.js | 1 + 7 files changed, 56 insertions(+), 23 deletions(-) create mode 100644 scripts/verify-apps.js diff --git a/migrations/scripts/5_apps.js b/migrations/scripts/5_apps.js index 609b64ad..377144c3 100644 --- a/migrations/scripts/5_apps.js +++ b/migrations/scripts/5_apps.js @@ -16,12 +16,10 @@ module.exports = async function (_, network, [, from]) { // --- WitnetRandomnessV20 -------------------------------------------------- await deploy({ - network, - targets, + network, targets, from: utils.isDryRun(network) ? from : specs.WitnetRandomness.from || from, key: targets.WitnetRandomness, - libs: specs.WitnetRandomness?.libs, - immutables: specs.WitnetRandomness?.immutables, + specs: specs.WitnetRandomness, intrinsics: { types: ["address"], values: [ @@ -31,8 +29,10 @@ module.exports = async function (_, network, [, from]) { }) } -async function deploy (specs) { - const { from, key, libs, intrinsics, immutables, network, targets } = specs +async function deploy (target) { + const { from, key, intrinsics, network, specs, targets } = target + const { libs, immutables, vanity } = specs + const salt = vanity ? "0x" + utils.padLeft(vanity.toString(16), "0", 64) : "0x0" const addresses = await utils.readJsonFromFile("./migrations/addresses.json") if (!addresses[network]) addresses[network] = {} @@ -58,20 +58,20 @@ async function deploy (specs) { console.info(" ", "> constructor types:", JSON.stringify(types)) console.info(" ", "> constructor args: ", constructorArgs.slice(2)) } - const coreBytecode = link(contract.toJSON().bytecode, libs, targets) - if (coreBytecode.indexOf("__") > -1) { - console.info(coreBytecode) + const bytecode = link(contract.toJSON().bytecode, libs, targets) + if (bytecode.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 }) + const initCode = bytecode + constructorArgs.slice(2) + const addr = await deployer.determineAddr.call(initCode, salt, { from }) + const tx = await deployer.deploy(initCode, salt || "0x0", { from }) utils.traceTx(tx) - if ((await web3.eth.getCode(coreAddr)).length > 3) { - addresses[network][key] = coreAddr + if ((await web3.eth.getCode(addr)).length > 3) { + addresses[network][key] = addr } else { - console.info(`Error: Contract was not deployed on expected address: ${coreAddr}`) + console.info(`Error: Contract was not deployed on expected address: ${addr}`) process.exit(1) } // save addresses file if required diff --git a/scripts/vanity2gen.js b/scripts/vanity2gen.js index 4b3847d7..f1586154 100644 --- a/scripts/vanity2gen.js +++ b/scripts/vanity2gen.js @@ -1,4 +1,3 @@ -const { assert } = require("chai") const create2 = require("./eth-create2") const fs = require("fs") const utils = require("../src/utils") @@ -23,10 +22,14 @@ module.exports = async function () { artifact = artifacts.require(args[index + 1]) } else if (argv === "--prefix") { prefix = args[index + 1].toLowerCase() - assert(web3.utils.isHexStrict(prefix), "--prefix: invalid hex string") + if (!web3.utils.isHexStrict(prefix)) { + throw new Error("--prefix: invalid hex string") + } } else if (argv === "--suffix") { suffix = args[index + 1].toLowerCase() - assert(web3.utils.isHexStrict(suffix), "--suffix: invalid hex string") + if (!web3.utils.isHexStrict(suffix)) { + throw new Error("--suffix: invalid hex string") + } } else if (argv === "--hits") { hits = parseInt(args[index + 1]) } else if (argv === "--network") { @@ -34,14 +37,16 @@ module.exports = async function () { } 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") + if (!web3.utils.isHexStrict("0x" + hexArgs)) { + throw new Error("--hexArgs: invalid hex string") + } } else if (argv === "--from") { from = args[index + 1] } return argv }) try { - from = from || addresses[ecosystem][network].WitnetDeployer + from = from || addresses[network]?.WitnetDeployer || addresses.default.WitnetDeployer } catch { console.error(`WitnetDeployer must have been previously deployed on network '${network}'.\n`) console.info("Usage:\n") diff --git a/scripts/verify-apps.js b/scripts/verify-apps.js new file mode 100644 index 00000000..092b9d74 --- /dev/null +++ b/scripts/verify-apps.js @@ -0,0 +1,27 @@ +#!/usr/bin/env node + +const utils = require("../src/utils") + +if (process.argv.length < 3) { + console.error("\nUsage:\n\n$ node ./scripts/verify-apps.js : ...OPTIONAL_ARGS\n") + process.exit(0) +} + +const network = process.argv[2].toLowerCase().replaceAll(".", ":") + +const header = network.toUpperCase() + " APPS" +console.info() +console.info(header) +console.info("=".repeat(header.length)) +console.info() + +const artifacts = settings.getArtifacts(network) +const apps = [ + artifacts.WitnetRandomness, +]; +const constructorArgs = require("../migrations/constructorArgs.json") +for (const index in apps) { + utils.traceVerify(network, `${apps[index]} --forceConstructorArgs string:${ + constructorArgs[network][apps[index]] + } --verifiers etherscan`) +} diff --git a/scripts/verify-core.js b/scripts/verify-core.js index 797a8509..d0451de4 100644 --- a/scripts/verify-core.js +++ b/scripts/verify-core.js @@ -3,7 +3,7 @@ const utils = require("../src/utils") if (process.argv.length < 3) { - console.error("\nUsage:\n\n$ node ./scripts/verify-proxies.js : ...OPTIONAL_ARGS\n") + console.error("\nUsage:\n\n$ node ./scripts/verify-core.js : ...OPTIONAL_ARGS\n") process.exit(0) } diff --git a/scripts/verify-impls.js b/scripts/verify-impls.js index c888ea61..eccb7290 100644 --- a/scripts/verify-impls.js +++ b/scripts/verify-impls.js @@ -4,7 +4,7 @@ const settings = require("../settings") const utils = require("../src/utils") if (process.argv.length < 3) { - console.error("\nUsage:\n\n$ node ./scripts/verify-proxies.js : ...OPTIONAL_ARGS\n") + console.error("\nUsage:\n\n$ node ./scripts/verify-impls.js : ...OPTIONAL_ARGS\n") process.exit(0) } diff --git a/scripts/verify-libs.js b/scripts/verify-libs.js index 79e79aa8..a35c4d61 100644 --- a/scripts/verify-libs.js +++ b/scripts/verify-libs.js @@ -4,7 +4,7 @@ const settings = require("../settings") const utils = require("../src/utils") if (process.argv.length < 3) { - console.error("\nUsage:\n\n$ node ./scripts/verify-proxies.js : ...OPTIONAL_ARGS\n") + console.error("\nUsage:\n\n$ node ./scripts/verify-libs.js : ...OPTIONAL_ARGS\n") process.exit(0) } diff --git a/src/index.js b/src/index.js index 1f475f7d..01f7d5b3 100644 --- a/src/index.js +++ b/src/index.js @@ -33,6 +33,7 @@ module.exports = { WitnetOracle: require("../artifacts/contracts/WitnetOracle.sol/WitnetOracle.json"), WitnetPriceFeeds: require("../artifacts/contracts/WitnetPriceFeeds.sol/WitnetPriceFeeds.json"), WitnetPriceRouteSolver: require("../artifacts/contracts/interfaces/IWitnetPriceSolver.sol/IWitnetPriceSolver.json"), + WitnetRandomness: require("../artifacts/contracts/WitnetRandomness.sol/WitnetRandomness.json"), WitnetRequest: require("../artifacts/contracts/WitnetRequest.sol/WitnetRequest.json"), WitnetRequestBytecodes: require("../artifacts/contracts/WitnetRequestBytecodes.sol/WitnetRequestBytecodes.json"), WitnetRequestFactory: require("../artifacts/contracts/WitnetRequestFactory.sol/WitnetRequestFactory.json"), From a57713ad59423901d9cd4880508dbe84b5c3470c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 15 Mar 2024 17:50:46 +0100 Subject: [PATCH 06/35] feat(wrb): limit max acceptable reward --- .../defaults/WitnetOracleTrustableBase.sol | 7 ++++- contracts/interfaces/IWitnetOracleEvents.sol | 28 +++++++++++++------ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/contracts/core/defaults/WitnetOracleTrustableBase.sol b/contracts/core/defaults/WitnetOracleTrustableBase.sol index 813a8466..c3c952c8 100644 --- a/contracts/core/defaults/WitnetOracleTrustableBase.sol +++ b/contracts/core/defaults/WitnetOracleTrustableBase.sol @@ -49,7 +49,12 @@ abstract contract WitnetOracleTrustableBase require( _getMsgValue() >= _baseFee, "WitnetOracle: insufficient reward" - ); _; + ); + require( + _getMsgValue() <= _baseFee * 10, + "WitnetOracle: too much reward" + ); + _; } modifier checkSLA(WitnetV2.RadonSLA calldata sla) { diff --git a/contracts/interfaces/IWitnetOracleEvents.sol b/contracts/interfaces/IWitnetOracleEvents.sol index 3ff8ffb1..599ba0ff 100644 --- a/contracts/interfaces/IWitnetOracleEvents.sol +++ b/contracts/interfaces/IWitnetOracleEvents.sol @@ -13,21 +13,31 @@ interface IWitnetOracleEvents { ); /// Emitted when a query with no callback gets reported into the WRB. - event WitnetQueryResponse(uint256 indexed id, uint256 evmGasPrice); + event WitnetQueryResponse( + uint256 id, + uint256 evmGasPrice + ); /// Emitted when a query with a callback gets successfully reported into the WRB. - event WitnetQueryResponseDelivered(uint256 indexed id, uint256 evmGasPrice, uint256 evmCallbackGas); + event WitnetQueryResponseDelivered( + uint256 indexed id, + uint256 evmGasPrice, + uint256 evmCallbackGas + ); /// Emitted when a query with a callback cannot get reported into the WRB. event WitnetQueryResponseDeliveryFailed( - uint256 indexed id, - bytes resultCborBytes, - uint256 evmGasPrice, - uint256 evmCallbackGas, - string evmCallbackRevertReason - ); + uint256 indexed id, + bytes resultCborBytes, + uint256 evmGasPrice, + uint256 evmCallbackActualGas, + string evmCallbackRevertReason + ); /// Emitted when the reward of some not-yet reported query is upgraded. - event WitnetQueryRewardUpgraded(uint256 indexed id, uint256 evmReward); + event WitnetQueryRewardUpgraded( + uint256 indexed id, + uint256 evmReward + ); } From 41f6741f951812ce562083aedb02e6c646e74c02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 15 Mar 2024 17:51:26 +0100 Subject: [PATCH 07/35] fix(rng): estimateRandomizeFee by providing the witnetRadHash --- contracts/apps/WitnetRandomnessV20.sol | 14 ++++++-------- contracts/interfaces/IWitnetRandomness.sol | 7 ++++++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/contracts/apps/WitnetRandomnessV20.sol b/contracts/apps/WitnetRandomnessV20.sol index fa81b2a9..8226ecb3 100644 --- a/contracts/apps/WitnetRandomnessV20.sol +++ b/contracts/apps/WitnetRandomnessV20.sol @@ -119,7 +119,10 @@ contract WitnetRandomnessV20 { return ( (100 + __witnetBaseFeeOverheadPercentage) - * __witnet.estimateBaseFee(_evmGasPrice, 32) + * __witnet.estimateBaseFee( + _evmGasPrice, + witnetRadHash + ) ) / 100; } @@ -353,8 +356,6 @@ contract WitnetRandomnessV20 /// @notice Requests the Witnet oracle to generate an EVM-agnostic and trustless source of randomness. /// @dev Only one randomness request per block will be actually posted to the Witnet Oracle. - /// @dev Only consumes the exact randomize fare as required for the `tx.gasprice`. Remaining funds will - /// @dev be transfered back to `msg.sender`. /// @return _witnetEvmReward Funds actually paid as randomize fee. function randomize() external payable @@ -362,11 +363,7 @@ contract WitnetRandomnessV20 returns (uint256 _witnetEvmReward) { if (__storage().lastRandomizeBlock < block.number) { - _witnetEvmReward = estimateRandomizeFee(tx.gasprice); - require( - msg.value >= _witnetEvmReward, - "WitnetRandomness: insufficient reward" - ); + _witnetEvmReward = msg.value; // Post the Witnet Randomness request: uint _witnetQueryId = __witnet.postRequest{ value: _witnetEvmReward @@ -385,6 +382,7 @@ contract WitnetRandomnessV20 // Throw event: emit Randomizing( block.number, + tx.gasprice, _witnetQueryId, _witnetEvmReward ); diff --git a/contracts/interfaces/IWitnetRandomness.sol b/contracts/interfaces/IWitnetRandomness.sol index 5db5783f..8fa766b5 100644 --- a/contracts/interfaces/IWitnetRandomness.sol +++ b/contracts/interfaces/IWitnetRandomness.sol @@ -8,7 +8,12 @@ import "../WitnetOracle.sol"; /// @author Witnet Foundation. interface IWitnetRandomness { - event Randomizing(uint256 blockNumber, uint256 witnetQueryId, uint256 witnetEvmReward); + event Randomizing( + uint256 blockNumber, + uint256 evmTxGasPrice, + uint256 witnetQueryId, + uint256 witnetEvmReward + ); /// @notice Returns amount of wei required to be paid as a fee when requesting randomization with a /// transaction gas price as the one given. From e4dd342d91582c92752533bce31f564b92bb2b70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 15 Mar 2024 17:53:17 +0100 Subject: [PATCH 08/35] chore: fmt! --- migrations/scripts/5_apps.js | 3 ++- scripts/vanity2gen.js | 1 - scripts/verify-apps.js | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/migrations/scripts/5_apps.js b/migrations/scripts/5_apps.js index 377144c3..1784e9d6 100644 --- a/migrations/scripts/5_apps.js +++ b/migrations/scripts/5_apps.js @@ -16,7 +16,8 @@ module.exports = async function (_, network, [, from]) { // --- WitnetRandomnessV20 -------------------------------------------------- await deploy({ - network, targets, + network, + targets, from: utils.isDryRun(network) ? from : specs.WitnetRandomness.from || from, key: targets.WitnetRandomness, specs: specs.WitnetRandomness, diff --git a/scripts/vanity2gen.js b/scripts/vanity2gen.js index f1586154..c05cb8ec 100644 --- a/scripts/vanity2gen.js +++ b/scripts/vanity2gen.js @@ -7,7 +7,6 @@ const addresses = require("../migrations/addresses") module.exports = async function () { let artifact let count = 0 - let ecosystem = "default" let from let hits = 10 let offset = 0 diff --git a/scripts/verify-apps.js b/scripts/verify-apps.js index 092b9d74..d4b1790c 100644 --- a/scripts/verify-apps.js +++ b/scripts/verify-apps.js @@ -1,5 +1,6 @@ #!/usr/bin/env node +const settings = require("../settings") const utils = require("../src/utils") if (process.argv.length < 3) { @@ -18,7 +19,7 @@ console.info() const artifacts = settings.getArtifacts(network) const apps = [ artifacts.WitnetRandomness, -]; +] const constructorArgs = require("../migrations/constructorArgs.json") for (const index in apps) { utils.traceVerify(network, `${apps[index]} --forceConstructorArgs string:${ From cf1386abcd72ade36569eb648d79b1631380e99a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 15 Mar 2024 17:53:35 +0100 Subject: [PATCH 09/35] chore: bump package version to 2.0.8 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5d17885c..1e250eaa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "witnet-solidity-bridge", - "version": "2.0.7", + "version": "2.0.8", "description": "Witnet Solidity Bridge contracts for EVM-compatible chains", "author": "Witnet Foundation ", "license": "MIT", From d14e890f20ff43bd6a00ae4d73ae277e5533d27d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 15 Mar 2024 18:01:37 +0100 Subject: [PATCH 10/35] feat: deploy WitnetRandomness only if explicitly specified or present in addresses file --- migrations/scripts/5_apps.js | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/migrations/scripts/5_apps.js b/migrations/scripts/5_apps.js index 1784e9d6..1f38d1bd 100644 --- a/migrations/scripts/5_apps.js +++ b/migrations/scripts/5_apps.js @@ -39,13 +39,12 @@ async function deploy (target) { if (!addresses[network]) addresses[network] = {} const selection = utils.getWitnetArtifactsFromArgs() - const contract = artifacts.require(key) if ( - utils.isNullAddress(addresses[network][key]) || - (await web3.eth.getCode(addresses[network][key])).length < 3 || - selection.includes(key) || - (libs && selection.filter(item => libs.includes(item)).length > 0) + addresses[network][key] === "" || + selection.includes(key) || + (libs && selection.filter(item => libs.includes(item)).length > 0) || + (!utils.isNullAddress(addresses[network][key]) && (await web3.eth.getCode(addresses[network][key])).length < 3) ) { utils.traceHeader(`Deploying '${key}'...`) console.info(" ", "> account: ", from) @@ -83,19 +82,21 @@ async function deploy (target) { args[network][key] = constructorArgs.slice(2) await utils.overwriteJsonFile("./migrations/constructorArgs.json", args) } - } else { + } else if (addresses[network][key]) { utils.traceHeader(`Skipped '${key}'`) } - contract.address = addresses[network][key] - for (const index in libs) { - const libname = libs[index] - const lib = artifacts.require(libname) - contract.link(lib) - console.info(" ", "> external library: ", `${libname}@${lib.address}`) - }; - console.info(" ", "> contract address: ", contract.address) - console.info(" ", "> contract codehash:", web3.utils.soliditySha3(await web3.eth.getCode(contract.address))) - console.info() + if (!utils.isNullAddress(addresses[network][key])) { + contract.address = addresses[network][key] + for (const index in libs) { + const libname = libs[index] + const lib = artifacts.require(libname) + contract.link(lib) + console.info(" ", "> external library: ", `${libname}@${lib.address}`) + }; + console.info(" ", "> contract address: ", contract.address) + console.info(" ", "> contract codehash:", web3.utils.soliditySha3(await web3.eth.getCode(contract.address))) + console.info() + } return contract } From d1637602c7b3f776c0943dde67b2c03d85fe3c0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 15 Mar 2024 18:14:33 +0100 Subject: [PATCH 11/35] chore: upgrade WPF to v2.0.8 on optimism:sepolia --- migrations/addresses.json | 4 ++-- migrations/constructorArgs.json | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/migrations/addresses.json b/migrations/addresses.json index f786dbe6..a293f31c 100644 --- a/migrations/addresses.json +++ b/migrations/addresses.json @@ -23,7 +23,7 @@ "WitnetPriceFeedsLib": "0x85aa4A0fDa112c47d4216448EE4D49Afd072675e", "WitnetOracleDataLib": "0xBeFdE8285b613b17CE94705b53A57E5509D40397", "WitnetOracleTrustableOvm2": "0x62cc7Ed0d00C7d34775A24D545Edf50721710962", - "WitnetPriceFeedsDefault": "0xF80CA682c967D8155de7ed9C9355dF661B08e5aD", + "WitnetPriceFeedsDefault": "0x73912b1E13C67485D6d38Ef4F2B750C67FD99DA9", "WitnetRequestBytecodesDefault": "0x65fB7A0C98719e967546317222dfF90A73C42296", "WitnetRequestFactoryDefault": "0x23873d132e4Ebc34C19F405cf2bFe31dA21630c2" }, @@ -34,7 +34,7 @@ "WitnetPriceFeedsLib": "0x85aa4A0fDa112c47d4216448EE4D49Afd072675e", "WitnetOracleDataLib": "0xBeFdE8285b613b17CE94705b53A57E5509D40397", "WitnetOracleTrustableObscuro": "0x24988fCB6bb6bCB5933CEeB9a729807A4d8C260E", - "WitnetPriceFeedsDefault": "0x1DbD1691979335481E8376ccB3300725a7bD7f1d", + "WitnetPriceFeedsDefault": "", "WitnetRequestBytecodesDefault": "0x05e81E99ba36dC08079193D0Fad4Eb579E43ECE7", "WitnetRequestFactoryDefault": "0x8C4ed866d3418c05CA0325524624EC6CE52ADC44" } diff --git a/migrations/constructorArgs.json b/migrations/constructorArgs.json index bcf32d97..3e93fcef 100644 --- a/migrations/constructorArgs.json +++ b/migrations/constructorArgs.json @@ -9,8 +9,7 @@ "WitnetRequestBytecodesDefault": "0000000000000000000000000000000000000000000000000000000000000001322e302e372d3264386665303400000000000000000000000000000000000000", "WitnetRequestFactoryDefault": "00000000000000000000000077703ae126b971c9946d562f41dd47071da00777000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e372d3264386665303400000000000000000000000000000000000000", "WitnetOracleTrustableOvm2": "000000000000000000000000000db36997af1f02209a6f995883b9b699900000000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e372d3264386665303400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e3aa000000000000000000000000000000000000000000000000000000000000fef90000000000000000000000000000000000000000000000000000000000010faa0000000000000000000000000000000000000000000000000000000000004e20", - "WitnetPriceFeedsDefault": "00000000000000000000000077703ae126b971c9946d562f41dd47071da007770000000000000000000000000000000000000000000000000000000000000001322e302e372d3264386665303400000000000000000000000000000000000000", - "WitnetOracleTrustableObscuro": "" + "WitnetPriceFeedsDefault": "00000000000000000000000077703ae126b971c9946d562f41dd47071da007770000000000000000000000000000000000000000000000000000000000000001322e302e382d6431346538393000000000000000000000000000000000000000" }, "ten:testnet": { "WitnetRequestBytecodesDefault": "0000000000000000000000000000000000000000000000000000000000000001322e302e372d3033346663383100000000000000000000000000000000000000", From 5ea91b7f34f4e795de9dad75a03ee7155870909f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 15 Mar 2024 18:17:49 +0100 Subject: [PATCH 12/35] chore: upgrade WRB to v2.0.8 on optimism:sepolia --- migrations/addresses.json | 4 ++-- migrations/constructorArgs.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/migrations/addresses.json b/migrations/addresses.json index a293f31c..262b85f2 100644 --- a/migrations/addresses.json +++ b/migrations/addresses.json @@ -22,7 +22,7 @@ "WitnetEncodingLib": "0xf321bcD29CFc6134c9Bf42F759f428F3A6010919", "WitnetPriceFeedsLib": "0x85aa4A0fDa112c47d4216448EE4D49Afd072675e", "WitnetOracleDataLib": "0xBeFdE8285b613b17CE94705b53A57E5509D40397", - "WitnetOracleTrustableOvm2": "0x62cc7Ed0d00C7d34775A24D545Edf50721710962", + "WitnetOracleTrustableOvm2": "0xec03FD9B5F300BB931A76D1646ECb71Ff8b775cA", "WitnetPriceFeedsDefault": "0x73912b1E13C67485D6d38Ef4F2B750C67FD99DA9", "WitnetRequestBytecodesDefault": "0x65fB7A0C98719e967546317222dfF90A73C42296", "WitnetRequestFactoryDefault": "0x23873d132e4Ebc34C19F405cf2bFe31dA21630c2" @@ -33,7 +33,7 @@ "WitnetEncodingLib": "0xf321bcD29CFc6134c9Bf42F759f428F3A6010919", "WitnetPriceFeedsLib": "0x85aa4A0fDa112c47d4216448EE4D49Afd072675e", "WitnetOracleDataLib": "0xBeFdE8285b613b17CE94705b53A57E5509D40397", - "WitnetOracleTrustableObscuro": "0x24988fCB6bb6bCB5933CEeB9a729807A4d8C260E", + "WitnetOracleTrustableObscuro": "", "WitnetPriceFeedsDefault": "", "WitnetRequestBytecodesDefault": "0x05e81E99ba36dC08079193D0Fad4Eb579E43ECE7", "WitnetRequestFactoryDefault": "0x8C4ed866d3418c05CA0325524624EC6CE52ADC44" diff --git a/migrations/constructorArgs.json b/migrations/constructorArgs.json index 3e93fcef..bdafbe9d 100644 --- a/migrations/constructorArgs.json +++ b/migrations/constructorArgs.json @@ -8,7 +8,7 @@ "optimism:sepolia": { "WitnetRequestBytecodesDefault": "0000000000000000000000000000000000000000000000000000000000000001322e302e372d3264386665303400000000000000000000000000000000000000", "WitnetRequestFactoryDefault": "00000000000000000000000077703ae126b971c9946d562f41dd47071da00777000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e372d3264386665303400000000000000000000000000000000000000", - "WitnetOracleTrustableOvm2": "000000000000000000000000000db36997af1f02209a6f995883b9b699900000000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e372d3264386665303400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e3aa000000000000000000000000000000000000000000000000000000000000fef90000000000000000000000000000000000000000000000000000000000010faa0000000000000000000000000000000000000000000000000000000000004e20", + "WitnetOracleTrustableOvm2": "000000000000000000000000000db36997af1f02209a6f995883b9b699900000000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e382d6431363337363000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e3aa000000000000000000000000000000000000000000000000000000000000fef90000000000000000000000000000000000000000000000000000000000010faa0000000000000000000000000000000000000000000000000000000000004e20", "WitnetPriceFeedsDefault": "00000000000000000000000077703ae126b971c9946d562f41dd47071da007770000000000000000000000000000000000000000000000000000000000000001322e302e382d6431346538393000000000000000000000000000000000000000" }, "ten:testnet": { From 5f305d6eb26e5665b8be32f33bba4f33a122db02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 15 Mar 2024 18:43:54 +0100 Subject: [PATCH 13/35] chore: deploy WitnetRandomnessV20 on optimism:sepolia --- migrations/addresses.json | 3 ++- migrations/constructorArgs.json | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/migrations/addresses.json b/migrations/addresses.json index 262b85f2..41c05054 100644 --- a/migrations/addresses.json +++ b/migrations/addresses.json @@ -25,7 +25,8 @@ "WitnetOracleTrustableOvm2": "0xec03FD9B5F300BB931A76D1646ECb71Ff8b775cA", "WitnetPriceFeedsDefault": "0x73912b1E13C67485D6d38Ef4F2B750C67FD99DA9", "WitnetRequestBytecodesDefault": "0x65fB7A0C98719e967546317222dfF90A73C42296", - "WitnetRequestFactoryDefault": "0x23873d132e4Ebc34C19F405cf2bFe31dA21630c2" + "WitnetRequestFactoryDefault": "0x23873d132e4Ebc34C19F405cf2bFe31dA21630c2", + "WitnetRandomnessV20": "0x2C821B0Ed577a600B29CcD89d0037402Ba0B2Eea" }, "ten:testnet": { "WitnetProxy": "0x4563C77E85c1374754ffec3e6220d13Ddc8620eF", diff --git a/migrations/constructorArgs.json b/migrations/constructorArgs.json index bdafbe9d..9abba040 100644 --- a/migrations/constructorArgs.json +++ b/migrations/constructorArgs.json @@ -6,6 +6,7 @@ "WitnetPriceFeedsDefault": "" }, "optimism:sepolia": { + "WitnetRandomnessV20": "00000000000000000000000077703ae126b971c9946d562f41dd47071da00777", "WitnetRequestBytecodesDefault": "0000000000000000000000000000000000000000000000000000000000000001322e302e372d3264386665303400000000000000000000000000000000000000", "WitnetRequestFactoryDefault": "00000000000000000000000077703ae126b971c9946d562f41dd47071da00777000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e372d3264386665303400000000000000000000000000000000000000", "WitnetOracleTrustableOvm2": "000000000000000000000000000db36997af1f02209a6f995883b9b699900000000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e382d6431363337363000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e3aa000000000000000000000000000000000000000000000000000000000000fef90000000000000000000000000000000000000000000000000000000000010faa0000000000000000000000000000000000000000000000000000000000004e20", From 4588b66ba78e3f49167123a688b0e1dcb56e3fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 15 Mar 2024 18:47:41 +0100 Subject: [PATCH 14/35] chore: verify WSB on optimism:sepolia into etherscan and sourcify --- migrations/addresses.json | 6 +++--- migrations/constructorArgs.json | 2 +- scripts/verify-apps.js | 2 +- settings/networks.js | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/migrations/addresses.json b/migrations/addresses.json index 41c05054..da28ff0c 100644 --- a/migrations/addresses.json +++ b/migrations/addresses.json @@ -18,11 +18,11 @@ }, "optimism:sepolia": { "WitnetProxy": "0x58Bd0091748d0438f379bbf7D8BfF3a624CEbc3F", - "WitnetErrorsLib": "0x19900f2432ffC755224bd9e5411c5B8E07883eC8", + "WitnetErrorsLib": "0x4f2F381Ed2020095F1a1B5a0BDe5AB30da916BC9", "WitnetEncodingLib": "0xf321bcD29CFc6134c9Bf42F759f428F3A6010919", "WitnetPriceFeedsLib": "0x85aa4A0fDa112c47d4216448EE4D49Afd072675e", - "WitnetOracleDataLib": "0xBeFdE8285b613b17CE94705b53A57E5509D40397", - "WitnetOracleTrustableOvm2": "0xec03FD9B5F300BB931A76D1646ECb71Ff8b775cA", + "WitnetOracleDataLib": "0x72b43a4062c81918112646b32268f7A748F8Fe08", + "WitnetOracleTrustableOvm2": "0x6a587296dEc2cAd88233bf6Bda862ED5396730b0", "WitnetPriceFeedsDefault": "0x73912b1E13C67485D6d38Ef4F2B750C67FD99DA9", "WitnetRequestBytecodesDefault": "0x65fB7A0C98719e967546317222dfF90A73C42296", "WitnetRequestFactoryDefault": "0x23873d132e4Ebc34C19F405cf2bFe31dA21630c2", diff --git a/migrations/constructorArgs.json b/migrations/constructorArgs.json index 9abba040..e0e46200 100644 --- a/migrations/constructorArgs.json +++ b/migrations/constructorArgs.json @@ -9,7 +9,7 @@ "WitnetRandomnessV20": "00000000000000000000000077703ae126b971c9946d562f41dd47071da00777", "WitnetRequestBytecodesDefault": "0000000000000000000000000000000000000000000000000000000000000001322e302e372d3264386665303400000000000000000000000000000000000000", "WitnetRequestFactoryDefault": "00000000000000000000000077703ae126b971c9946d562f41dd47071da00777000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e372d3264386665303400000000000000000000000000000000000000", - "WitnetOracleTrustableOvm2": "000000000000000000000000000db36997af1f02209a6f995883b9b699900000000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e382d6431363337363000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e3aa000000000000000000000000000000000000000000000000000000000000fef90000000000000000000000000000000000000000000000000000000000010faa0000000000000000000000000000000000000000000000000000000000004e20", + "WitnetOracleTrustableOvm2": "000000000000000000000000000db36997af1f02209a6f995883b9b699900000000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e382d3565613931623700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e3aa000000000000000000000000000000000000000000000000000000000000fef90000000000000000000000000000000000000000000000000000000000010faa0000000000000000000000000000000000000000000000000000000000004e20", "WitnetPriceFeedsDefault": "00000000000000000000000077703ae126b971c9946d562f41dd47071da007770000000000000000000000000000000000000000000000000000000000000001322e302e382d6431346538393000000000000000000000000000000000000000" }, "ten:testnet": { diff --git a/scripts/verify-apps.js b/scripts/verify-apps.js index d4b1790c..cac4e373 100644 --- a/scripts/verify-apps.js +++ b/scripts/verify-apps.js @@ -24,5 +24,5 @@ const constructorArgs = require("../migrations/constructorArgs.json") for (const index in apps) { utils.traceVerify(network, `${apps[index]} --forceConstructorArgs string:${ constructorArgs[network][apps[index]] - } --verifiers etherscan`) + }`) } diff --git a/settings/networks.js b/settings/networks.js index deb29af1..6a43e094 100644 --- a/settings/networks.js +++ b/settings/networks.js @@ -295,9 +295,9 @@ module.exports = { port: 8503, network_id: 11155420, verify: { - apiKey: process.env.ETHERSCAN_API_KEY, - apiUrl: "https://optimism-sepolia.blockscout.com/api", - explorerUrl: "https://optimism-sepolia.blockscout.com/", + apiKey: process.env.ETHERSCAN_OPTIMISM_API_KEY, + apiUrl: "https://api-sepolia-optimistic.etherscan.io/api", + explorerUrl: "https://sepolia-optimism.etherscan.io/address", }, }, "optimism:mainnet": { From 71f3a8bf3a1f1442c8289e80614f16cbbdde7dac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 15 Mar 2024 19:08:23 +0100 Subject: [PATCH 15/35] feat: package script verify:apps --- migrations/addresses.json | 3 ++- migrations/scripts/5_apps.js | 17 +++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/migrations/addresses.json b/migrations/addresses.json index da28ff0c..d06ff133 100644 --- a/migrations/addresses.json +++ b/migrations/addresses.json @@ -3,6 +3,7 @@ "WitnetDeployer": "0x03232aBE800D1638B30432FeEF300581De323a4E", "WitnetOracle": "0x77703aE126B971c9946d562F41Dd47071dA00777", "WitnetPriceFeeds": "0x1111AbA2164AcdC6D291b08DfB374280035E1111", + "WitnetRandomness": "0x2C821B0Ed577a600B29CcD89d0037402Ba0B2Eea", "WitnetRequestBytecodes": "0x000B61Fe075F545fd37767f40391658275900000", "WitnetRequestFactory": "0x000DB36997AF1F02209A6F995883B9B699900000" }, @@ -26,7 +27,7 @@ "WitnetPriceFeedsDefault": "0x73912b1E13C67485D6d38Ef4F2B750C67FD99DA9", "WitnetRequestBytecodesDefault": "0x65fB7A0C98719e967546317222dfF90A73C42296", "WitnetRequestFactoryDefault": "0x23873d132e4Ebc34C19F405cf2bFe31dA21630c2", - "WitnetRandomnessV20": "0x2C821B0Ed577a600B29CcD89d0037402Ba0B2Eea" + "WitnetRandomness": "0x2C821B0Ed577a600B29CcD89d0037402Ba0B2Eea" }, "ten:testnet": { "WitnetProxy": "0x4563C77E85c1374754ffec3e6220d13Ddc8620eF", diff --git a/migrations/scripts/5_apps.js b/migrations/scripts/5_apps.js index 1f38d1bd..0bb1c1ea 100644 --- a/migrations/scripts/5_apps.js +++ b/migrations/scripts/5_apps.js @@ -19,7 +19,7 @@ module.exports = async function (_, network, [, from]) { network, targets, from: utils.isDryRun(network) ? from : specs.WitnetRandomness.from || from, - key: targets.WitnetRandomness, + key: "WitnetRandomness", specs: specs.WitnetRandomness, intrinsics: { types: ["address"], @@ -39,7 +39,8 @@ async function deploy (target) { if (!addresses[network]) addresses[network] = {} const selection = utils.getWitnetArtifactsFromArgs() - const contract = artifacts.require(key) + const artifact = artifacts.require(key) + const contract = artifacts.require(targets[key]) if ( addresses[network][key] === "" || selection.includes(key) || @@ -79,22 +80,26 @@ async function deploy (target) { await utils.overwriteJsonFile("./migrations/addresses.json", addresses) const args = await utils.readJsonFromFile("./migrations/constructorArgs.json") if (!args[network]) args[network] = {} - args[network][key] = constructorArgs.slice(2) + args[network][targets[key]] = constructorArgs.slice(2) await utils.overwriteJsonFile("./migrations/constructorArgs.json", args) } } else if (addresses[network][key]) { utils.traceHeader(`Skipped '${key}'`) } if (!utils.isNullAddress(addresses[network][key])) { + artifact.address = addresses[network][key] contract.address = addresses[network][key] for (const index in libs) { const libname = libs[index] const lib = artifacts.require(libname) contract.link(lib) - console.info(" ", "> external library: ", `${libname}@${lib.address}`) + console.info(" ", "> external library: ", `${libname}@${lib.address}`) }; - console.info(" ", "> contract address: ", contract.address) - console.info(" ", "> contract codehash:", web3.utils.soliditySha3(await web3.eth.getCode(contract.address))) + const appliance = await artifact.deployed() + console.info(" ", "> appliance address: ", appliance.address) + console.info(" ", "> appliance class: ", await appliance.class({ from })) + console.info(" ", "> appliance codehash:", web3.utils.soliditySha3(await web3.eth.getCode(appliance.address))) + console.info(" ", "> appliance specs: ", await appliance.specs({ from })) console.info() } return contract From e67ba95853aec2ea0451ff7a10e7adb71e9cdcef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 15 Mar 2024 19:18:42 +0100 Subject: [PATCH 16/35] chore: declare WitnetRandomness to be IWitnetOracleEvents emitter --- contracts/{apps => }/WitnetFeeds.sol | 6 +++--- contracts/WitnetPriceFeeds.sol | 2 +- contracts/WitnetRandomness.sol | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) rename contracts/{apps => }/WitnetFeeds.sol (88%) diff --git a/contracts/apps/WitnetFeeds.sol b/contracts/WitnetFeeds.sol similarity index 88% rename from contracts/apps/WitnetFeeds.sol rename to contracts/WitnetFeeds.sol index 97462e64..67e97247 100644 --- a/contracts/apps/WitnetFeeds.sol +++ b/contracts/WitnetFeeds.sol @@ -2,9 +2,9 @@ pragma solidity >=0.7.0 <0.9.0; -import "../interfaces/IFeeds.sol"; -import "../interfaces/IWitnetFeeds.sol"; -import "../interfaces/IWitnetFeedsAdmin.sol"; +import "./interfaces/IFeeds.sol"; +import "./interfaces/IWitnetFeeds.sol"; +import "./interfaces/IWitnetFeedsAdmin.sol"; import "ado-contracts/contracts/interfaces/IERC2362.sol"; diff --git a/contracts/WitnetPriceFeeds.sol b/contracts/WitnetPriceFeeds.sol index 709f2958..cc9c83e4 100644 --- a/contracts/WitnetPriceFeeds.sol +++ b/contracts/WitnetPriceFeeds.sol @@ -2,7 +2,7 @@ pragma solidity >=0.7.0 <0.9.0; -import "./apps/WitnetFeeds.sol"; +import "./WitnetFeeds.sol"; import "./interfaces/IWitnetPriceFeeds.sol"; import "./interfaces/IWitnetPriceSolverDeployer.sol"; diff --git a/contracts/WitnetRandomness.sol b/contracts/WitnetRandomness.sol index ac1dc3fc..ecefa88b 100644 --- a/contracts/WitnetRandomness.sol +++ b/contracts/WitnetRandomness.sol @@ -2,10 +2,12 @@ pragma solidity >=0.8.0 <0.9.0; +import "./interfaces/IWitnetOracleEvents.sol"; import "./interfaces/IWitnetRandomness.sol"; abstract contract WitnetRandomness is + IWitnetOracleEvents, IWitnetRandomness { function class() virtual external view returns (string memory); From 9b5f6413dd313d9ae250ee47465c5be07e9f5009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 15 Mar 2024 20:09:00 +0100 Subject: [PATCH 17/35] fix(rng): recursiveness on fetchRandomness* --- contracts/apps/WitnetRandomnessV20.sol | 15 ++++++++------- contracts/interfaces/IWitnetRandomness.sol | 5 ++--- migrations/addresses.json | 5 ++--- migrations/scripts/5_apps.js | 14 ++++++++------ 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/contracts/apps/WitnetRandomnessV20.sol b/contracts/apps/WitnetRandomnessV20.sol index 8226ecb3..10b68cb9 100644 --- a/contracts/apps/WitnetRandomnessV20.sol +++ b/contracts/apps/WitnetRandomnessV20.sol @@ -42,7 +42,10 @@ contract WitnetRandomnessV20 require( address(_witnet) == address(0) || _witnet.specs() == type(IWitnetOracle).interfaceId, - "WitnetRandomnessV2: uncompliant WitnetOracle" + string(abi.encodePacked( + class(), + ": uncompliant WitnetOracle" + )) ); WitnetRequestBytecodes _registry = witnet().registry(); { @@ -138,12 +141,11 @@ contract WitnetRandomnessV20 virtual override returns (bytes32) { - Randomize storage __randomize = __storage().randomize_[_blockNumber]; - - if (__randomize.witnetQueryId == 0) { + if (__storage().randomize_[_blockNumber].witnetQueryId == 0) { _blockNumber = getRandomizeNextBlock(_blockNumber); } + Randomize storage __randomize = __storage().randomize_[_blockNumber]; uint256 _witnetQueryId = __randomize.witnetQueryId; require( _witnetQueryId != 0, @@ -190,12 +192,11 @@ contract WitnetRandomnessV20 uint256 _witnetResultFinalityBlock ) { - Randomize storage __randomize = __storage().randomize_[_blockNumber]; - - if (__randomize.witnetQueryId == 0) { + if (__storage().randomize_[_blockNumber].witnetQueryId == 0) { _blockNumber = getRandomizeNextBlock(_blockNumber); } + Randomize storage __randomize = __storage().randomize_[_blockNumber]; uint256 _witnetQueryId = __randomize.witnetQueryId; require( _witnetQueryId != 0, diff --git a/contracts/interfaces/IWitnetRandomness.sol b/contracts/interfaces/IWitnetRandomness.sol index 8fa766b5..fbb787b8 100644 --- a/contracts/interfaces/IWitnetRandomness.sol +++ b/contracts/interfaces/IWitnetRandomness.sol @@ -93,9 +93,8 @@ interface IWitnetRandomness { /// @notice Requests the Witnet oracle to generate an EVM-agnostic and trustless source of randomness. /// @dev Only one randomness request per block will be actually posted to the Witnet Oracle. - /// @dev Only consumes the exact randomize fare as expected for the `tx.gasprice`. Remaining funds will - /// @dev be transfered back to `msg.sender`. - /// @return Funds actually paid as randomize fee. + /// @dev Unused funds will be transfered back to the `msg.sender`. + /// @return Funds actually paid as randomize fee. function randomize() external payable returns (uint256); /// @notice Returns address of the Witnet Oracle bridging contract being used for solving randomness requests. diff --git a/migrations/addresses.json b/migrations/addresses.json index d06ff133..9b3806b9 100644 --- a/migrations/addresses.json +++ b/migrations/addresses.json @@ -3,7 +3,6 @@ "WitnetDeployer": "0x03232aBE800D1638B30432FeEF300581De323a4E", "WitnetOracle": "0x77703aE126B971c9946d562F41Dd47071dA00777", "WitnetPriceFeeds": "0x1111AbA2164AcdC6D291b08DfB374280035E1111", - "WitnetRandomness": "0x2C821B0Ed577a600B29CcD89d0037402Ba0B2Eea", "WitnetRequestBytecodes": "0x000B61Fe075F545fd37767f40391658275900000", "WitnetRequestFactory": "0x000DB36997AF1F02209A6F995883B9B699900000" }, @@ -25,9 +24,9 @@ "WitnetOracleDataLib": "0x72b43a4062c81918112646b32268f7A748F8Fe08", "WitnetOracleTrustableOvm2": "0x6a587296dEc2cAd88233bf6Bda862ED5396730b0", "WitnetPriceFeedsDefault": "0x73912b1E13C67485D6d38Ef4F2B750C67FD99DA9", + "WitnetRandomnessV20": "0x378C86Df3beed6808BFfbfCBF96B0e8abef5f70D", "WitnetRequestBytecodesDefault": "0x65fB7A0C98719e967546317222dfF90A73C42296", - "WitnetRequestFactoryDefault": "0x23873d132e4Ebc34C19F405cf2bFe31dA21630c2", - "WitnetRandomness": "0x2C821B0Ed577a600B29CcD89d0037402Ba0B2Eea" + "WitnetRequestFactoryDefault": "0x23873d132e4Ebc34C19F405cf2bFe31dA21630c2" }, "ten:testnet": { "WitnetProxy": "0x4563C77E85c1374754ffec3e6220d13Ddc8620eF", diff --git a/migrations/scripts/5_apps.js b/migrations/scripts/5_apps.js index 0bb1c1ea..d1521126 100644 --- a/migrations/scripts/5_apps.js +++ b/migrations/scripts/5_apps.js @@ -42,10 +42,12 @@ async function deploy (target) { const artifact = artifacts.require(key) const contract = artifacts.require(targets[key]) if ( - addresses[network][key] === "" || + addresses[network][targets[key]] === "" || selection.includes(key) || (libs && selection.filter(item => libs.includes(item)).length > 0) || - (!utils.isNullAddress(addresses[network][key]) && (await web3.eth.getCode(addresses[network][key])).length < 3) + (!utils.isNullAddress(addresses[network][targets[key]]) && ( + await web3.eth.getCode(addresses[network][targets[key]])).length < 3 + ) ) { utils.traceHeader(`Deploying '${key}'...`) console.info(" ", "> account: ", from) @@ -70,7 +72,7 @@ async function deploy (target) { const tx = await deployer.deploy(initCode, salt || "0x0", { from }) utils.traceTx(tx) if ((await web3.eth.getCode(addr)).length > 3) { - addresses[network][key] = addr + addresses[network][targets[key]] = addr } else { console.info(`Error: Contract was not deployed on expected address: ${addr}`) process.exit(1) @@ -86,9 +88,9 @@ async function deploy (target) { } else if (addresses[network][key]) { utils.traceHeader(`Skipped '${key}'`) } - if (!utils.isNullAddress(addresses[network][key])) { - artifact.address = addresses[network][key] - contract.address = addresses[network][key] + if (!utils.isNullAddress(addresses[network][targets[key]])) { + artifact.address = addresses[network][targets[key]] + contract.address = addresses[network][targets[key]] for (const index in libs) { const libname = libs[index] const lib = artifacts.require(libname) From d473c35fa7892add49efdb6b98efe293c51785f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Tue, 19 Mar 2024 08:56:28 +0100 Subject: [PATCH 18/35] feat: implement WitnetOracle.getQueryEvmReward(uint256) --- contracts/core/defaults/WitnetOracleTrustableBase.sol | 11 +++++++++++ contracts/interfaces/IWitnetOracle.sol | 3 +++ migrations/addresses.json | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/contracts/core/defaults/WitnetOracleTrustableBase.sol b/contracts/core/defaults/WitnetOracleTrustableBase.sol index c3c952c8..e57ca629 100644 --- a/contracts/core/defaults/WitnetOracleTrustableBase.sol +++ b/contracts/core/defaults/WitnetOracleTrustableBase.sol @@ -264,6 +264,17 @@ abstract contract WitnetOracleTrustableBase { return __storage().queries[_witnetQueryId]; } + + /// @notice Gets current EVM reward the report can claim, if not done yet. + function getQueryEvmReward(uint256 _witnetQueryId) + external view + virtual override + returns (uint256) + { + return __storage().queries[_witnetQueryId].request.evmReward; + } + + /// @notice Retrieves the RAD hash and SLA parameters of the given query. /// @param _witnetQueryId The unique query identifier. diff --git a/contracts/interfaces/IWitnetOracle.sol b/contracts/interfaces/IWitnetOracle.sol index 7de5552f..f0599cb1 100644 --- a/contracts/interfaces/IWitnetOracle.sol +++ b/contracts/interfaces/IWitnetOracle.sol @@ -32,6 +32,9 @@ interface IWitnetOracle { /// @notice Gets the whole Query data contents, if any, no matter its current status. function getQuery(uint256 queryId) external view returns (WitnetV2.Query memory); + /// @notice Gets current EVM reward the report can claim, if not done yet. + function getQueryEvmReward(uint256 queryId) external view returns (uint256); + /// @notice Retrieves the RAD hash and SLA parameters of the given query. /// @param queryId The unique query identifier. function getQueryRequest(uint256 queryId) external view returns (WitnetV2.Request memory); diff --git a/migrations/addresses.json b/migrations/addresses.json index 9b3806b9..5c8bcb0d 100644 --- a/migrations/addresses.json +++ b/migrations/addresses.json @@ -22,7 +22,7 @@ "WitnetEncodingLib": "0xf321bcD29CFc6134c9Bf42F759f428F3A6010919", "WitnetPriceFeedsLib": "0x85aa4A0fDa112c47d4216448EE4D49Afd072675e", "WitnetOracleDataLib": "0x72b43a4062c81918112646b32268f7A748F8Fe08", - "WitnetOracleTrustableOvm2": "0x6a587296dEc2cAd88233bf6Bda862ED5396730b0", + "WitnetOracleTrustableOvm2": "", "WitnetPriceFeedsDefault": "0x73912b1E13C67485D6d38Ef4F2B750C67FD99DA9", "WitnetRandomnessV20": "0x378C86Df3beed6808BFfbfCBF96B0e8abef5f70D", "WitnetRequestBytecodesDefault": "0x65fB7A0C98719e967546317222dfF90A73C42296", From 1512f25d32c41764a330a6f6abeaf9751d1659af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Tue, 19 Mar 2024 13:22:42 +0100 Subject: [PATCH 19/35] chore: upgrade WRB on optimism:sepolia --- contracts/core/defaults/WitnetOracleTrustableBase.sol | 4 +--- contracts/interfaces/IWitnetOracle.sol | 2 +- migrations/addresses.json | 2 +- migrations/constructorArgs.json | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/contracts/core/defaults/WitnetOracleTrustableBase.sol b/contracts/core/defaults/WitnetOracleTrustableBase.sol index e57ca629..9fa4be80 100644 --- a/contracts/core/defaults/WitnetOracleTrustableBase.sol +++ b/contracts/core/defaults/WitnetOracleTrustableBase.sol @@ -265,7 +265,7 @@ abstract contract WitnetOracleTrustableBase return __storage().queries[_witnetQueryId]; } - /// @notice Gets current EVM reward the report can claim, if not done yet. + /// @notice Gets the current EVM reward the report can claim, if not done yet. function getQueryEvmReward(uint256 _witnetQueryId) external view virtual override @@ -274,8 +274,6 @@ abstract contract WitnetOracleTrustableBase return __storage().queries[_witnetQueryId].request.evmReward; } - - /// @notice Retrieves the RAD hash and SLA parameters of the given query. /// @param _witnetQueryId The unique query identifier. function getQueryRequest(uint256 _witnetQueryId) diff --git a/contracts/interfaces/IWitnetOracle.sol b/contracts/interfaces/IWitnetOracle.sol index f0599cb1..eaa46cc0 100644 --- a/contracts/interfaces/IWitnetOracle.sol +++ b/contracts/interfaces/IWitnetOracle.sol @@ -32,7 +32,7 @@ interface IWitnetOracle { /// @notice Gets the whole Query data contents, if any, no matter its current status. function getQuery(uint256 queryId) external view returns (WitnetV2.Query memory); - /// @notice Gets current EVM reward the report can claim, if not done yet. + /// @notice Gets the current EVM reward the report can claim, if not done yet. function getQueryEvmReward(uint256 queryId) external view returns (uint256); /// @notice Retrieves the RAD hash and SLA parameters of the given query. diff --git a/migrations/addresses.json b/migrations/addresses.json index 5c8bcb0d..62d98765 100644 --- a/migrations/addresses.json +++ b/migrations/addresses.json @@ -22,7 +22,7 @@ "WitnetEncodingLib": "0xf321bcD29CFc6134c9Bf42F759f428F3A6010919", "WitnetPriceFeedsLib": "0x85aa4A0fDa112c47d4216448EE4D49Afd072675e", "WitnetOracleDataLib": "0x72b43a4062c81918112646b32268f7A748F8Fe08", - "WitnetOracleTrustableOvm2": "", + "WitnetOracleTrustableOvm2": "0xFa01Fb19696626dbBc53Cf2Ebd81356C55f32Fdf", "WitnetPriceFeedsDefault": "0x73912b1E13C67485D6d38Ef4F2B750C67FD99DA9", "WitnetRandomnessV20": "0x378C86Df3beed6808BFfbfCBF96B0e8abef5f70D", "WitnetRequestBytecodesDefault": "0x65fB7A0C98719e967546317222dfF90A73C42296", diff --git a/migrations/constructorArgs.json b/migrations/constructorArgs.json index e0e46200..829ec1c2 100644 --- a/migrations/constructorArgs.json +++ b/migrations/constructorArgs.json @@ -9,7 +9,7 @@ "WitnetRandomnessV20": "00000000000000000000000077703ae126b971c9946d562f41dd47071da00777", "WitnetRequestBytecodesDefault": "0000000000000000000000000000000000000000000000000000000000000001322e302e372d3264386665303400000000000000000000000000000000000000", "WitnetRequestFactoryDefault": "00000000000000000000000077703ae126b971c9946d562f41dd47071da00777000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e372d3264386665303400000000000000000000000000000000000000", - "WitnetOracleTrustableOvm2": "000000000000000000000000000db36997af1f02209a6f995883b9b699900000000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e382d3565613931623700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e3aa000000000000000000000000000000000000000000000000000000000000fef90000000000000000000000000000000000000000000000000000000000010faa0000000000000000000000000000000000000000000000000000000000004e20", + "WitnetOracleTrustableOvm2": "000000000000000000000000000db36997af1f02209a6f995883b9b699900000000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e382d6434373363333500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e3aa000000000000000000000000000000000000000000000000000000000000fef90000000000000000000000000000000000000000000000000000000000010faa0000000000000000000000000000000000000000000000000000000000004e20", "WitnetPriceFeedsDefault": "00000000000000000000000077703ae126b971c9946d562f41dd47071da007770000000000000000000000000000000000000000000000000000000000000001322e302e382d6431346538393000000000000000000000000000000000000000" }, "ten:testnet": { From 20419abe46fea2d9331217cb2bcd5f5baf651223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Tue, 19 Mar 2024 13:23:44 +0100 Subject: [PATCH 20/35] refactor: WitnetRandomnessV20 -> WitnetRandomnessV2 --- .../{WitnetRandomnessV20.sol => WitnetRandomnessV2.sol} | 6 +++--- migrations/addresses.json | 2 +- migrations/constructorArgs.json | 2 +- migrations/scripts/5_apps.js | 2 +- settings/artifacts.js | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) rename contracts/apps/{WitnetRandomnessV20.sol => WitnetRandomnessV2.sol} (99%) diff --git a/contracts/apps/WitnetRandomnessV20.sol b/contracts/apps/WitnetRandomnessV2.sol similarity index 99% rename from contracts/apps/WitnetRandomnessV20.sol rename to contracts/apps/WitnetRandomnessV2.sol index 10b68cb9..13164922 100644 --- a/contracts/apps/WitnetRandomnessV20.sol +++ b/contracts/apps/WitnetRandomnessV2.sol @@ -7,9 +7,9 @@ import "../apps/UsingWitnet.sol"; import "../interfaces/IWitnetRandomnessAdmin.sol"; import "../patterns/Ownable2Step.sol"; -/// @title WitnetRandomnessV20: Unmalleable and provably-fair randomness generation based on the Witnet Oracle. +/// @title WitnetRandomnessV2: Unmalleable and provably-fair randomness generation based on the Witnet Oracle v2.*. /// @author The Witnet Foundation. -contract WitnetRandomnessV20 +contract WitnetRandomnessV2 is Ownable2Step, UsingWitnet, @@ -96,7 +96,7 @@ contract WitnetRandomnessV20 } function class() virtual override public pure returns (string memory) { - return type(WitnetRandomnessV20).name; + return type(WitnetRandomnessV2).name; } function specs() virtual override external pure returns (bytes4) { diff --git a/migrations/addresses.json b/migrations/addresses.json index 62d98765..fc6574ee 100644 --- a/migrations/addresses.json +++ b/migrations/addresses.json @@ -24,7 +24,7 @@ "WitnetOracleDataLib": "0x72b43a4062c81918112646b32268f7A748F8Fe08", "WitnetOracleTrustableOvm2": "0xFa01Fb19696626dbBc53Cf2Ebd81356C55f32Fdf", "WitnetPriceFeedsDefault": "0x73912b1E13C67485D6d38Ef4F2B750C67FD99DA9", - "WitnetRandomnessV20": "0x378C86Df3beed6808BFfbfCBF96B0e8abef5f70D", + "WitnetRandomnessV2": "0xD527ac743576A6c9fe9AeDD6dd891a6A1D337eEc", "WitnetRequestBytecodesDefault": "0x65fB7A0C98719e967546317222dfF90A73C42296", "WitnetRequestFactoryDefault": "0x23873d132e4Ebc34C19F405cf2bFe31dA21630c2" }, diff --git a/migrations/constructorArgs.json b/migrations/constructorArgs.json index 829ec1c2..e3fc0991 100644 --- a/migrations/constructorArgs.json +++ b/migrations/constructorArgs.json @@ -6,7 +6,7 @@ "WitnetPriceFeedsDefault": "" }, "optimism:sepolia": { - "WitnetRandomnessV20": "00000000000000000000000077703ae126b971c9946d562f41dd47071da00777", + "WitnetRandomnessV2": "00000000000000000000000077703ae126b971c9946d562f41dd47071da00777", "WitnetRequestBytecodesDefault": "0000000000000000000000000000000000000000000000000000000000000001322e302e372d3264386665303400000000000000000000000000000000000000", "WitnetRequestFactoryDefault": "00000000000000000000000077703ae126b971c9946d562f41dd47071da00777000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e372d3264386665303400000000000000000000000000000000000000", "WitnetOracleTrustableOvm2": "000000000000000000000000000db36997af1f02209a6f995883b9b699900000000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e382d6434373363333500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e3aa000000000000000000000000000000000000000000000000000000000000fef90000000000000000000000000000000000000000000000000000000000010faa0000000000000000000000000000000000000000000000000000000000004e20", diff --git a/migrations/scripts/5_apps.js b/migrations/scripts/5_apps.js index d1521126..676f8c9f 100644 --- a/migrations/scripts/5_apps.js +++ b/migrations/scripts/5_apps.js @@ -13,7 +13,7 @@ module.exports = async function (_, network, [, from]) { // once all core Witnet Oracle artifacts get deployed and initialized. // ========================================================================== - // --- WitnetRandomnessV20 -------------------------------------------------- + // --- WitnetRandomnessV2 -------------------------------------------------- await deploy({ network, diff --git a/settings/artifacts.js b/settings/artifacts.js index 45ccc11f..a4778c97 100644 --- a/settings/artifacts.js +++ b/settings/artifacts.js @@ -2,7 +2,7 @@ module.exports = { default: { WitnetOracle: "WitnetOracleTrustableDefault", WitnetPriceFeeds: "WitnetPriceFeedsDefault", - WitnetRandomness: "WitnetRandomnessV20", + WitnetRandomness: "WitnetRandomnessV2", WitnetRequestBytecodes: "WitnetRequestBytecodesDefault", WitnetRequestFactory: "WitnetRequestFactoryDefault", WitnetEncodingLib: "WitnetEncodingLib", From 7b7dda865baf7082a879c92ffa79853f22ae9afa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Tue, 19 Mar 2024 14:50:48 +0100 Subject: [PATCH 21/35] fix/feat: reported callbacks requires specific WitnetV2.ResponseStatus value --- contracts/data/WitnetOracleDataLib.sol | 15 ++++++++++----- contracts/libs/WitnetV2.sol | 3 ++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/contracts/data/WitnetOracleDataLib.sol b/contracts/data/WitnetOracleDataLib.sol index d0300aab..3686a319 100644 --- a/contracts/data/WitnetOracleDataLib.sol +++ b/contracts/data/WitnetOracleDataLib.sol @@ -70,11 +70,16 @@ library WitnetOracleDataLib { WitnetV2.QueryStatus _queryStatus = seekQueryStatus(queryId); if (_queryStatus == WitnetV2.QueryStatus.Finalized) { bytes storage __cborValues = data().queries[queryId].response.resultCborBytes; - // determine whether reported result is an error by peeking the first byte - return (__cborValues[0] == bytes1(0xd8) - ? WitnetV2.ResponseStatus.Error - : WitnetV2.ResponseStatus.Ready - ); + if (__cborValues.length > 0) { + // determine whether stored result is an error by peeking the first byte + return (__cborValues[0] == bytes1(0xd8) + ? WitnetV2.ResponseStatus.Error + : WitnetV2.ResponseStatus.Ready + ); + } else { + // the result is final but delivered to the requesting address + return WitnetV2.ResponseStatus.Delivered; + } } else if (_queryStatus == WitnetV2.QueryStatus.Posted) { return WitnetV2.ResponseStatus.Awaiting; } else if (_queryStatus == WitnetV2.QueryStatus.Reported) { diff --git a/contracts/libs/WitnetV2.sol b/contracts/libs/WitnetV2.sol index 1d7cf08c..01172470 100644 --- a/contracts/libs/WitnetV2.sol +++ b/contracts/libs/WitnetV2.sol @@ -45,7 +45,8 @@ library WitnetV2 { Awaiting, Ready, Error, - Finalizing + Finalizing, + Delivered } struct RadonSLA { From 703351a4ff66f6c58385a03d3607da9b55f0baf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Tue, 19 Mar 2024 14:58:39 +0100 Subject: [PATCH 22/35] chore: upgrade wrb on optimism:sepolia --- migrations/addresses.json | 4 ++-- migrations/constructorArgs.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/migrations/addresses.json b/migrations/addresses.json index fc6574ee..913cd08c 100644 --- a/migrations/addresses.json +++ b/migrations/addresses.json @@ -21,8 +21,8 @@ "WitnetErrorsLib": "0x4f2F381Ed2020095F1a1B5a0BDe5AB30da916BC9", "WitnetEncodingLib": "0xf321bcD29CFc6134c9Bf42F759f428F3A6010919", "WitnetPriceFeedsLib": "0x85aa4A0fDa112c47d4216448EE4D49Afd072675e", - "WitnetOracleDataLib": "0x72b43a4062c81918112646b32268f7A748F8Fe08", - "WitnetOracleTrustableOvm2": "0xFa01Fb19696626dbBc53Cf2Ebd81356C55f32Fdf", + "WitnetOracleDataLib": "0xe4e7c3cfc60c10190c74316c3E7711e59B7a7B7a", + "WitnetOracleTrustableOvm2": "0xE628af2Fd6fcfA1c048697f37061C033F21301F0", "WitnetPriceFeedsDefault": "0x73912b1E13C67485D6d38Ef4F2B750C67FD99DA9", "WitnetRandomnessV2": "0xD527ac743576A6c9fe9AeDD6dd891a6A1D337eEc", "WitnetRequestBytecodesDefault": "0x65fB7A0C98719e967546317222dfF90A73C42296", diff --git a/migrations/constructorArgs.json b/migrations/constructorArgs.json index e3fc0991..b2c43fac 100644 --- a/migrations/constructorArgs.json +++ b/migrations/constructorArgs.json @@ -9,7 +9,7 @@ "WitnetRandomnessV2": "00000000000000000000000077703ae126b971c9946d562f41dd47071da00777", "WitnetRequestBytecodesDefault": "0000000000000000000000000000000000000000000000000000000000000001322e302e372d3264386665303400000000000000000000000000000000000000", "WitnetRequestFactoryDefault": "00000000000000000000000077703ae126b971c9946d562f41dd47071da00777000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e372d3264386665303400000000000000000000000000000000000000", - "WitnetOracleTrustableOvm2": "000000000000000000000000000db36997af1f02209a6f995883b9b699900000000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e382d6434373363333500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e3aa000000000000000000000000000000000000000000000000000000000000fef90000000000000000000000000000000000000000000000000000000000010faa0000000000000000000000000000000000000000000000000000000000004e20", + "WitnetOracleTrustableOvm2": "000000000000000000000000000db36997af1f02209a6f995883b9b699900000000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e382d3762376464613800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e3aa000000000000000000000000000000000000000000000000000000000000fef90000000000000000000000000000000000000000000000000000000000010faa0000000000000000000000000000000000000000000000000000000000004e20", "WitnetPriceFeedsDefault": "00000000000000000000000077703ae126b971c9946d562f41dd47071da007770000000000000000000000000000000000000000000000000000000000000001322e302e382d6431346538393000000000000000000000000000000000000000" }, "ten:testnet": { From 93eaeb185f7f788e874bcd9ccdd68abbda94548e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Tue, 19 Mar 2024 18:06:25 +0100 Subject: [PATCH 23/35] chore: unindex query ids on IWitnetOracleEvents --- contracts/interfaces/IWitnetOracleEvents.sol | 8 ++++---- migrations/addresses.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts/interfaces/IWitnetOracleEvents.sol b/contracts/interfaces/IWitnetOracleEvents.sol index 599ba0ff..81da5ac9 100644 --- a/contracts/interfaces/IWitnetOracleEvents.sol +++ b/contracts/interfaces/IWitnetOracleEvents.sol @@ -7,7 +7,7 @@ interface IWitnetOracleEvents { /// Emitted every time a new query containing some verified data request is posted to the WRB. event WitnetQuery( - uint256 indexed id, + uint256 id, uint256 evmReward, WitnetV2.RadonSLA witnetSLA ); @@ -20,14 +20,14 @@ interface IWitnetOracleEvents { /// Emitted when a query with a callback gets successfully reported into the WRB. event WitnetQueryResponseDelivered( - uint256 indexed id, + uint256 id, uint256 evmGasPrice, uint256 evmCallbackGas ); /// Emitted when a query with a callback cannot get reported into the WRB. event WitnetQueryResponseDeliveryFailed( - uint256 indexed id, + uint256 id, bytes resultCborBytes, uint256 evmGasPrice, uint256 evmCallbackActualGas, @@ -36,7 +36,7 @@ interface IWitnetOracleEvents { /// Emitted when the reward of some not-yet reported query is upgraded. event WitnetQueryRewardUpgraded( - uint256 indexed id, + uint256 id, uint256 evmReward ); diff --git a/migrations/addresses.json b/migrations/addresses.json index 913cd08c..20f54fbb 100644 --- a/migrations/addresses.json +++ b/migrations/addresses.json @@ -22,7 +22,7 @@ "WitnetEncodingLib": "0xf321bcD29CFc6134c9Bf42F759f428F3A6010919", "WitnetPriceFeedsLib": "0x85aa4A0fDa112c47d4216448EE4D49Afd072675e", "WitnetOracleDataLib": "0xe4e7c3cfc60c10190c74316c3E7711e59B7a7B7a", - "WitnetOracleTrustableOvm2": "0xE628af2Fd6fcfA1c048697f37061C033F21301F0", + "WitnetOracleTrustableOvm2": "", "WitnetPriceFeedsDefault": "0x73912b1E13C67485D6d38Ef4F2B750C67FD99DA9", "WitnetRandomnessV2": "0xD527ac743576A6c9fe9AeDD6dd891a6A1D337eEc", "WitnetRequestBytecodesDefault": "0x65fB7A0C98719e967546317222dfF90A73C42296", From 04b55896689adbfda5782f5e60f21b1f0996bcf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 21 Mar 2024 12:07:16 +0100 Subject: [PATCH 24/35] feat(rng): ensure that different block number will always be assigned different randomness values --- contracts/apps/WitnetRandomnessV2.sol | 53 ++++++++++++++-------- contracts/interfaces/IWitnetRandomness.sol | 19 ++++---- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/contracts/apps/WitnetRandomnessV2.sol b/contracts/apps/WitnetRandomnessV2.sol index 13164922..a84963ce 100644 --- a/contracts/apps/WitnetRandomnessV2.sol +++ b/contracts/apps/WitnetRandomnessV2.sol @@ -129,8 +129,9 @@ contract WitnetRandomnessV2 ) / 100; } - /// @notice Retrieves the randomness value generated by the Witnet Oracle blockchain in response to the - /// @notice first non-errored randomize request solved after the given block number. + /// @notice Retrieves the result of keccak256-hashing the given block number with the randomness value + /// @notice generated by the Witnet Oracle blockchain in response to the first non-errored randomize request solved + /// @notice after such block number. /// @dev Reverts if: /// @dev i. no `randomize()` was requested on neither the given block, nor afterwards. /// @dev ii. the first non-errored `randomize()` request found on or after the given block is not solved yet. @@ -140,6 +141,18 @@ contract WitnetRandomnessV2 public view virtual override returns (bytes32) + { + return keccak256( + abi.encode( + _blockNumber, + _fetchRandomnessAfter(_blockNumber) + ) + ); + } + + function _fetchRandomnessAfter(uint256 _blockNumber) + virtual internal view + returns (bytes32) { if (__storage().randomize_[_blockNumber].witnetQueryId == 0) { _blockNumber = getRandomizeNextBlock(_blockNumber); @@ -147,32 +160,32 @@ contract WitnetRandomnessV2 Randomize storage __randomize = __storage().randomize_[_blockNumber]; uint256 _witnetQueryId = __randomize.witnetQueryId; - require( + _require( _witnetQueryId != 0, - "WitnetRandomness: not randomized" + "not randomized" ); WitnetV2.ResponseStatus _status = __witnet.getQueryResponseStatus(_witnetQueryId); if (_status == WitnetV2.ResponseStatus.Ready) { - return (__witnet.getQueryResponse(_witnetQueryId) - .resultCborBytes - .toWitnetResult() - .asBytes32() + return ( + __witnet.getQueryResultCborBytes(_witnetQueryId) + .toWitnetResult() + .asBytes32() ); } else if (_status == WitnetV2.ResponseStatus.Error) { uint256 _nextRandomizeBlock = __randomize.nextBlock; - require( + _require( _nextRandomizeBlock != 0, - "WitnetRandomness: faulty randomize" + "faulty randomize" ); - return fetchRandomnessAfter(_nextRandomizeBlock); + return _fetchRandomnessAfter(_nextRandomizeBlock); } else { - revert("WitnetRandomness: pending randomize"); + _revert("pending randomize"); } } - /// @notice Retrieves the unique hash and timestamp of the witnessing commit/reveal act that took + /// @notice Retrieves the actual random value, unique hash and timestamp of the witnessing commit/reveal act that took /// @notice place in the Witnet Oracle blockchain in response to the first non-errored randomize request /// @notice solved after the given block number. /// @dev Reverts if: @@ -180,6 +193,7 @@ contract WitnetRandomnessV2 /// @dev ii. the first non-errored `randomize()` request found on or after the given block is not solved yet. /// @dev iii. all `randomize()` requests that took place on or after the given block were solved with errors. /// @param _blockNumber Block number from which the search will start. + /// @return _witnetResultRandomness Random value provided by the Witnet blockchain and used for solving randomness after given block. /// @return _witnetResultTimestamp Timestamp at which the randomness value was generated by the Witnet blockchain. /// @return _witnetResultTallyHash Hash of the witnessing commit/reveal act that took place on the Witnet blockchain. /// @return _witnetResultFinalityBlock EVM block number from which the provided randomness can be considered to be final. @@ -187,6 +201,7 @@ contract WitnetRandomnessV2 virtual override public view returns ( + bytes32 _witnetResultRandomness, uint64 _witnetResultTimestamp, bytes32 _witnetResultTallyHash, uint256 _witnetResultFinalityBlock @@ -198,9 +213,9 @@ contract WitnetRandomnessV2 Randomize storage __randomize = __storage().randomize_[_blockNumber]; uint256 _witnetQueryId = __randomize.witnetQueryId; - require( + _require( _witnetQueryId != 0, - "WitnetRandomness: not randomized" + "not randomized" ); WitnetV2.ResponseStatus _status = __witnet.getQueryResponseStatus(_witnetQueryId); @@ -209,17 +224,18 @@ contract WitnetRandomnessV2 _witnetResultTimestamp = _witnetQueryResponse.resultTimestamp; _witnetResultTallyHash = _witnetQueryResponse.resultTallyHash; _witnetResultFinalityBlock = _witnetQueryResponse.finality; + _witnetResultRandomness = _witnetQueryResponse.resultCborBytes.toWitnetResult().asBytes32(); } else if (_status == WitnetV2.ResponseStatus.Error) { uint256 _nextRandomizeBlock = __randomize.nextBlock; - require( + _require( _nextRandomizeBlock != 0, - "WitnetRandomness: faulty randomize" + "faulty randomize" ); return fetchRandomnessAfterProof(_nextRandomizeBlock); } else { - revert("WitnetRandomness: pending randomize"); + _revert("pending randomize"); } } @@ -348,7 +364,6 @@ contract WitnetRandomnessV2 keccak256( abi.encode( msg.sender, - _blockNumber, fetchRandomnessAfter(_blockNumber) ) ) diff --git a/contracts/interfaces/IWitnetRandomness.sol b/contracts/interfaces/IWitnetRandomness.sol index fbb787b8..01ee4517 100644 --- a/contracts/interfaces/IWitnetRandomness.sol +++ b/contracts/interfaces/IWitnetRandomness.sol @@ -19,8 +19,9 @@ interface IWitnetRandomness { /// transaction gas price as the one given. function estimateRandomizeFee(uint256 evmGasPrice) external view returns (uint256); - /// @notice Retrieves the randomness value generated by the Witnet Oracle blockchain in response to the - /// @notice first non-errored randomize request solved after the given block number. + /// @notice Retrieves the result of keccak256-hashing the given block number with the randomness value + /// @notice generated by the Witnet Oracle blockchain in response to the first non-errored randomize request solved + /// @notice after such block number. /// @dev Reverts if: /// @dev i. no `randomize()` was requested on neither the given block, nor afterwards. /// @dev ii. the first non-errored `randomize()` request found on or after the given block is not solved yet. @@ -28,7 +29,7 @@ interface IWitnetRandomness { /// @param blockNumber Block number from which the search will start. function fetchRandomnessAfter(uint256 blockNumber) external view returns (bytes32); - /// @notice Retrieves the unique hash and timestamp of the witnessing commit/reveal act that took + /// @notice Retrieves the actual random value, unique hash and timestamp of the witnessing commit/reveal act that took /// @notice place in the Witnet Oracle blockchain in response to the first non-errored randomize request /// @notice solved after the given block number. /// @dev Reverts if: @@ -36,13 +37,15 @@ interface IWitnetRandomness { /// @dev ii. the first non-errored `randomize()` request found on or after the given block is not solved yet. /// @dev iii. all `randomize()` requests that took place on or after the given block were solved with errors. /// @param blockNumber Block number from which the search will start. + /// @return witnetResultRandomness Random value provided by the Witnet blockchain and used for solving randomness after given block. /// @return witnetResultTimestamp Timestamp at which the randomness value was generated by the Witnet blockchain. /// @return witnetResultTallyHash Hash of the witnessing commit/reveal act that took place on the Witnet blockchain. - /// @return witnetEvmFinalityBlock EVM block number from which the provided randomness can be considered to be final. + /// @return witnetResultFinalityBlock EVM block number from which the provided randomness can be considered to be final. function fetchRandomnessAfterProof(uint256 blockNumber) external view returns ( - uint64 witnetResultTimestamp, - bytes32 witnetResultTallyHash, - uint256 witnetEvmFinalityBlock + bytes32 witnetResultRandomness, + uint64 witnetResultTimestamp, + bytes32 witnetResultTallyHash, + uint256 witnetResultFinalityBlock ); /// @notice Returns last block number on which a randomize was requested. @@ -106,6 +109,6 @@ interface IWitnetRandomness { /// @notice - reward in $nanoWIT received per witnessing node in the Witnet blockchain function witnetQuerySLA() external view returns (WitnetV2.RadonSLA memory); - /// @notice Returns address of the Witnet-compliant data request being used for solving randomness. + /// @notice Returns the unique identifier of the Witnet-compliant data request being used for solving randomness. function witnetRadHash() external view returns (bytes32); } From 94c621c41e01f08e1ff2eb9120b7fffcc60ccb9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 21 Mar 2024 12:08:15 +0100 Subject: [PATCH 25/35] chore(rng): optimize required storage for human-readable revert messages --- contracts/apps/WitnetRandomnessV2.sol | 50 ++++++++++++++++++--------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/contracts/apps/WitnetRandomnessV2.sol b/contracts/apps/WitnetRandomnessV2.sol index a84963ce..70ffbe98 100644 --- a/contracts/apps/WitnetRandomnessV2.sol +++ b/contracts/apps/WitnetRandomnessV2.sol @@ -32,20 +32,19 @@ contract WitnetRandomnessV2 } /// @notice Unique identifier of the RNG data request used on the Witnet Oracle blockchain for solving randomness. - /// @dev Can be used to track all randomness requests solved on the Witnet Oracle blockchain. + /// @dev Can be used to track all randomness requests solved so far on the Witnet Oracle blockchain. bytes32 immutable public override witnetRadHash; - constructor(WitnetOracle _witnet) + constructor( + WitnetOracle _witnet + ) Ownable(address(msg.sender)) UsingWitnet(_witnet) { - require( + _require( address(_witnet) == address(0) || _witnet.specs() == type(IWitnetOracle).interfaceId, - string(abi.encodePacked( - class(), - ": uncompliant WitnetOracle" - )) + "uncompliant WitnetOracle" ); WitnetRequestBytecodes _registry = witnet().registry(); { @@ -78,16 +77,12 @@ contract WitnetRandomnessV2 } receive() virtual external payable { - revert(string(abi.encodePacked( - class(), - ": no transfers accepted" - ))); + _revert("no transfers accepted"); } fallback() virtual external payable { - revert(string(abi.encodePacked( - class(), - ": not implemented: 0x", + _revert(string(abi.encodePacked( + "not implemented: 0x", Witnet.toHexString(uint8(bytes1(msg.sig))), Witnet.toHexString(uint8(bytes1(msg.sig << 8))), Witnet.toHexString(uint8(bytes1(msg.sig << 16))), @@ -477,9 +472,9 @@ contract WitnetRandomnessV2 external onlyOwner { - require( + _require( _witnetQuerySLA.isValid(), - "WitnetRandomness: invalid SLA" + "invalid SLA" ); __witnetDefaultSLA = _witnetQuerySLA; } @@ -488,6 +483,29 @@ contract WitnetRandomnessV2 // ================================================================================================================ // --- Internal methods ------------------------------------------------------------------------------------------- + function _require( + bool _condition, + string memory _message + ) + internal pure + { + if (!_condition) { + _revert(_message); + } + } + + function _revert(string memory _message) + internal pure + { + revert( + string(abi.encodePacked( + class(), + ": ", + _message + )) + ); + } + /// @dev Recursively searches for the number of the first block after the given one in which a Witnet /// @dev randomness request was posted. Returns 0 if none found. function _searchNextBlock(uint256 _target, uint256 _latest) internal view returns (uint256) { From e7121c98ca0fb5e27632608b3c69eb460bab2d38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 21 Mar 2024 12:08:41 +0100 Subject: [PATCH 26/35] chore: removed currently unused witnet 2.0 protocol constants --- contracts/libs/WitnetV2.sol | 43 +------------------------------------ 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/contracts/libs/WitnetV2.sol b/contracts/libs/WitnetV2.sol index 01172470..b3cd4638 100644 --- a/contracts/libs/WitnetV2.sol +++ b/contracts/libs/WitnetV2.sol @@ -108,45 +108,4 @@ library WitnetV2 { ) & uint256(2 ** 224 - 1); return uint32((_number * range) >> 224); } - - - /// =============================================================================================================== - /// --- Witnet protocol v2.0 helper methods ----------------------------------------------------------------------- - - 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 ( - _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; - } - } - - 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 4468d282962af60dc2f5abfc502611f508658c9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 21 Mar 2024 12:09:52 +0100 Subject: [PATCH 27/35] feat(wrb): getQueryResultCborbytes --- contracts/core/defaults/WitnetOracleTrustableBase.sol | 10 ++++++++++ contracts/interfaces/IWitnetOracle.sol | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/contracts/core/defaults/WitnetOracleTrustableBase.sol b/contracts/core/defaults/WitnetOracleTrustableBase.sol index 9fa4be80..08456d0b 100644 --- a/contracts/core/defaults/WitnetOracleTrustableBase.sol +++ b/contracts/core/defaults/WitnetOracleTrustableBase.sol @@ -308,6 +308,16 @@ abstract contract WitnetOracleTrustableBase return WitnetOracleDataLib.seekQueryResponseStatus(_witnetQueryId); } + /// @notice Retrieves the CBOR-encoded buffer containing the Witnet-provided result to the given query. + /// @param _witnetQueryId The unique query identifier. + function getQueryResultCborBytes(uint256 _witnetQueryId) + external view + virtual override + returns (bytes memory) + { + return WitnetOracleDataLib.seekQueryResponse(_witnetQueryId).resultCborBytes; + } + /// @notice Gets error code identifying some possible failure on the resolution of the given query. /// @param _witnetQueryId The unique query identifier. function getQueryResultError(uint256 _witnetQueryId) diff --git a/contracts/interfaces/IWitnetOracle.sol b/contracts/interfaces/IWitnetOracle.sol index eaa46cc0..b9825eb5 100644 --- a/contracts/interfaces/IWitnetOracle.sol +++ b/contracts/interfaces/IWitnetOracle.sol @@ -51,6 +51,10 @@ interface IWitnetOracle { /// @param queryId The unique query identifier. function getQueryResponseStatus(uint256 queryId) external view returns (WitnetV2.ResponseStatus); + /// @notice Retrieves the CBOR-encoded buffer containing the Witnet-provided result to the given query. + /// @param queryId The unique query identifier. + function getQueryResultCborBytes(uint256 queryId) external view returns (bytes memory); + /// @notice Gets error code identifying some possible failure on the resolution of the given query. /// @param queryId The unique query identifier. function getQueryResultError(uint256 queryId) external view returns (Witnet.ResultError memory); From 4ebd46c1a4904afc63479e715cb335bb14e2a191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 21 Mar 2024 12:14:45 +0100 Subject: [PATCH 28/35] chore: optimize framework storage footprint for human-readable revert messages --- contracts/core/WitnetUpgradableBase.sol | 29 ++++++- .../customs/WitnetOracleTrustableObscuro.sol | 2 +- .../customs/WitnetOracleTrustableOvm2.sol | 2 +- .../customs/WitnetOracleTrustableReef.sol | 2 +- .../WitnetRequestBytecodesNoSha256.sol | 2 +- .../customs/WitnetRequestFactoryCfxCore.sol | 2 +- .../defaults/WitnetOracleTrustableBase.sol | 83 +++++++++++-------- .../defaults/WitnetOracleTrustableDefault.sol | 2 +- .../core/defaults/WitnetPriceFeedsDefault.sol | 2 +- .../WitnetRequestBytecodesDefault.sol | 6 +- .../defaults/WitnetRequestFactoryDefault.sol | 4 +- contracts/data/WitnetOracleDataLib.sol | 8 +- 12 files changed, 93 insertions(+), 51 deletions(-) diff --git a/contracts/core/WitnetUpgradableBase.sol b/contracts/core/WitnetUpgradableBase.sol index 57b31627..5c056b7f 100644 --- a/contracts/core/WitnetUpgradableBase.sol +++ b/contracts/core/WitnetUpgradableBase.sol @@ -35,9 +35,13 @@ abstract contract WitnetUpgradableBase /// @dev Reverts if proxy delegatecalls to unexistent method. fallback() virtual external { - revert("WitnetUpgradableBase: not implemented"); + _revert("not implemented"); } + + function class() virtual public view returns (string memory) { + return type(WitnetUpgradableBase).name; + } // ================================================================================================================ // --- Overrides 'Proxiable' -------------------------------------------------------------------------------------- @@ -60,6 +64,29 @@ abstract contract WitnetUpgradableBase // ================================================================================================================ // --- Internal methods ------------------------------------------------------------------------------------------- + function _require( + bool _condition, + string memory _message + ) + internal view + { + if (!_condition) { + _revert(_message); + } + } + + function _revert(string memory _message) + internal view + { + revert( + string(abi.encodePacked( + class(), + ": ", + _message + )) + ); + } + /// Converts bytes32 into string. function _toString(bytes32 _bytes32) internal pure diff --git a/contracts/core/customs/WitnetOracleTrustableObscuro.sol b/contracts/core/customs/WitnetOracleTrustableObscuro.sol index 06a3cb1a..34418f09 100644 --- a/contracts/core/customs/WitnetOracleTrustableObscuro.sol +++ b/contracts/core/customs/WitnetOracleTrustableObscuro.sol @@ -16,7 +16,7 @@ contract WitnetOracleTrustableObscuro is WitnetOracleTrustableDefault { - function class() virtual override external view returns (string memory) { + function class() virtual override public view returns (string memory) { return type(WitnetOracleTrustableObscuro).name; } diff --git a/contracts/core/customs/WitnetOracleTrustableOvm2.sol b/contracts/core/customs/WitnetOracleTrustableOvm2.sol index f74e4ba9..eedb7001 100644 --- a/contracts/core/customs/WitnetOracleTrustableOvm2.sol +++ b/contracts/core/customs/WitnetOracleTrustableOvm2.sol @@ -23,7 +23,7 @@ contract WitnetOracleTrustableOvm2 { using WitnetV2 for WitnetV2.RadonSLA; - function class() virtual override external view returns (string memory) { + function class() virtual override public view returns (string memory) { return type(WitnetOracleTrustableOvm2).name; } diff --git a/contracts/core/customs/WitnetOracleTrustableReef.sol b/contracts/core/customs/WitnetOracleTrustableReef.sol index 4d51180f..220d1f53 100644 --- a/contracts/core/customs/WitnetOracleTrustableReef.sol +++ b/contracts/core/customs/WitnetOracleTrustableReef.sol @@ -17,7 +17,7 @@ contract WitnetOracleTrustableReef is WitnetOracleTrustableDefault { - function class() virtual override external view returns (string memory) { + function class() virtual override public view returns (string memory) { return type(WitnetOracleTrustableReef).name; } diff --git a/contracts/core/customs/WitnetRequestBytecodesNoSha256.sol b/contracts/core/customs/WitnetRequestBytecodesNoSha256.sol index dc0c02f0..719f909a 100644 --- a/contracts/core/customs/WitnetRequestBytecodesNoSha256.sol +++ b/contracts/core/customs/WitnetRequestBytecodesNoSha256.sol @@ -9,7 +9,7 @@ contract WitnetRequestBytecodesNoSha256 is WitnetRequestBytecodesDefault { - function class() virtual override external view returns (string memory) { + function class() virtual override public view returns (string memory) { return type(WitnetRequestBytecodesNoSha256).name; } diff --git a/contracts/core/customs/WitnetRequestFactoryCfxCore.sol b/contracts/core/customs/WitnetRequestFactoryCfxCore.sol index 2a820cbd..de13a150 100644 --- a/contracts/core/customs/WitnetRequestFactoryCfxCore.sol +++ b/contracts/core/customs/WitnetRequestFactoryCfxCore.sol @@ -9,7 +9,7 @@ contract WitnetRequestFactoryCfxCore is WitnetRequestFactoryDefault { - function class() virtual override external view returns (string memory) { + function class() virtual override public view returns (string memory) { return type(WitnetRequestFactoryCfxCore).name; } diff --git a/contracts/core/defaults/WitnetOracleTrustableBase.sol b/contracts/core/defaults/WitnetOracleTrustableBase.sol index 08456d0b..a1ec3d52 100644 --- a/contracts/core/defaults/WitnetOracleTrustableBase.sol +++ b/contracts/core/defaults/WitnetOracleTrustableBase.sol @@ -39,35 +39,35 @@ abstract contract WitnetOracleTrustableBase WitnetRequestFactory immutable private __factory; modifier checkCallbackRecipient(address _addr, uint24 _callbackGasLimit) { - require( + _require( _addr.code.length > 0 && IWitnetConsumer(_addr).reportableFrom(address(this)) && _callbackGasLimit > 0, - "WitnetOracle: invalid callback" + "invalid callback" ); _; } modifier checkReward(uint256 _baseFee) { - require( + _require( _getMsgValue() >= _baseFee, - "WitnetOracle: insufficient reward" + "insufficient reward" ); - require( + _require( _getMsgValue() <= _baseFee * 10, - "WitnetOracle: too much reward" + "too much reward" ); _; } modifier checkSLA(WitnetV2.RadonSLA calldata sla) { - require( + _require( WitnetV2.isValid(sla), - "WitnetOracle: invalid SLA" + "invalid SLA" ); _; } /// Asserts the given query is currently in the given status. modifier inStatus(uint256 _queryId, WitnetV2.QueryStatus _status) { if (WitnetOracleDataLib.seekQueryStatus(_queryId) != _status) { - revert(WitnetOracleDataLib.notInStatusRevertMessage(_status)); + _revert(WitnetOracleDataLib.notInStatusRevertMessage(_status)); } else { _; } @@ -75,17 +75,17 @@ abstract contract WitnetOracleTrustableBase /// Asserts the caller actually posted the referred query. modifier onlyRequester(uint256 _queryId) { - require( + _require( msg.sender == WitnetOracleDataLib.seekQueryRequest(_queryId).requester, - "WitnetOracle: not the requester" + "not the requester" ); _; } /// Asserts the caller is authorized as a reporter modifier onlyReporters { - require( + _require( __storage().reporters[msg.sender], - "WitnetOracle: unauthorized reporter" + "unauthorized reporter" ); _; } @@ -110,7 +110,7 @@ abstract contract WitnetOracleTrustableBase } receive() external payable { - revert("WitnetOracle: no transfers accepted"); + _revert("no transfers accepted"); } /// @dev Provide backwards compatibility for dapps bound to versions <= 0.6.1 @@ -119,8 +119,8 @@ abstract contract WitnetOracleTrustableBase /* solhint-disable payable-fallback */ /* solhint-disable no-complex-fallback */ fallback() override external { - revert(string(abi.encodePacked( - "WitnetOracle: not implemented: 0x", + _revert(string(abi.encodePacked( + "not implemented: 0x", Witnet.toHexString(uint8(bytes1(msg.sig))), Witnet.toHexString(uint8(bytes1(msg.sig << 8))), Witnet.toHexString(uint8(bytes1(msg.sig << 16))), @@ -132,6 +132,14 @@ abstract contract WitnetOracleTrustableBase return bytes4(keccak256(abi.encode(address(this), block.chainid))); } + function class() + public view + virtual override(WitnetOracle, WitnetUpgradableBase) + returns (string memory) + { + return type(WitnetOracleTrustableBase).name; + } + function factory() virtual override public view returns (WitnetRequestFactory) { return __factory; } @@ -172,9 +180,9 @@ abstract contract WitnetOracleTrustableBase _newReporters = abi.decode(_newReportersRaw, (address[])); } else { // only owner can initialize: - require( + _require( msg.sender == _owner, - "WitnetOracle: not the owner" + "not the owner" ); // get reporters from _initData _newReporters = abi.decode(_initData, (address[])); @@ -184,22 +192,22 @@ abstract contract WitnetOracleTrustableBase __proxiable().codehash != bytes32(0) && __proxiable().codehash == codehash() ) { - revert("WitnetOracle: already upgraded"); + _revert("already upgraded"); } __proxiable().codehash = codehash(); - require( + _require( address(__factory).code.length > 0, - "WitnetOracle: inexistent factory" + "inexistent factory" ); - require( + _require( __factory.specs() == type(IWitnetRequestFactory).interfaceId, - "WitnetOracle: uncompliant factory" + "uncompliant factory" ); - require( + _require( address(__factory.witnet()) == address(this) && address(__factory.registry()) == address(registry), - "WitnetOracle: discordant factory" + "discordant factory" ); // Set reporters, if any @@ -231,9 +239,9 @@ abstract contract WitnetOracleTrustableBase returns (uint256) { uint16 _resultMaxSize = registry.lookupRadonRequestResultMaxSize(radHash); - require( + _require( _resultMaxSize > 0, - "WitnetOracleTrustableDefault: invalid RAD" + "invalid RAD" ); return estimateBaseFee( gasPrice, @@ -290,7 +298,7 @@ abstract contract WitnetOracleTrustableBase function getQueryResponse(uint256 _witnetQueryId) public view virtual override - returns (WitnetV2.Response memory _response) + returns (WitnetV2.Response memory) { return WitnetOracleDataLib.seekQueryResponse(_witnetQueryId); } @@ -562,9 +570,9 @@ abstract contract WitnetOracleTrustableBase returns (uint256) { // results cannot be empty: - require( + _require( _witnetQueryResultCborBytes.length != 0, - "WitnetOracleTrustableDefault: result cannot be empty" + "result cannot be empty" ); // do actual report and return reward transfered to the reproter: // solhint-disable not-rely-on-time @@ -599,15 +607,15 @@ abstract contract WitnetOracleTrustableBase returns (uint256) { // validate timestamp - require( + _require( _witnetQueryResultTimestamp > 0 && _witnetQueryResultTimestamp <= block.timestamp, - "WitnetOracleTrustableDefault: bad timestamp" + "bad timestamp" ); // results cannot be empty - require( + _require( _witnetQueryResultCborBytes.length != 0, - "WitnetOracleTrustableDefault: result cannot be empty" + "result cannot be empty" ); // do actual report and return reward transfered to the reproter: return __reportResultAndReward( @@ -647,7 +655,10 @@ abstract contract WitnetOracleTrustableBase ) { emit BatchReportError( _batchResults[_i].queryId, - "WitnetOracle: invalid report data" + string(abi.encodePacked( + class(), + "invalid report data" + )) ); } else { _batchReward += __reportResult( @@ -728,7 +739,7 @@ abstract contract WitnetOracleTrustableBase { _witnetQueryId = ++ __storage().nonce; //__newQueryId(_radHash, _packedSLA); WitnetV2.Request storage __request = WitnetOracleDataLib.seekQueryRequest(_witnetQueryId); - require(__request.requester == address(0), "WitnetOracle: already posted"); + _require(__request.requester == address(0), "already posted"); { __request.requester = msg.sender; __request.gasCallback = _callbackGasLimit; diff --git a/contracts/core/defaults/WitnetOracleTrustableDefault.sol b/contracts/core/defaults/WitnetOracleTrustableDefault.sol index 137d49ac..46ca011a 100644 --- a/contracts/core/defaults/WitnetOracleTrustableDefault.sol +++ b/contracts/core/defaults/WitnetOracleTrustableDefault.sol @@ -16,7 +16,7 @@ contract WitnetOracleTrustableDefault is WitnetOracleTrustableBase { - function class() virtual override external view returns (string memory) { + function class() virtual override public view returns (string memory) { return type(WitnetOracleTrustableDefault).name; } diff --git a/contracts/core/defaults/WitnetPriceFeedsDefault.sol b/contracts/core/defaults/WitnetPriceFeedsDefault.sol index 503697bb..63dbd04b 100644 --- a/contracts/core/defaults/WitnetPriceFeedsDefault.sol +++ b/contracts/core/defaults/WitnetPriceFeedsDefault.sol @@ -26,7 +26,7 @@ contract WitnetPriceFeedsDefault using WitnetV2 for WitnetV2.Response; using WitnetV2 for WitnetV2.RadonSLA; - function class() virtual override external view returns (string memory) { + function class() virtual override(WitnetFeeds, WitnetUpgradableBase) public view returns (string memory) { return type(WitnetPriceFeedsDefault).name; } diff --git a/contracts/core/defaults/WitnetRequestBytecodesDefault.sol b/contracts/core/defaults/WitnetRequestBytecodesDefault.sol index 8938b9cd..07c41458 100644 --- a/contracts/core/defaults/WitnetRequestBytecodesDefault.sol +++ b/contracts/core/defaults/WitnetRequestBytecodesDefault.sol @@ -29,7 +29,11 @@ contract WitnetRequestBytecodesDefault using WitnetEncodingLib for Witnet.RadonSLA; using WitnetEncodingLib for Witnet.RadonDataTypes; - function class() virtual override external view returns (string memory) { + function class() + public view + virtual override(WitnetRequestBytecodes, WitnetUpgradableBase) + returns (string memory) + { return type(WitnetRequestBytecodesDefault).name; } diff --git a/contracts/core/defaults/WitnetRequestFactoryDefault.sol b/contracts/core/defaults/WitnetRequestFactoryDefault.sol index 38b577ae..b5e94849 100644 --- a/contracts/core/defaults/WitnetRequestFactoryDefault.sol +++ b/contracts/core/defaults/WitnetRequestFactoryDefault.sol @@ -188,8 +188,8 @@ contract WitnetRequestFactoryDefault } function class() - virtual override(WitnetRequestFactory, WitnetRequestTemplate) - external view + virtual override(WitnetRequestFactory, WitnetRequestTemplate, WitnetUpgradableBase) + public view returns (string memory) { if ( diff --git a/contracts/data/WitnetOracleDataLib.sol b/contracts/data/WitnetOracleDataLib.sol index 3686a319..a76370a1 100644 --- a/contracts/data/WitnetOracleDataLib.sol +++ b/contracts/data/WitnetOracleDataLib.sol @@ -117,13 +117,13 @@ library WitnetOracleDataLib { function notInStatusRevertMessage(WitnetV2.QueryStatus self) public pure returns (string memory) { if (self == WitnetV2.QueryStatus.Posted) { - return "WitnetOracle: query not in Posted status"; + return "query not in Posted status"; } else if (self == WitnetV2.QueryStatus.Reported) { - return "WitnetOracle: query not in Reported status"; + return "query not in Reported status"; } else if (self == WitnetV2.QueryStatus.Finalized) { - return "WitnetOracle: query not in Finalized status"; + return "query not in Finalized status"; } else { - return "WitnetOracle: bad mood"; + return "bad mood"; } } } From 03de54196a24ecbb02d10450855b737190982215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 21 Mar 2024 18:34:56 +0100 Subject: [PATCH 29/35] chore: upgrade optimism:sepolia --- migrations/addresses.json | 12 ++++++------ migrations/constructorArgs.json | 8 ++++---- settings/networks.js | 1 + 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/migrations/addresses.json b/migrations/addresses.json index 20f54fbb..2e597cfb 100644 --- a/migrations/addresses.json +++ b/migrations/addresses.json @@ -21,12 +21,12 @@ "WitnetErrorsLib": "0x4f2F381Ed2020095F1a1B5a0BDe5AB30da916BC9", "WitnetEncodingLib": "0xf321bcD29CFc6134c9Bf42F759f428F3A6010919", "WitnetPriceFeedsLib": "0x85aa4A0fDa112c47d4216448EE4D49Afd072675e", - "WitnetOracleDataLib": "0xe4e7c3cfc60c10190c74316c3E7711e59B7a7B7a", - "WitnetOracleTrustableOvm2": "", - "WitnetPriceFeedsDefault": "0x73912b1E13C67485D6d38Ef4F2B750C67FD99DA9", - "WitnetRandomnessV2": "0xD527ac743576A6c9fe9AeDD6dd891a6A1D337eEc", - "WitnetRequestBytecodesDefault": "0x65fB7A0C98719e967546317222dfF90A73C42296", - "WitnetRequestFactoryDefault": "0x23873d132e4Ebc34C19F405cf2bFe31dA21630c2" + "WitnetOracleDataLib": "0x25d57Cf8a047B14172Ba2a929C1441E1A77c3f9D", + "WitnetOracleTrustableOvm2": "0xeE04B260D4aBE8ABb2BB174D33b2C8731d518DdE", + "WitnetPriceFeedsDefault": "0xa07f16b1312d68bcDed1AD1164F644b309F96d06", + "WitnetRandomnessV2": "0x3C027d97b18aE66a8EE4AeDD745f0224BFbf5B40", + "WitnetRequestBytecodesDefault": "0x2D8BCBC4F8c97CC227e770d95d19914324baBF2A", + "WitnetRequestFactoryDefault": "0x3D551165020a4014A8d5b9E4b73D2b3Dbe401546" }, "ten:testnet": { "WitnetProxy": "0x4563C77E85c1374754ffec3e6220d13Ddc8620eF", diff --git a/migrations/constructorArgs.json b/migrations/constructorArgs.json index b2c43fac..4bb2b6ca 100644 --- a/migrations/constructorArgs.json +++ b/migrations/constructorArgs.json @@ -7,10 +7,10 @@ }, "optimism:sepolia": { "WitnetRandomnessV2": "00000000000000000000000077703ae126b971c9946d562f41dd47071da00777", - "WitnetRequestBytecodesDefault": "0000000000000000000000000000000000000000000000000000000000000001322e302e372d3264386665303400000000000000000000000000000000000000", - "WitnetRequestFactoryDefault": "00000000000000000000000077703ae126b971c9946d562f41dd47071da00777000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e372d3264386665303400000000000000000000000000000000000000", - "WitnetOracleTrustableOvm2": "000000000000000000000000000db36997af1f02209a6f995883b9b699900000000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e382d3762376464613800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e3aa000000000000000000000000000000000000000000000000000000000000fef90000000000000000000000000000000000000000000000000000000000010faa0000000000000000000000000000000000000000000000000000000000004e20", - "WitnetPriceFeedsDefault": "00000000000000000000000077703ae126b971c9946d562f41dd47071da007770000000000000000000000000000000000000000000000000000000000000001322e302e382d6431346538393000000000000000000000000000000000000000" + "WitnetRequestBytecodesDefault": "0000000000000000000000000000000000000000000000000000000000000001322e302e382d3465626434366300000000000000000000000000000000000000", + "WitnetRequestFactoryDefault": "00000000000000000000000077703ae126b971c9946d562f41dd47071da00777000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e382d3465626434366300000000000000000000000000000000000000", + "WitnetOracleTrustableOvm2": "000000000000000000000000000db36997af1f02209a6f995883b9b699900000000000000000000000000000000b61fe075f545fd37767f403916582759000000000000000000000000000000000000000000000000000000000000000000001322e302e382d3465626434366300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e3aa000000000000000000000000000000000000000000000000000000000000fef90000000000000000000000000000000000000000000000000000000000010faa0000000000000000000000000000000000000000000000000000000000004e20", + "WitnetPriceFeedsDefault": "00000000000000000000000077703ae126b971c9946d562f41dd47071da007770000000000000000000000000000000000000000000000000000000000000001322e302e382d3465626434366300000000000000000000000000000000000000" }, "ten:testnet": { "WitnetRequestBytecodesDefault": "0000000000000000000000000000000000000000000000000000000000000001322e302e372d3033346663383100000000000000000000000000000000000000", diff --git a/settings/networks.js b/settings/networks.js index 6a43e094..60140a84 100644 --- a/settings/networks.js +++ b/settings/networks.js @@ -294,6 +294,7 @@ module.exports = { "optimism:sepolia": { port: 8503, network_id: 11155420, + confirmations: 2, verify: { apiKey: process.env.ETHERSCAN_OPTIMISM_API_KEY, apiUrl: "https://api-sepolia-optimistic.etherscan.io/api", From 540386c1a728e31452b555e417500c49ef591b3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 22 Mar 2024 11:28:27 +0100 Subject: [PATCH 30/35] chore: refactor WitnetV2.randomUint32 -> *.randomUniformUint32 --- contracts/apps/WitnetRandomnessV2.sol | 2 +- contracts/libs/WitnetV2.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/apps/WitnetRandomnessV2.sol b/contracts/apps/WitnetRandomnessV2.sol index 70ffbe98..3f2cb56e 100644 --- a/contracts/apps/WitnetRandomnessV2.sol +++ b/contracts/apps/WitnetRandomnessV2.sol @@ -353,7 +353,7 @@ contract WitnetRandomnessV2 virtual override returns (uint32) { - return WitnetV2.randomUint32( + return WitnetV2.randomUniformUint32( _range, _nonce, keccak256( diff --git a/contracts/libs/WitnetV2.sol b/contracts/libs/WitnetV2.sol index b3cd4638..6d8cd7d1 100644 --- a/contracts/libs/WitnetV2.sol +++ b/contracts/libs/WitnetV2.sol @@ -97,7 +97,7 @@ library WitnetV2 { /// Generates a pseudo-random uint32 number uniformly distributed within the range `[0 .. range)`, based on /// the given `nonce` and `seed` values. - function randomUint32(uint32 range, uint256 nonce, bytes32 seed) + function randomUniformUint32(uint32 range, uint256 nonce, bytes32 seed) internal pure returns (uint32) { From 2728fdda6e2528fb66560e39d154ae520ed2bde4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 22 Mar 2024 11:29:32 +0100 Subject: [PATCH 31/35] refactor: WitnetRandomnessConsumer -> WitnetRandomnessRequestConsumer --- ...ndomnessConsumer.sol => WitnetRandomnessRequestConsumer.sol} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename contracts/apps/{WitnetRandomnessConsumer.sol => WitnetRandomnessRequestConsumer.sol} (98%) diff --git a/contracts/apps/WitnetRandomnessConsumer.sol b/contracts/apps/WitnetRandomnessRequestConsumer.sol similarity index 98% rename from contracts/apps/WitnetRandomnessConsumer.sol rename to contracts/apps/WitnetRandomnessRequestConsumer.sol index fe23b851..d7c1d1fe 100644 --- a/contracts/apps/WitnetRandomnessConsumer.sol +++ b/contracts/apps/WitnetRandomnessRequestConsumer.sol @@ -6,7 +6,7 @@ pragma experimental ABIEncoderV2; import "./WitnetConsumer.sol"; import "../WitnetRequest.sol"; -abstract contract WitnetRandomnessConsumer +abstract contract WitnetRandomnessRequestConsumer is WitnetConsumer { From 7e65127dcad73b20f1e7ad2b845cdc123ab61ebd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 22 Mar 2024 11:31:19 +0100 Subject: [PATCH 32/35] chore: IWitnetRandomnessEvents --- contracts/WitnetRandomness.sol | 6 ++++-- contracts/apps/WitnetRandomnessV2.sol | 15 ++++++++------- contracts/interfaces/IWitnetRandomness.sol | 8 +------- .../interfaces/IWitnetRandomnessEvents.sol | 18 ++++++++++++++++++ 4 files changed, 31 insertions(+), 16 deletions(-) create mode 100644 contracts/interfaces/IWitnetRandomnessEvents.sol diff --git a/contracts/WitnetRandomness.sol b/contracts/WitnetRandomness.sol index ecefa88b..1066cd7c 100644 --- a/contracts/WitnetRandomness.sol +++ b/contracts/WitnetRandomness.sol @@ -4,12 +4,14 @@ pragma solidity >=0.8.0 <0.9.0; import "./interfaces/IWitnetOracleEvents.sol"; import "./interfaces/IWitnetRandomness.sol"; +import "./interfaces/IWitnetRandomnessEvents.sol"; abstract contract WitnetRandomness is IWitnetOracleEvents, - IWitnetRandomness + IWitnetRandomness, + IWitnetRandomnessEvents { function class() virtual external view returns (string memory); function specs() virtual external view returns (bytes4); -} \ No newline at end of file +} diff --git a/contracts/apps/WitnetRandomnessV2.sol b/contracts/apps/WitnetRandomnessV2.sol index 3f2cb56e..80e119d8 100644 --- a/contracts/apps/WitnetRandomnessV2.sol +++ b/contracts/apps/WitnetRandomnessV2.sol @@ -367,17 +367,17 @@ contract WitnetRandomnessV2 /// @notice Requests the Witnet oracle to generate an EVM-agnostic and trustless source of randomness. /// @dev Only one randomness request per block will be actually posted to the Witnet Oracle. - /// @return _witnetEvmReward Funds actually paid as randomize fee. + /// @return _evmRandomizeFee Funds actually paid as randomize fee. function randomize() external payable virtual override - returns (uint256 _witnetEvmReward) + returns (uint256 _evmRandomizeFee) { if (__storage().lastRandomizeBlock < block.number) { - _witnetEvmReward = msg.value; + _evmRandomizeFee = msg.value; // Post the Witnet Randomness request: uint _witnetQueryId = __witnet.postRequest{ - value: _witnetEvmReward + value: _evmRandomizeFee }( witnetRadHash, __witnetDefaultSLA @@ -394,13 +394,14 @@ contract WitnetRandomnessV2 emit Randomizing( block.number, tx.gasprice, + _evmRandomizeFee, _witnetQueryId, - _witnetEvmReward + __witnetDefaultSLA ); } // Transfer back unused funds: - if (_witnetEvmReward < msg.value) { - payable(msg.sender).transfer(msg.value - _witnetEvmReward); + if (_evmRandomizeFee < msg.value) { + payable(msg.sender).transfer(msg.value - _evmRandomizeFee); } } diff --git a/contracts/interfaces/IWitnetRandomness.sol b/contracts/interfaces/IWitnetRandomness.sol index 01ee4517..70018866 100644 --- a/contracts/interfaces/IWitnetRandomness.sol +++ b/contracts/interfaces/IWitnetRandomness.sol @@ -1,19 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.7.0 <0.9.0; +pragma experimental ABIEncoderV2; import "../WitnetOracle.sol"; /// @title The Witnet Randomness generator interface. /// @author Witnet Foundation. interface IWitnetRandomness { - - event Randomizing( - uint256 blockNumber, - uint256 evmTxGasPrice, - uint256 witnetQueryId, - uint256 witnetEvmReward - ); /// @notice Returns amount of wei required to be paid as a fee when requesting randomization with a /// transaction gas price as the one given. diff --git a/contracts/interfaces/IWitnetRandomnessEvents.sol b/contracts/interfaces/IWitnetRandomnessEvents.sol new file mode 100644 index 00000000..456fcedb --- /dev/null +++ b/contracts/interfaces/IWitnetRandomnessEvents.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.7.0 <0.9.0; +pragma experimental ABIEncoderV2; + +import "../libs/WitnetV2.sol"; + +/// @title The Witnet Randomness generator interface. +/// @author Witnet Foundation. +interface IWitnetRandomnessEvents { + event Randomizing( + uint256 blockNumber, + uint256 evmTxGasPrice, + uint256 evmRandomizeFee, + uint256 witnetQueryId, + WitnetV2.RadonSLA witnetQuerySLA + ); +} From b69481f3657036d12798fab95079ba3901e30ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 22 Mar 2024 11:31:49 +0100 Subject: [PATCH 33/35] feat: UsingWitnetRandomness abstract contract --- contracts/apps/UsingWitnetRandomness.sol | 30 ++++++++++++++++++++++++ 1 file changed, 30 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 00000000..1766c1b7 --- /dev/null +++ b/contracts/apps/UsingWitnetRandomness.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.7.0 <0.9.0; +pragma experimental ABIEncoderV2; + +import "../WitnetRandomness.sol"; + +/// @title The UsingWitnetRandomness contract +/// @dev Contracts willing to interact with WitnetRandomness appliance should just inherit from this contract. +/// @author The Witnet Foundation. +abstract contract UsingWitnetRandomness + is + IWitnetOracleEvents, + IWitnetRandomnessEvents +{ + WitnetOracle immutable public witnet; + WitnetRandomness immutable public _RNG; + + constructor(WitnetRandomness _witnetRandomness) { + require( + address(_witnetRandomness).code.length > 0 + && _witnetRandomness.specs() == type(WitnetRandomness).interfaceId, + "UsingWitnetRandomness: uncompliant WitnetRandomness appliance" + ); + _RNG = _witnetRandomness; + witnet = _RNG.witnet(); + } + +} + From ddc33da613439d6caa27bd0a3ca9de169f427fc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 22 Mar 2024 12:39:17 +0100 Subject: [PATCH 34/35] feat: WitnetMockedRandomness --- contracts/apps/UsingWitnetRandomness.sol | 6 +++--- contracts/mocks/WitnetMockedOracle.sol | 1 + contracts/mocks/WitnetMockedRandomness.sol | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 contracts/mocks/WitnetMockedRandomness.sol diff --git a/contracts/apps/UsingWitnetRandomness.sol b/contracts/apps/UsingWitnetRandomness.sol index 1766c1b7..b26bbd11 100644 --- a/contracts/apps/UsingWitnetRandomness.sol +++ b/contracts/apps/UsingWitnetRandomness.sol @@ -14,7 +14,7 @@ abstract contract UsingWitnetRandomness IWitnetRandomnessEvents { WitnetOracle immutable public witnet; - WitnetRandomness immutable public _RNG; + WitnetRandomness immutable public __RNG; constructor(WitnetRandomness _witnetRandomness) { require( @@ -22,8 +22,8 @@ abstract contract UsingWitnetRandomness && _witnetRandomness.specs() == type(WitnetRandomness).interfaceId, "UsingWitnetRandomness: uncompliant WitnetRandomness appliance" ); - _RNG = _witnetRandomness; - witnet = _RNG.witnet(); + __RNG = _witnetRandomness; + witnet = __RNG.witnet(); } } diff --git a/contracts/mocks/WitnetMockedOracle.sol b/contracts/mocks/WitnetMockedOracle.sol index fc92265d..39701641 100644 --- a/contracts/mocks/WitnetMockedOracle.sol +++ b/contracts/mocks/WitnetMockedOracle.sol @@ -8,6 +8,7 @@ import "./WitnetMockedRequestFactory.sol"; import "../core/defaults/WitnetOracleTrustableDefault.sol"; import "./WitnetMockedPriceFeeds.sol"; +import "./WitnetMockedRandomness.sol"; /// @title Mocked implementation of `WitnetOracle`. /// @dev TO BE USED ONLY ON DEVELOPMENT ENVIRONMENTS. diff --git a/contracts/mocks/WitnetMockedRandomness.sol b/contracts/mocks/WitnetMockedRandomness.sol new file mode 100644 index 00000000..b8e9d451 --- /dev/null +++ b/contracts/mocks/WitnetMockedRandomness.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.7.0 <0.9.0; +pragma experimental ABIEncoderV2; + +import "./WitnetMockedOracle.sol"; +import "../apps/WitnetRandomnessV2.sol"; + +/// @title Mocked implementation of `WitnetRandomness`. +/// @dev TO BE USED ONLY ON DEVELOPMENT ENVIRONMENTS. +/// @dev ON SUPPORTED TESTNETS AND MAINNETS, PLEASE USE +/// @dev THE `WitnetRandomness` CONTRACT ADDRESS PROVIDED +/// @dev BY THE WITNET FOUNDATION. +contract WitnetMockedRandomness is WitnetRandomnessV2 { + constructor(WitnetMockedOracle _wrb) + WitnetRandomnessV2(_wrb) + {} +} From 21c62e8fb860d2ef97a49a8a7a7a8bd75841eb36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Fri, 22 Mar 2024 12:39:45 +0100 Subject: [PATCH 35/35] chore: export WitnetRandomnessV2 address --- src/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index 01f7d5b3..a69152a1 100644 --- a/src/index.js +++ b/src/index.js @@ -11,8 +11,9 @@ module.exports = { addresses[net], ) return { - WitnetPriceFeeds: merged?.WitnetPriceFeeds, WitnetOracle: merged?.WitnetOracle, + WitnetPriceFeeds: merged?.WitnetPriceFeeds, + WitnetRandomnessV2: merged?.WitnetRandomnessV2, } } else { return {}