WitOracleDataLib

Description:

Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "/contracts/data/WitOracleDataLib.sol": {
      "content": "// SPDX-License-Identifier: MIT\r
\r
pragma solidity >=0.8.0 <0.9.0;\r
\r
import "../interfaces/IWitOracleQueriableConsumer.sol";\r
import "../interfaces/IWitOracleQueriableEvents.sol";\r
import "../interfaces/IWitOracleQueriableExperimental.sol";\r
import "../interfaces/IWitOracleRadonRegistry.sol";\r
import "../interfaces/IWitOracleTrustableAdmin.sol";\r
import "../interfaces/IWitOracleQueriableTrustableReporter.sol";\r
\r
import "../interfaces/legacy/IWitOracleLegacy.sol";\r
\r
import "../libs/Witnet.sol";\r
\r
/// @title Witnet Request Board base data model library\r
/// @author The Witnet Foundation.\r
library WitOracleDataLib {  \r
\r
    using Witnet for Witnet.DataPushReport;\r
    using Witnet for Witnet.QuerySLA;\r
    using Witnet for Witnet.RadonHash;\r
    using Witnet for Witnet.Timestamp;\r
    \r
    using WitnetCBOR for WitnetCBOR.CBOR;\r
\r
    bytes32 internal constant _WIT_ORACLE_DATA_SLOTHASH =\r
        /* keccak256("io.witnet.boards.data") */\r
        0xf595240b351bc8f951c2f53b26f4e78c32cb62122cf76c19b7fdda7d4968e183;\r
\r
    struct Storage {\r
        uint64 nonce;\r
        mapping (uint256 => Query) queries;\r
        mapping (address => bool) reporters;\r
        mapping (address => mapping (Witnet.RadonHash => Committee)) committees;\r
    }\r
\r
    struct Query {\r
        QueryRequest request;\r
        QueryResponse response;\r
        Witnet.QuerySLA slaParams;\r
        Witnet.QueryUUID uuid;\r
        Witnet.QueryEvmReward reward;\r
        Witnet.BlockNumber checkpoint;\r
    }\r
\r
    struct QueryRequest {\r
        address requester; uint24 callbackGas; uint72 _0;\r
        bytes radonBytecode;\r
        bytes32 radonHash; \r
        uint256 _1;\r
    }\r
\r
    struct QueryResponse {\r
        address reporter; uint32 _0; uint64 resultTimestamp;\r
        bytes32 resultDrTxHash;\r
        bytes resultCborBytes;\r
        address disputer;\r
    }\r
\r
    struct Committee {\r
        bytes32 hash;\r
        Witnet.ServiceProvider[] members;\r
    }\r
\r
    \r
    // ================================================================================================================\r
    // --- Internal functions -----------------------------------------------------------------------------------------\r
\r
    /// Returns storage pointer to contents of 'WitnetBoardState' struct.\r
    function data() internal pure returns (Storage storage _ptr)\r
    {\r
        assembly {\r
            _ptr.slot := _WIT_ORACLE_DATA_SLOTHASH\r
        }\r
    }\r
\r
    function hashify(\r
            Witnet.QuerySLA memory querySLA, \r
            address evmRequester, \r
            Witnet.RadonHash radonHash\r
        ) \r
        internal view\r
        returns (bytes32)\r
    {\r
        return (\r
            data().committees[evmRequester][radonHash].hash != bytes32(0)\r
                ? querySLA.hashify()\r
                : keccak256(abi.encode(\r
                    querySLA.hashify(),\r
                    data().committees[evmRequester][radonHash].hash\r
                )\r
            )\r
        );\r
    }\r
\r
    /// Gets query storage by query id.\r
    function seekQuery(uint256 queryId) internal view returns (Query storage) {\r
      return data().queries[queryId];\r
    }\r
\r
    /// Gets the Witnet.QueryRequest part of a given query.\r
    function seekQueryRequest(uint256 queryId) internal view returns (QueryRequest storage) {\r
        return data().queries[queryId].request;\r
    }   \r
\r
    /// Gets the Witnet.Result part of a given query.\r
    function seekQueryResponse(uint256 queryId) internal view returns (QueryResponse storage) {\r
        return data().queries[queryId].response;\r
    }\r
\r
    function intoDataResult(\r
            QueryResponse memory queryResponse, \r
            Witnet.QueryStatus queryStatus,\r
            uint64 finalityBlock\r
        )\r
        internal pure\r
        returns (Witnet.DataResult memory _result)\r
    {\r
        _result.drTxHash = Witnet.TransactionHash.wrap(queryResponse.resultDrTxHash);\r
        if (queryResponse._0 > 0) {\r
            _result.finality = (\r
                queryResponse._0 | uint64(\r
                    (queryResponse.resultTimestamp & 0xffffffff) << 32\r
                )\r
            );\r
            _result.timestamp = Witnet.Timestamp.wrap(queryResponse.resultTimestamp >> 32);\r
        } else {\r
            _result.finality = finalityBlock;\r
            _result.timestamp = Witnet.Timestamp.wrap(queryResponse.resultTimestamp);\r
        }\r
        if (queryResponse.resultCborBytes.length > 0) {\r
            _result.value = WitnetCBOR.fromBytes(queryResponse.resultCborBytes);\r
            _result.dataType = Witnet.peekRadonDataType(_result.value);\r
        }\r
        if (queryStatus == Witnet.QueryStatus.Finalized) {\r
            if (queryResponse.resultCborBytes.length > 0) {\r
                // determine whether stored result is an error by peeking the first byte\r
                if (queryResponse.resultCborBytes[0] == bytes1(0xd8)) {\r
                    if (\r
                        _result.dataType == Witnet.RadonDataTypes.Array\r
                            && WitnetCBOR.readLength(_result.value.buffer, _result.value.additionalInformation) >= 1\r
                    ) {\r
                        if (Witnet.peekRadonDataType(_result.value) == Witnet.RadonDataTypes.Integer) {\r
                            _result.status = Witnet.ResultStatus(_result.value.readInt());\r
                        \r
                        } else {\r
                            _result.status = Witnet.ResultStatus.UnhandledIntercept;\r
                        }\r
                    } else {\r
                        _result.status = Witnet.ResultStatus.UnhandledIntercept;\r
                    }            \r
                } else {\r
                    _result.status = Witnet.ResultStatus.NoErrors;\r
                }\r
            } else {\r
                // the result is final but was delivered to some consuming contract:\r
                _result.status = Witnet.ResultStatus.NoErrors;\r
            }\r
        \r
        } else if (queryStatus == Witnet.QueryStatus.Reported) {\r
            _result.status = Witnet.ResultStatus.BoardFinalizingResult;\r
\r
        } else if (\r
            queryStatus == Witnet.QueryStatus.Posted\r
                || queryStatus == Witnet.QueryStatus.Delayed\r
        ) {\r
            _result.status = Witnet.ResultStatus.BoardAwaitingResult;\r
        \r
        } else if (\r
            queryStatus == Witnet.QueryStatus.Expired\r
                || queryStatus == Witnet.QueryStatus.Disputed\r
        ) {\r
            _result.status = Witnet.ResultStatus.BoardResolutionTimeout;\r
        \r
        } else {\r
            _result.status = Witnet.ResultStatus.UnhandledIntercept;\r
        }\r
    }\r
\r
    function intoString(Witnet.QueryStatus _status) internal pure returns (string memory) {\r
        if (_status == Witnet.QueryStatus.Posted) {\r
            return "Posted";\r
        } else if (_status == Witnet.QueryStatus.Reported) {\r
            return "Reported";\r
        } else if (_status == Witnet.QueryStatus.Finalized) {\r
            return "Finalized";\r
        } else if (_status == Witnet.QueryStatus.Delayed) {\r
            return "Delayed";\r
        } else if (_status == Witnet.QueryStatus.Expired) {\r
            return "Expired";\r
        } else if (_status == Witnet.QueryStatus.Disputed) {\r
            return "Disputed";\r
        } else {\r
            return "Unknown";\r
        }\r
    }\r
\r
\r
    /// =======================================================================\r
    /// --- IWitOracleTrustableAdmin -----------------------------------------------\r
\r
    function isReporter(address addr) internal view returns (bool) {\r
        return data().reporters[addr];\r
    }\r
\r
    function setReporters(address[] calldata reporters) public {\r
        for (uint ix = 0; ix < reporters.length; ix ++) {\r
            data().reporters[reporters[ix]] = true;\r
        }\r
        emit IWitOracleTrustableAdmin.ReportersSet(reporters);\r
    }\r
\r
    function unsetReporters(address[] calldata reporters) public {\r
        for (uint ix = 0; ix < reporters.length; ix ++) {\r
            data().reporters[reporters[ix]] = false;\r
        }\r
        emit IWitOracleTrustableAdmin.ReportersUnset(reporters);\r
    }\r
\r
    \r
    /// =======================================================================\r
    /// --- IWitOracle --------------------------------------------------------\r
\r
    function extractDataResult(\r
            QueryResponse memory queryResponse, \r
            Witnet.QueryStatus queryStatus,\r
            uint64 finalityBlock\r
        )\r
        public pure \r
        returns (Witnet.DataResult memory)\r
    {\r
        return intoDataResult(queryResponse, queryStatus, finalityBlock);\r
    }\r
\r
    function parseDataReport(\r
            Witnet.DataPushReport calldata _dataPushReport, \r
            bytes calldata _signature\r
        )\r
        public view\r
        returns (\r
            address _evmReporter, \r
            Witnet.DataResult memory _data\r
        )\r
    {\r
        _evmReporter = Witnet.recoverEvmAddr(_signature, _dataPushReport.digest());\r
        require(data().reporters[_evmReporter], "WitOracleDataLib: invalid signature");\r
        _data = extractDataResult(\r
            QueryResponse({\r
                reporter: _evmReporter, \r
                resultCborBytes: _dataPushReport.resultCborBytes,\r
                resultDrTxHash: Witnet.TransactionHash.unwrap(_dataPushReport.witDrTxHash),\r
                resultTimestamp: Witnet.Timestamp.unwrap(_dataPushReport.resultTimestamp),\r
                disputer: address(0), _0: 0\r
            }), \r
            Witnet.QueryStatus.Finalized,\r
            uint64(block.number)\r
        );\r
    }\r
\r
    /// =======================================================================\r
    /// --- IWitOracleQueriable -----------------------------------------------\r
\r
    function deleteQuery(uint256 queryId) \r
        public \r
        returns (Witnet.QueryEvmReward _evmPayback) \r
    {\r
        WitOracleDataLib.Query storage __query = seekQuery(queryId);\r
        require(\r
            msg.sender == __query.request.requester,\r
            "not the requester"\r
        );\r
        Witnet.QueryStatus _queryStatus = getQueryStatus(queryId);\r
        if (\r
            _queryStatus != Witnet.QueryStatus.Expired\r
                && _queryStatus != Witnet.QueryStatus.Finalized\r
        ) {\r
            revert(string(abi.encodePacked(\r
                "invalid query status: ",\r
                toString(_queryStatus)\r
            )));\r
        }\r
        _evmPayback = __query.reward;\r
        delete data().queries[queryId];\r
    }\r
\r
    function getQuery(Witnet.QueryId queryId) public view returns (Witnet.Query memory) {\r
        WitOracleDataLib.Query storage __query = data().queries[Witnet.QueryId.unwrap(queryId)];\r
        Witnet.QueryUUID _uuid;\r
        Witnet.QueryEvmReward _reward;\r
        Witnet.BlockNumber _checkpoint;\r
        if (__query.request._1 > 0) {\r
            // read from v2 layout\r
            _checkpoint = Witnet.BlockNumber.wrap(__query.response._0);\r
            _reward = Witnet.QueryEvmReward.wrap(__query.request._0);\r
\r
        } else if (__query.request.radonBytecode.length <= 65535) {\r
            // read from v3 layout\r
            _checkpoint = __query.checkpoint;\r
            _reward = __query.reward;\r
            _uuid = __query.uuid;\r
        }\r
        return Witnet.Query({\r
            request: getQueryRequest(queryId),\r
            response: getQueryResponse(queryId),\r
            slaParams: __query.slaParams,\r
            uuid: __query.uuid,\r
            reward: __query.reward,\r
            checkpoint: __query.checkpoint\r
        });\r
    }\r
\r
    function getQueryRequest(Witnet.QueryId queryId) public view returns (Witnet.QueryRequest memory) {\r
        WitOracleDataLib.Query storage __query = data().queries[Witnet.QueryId.unwrap(queryId)];\r
        if (__query.request.radonBytecode.length > 65535) {\r
            // read from v1 layout\r
            return Witnet.QueryRequest({\r
                requester: address(0),\r
                callbackGas: 0,\r
                radonBytecode: hex"",\r
                radonHash: Witnet.RadonHash.wrap(__query.request.radonHash)\r
            });\r
        } else {\r
            return Witnet.QueryRequest({\r
                requester: __query.request.requester,\r
                callbackGas: __query.request.callbackGas,\r
                radonBytecode: __query.request.radonBytecode,\r
                radonHash: Witnet.RadonHash.wrap(__query.request.radonHash)\r
            });\r
        }\r
    }\r
\r
    function getQueryResponse(Witnet.QueryId queryId) public view returns (Witnet.QueryResponse memory) {\r
        WitOracleDataLib.Query storage __query = data().queries[Witnet.QueryId.unwrap(queryId)];\r
        if (__query.request.radonBytecode.length > 65535) {\r
            // read from v1 layout\r
            return Witnet.QueryResponse({\r
                reporter: address(0),\r
                resultTimestamp: Witnet.Timestamp.wrap(0),\r
                resultDrTxHash: Witnet.TransactionHash.wrap(0),\r
                resultCborBytes: __query.response.resultCborBytes,\r
                disputer: address(0)\r
            });\r
        } else if (__query.request._1 > 0) {\r
            // read from v2 layout\r
            return Witnet.QueryResponse({\r
                reporter: __query.response.reporter,\r
                resultTimestamp: Witnet.Timestamp.wrap(__query.response.resultTimestamp >> 32),\r
                resultDrTxHash: Witnet.TransactionHash.wrap(__query.response.resultDrTxHash),\r
                resultCborBytes: __query.response.resultCborBytes,\r
                disputer: address(0)\r
            });\r
        } else {\r
            return Witnet.QueryResponse({\r
                reporter: __query.response.reporter,\r
                resultTimestamp: Witnet.Timestamp.wrap(__query.response.resultTimestamp),\r
                resultDrTxHash: Witnet.TransactionHash.wrap(__query.response.resultDrTxHash),\r
                resultCborBytes: __query.response.resultCborBytes,\r
                disputer: __query.response.disputer\r
            });\r
        }\r
    }\r
\r
    function getQueryStatus(uint256 queryId) public view returns (Witnet.QueryStatus) {\r
        WitOracleDataLib.Query storage __query = seekQuery(queryId);\r
        if (__query.response.resultTimestamp != 0) {\r
            return Witnet.QueryStatus.Finalized;\r
            \r
        } else if (__query.request.requester != address(0)) {\r
            return Witnet.QueryStatus.Posted;\r
        \r
        } else {\r
            return Witnet.QueryStatus.Unknown;\r
        }\r
    }\r
\r
    function getQueryResult(uint256 queryId) public view returns (Witnet.DataResult memory _result) {\r
        Witnet.QueryStatus _queryStatus = getQueryStatus(queryId);\r
        WitOracleDataLib.Query storage __query = seekQuery(queryId);\r
        return intoDataResult(\r
            __query.response,\r
            _queryStatus,\r
            Witnet.BlockNumber.unwrap(__query.checkpoint)\r
        );\r
    }\r
    \r
    function getQueryResultStatus(uint256 queryId) public view returns (Witnet.ResultStatus) {\r
        Witnet.QueryStatus _queryStatus = getQueryStatus(queryId);\r
        QueryResponse storage __response = seekQueryResponse(queryId);\r
        if (_queryStatus == Witnet.QueryStatus.Finalized) {\r
            if (__response.resultCborBytes.length > 0) {\r
                // determine whether stored result is an error by peeking the first byte\r
                if (__response.resultCborBytes[0] == bytes1(0xd8)) {\r
                    WitnetCBOR.CBOR[] memory _error = WitnetCBOR.fromBytes(__response.resultCborBytes).readArray();\r
                    if (_error.length < 2) {\r
                        return Witnet.ResultStatus.UnhandledIntercept;\r
                    } else {\r
                        return Witnet.ResultStatus(_error[0].readUint());\r
                    }\r
                }\r
            }\r
            return Witnet.ResultStatus.NoErrors;\r
        \r
        } else if (_queryStatus == Witnet.QueryStatus.Reported) {\r
            return Witnet.ResultStatus.BoardFinalizingResult;\r
\r
        } else if (\r
            _queryStatus == Witnet.QueryStatus.Posted\r
                || _queryStatus == Witnet.QueryStatus.Delayed\r
        ) {\r
            return Witnet.ResultStatus.BoardAwaitingResult;\r
        \r
        } else if (\r
            _queryStatus == Witnet.QueryStatus.Expired\r
                || _queryStatus == Witnet.QueryStatus.Disputed\r
        ) {\r
            return Witnet.ResultStatus.BoardResolutionTimeout;\r
        \r
        } else {\r
            return Witnet.ResultStatus.UnhandledIntercept;\r
        }\r
    }\r
\r
    function getQueryResponseStatus(uint256 queryId)\r
        public view \r
        returns (IWitOracleLegacy.QueryResponseStatus)\r
    {\r
        Witnet.QueryStatus _queryStatus = getQueryStatus(queryId);\r
        if (_queryStatus == Witnet.QueryStatus.Finalized) {\r
            bytes storage __cborValues = WitOracleDataLib.seekQueryResponse(queryId).resultCborBytes;\r
            if (__cborValues.length > 0) {\r
                // determine whether stored result is an error by peeking the first byte\r
                return (__cborValues[0] == bytes1(0xd8)\r
                    ? IWitOracleLegacy.QueryResponseStatus.Error \r
                    : IWitOracleLegacy.QueryResponseStatus.Ready\r
                );\r
            \r
            } else {\r
                // the result is final but delivered to the requesting address\r
                return IWitOracleLegacy.QueryResponseStatus.Delivered;\r
            }\r
        \r
        } else if (_queryStatus == Witnet.QueryStatus.Posted) {\r
            return IWitOracleLegacy.QueryResponseStatus.Awaiting;\r
        \r
        } else if (_queryStatus == Witnet.QueryStatus.Expired) {\r
            return IWitOracleLegacy.QueryResponseStatus.Expired;\r
        \r
        } else {\r
            return IWitOracleLegacy.QueryResponseStatus.Void;\r
        }\r
    }\r
\r
    \r
    /// ================================================================================\r
    /// --- IWitOracleQueriableTrustableReporter ---------------------------------------\r
\r
    function extractRadonBytecodes(\r
            IWitOracleRadonRegistry registry, \r
            Witnet.QueryId[] calldata queryIds\r
        )\r
        public view\r
        returns (bytes[] memory bytecodes)\r
    {\r
        bytecodes = new bytes[](queryIds.length);\r
        for (uint _ix = 0; _ix < queryIds.length; _ix ++) {\r
            uint256 _queryId = Witnet.QueryId.unwrap(queryIds[_ix]);\r
            WitOracleDataLib.Query storage __query = seekQuery(_queryId);\r
            bytecodes[_ix] = (__query.request.radonHash != bytes32(0)\r
                ? registry.bytecodeOf(Witnet.RadonHash.wrap(__query.request.radonHash), __query.slaParams)\r
                : registry.bytecodeOf(__query.request.radonBytecode, __query.slaParams)\r
            );\r
        }\r
    }\r
\r
    function reportResult(\r
            address evmReporter,\r
            uint256 evmGasPrice,\r
            uint64  evmFinalityBlock,\r
            uint256 queryId,\r
            Witnet.Timestamp resultTimestamp,\r
            Witnet.TransactionHash witDrTxHash,\r
            bytes calldata resultCborBytes\r
        )\r
        public returns (uint256 evmReward)\r
    {\r
        // read requester address and whether a callback was requested:\r
        WitOracleDataLib.Query storage __query = seekQuery(queryId);\r
\r
        // read query EVM reward:\r
        evmReward = Witnet.QueryEvmReward.unwrap(__query.reward);\r
\r
        // set EVM reward right now as to avoid re-entrancy attacks:\r
        __query.reward = Witnet.QueryEvmReward.wrap(0);\r
\r
        // determine whether a callback is required\r
        if (__query.request.callbackGas > 0) {\r
            (\r
                uint256 _evmCallbackActualGas, \r
                bool _evmCallbackSuccess, \r
                string memory _evmCallbackRevertMessage\r
            ) = __reportResultCallback(\r
                evmReporter,\r
                __query.request.requester,\r
                __query.request.callbackGas,\r
                evmFinalityBlock,\r
                Witnet.QueryId.wrap(uint64(queryId)),\r
                resultTimestamp,\r
                witDrTxHash,\r
                resultCborBytes\r
            );\r
            if (_evmCallbackSuccess) {\r
                // => the callback run successfully\r
                emit IWitOracleQueriableEvents.WitOracleQueryReportDelivery(\r
                    Witnet.QueryId.wrap(uint64(queryId)),\r
                    __query.request.requester,\r
                    evmGasPrice,\r
                    _evmCallbackActualGas\r
                );\r
            } else {\r
                // => the callback reverted\r
                emit IWitOracleQueriableEvents.WitOracleResportDeliveryFailed(\r
                    Witnet.QueryId.wrap(uint64(queryId)),\r
                    __query.request.requester,\r
                    evmGasPrice,\r
                    _evmCallbackActualGas,\r
                    bytes(_evmCallbackRevertMessage).length > 0 \r
                        ? _evmCallbackRevertMessage\r
                        : "WitOracleDataLib: callback exceeded gas limit",\r
                    resultCborBytes\r
                );\r
            }\r
            // upon delivery, successfull or not, the audit trail is saved into storage, \r
            // but not the actual result which was intended to be passed over to the requester:\r
            __saveQueryResponse(\r
                evmReporter,\r
                evmFinalityBlock,\r
                queryId,\r
                resultTimestamp, \r
                witDrTxHash,\r
                hex""\r
            );\r
        } else {\r
            // => no callback is involved\r
            emit IWitOracleQueriableEvents.WitOracleQueryReport(\r
                Witnet.QueryId.wrap(uint64(queryId)),\r
                evmGasPrice\r
            );\r
            // write query result and audit trail data into storage \r
            __saveQueryResponse(\r
                evmReporter,\r
                evmFinalityBlock,\r
                queryId,\r
                resultTimestamp,\r
                witDrTxHash,\r
                resultCborBytes\r
            );\r
        }\r
    }\r
\r
    function __reportResultCallback(\r
            address evmReporter,\r
            address evmRequester,\r
            uint24  evmCallbackGasLimit,\r
            uint64  evmFinalityBlock,\r
            Witnet.QueryId queryId,\r
            Witnet.Timestamp resultTimestamp,\r
            Witnet.TransactionHash witDrTxHash,\r
            bytes calldata resultCborBytes\r
        )\r
        private returns (\r
            uint256 evmCallbackActualGas, \r
            bool evmCallbackSuccess, \r
            string memory evmCallbackRevertMessage\r
        )\r
    {\r
        evmCallbackActualGas = gasleft();\r
        Witnet.DataResult memory _result = intoDataResult(\r
            QueryResponse({\r
                reporter: evmReporter,\r
                resultTimestamp: Witnet.Timestamp.unwrap(resultTimestamp),\r
                resultDrTxHash: Witnet.TransactionHash.unwrap(witDrTxHash),\r
                resultCborBytes: resultCborBytes,\r
                disputer: address(0), _0: 0\r
            }),\r
            evmFinalityBlock <= block.number ? Witnet.QueryStatus.Finalized : Witnet.QueryStatus.Reported,\r
            evmFinalityBlock\r
        );\r
        try IWitOracleQueriableConsumer(evmRequester).reportWitOracleQueryResult{\r
            gas: evmCallbackGasLimit\r
        } (\r
            Witnet.QueryId.unwrap(queryId),\r
            abi.encode(_result)\r
        ) {\r
            evmCallbackSuccess = true;\r
        \r
        } catch Error(string memory err) {\r
            evmCallbackRevertMessage = err;\r
        \r
        } catch (bytes memory) {\r
            evmCallbackRevertMessage = "callback revert";\r
        }\r
        evmCallbackActualGas -= gasleft();\r
    }\r
\r
    /// Saves query response into storage.\r
    function __saveQueryResponse(\r
            address evmReporter,\r
            uint64  evmFinalityBlock,\r
            uint256 queryId,\r
            Witnet.Timestamp resultTimestamp,\r
            Witnet.TransactionHash witDrTxHash,\r
            bytes memory resultCborBytes\r
        ) private\r
    {\r
        WitOracleDataLib.Query storage __query = seekQuery(queryId);\r
        __query.checkpoint = Witnet.BlockNumber.wrap(evmFinalityBlock);\r
        __query.response.reporter = evmReporter; \r
        __query.response.resultTimestamp = Witnet.Timestamp.unwrap(resultTimestamp);\r
        __query.response.resultDrTxHash = Witnet.TransactionHash.unwrap(witDrTxHash);\r
        __query.response.resultCborBytes = resultCborBytes;\r
    }\r
\r
\r
    /// =======================================================================\r
    /// --- IWitOracleQueriableExperimental -----------------------------------\r
\r
    function extractDelegatedDataRequest(\r
            IWitOracleRadonRegistry registry,\r
            Witnet.QueryId queryId\r
        )\r
        public view\r
        returns (IWitOracleQueriableExperimental.DDR memory)\r
    {\r
        WitOracleDataLib.Query storage __query = seekQuery(Witnet.QueryId.unwrap(queryId));\r
        \r
        bytes memory _radonBytecode;\r
        Witnet.RadonHash _radonHash = Witnet.RadonHash.wrap(__query.request.radonHash);\r
        if (_radonHash.isZero()) {\r
            _radonBytecode = __query.request.radonBytecode;\r
            _radonHash = registry.hashOf(_radonBytecode);\r
        } else {\r
            _radonBytecode = registry.lookupRadonRequestBytecode(_radonHash);\r
        }\r
        \r
        Witnet.ServiceProvider[] memory _providers = data().committees\r
            [__query.request.requester]\r
            [_radonHash]\r
            .members;\r
\r
        Witnet.QuerySLA memory _querySLA = __query.slaParams;\r
        \r
        return IWitOracleQueriableExperimental.DDR({\r
            queryId: queryId,\r
            queryUUID: __query.uuid,\r
            queryEvmReward: __query.reward,\r
            queryParams: IWitOracleQueriableExperimental.QueryParams({\r
                witResultMaxSize: _querySLA.witResultMaxSize,\r
                witCommitteeSize: _querySLA.witCommitteeSize,\r
                witUnitaryReward: _querySLA.witUnitaryReward,\r
                providers: _providers\r
            }),\r
            radonBytecode: _radonBytecode\r
        });\r
    }\r
\r
    \r
    /// =======================================================================\r
    /// --- Other public helper methods ---------------------------------------\r
\r
    function notInStatusRevertMessage(Witnet.QueryStatus self) public pure returns (string memory) {\r
        if (self == Witnet.QueryStatus.Posted) {\r
            return "not in Posted status";\r
        } else if (self == Witnet.QueryStatus.Reported) {\r
            return "not in Reported status";\r
        } else if (self == Witnet.QueryStatus.Finalized) {\r
            return "not in Finalized status";\r
        } else {\r
            return "bad mood";\r
        }\r
    }\r
\r
    function settle(Committee storage self, Witnet.ServiceProvider[] calldata members) public returns (bytes32 hash) {\r
        if (members.length > 0) {\r
            hash = keccak256(abi.encodePacked(members));\r
            self.hash = hash;\r
            self.members = members;\r
        } else {\r
            delete self.members;\r
            self.hash = bytes32(0);\r
        }\r
    }\r
\r
    function toString(Witnet.QueryStatus _status) public pure returns (string memory) {\r
        return intoString(_status);\r
    }\r
\r
}\r
"
    },
    "/contracts/libs/WitnetCBOR.sol": {
      "content": "// SPDX-License-Identifier: MIT\r
\r
pragma solidity >=0.8.0 <0.9.0;\r
\r
import "./WitnetBuffer.sol";\r
\r
/// @title A minimalistic implementation of “RFC 7049 Concise Binary Object Representation”\r
/// @notice This library leverages a buffer-like structure for step-by-step decoding of bytes so as to minimize\r
/// the gas cost of decoding them into a useful native type.\r
/// @dev Most of the logic has been borrowed from Patrick Gansterer’s cbor.js library: https://github.com/paroga/cbor-js\r
/// @author The Witnet Foundation.\r
\r
library WitnetCBOR {\r
\r
  using WitnetBuffer for WitnetBuffer.Buffer;\r
  using WitnetCBOR for WitnetCBOR.CBOR;\r
\r
  /// Data struct following the RFC-7049 standard: Concise Binary Object Representation.\r
  struct CBOR {\r
      WitnetBuffer.Buffer buffer;\r
      uint8 initialByte;\r
      uint8 majorType;\r
      uint8 additionalInformation;\r
      uint64 len;\r
      uint64 tag;\r
  }\r
\r
  uint8 internal constant MAJOR_TYPE_INT = 0;\r
  uint8 internal constant MAJOR_TYPE_NEGATIVE_INT = 1;\r
  uint8 internal constant MAJOR_TYPE_BYTES = 2;\r
  uint8 internal constant MAJOR_TYPE_STRING = 3;\r
  uint8 internal constant MAJOR_TYPE_ARRAY = 4;\r
  uint8 internal constant MAJOR_TYPE_MAP = 5;\r
  uint8 internal constant MAJOR_TYPE_TAG = 6;\r
  uint8 internal constant MAJOR_TYPE_CONTENT_FREE = 7;\r
\r
  uint32 internal constant UINT32_MAX = type(uint32).max;\r
  uint64 internal constant UINT64_MAX = type(uint64).max;\r
  \r
  error EmptyArray();\r
  error InvalidLengthEncoding(uint length);\r
  error UnexpectedMajorType(uint read, uint expected);\r
  error UnsupportedPrimitive(uint primitive);\r
  error UnsupportedMajorType(uint unexpected);  \r
\r
  modifier isMajorType(\r
      WitnetCBOR.CBOR memory cbor,\r
      uint8 expected\r
  ) {\r
    if (cbor.majorType != expected) {\r
      revert UnexpectedMajorType(cbor.majorType, expected);\r
    }\r
    _;\r
  }\r
\r
  modifier notEmpty(WitnetBuffer.Buffer memory buffer) {\r
    if (buffer.data.length == 0) {\r
      revert WitnetBuffer.EmptyBuffer();\r
    }\r
    _;\r
  }\r
\r
  function eof(CBOR memory cbor)\r
    internal pure\r
    returns (bool)\r
  {\r
    return cbor.buffer.cursor >= cbor.buffer.data.length;\r
  }\r
\r
  /// @notice Decode a CBOR structure from raw bytes.\r
  /// @dev This is the main factory for CBOR instances, which can be later decoded into native EVM types.\r
  /// @param bytecode Raw bytes representing a CBOR-encoded value.\r
  /// @return A `CBOR` instance containing a partially decoded value.\r
  function fromBytes(bytes memory bytecode)\r
    internal pure\r
    returns (CBOR memory)\r
  {\r
    WitnetBuffer.Buffer memory buffer = WitnetBuffer.Buffer(bytecode, 0);\r
    return fromBuffer(buffer);\r
  }\r
\r
  /// @notice Decode a CBOR structure from raw bytes.\r
  /// @dev This is an alternate factory for CBOR instances, which can be later decoded into native EVM types.\r
  /// @param buffer A Buffer structure representing a CBOR-encoded value.\r
  /// @return A `CBOR` instance containing a partially decoded value.\r
  function fromBuffer(WitnetBuffer.Buffer memory buffer)\r
    internal pure\r
    notEmpty(buffer)\r
    returns (CBOR memory)\r
  {\r
    uint8 initialByte;\r
    uint8 majorType = 255;\r
    uint8 additionalInformation;\r
    uint64 tag = UINT64_MAX;\r
    uint256 len;\r
    bool isTagged = true;\r
    while (isTagged) {\r
      // Extract basic CBOR properties from input bytes\r
      initialByte = buffer.readUint8();\r
      len ++;\r
      majorType = initialByte >> 5;\r
      additionalInformation = initialByte & 0x1f;\r
      // Early CBOR tag parsing.\r
      if (majorType == MAJOR_TYPE_TAG) {\r
        uint _cursor = buffer.cursor;\r
        tag = readLength(buffer, additionalInformation);\r
        len += buffer.cursor - _cursor;\r
      } else {\r
        isTagged = false;\r
      }\r
    }\r
    if (majorType > MAJOR_TYPE_CONTENT_FREE) {\r
      revert UnsupportedMajorType(majorType);\r
    }\r
    return CBOR(\r
      buffer,\r
      initialByte,\r
      majorType,\r
      additionalInformation,\r
      uint64(len),\r
      tag\r
    );\r
  }\r
\r
  function fork(WitnetCBOR.CBOR memory self)\r
    internal pure\r
    returns (WitnetCBOR.CBOR memory)\r
  {\r
    return CBOR({\r
      buffer: self.buffer.fork(),\r
      initialByte: self.initialByte,\r
      majorType: self.majorType,\r
      additionalInformation: self.additionalInformation,\r
      len: self.len,\r
      tag: self.tag\r
    });\r
  }\r
\r
  function settle(CBOR memory self)\r
      internal pure\r
      returns (WitnetCBOR.CBOR memory)\r
  {\r
    if (!self.eof()) {\r
      return fromBuffer(self.buffer);\r
    } else {\r
      return self;\r
    }\r
  }\r
\r
  function skip(CBOR memory self)\r
      internal pure\r
      returns (WitnetCBOR.CBOR memory)\r
  {\r
    if (\r
      self.majorType == MAJOR_TYPE_INT\r
        || self.majorType == MAJOR_TYPE_NEGATIVE_INT\r
        || (\r
          self.majorType == MAJOR_TYPE_CONTENT_FREE \r
            && self.additionalInformation >= 25\r
            && self.additionalInformation <= 27\r
        )\r
    ) {\r
      self.buffer.cursor += self.peekLength();\r
    } else if (\r
        self.majorType == MAJOR_TYPE_STRING\r
          || self.majorType == MAJOR_TYPE_BYTES\r
    ) {\r
      uint64 len = readLength(self.buffer, self.additionalInformation);\r
      self.buffer.cursor += len;\r
    } else if (\r
      self.majorType == MAJOR_TYPE_ARRAY\r
        || self.majorType == MAJOR_TYPE_MAP\r
    ) { \r
      self.len = readLength(self.buffer, self.additionalInformation);      \r
    } else if (\r
       self.majorType != MAJOR_TYPE_CONTENT_FREE\r
        || (\r
          self.additionalInformation != 20\r
            && self.additionalInformation != 21\r
        )\r
    ) {\r
      revert("WitnetCBOR.skip: unsupported major type");\r
    }\r
    return self;\r
  }\r
\r
  function peekLength(CBOR memory self)\r
    internal pure\r
    returns (uint64)\r
  {\r
    if (self.additionalInformation < 24) {\r
      return 0;\r
    } else if (self.additionalInformation < 28) {\r
      return uint64(1 << (self.additionalInformation - 24));\r
    } else {\r
      revert InvalidLengthEncoding(self.additionalInformation);\r
    }\r
  }\r
\r
  function readArray(CBOR memory self)\r
    internal pure\r
    isMajorType(self, MAJOR_TYPE_ARRAY)\r
    returns (CBOR[] memory items)\r
  {\r
    // read array's length and move self cursor forward to the first array element:\r
    uint64 len = readLength(self.buffer, self.additionalInformation);\r
    items = new CBOR[](len + 1);\r
    for (uint ix = 0; ix < len; ix ++) {\r
      // settle next element in the array:\r
      self = self.settle();\r
      // fork it and added to the list of items to be returned:\r
      items[ix] = self.fork();\r
      if (self.majorType == MAJOR_TYPE_ARRAY) {\r
        CBOR[] memory _subitems = self.readArray();\r
        // move forward to the first element after inner array:\r
        self = _subitems[_subitems.length - 1];\r
      } else if (self.majorType == MAJOR_TYPE_MAP) {\r
        CBOR[] memory _subitems = self.readMap();\r
        // move forward to the first element after inner map:\r
        self = _subitems[_subitems.length - 1];\r
      } else {\r
        // move forward to the next element:\r
        self.skip();\r
      }\r
    }\r
    // return self cursor as extra item at the end of the list,\r
    // as to optimize recursion when jumping over nested arrays:\r
    items[len] = self;\r
  }\r
\r
  function readMap(CBOR memory self)\r
    internal pure\r
    isMajorType(self, MAJOR_TYPE_MAP)\r
    returns (CBOR[] memory items)\r
  {\r
    // read number of items within the map and move self cursor forward to the first inner element:\r
    uint64 len = readLength(self.buffer, self.additionalInformation) * 2;\r
    items = new CBOR[](len + 1);\r
    for (uint ix = 0; ix < len; ix ++) {\r
      // settle next element in the array:\r
      self = self.settle();\r
      // fork it and added to the list of items to be returned:\r
      items[ix] = self.fork();\r
      if (ix % 2 == 0 && self.majorType != MAJOR_TYPE_STRING) {\r
        revert UnexpectedMajorType(self.majorType, MAJOR_TYPE_STRING);\r
      } else if (self.majorType == MAJOR_TYPE_ARRAY || self.majorType == MAJOR_TYPE_MAP) {\r
        CBOR[] memory _subitems = (self.majorType == MAJOR_TYPE_ARRAY\r
            ? self.readArray()\r
            : self.readMap()\r
        );\r
        // move forward to the first element after inner array or map:\r
        self = _subitems[_subitems.length - 1];\r
      } else {\r
        // move forward to the next element:\r
        self.skip();\r
      }\r
    }\r
    // return self cursor as extra item at the end of the list,\r
    // as to optimize recursion when jumping over nested arrays:\r
    items[len] = self;\r
  }\r
\r
  /// Reads the length of the settle CBOR item from a buffer, consuming a different number of bytes depending on the\r
  /// value of the `additionalInformation` argument.\r
  function readLength(\r
      WitnetBuffer.Buffer memory buffer,\r
      uint8 additionalInformation\r
    ) \r
    internal pure\r
    returns (uint64)\r
  {\r
    if (additionalInformation < 24) {\r
      return additionalInformation;\r
    }\r
    if (additionalInformation == 24) {\r
      return buffer.readUint8();\r
    }\r
    if (additionalInformation == 25) {\r
      return buffer.readUint16();\r
    }\r
    if (additionalInformation == 26) {\r
      return buffer.readUint32();\r
    }\r
    if (additionalInformation == 27) {\r
      return buffer.readUint64();\r
    }\r
    if (additionalInformation == 31) {\r
      return UINT64_MAX;\r
    }\r
    revert InvalidLengthEncoding(additionalInformation);\r
  }\r
\r
  /// @notice Read a `CBOR` structure into a native `bool` value.\r
  /// @param cbor An instance of `CBOR`.\r
  /// @return The value represented by the input, as a `bool` value.\r
  function readBool(CBOR memory cbor)\r
    internal pure\r
    isMajorType(cbor, MAJOR_TYPE_CONTENT_FREE)\r
    returns (bool)\r
  {\r
    if (cbor.additionalInformation == 20) {\r
      return false;\r
    } else if (cbor.additionalInformation == 21) {\r
      return true;\r
    } else {\r
      revert UnsupportedPrimitive(cbor.additionalInformation);\r
    }\r
  }\r
\r
  /// @notice Decode a `CBOR` structure into a native `bytes` value.\r
  /// @param cbor An instance of `CBOR`.\r
  /// @return output The value represented by the input, as a `bytes` value.   \r
  function readBytes(CBOR memory cbor)\r
    internal pure\r
    isMajorType(cbor, MAJOR_TYPE_BYTES)\r
    returns (bytes memory output)\r
  {\r
    cbor.len = readLength(\r
      cbor.buffer,\r
      cbor.additionalInformation\r
    );\r
    if (cbor.len == UINT32_MAX) {\r
      // These checks look repetitive but the equivalent loop would be more expensive.\r
      uint32 length = uint32(_readIndefiniteStringLength(\r
        cbor.buffer,\r
        cbor.majorType\r
      ));\r
      if (length < UINT32_MAX) {\r
        output = abi.encodePacked(cbor.buffer.read(length));\r
        length = uint32(_readIndefiniteStringLength(\r
          cbor.buffer,\r
          cbor.majorType\r
        ));\r
        if (length < UINT32_MAX) {\r
          output = abi.encodePacked(\r
            output,\r
            cbor.buffer.read(length)\r
          );\r
        }\r
      }\r
    } else {\r
      return cbor.buffer.read(uint32(cbor.len));\r
    }\r
  }\r
\r
  /// @notice Decode a `CBOR` structure into a `fixed16` value.\r
  /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values\r
  /// by 5 decimal orders so as to get a fixed precision of 5 decimal positions, which should be OK for most `fixed16`\r
  /// use cases. In other words, the output of this method is 10,000 times the actual value, encoded into an `int32`.\r
  /// @param cbor An instance of `CBOR`.\r
  /// @return The value represented by the input, as an `int128` value.\r
  function readFloat16(CBOR memory cbor)\r
    internal pure\r
    isMajorType(cbor, MAJOR_TYPE_CONTENT_FREE)\r
    returns (int32)\r
  {\r
    if (cbor.additionalInformation == 25) {\r
      return cbor.buffer.readFloat16();\r
    } else {\r
      revert UnsupportedPrimitive(cbor.additionalInformation);\r
    }\r
  }\r
\r
  /// @notice Decode a `CBOR` structure into a `fixed32` value.\r
  /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values\r
  /// by 9 decimal orders so as to get a fixed precision of 9 decimal positions, which should be OK for most `fixed64`\r
  /// use cases. In other words, the output of this method is 10^9 times the actual value, encoded into an `int`.\r
  /// @param cbor An instance of `CBOR`.\r
  /// @return The value represented by the input, as an `int` value.\r
  function readFloat32(CBOR memory cbor)\r
    internal pure\r
    isMajorType(cbor, MAJOR_TYPE_CONTENT_FREE)\r
    returns (int)\r
  {\r
    if (cbor.additionalInformation == 26) {\r
      return cbor.buffer.readFloat32();\r
    } else {\r
      revert UnsupportedPrimitive(cbor.additionalInformation);\r
    }\r
  }\r
\r
  /// @notice Decode a `CBOR` structure into a `fixed64` value.\r
  /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values\r
  /// by 15 decimal orders so as to get a fixed precision of 15 decimal positions, which should be OK for most `fixed64`\r
  /// use cases. In other words, the output of this method is 10^15 times the actual value, encoded into an `int`.\r
  /// @param cbor An instance of `CBOR`.\r
  /// @return The value represented by the input, as an `int` value.\r
  function readFloat64(CBOR memory cbor)\r
    internal pure\r
    isMajorType(cbor, MAJOR_TYPE_CONTENT_FREE)\r
    returns (int)\r
  {\r
    if (cbor.additionalInformation == 27) {\r
      return cbor.buffer.readFloat64();\r
    } else {\r
      revert UnsupportedPrimitive(cbor.additionalInformation);\r
    }\r
  }\r
\r
  /// @notice Decode a `CBOR` structure into a native `int128[]` value whose inner values follow the same convention \r
  /// @notice as explained in `decodeFixed16`.\r
  /// @param cbor An instance of `CBOR`.\r
  function readFloat16Array(CBOR memory cbor)\r
    internal pure\r
    isMajorType(cbor, MAJOR_TYPE_ARRAY)\r
    returns (int32[] memory values)\r
  {\r
    uint64 length = readLength(cbor.buffer, cbor.additionalInformation);\r
    if (length < UINT64_MAX) {\r
      values = new int32[](length);\r
      for (uint64 i = 0; i < length; ) {\r
        CBOR memory item = fromBuffer(cbor.buffer);\r
        values[i] = readFloat16(item);\r
        unchecked {\r
          i ++;\r
        }\r
      }\r
    } else {\r
      revert InvalidLengthEncoding(length);\r
    }\r
  }\r
\r
  /// @notice Decode a `CBOR` structure into a native `int128` value.\r
  /// @param cbor An instance of `CBOR`.\r
  /// @return The value represented by the input, as an `int128` value.\r
  function readInt(CBOR memory cbor)\r
    internal pure\r
    returns (int64)\r
  {\r
    if (cbor.majorType == 1) {\r
      uint64 _value = readLength(\r
        cbor.buffer,\r
        cbor.additionalInformation\r
      );\r
      return int64(-1) - int64(uint64(_value));\r
    } else if (cbor.majorType == 0) {\r
      // Any `uint64` can be safely casted to `int128`, so this method supports majorType 1 as well so as to have offer\r
      // a uniform API for positive and negative numbers\r
      return int64(readUint(cbor));\r
    }\r
    else {\r
      revert UnexpectedMajorType(cbor.majorType, 1);\r
    }\r
  }\r
\r
  /// @notice Decode a `CBOR` structure into a native `int[]` value.\r
  /// @param cbor instance of `CBOR`.\r
  /// @return array The value represented by the input, as an `int[]` value.\r
  function readIntArray(CBOR memory cbor)\r
    internal pure\r
    isMajorType(cbor, MAJOR_TYPE_ARRAY)\r
    returns (int64[] memory array)\r
  {\r
    uint64 length = readLength(cbor.buffer, cbor.additionalInformation);\r
    if (length < UINT64_MAX) {\r
      array = new int64[](length);\r
      for (uint i = 0; i < length; ) {\r
        CBOR memory item = fromBuffer(cbor.buffer);\r
        array[i] = readInt(item);\r
        unchecked {\r
          i ++;\r
        }\r
      }\r
    } else {\r
      revert InvalidLengthEncoding(length);\r
    }\r
  }\r
\r
  /// @notice Decode a `CBOR` structure into a native `string` value.\r
  /// @param cbor An instance of `CBOR`.\r
  /// @return text The value represented by the input, as a `string` value.\r
  function readString(CBOR memory cbor)\r
    internal pure\r
    isMajorType(cbor, MAJOR_TYPE_STRING)\r
    returns (string memory text)\r
  {\r
    cbor.len = readLength(cbor.buffer, cbor.additionalInformation);\r
    if (cbor.len == UINT64_MAX) {\r
      bool _done;\r
      while (!_done) {\r
        uint64 length = _readIndefiniteStringLength(\r
          cbor.buffer,\r
          cbor.majorType\r
        );\r
        if (length < UINT64_MAX) {\r
          text = string(abi.encodePacked(\r
            text,\r
            cbor.buffer.readText(length / 4)\r
          ));\r
        } else {\r
          _done = true;\r
        }\r
      }\r
    } else {\r
      return string(cbor.buffer.readText(cbor.len));\r
    }\r
  }\r
\r
  /// @notice Decode a `CBOR` structure into a native `string[]` value.\r
  /// @param cbor An instance of `CBOR`.\r
  /// @return strings The value represented by the input, as an `string[]` value.\r
  function readStringArray(CBOR memory cbor)\r
    internal pure\r
    isMajorType(cbor, MAJOR_TYPE_ARRAY)\r
    returns (string[] memory strings)\r
  {\r
    uint length = readLength(cbor.buffer, cbor.additionalInformation);\r
    if (length < UINT64_MAX) {\r
      strings = new string[](length);\r
      for (uint i = 0; i < length; ) {\r
        CBOR memory item = fromBuffer(cbor.buffer);\r
        strings[i] = readString(item);\r
        unchecked {\r
          i ++;\r
        }\r
      }\r
    } else {\r
      revert InvalidLengthEncoding(length);\r
    }\r
  }\r
\r
  /// @notice Decode a `CBOR` structure into a native `uint64` value.\r
  /// @param cbor An instance of `CBOR`.\r
  /// @return The value represented by the input, as an `uint64` value.\r
  function readUint(CBOR memory cbor)\r
    internal pure\r
    isMajorType(cbor, MAJOR_TYPE_INT)\r
    returns (uint64)\r
  {\r
    return readLength(\r
      cbor.buffer,\r
      cbor.additionalInformation\r
    );\r
  }\r
\r
  /// @notice Decode a `CBOR` structure into a native `uint64[]` value.\r
  /// @param cbor An instance of `CBOR`.\r
  /// @return values The value represented by the input, as an `uint64[]` value.\r
  function readUintArray(CBOR memory cbor)\r
    internal pure\r
    isMajorType(cbor, MAJOR_TYPE_ARRAY)\r
    returns (uint64[] memory values)\r
  {\r
    uint64 length = readLength(cbor.buffer, cbor.additionalInformation);\r
    if (length < UINT64_MAX) {\r
      values = new uint64[](length);\r
      for (uint ix = 0; ix < length; ) {\r
        CBOR memory item = fromBuffer(cbor.buffer);\r
        values[ix] = readUint(item);\r
        unchecked {\r
          ix ++;\r
        }\r
      }\r
    } else {\r
      revert InvalidLengthEncoding(length);\r
    }\r
  }  \r
\r
  /// Read the length of a CBOR indifinite-length item (arrays, maps, byte strings and text) from a buffer, consuming\r
  /// as many bytes as specified by the first byte.\r
  function _readIndefiniteStringLength(\r
      WitnetBuffer.Buffer memory buffer,\r
      uint8 majorType\r
    )\r
    private pure\r
    returns (uint64 len)\r
  {\r
    uint8 initialByte = buffer.readUint8();\r
    if (initialByte == 0xff) {\r
      return UINT64_MAX;\r
    }\r
    len = readLength(\r
      buffer,\r
      initialByte & 0x1f\r
    );\r
    if (len >= UINT64_MAX) {\r
      revert InvalidLengthEncoding(len);\r
    } else if (majorType != (initialByte >> 5)) {\r
      revert UnexpectedMajorType((initialByte >> 5), majorType);\r
    }\r
  }\r
 \r
}"
    },
    "/contracts/libs/WitnetBuffer.sol": {
      "content": "// SPDX-License-Identifier: MIT\r
\r
pragma solidity >=0.8.0 <0.9.0;\r
\r
/// @title A convenient wrapper around the `bytes memory` type that exposes a buffer-like interface\r
/// @notice The buffer has an inner cursor that tracks the final offset of every read, i.e. any subsequent read will\r
/// start with the byte that goes right after the last one in the previous read.\r
/// @dev `uint32` is used here for `cursor` because `uint16` would only enable seeking up to 8KB, which could in some\r
/// theoretical use cases be exceeded. Conversely, `uint32` supports up to 512MB, which cannot credibly be exceeded.\r
/// @author The Witnet Foundation.\r
library WitnetBuffer {\r
\r
  error EmptyBuffer();\r
  error IndexOutOfBounds(uint index, uint range);\r
  error MissingArgs(uint expected, uint given);\r
\r
  /// Iterable bytes buffer.\r
  struct Buffer {\r
      bytes data;\r
      uint cursor;\r
  }\r
\r
  // Ensures we access an existing index in an array\r
  modifier withinRange(uint index, uint _range) {\r
    if (index > _range) {\r
      revert IndexOutOfBounds(index, _range);\r
    }\r
    _;\r
  }\r
\r
  /// @notice Concatenate undefinite number of bytes chunks.\r
  /// @dev Faster than looping on `abi.encodePacked(output, _buffs[ix])`.\r
  function concat(bytes[] memory _buffs)\r
    internal pure\r
    returns (bytes memory output)\r
  {\r
    unchecked {\r
      uint destinationPointer;\r
      uint destinationLength;\r
      assembly {\r
        // get safe scratch location\r
        output := mload(0x40)\r
        // set starting destination pointer\r
        destinationPointer := add(output, 32)\r
      }      \r
      for (uint ix = 1; ix <= _buffs.length; ix ++) {  \r
        uint source;\r
        uint sourceLength;\r
        uint sourcePointer;        \r
        assembly {\r
          // load source length pointer\r
          source := mload(add(_buffs, mul(ix, 32)))\r
          // load source length\r
          sourceLength := mload(source)\r
          // sets source memory pointer\r
          sourcePointer := add(source, 32)\r
        }\r
        memcpy(\r
          destinationPointer,\r
          sourcePointer,\r
          sourceLength\r
        );\r
        assembly {          \r
          // increase total destination length\r
          destinationLength := add(destinationLength, sourceLength)\r
          // sets destination memory pointer\r
          destinationPointer := add(destinationPointer, sourceLength)\r
        }\r
      }\r
      assembly {\r
        // protect output bytes\r
        mstore(output, destinationLength)\r
        // set final output length\r
        mstore(0x40, add(mload(0x40), add(destinationLength, 32)))\r
      }\r
    }\r
  }\r
\r
  function fork(WitnetBuffer.Buffer memory buffer)\r
    internal pure\r
    returns (WitnetBuffer.Buffer memory)\r
  {\r
    return Buffer(\r
      buffer.data,\r
      buffer.cursor\r
    );\r
  }\r
\r
  function mutate(\r
      WitnetBuffer.Buffer memory buffer,\r
      uint length,\r
      bytes memory pokes\r
    )\r
    internal pure\r
    withinRange(length, buffer.data.length - buffer.cursor + 1)\r
  {\r
    bytes[] memory parts = new bytes[](3);\r
    parts[0] = peek(\r
      buffer,\r
      0,\r
      buffer.cursor\r
    );\r
    parts[1] = pokes;\r
    parts[2] = peek(\r
      buffer,\r
      buffer.cursor + length,\r
      buffer.data.length - buffer.cursor - length\r
    );\r
    buffer.data = concat(parts);\r
  }\r
\r
  /// @notice Read and consume the next byte from the buffer.\r
  /// @param buffer An instance of `Buffer`.\r
  /// @return The next byte in the buffer counting from the cursor position.\r
  function next(Buffer memory buffer)\r
    internal pure\r
    withinRange(buffer.cursor, buffer.data.length)\r
    returns (bytes1)\r
  {\r
    // Return the byte at the position marked by the cursor and advance the cursor all at once\r
    return buffer.data[buffer.cursor ++];\r
  }\r
\r
  function peek(\r
      WitnetBuffer.Buffer memory buffer,\r
      uint offset,\r
      uint length\r
    )\r
    internal pure\r
    withinRange(offset + length, buffer.data.length)\r
    returns (bytes memory)\r
  {\r
    bytes memory data = buffer.data;\r
    bytes memory peeks = new bytes(length);\r
    uint destinationPointer;\r
    uint sourcePointer;\r
    assembly {\r
      destinationPointer := add(peeks, 32)\r
      sourcePointer := add(add(data, 32), offset)\r
    }\r
    memcpy(\r
      destinationPointer,\r
      sourcePointer,\r
      length\r
    );\r
    return peeks;\r
  }\r
\r
  // @notice Extract bytes array from buffer starting from current cursor.\r
  /// @param buffer An instance of `Buffer`.\r
  /// @param length How many bytes to peek from the Buffer.\r
  // solium-disable-next-line security/no-assign-params\r
  function peek(\r
      WitnetBuffer.Buffer memory buffer,\r
      uint length\r
    )\r
    internal pure\r
    withinRange(length, buffer.data.length - buffer.cursor)\r
    returns (bytes memory)\r
  {\r
    return peek(\r
      buffer,\r
      buffer.cursor,\r
      length\r
    );\r
  }\r
\r
  /// @notice Read and consume a certain amount of bytes from the buffer.\r
  /// @param buffer An instance of `Buffer`.\r
  /// @param length How many bytes to read and consume from the buffer.\r
  /// @return output A `bytes memory` containing the first `length` bytes from the buffer, counting from the cursor position.\r
  function read(Buffer memory buffer, uint length)\r
    internal pure\r
    withinRange(buffer.cursor + length, buffer.data.length)\r
    returns (bytes memory output)\r
  {\r
    // Create a new `bytes memory destination` value\r
    output = new bytes(length);\r
    // Early return in case that bytes length is 0\r
    if (length > 0) {\r
      bytes memory input = buffer.data;\r
      uint offset = buffer.cursor;\r
      // Get raw pointers for source and destination\r
      uint sourcePointer;\r
      uint destinationPointer;\r
      assembly {\r
        sourcePointer := add(add(input, 32), offset)\r
        destinationPointer := add(output, 32)\r
      }\r
      // Copy `length` bytes from source to destination\r
      memcpy(\r
        destinationPointer,\r
        sourcePointer,\r
        length\r
      );\r
      // Move the cursor forward by `length` bytes\r
      seek(\r
        buffer,\r
        length,\r
        true\r
      );\r
    }\r
  }\r
  \r
  /// @notice Read and consume the next 2 bytes from the buffer as an IEEE 754-2008 floating point number enclosed in an\r
  /// `int32`.\r
  /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values\r
  /// by 5 decimal orders so as to get a fixed precision of 5 decimal positions, which should be OK for most `float16`\r
  /// use cases. In other words, the integer output of this method is 10,000 times the actual value. The input bytes are\r
  /// expected to follow the 16-bit base-2 format (a.k.a. `binary16`) in the IEEE 754-2008 standard.\r
  /// @param buffer An instance of `Buffer`.\r
  /// @return result The `int32` value of the next 4 bytes in the buffer counting from the cursor position.\r
  function readFloat16(Buffer memory buffer)\r
    internal pure\r
    returns (int32 result)\r
  {\r
    uint32 value = readUint16(buffer);\r
    // Get bit at position 0\r
    uint32 sign = value & 0x8000;\r
    // Get bits 1 to 5, then normalize to the [-15, 16] range so as to counterweight the IEEE 754 exponent bias\r
    int32 exponent = (int32(value & 0x7c00) >> 10) - 15;\r
    // Get bits 6 to 15\r
    int32 fraction = int32(value & 0x03ff);\r
    // Add 2^10 to the fraction if exponent is not -15\r
    if (exponent != -15) {\r
      fraction |= 0x400;\r
    } else if (exponent == 16) {\r
      revert(\r
        string(abi.encodePacked(\r
          "WitnetBuffer.readFloat16: ",\r
          sign != 0 ? "negative" : hex"",\r
          " infinity"\r
        ))\r
      );\r
    }\r
    // Compute `2 ^ exponent · (1 + fraction / 1024)`\r
    if (exponent >= 0) {\r
      result = int32(int(\r
        int(1 << uint256(int256(exponent)))\r
          * 10000\r
          * fraction\r
      ) >> 10);\r
    } else {\r
      result = int32(int(\r
        int(fraction)\r
          * 10000\r
          / int(1 << uint(int(- exponent)))\r
      ) >> 10);\r
    }\r
    // Make the result negative if the sign bit is not 0\r
    if (sign != 0) {\r
      result *= -1;\r
    }\r
  }\r
\r
  /// @notice Consume the next 4 bytes from the buffer as an IEEE 754-2008 floating point number enclosed into an `int`.\r
  /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values\r
  /// by 9 decimal orders so as to get a fixed precision of 9 decimal positions, which should be OK for most `float32`\r
  /// use cases. In other words, the integer output of this method is 10^9 times the actual value. The input bytes are\r
  /// expected to follow the 64-bit base-2 format (a.k.a. `binary32`) in the IEEE 754-2008 standard.\r
  /// @param buffer An instance of `Buffer`.\r
  /// @return result The `int` value of the next 8 bytes in the buffer counting from the cursor position.\r
  function readFloat32(Buffer memory buffer)\r
    internal pure\r
    returns (int result)\r
  {\r
    uint value = readUint32(buffer);\r
    // Get bit at position 0\r
    uint sign = value & 0x80000000;\r
    // Get bits 1 to 8, then normalize to the [-127, 128] range so as to counterweight the IEEE 754 exponent bias\r
    int exponent = (int(value & 0x7f800000) >> 23) - 127;\r
    // Get bits 9 to 31\r
    int fraction = int(value & 0x007fffff);\r
    // Add 2^23 to the fraction if exponent is not -127\r
    if (exponent != -127) {\r
      fraction |= 0x800000;\r
    } else if (exponent == 128) {\r
      revert(\r
        string(abi.encodePacked(\r
          "WitnetBuffer.readFloat32: ",\r
          sign != 0 ? "negative" : hex"",\r
          " infinity"\r
        ))\r
      );\r
    }\r
    // Compute `2 ^ exponent · (1 + fraction / 2^23)`\r
    if (exponent >= 0) {\r
      result = (\r
        int(1 << uint(exponent))\r
          * (10 ** 9)\r
          * fraction\r
      ) >> 23;\r
    } else {\r
      result = (\r
        fraction \r
          * (10 ** 9)\r
          / int(1 << uint(-exponent)) \r
      ) >> 23;\r
    }\r
    // Make the result negative if the sign bit is not 0\r
    if (sign != 0) {\r
      result *= -1;\r
    }\r
  }\r
\r
  /// @notice Consume the next 8 bytes from the buffer as an IEEE 754-2008 floating point number enclosed into an `int`.\r
  /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values\r
  /// by 15 decimal orders so as to get a fixed precision of 15 decimal positions, which should be OK for most `float64`\r
  /// use cases. In other words, the integer output of this method is 10^15 times the actual value. The input bytes are\r
  /// expected to follow the 64-bit base-2 format (a.k.a. `binary64`) in the IEEE 754-2008 standard.\r
  /// @param buffer An instance of `Buffer`.\r
  /// @return result The `int` value of the next 8 bytes in the buffer counting from the cursor position.\r
  function readFloat64(Buffer memory buffer)\r
    internal pure\r
    returns (int result)\r
  {\r
    uint value = readUint64(buffer);\r
    // Get bit at position 0\r
    uint sign = value & 0x8000000000000000;\r
    // Get bits 1 to 12, then normalize to the [-1023, 1024] range so as to counterweight the IEEE 754 exponent bias\r
    int exponent = (int(value & 0x7ff0000000000000) >> 52) - 1023;\r
    // Get bits 6 to 15\r
    int fraction = int(value & 0x000fffffffffffff);\r
    // Add 2^52 to the fraction if exponent is not -1023\r
    if (exponent != -1023) {\r
      fraction |= 0x10000000000000;\r
    } else if (exponent == 1024) {\r
      revert(\r
        string(abi.encodePacked(\r
          "WitnetBuffer.readFloat64: ",\r
          sign != 0 ? "negative" : hex"",\r
          " infinity"\r
        ))\r
      );\r
    }\r
    // Compute `2 ^ exponent · (1 + fraction / 1024)`\r
    if (exponent >= 0) {\r
      result = (\r
        int(1 << uint(exponent))\r
          * (10 ** 15)\r
          * fraction\r
      ) >> 52;\r
    } else {\r
      result = (\r
        fraction \r
          * (10 ** 15)\r
          / int(1 << uint(-exponent)) \r
      ) >> 52;\r
    }\r
    // Make the result negative if the sign bit is not 0\r
    if (sign != 0) {\r
      result *= -1;\r
    }\r
  }\r
\r
  // Read a text string of a given length from a buffer. Returns a `bytes memory` value for the sake of genericness,\r
  /// but it can be easily casted into a string with `string(result)`.\r
  // solium-disable-next-line security/no-assign-params\r
  function readText(\r
      WitnetBuffer.Buffer memory buffer,\r
      uint64 length\r
    )\r
    internal pure\r
    returns (bytes memory text)\r
  {\r
    text = new bytes(length);\r
    unchecked {\r
      for (uint64 index = 0; index < length; index ++) {\r
        uint8 char = readUint8(buffer);\r
        if (char & 0x80 != 0) {\r
          if (char < 0xe0) {\r
            char = (char & 0x1f) << 6\r
              | (readUint8(buffer) & 0x3f);\r
            length -= 1;\r
          } else if (char < 0xf0) {\r
            char  = (char & 0x0f) << 12\r
              | (readUint8(buffer) & 0x3f) << 6\r
              | (readUint8(buffer) & 0x3f);\r
            length -= 2;\r
          } else {\r
            char = (char & 0x0f) << 18\r
              | (readUint8(buffer) & 0x3f) << 12\r
              | (readUint8(buffer) & 0x3f) << 6  \r
              | (readUint8(buffer) & 0x3f);\r
            length -= 3;\r
          }\r
        }\r
        text[index] = bytes1(char);\r
      }\r
      // Adjust text to actual length:\r
      assembly {\r
        mstore(text, length)\r
      }\r
    }\r
  }\r
\r
  /// @notice Read and consume the next byte from the buffer as an `uint8`.\r
  /// @param buffer An instance of `Buffer`.\r
  /// @return value The `uint8` value of the next byte in the buffer counting from the cursor position.\r
  function readUint8(Buffer memory buffer)\r
    internal pure\r
    withinRange(buffer.cursor, buffer.data.length)\r
    returns (uint8 value)\r
  {\r
    bytes memory data = buffer.data;\r
    uint offset = buffer.cursor;\r
    assembly {\r
      value := mload(add(add(data, 1), offset))\r
    }\r
    buffer.cursor ++;\r
  }\r
\r
  /// @notice Read and consume the next 2 bytes from the buffer as an `uint16`.\r
  /// @param buffer An instance of `Buffer`.\r
  /// @return value The `uint16` value of the next 2 bytes in the buffer counting from the cursor position.\r
  function readUint16(Buffer memory buffer)\r
    internal pure\r
    withinRange(buffer.cursor + 2, buffer.data.length)\r
    returns (uint16 value)\r
  {\r
    bytes memory data = buffer.data;\r
    uint offset = buffer.cursor;\r
    assembly {\r
      value := mload(add(

Tags:
Proxy, Upgradeable, Factory, Oracle|addr:0x240c2af76dded5d5cff893178d9d8bfa97b90e5f|verified:true|block:23575450|tx:0x1e879fe336b92a0116b09a77b38adac8b0c27396f6e85a29d67ca194d97ff3c5|first_check:1760442578

Submitted on: 2025-10-14 13:49:39

Comments

Log in to comment.

No comments yet.