Address Details
contract

0xC0FFEE98AD1434aCbDB894BbB752e138c1006fAB

Contract Name
WitnetRandomnessV2
Creator
0x03232a–323a4e at 0x868f5d–5e5679
Balance
0 CELO ( )
Locked CELO Balance
0.00 CELO
Voting CELO Balance
0.00 CELO
Pending Unlocked Gold
0.00 CELO
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
1 Transfers
Gas Used
Fetching gas used...
Last Balance Update
26689353
This contract has been verified via Sourcify. View contract in Sourcify repository
Contract name:
WitnetRandomnessV2




Optimization enabled
true
Compiler version
v0.8.25+commit.b61c2a91




Optimization runs
200
EVM Version
paris




Verified at
2024-08-10T07:10:31.485024Z

project:/contracts/apps/WitnetRandomnessV2.sol

// 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 WitnetRandomnessV2: Unmalleable and provably-fair randomness generation based on the Witnet Oracle v2.*.
/// @author The Witnet Foundation.
contract WitnetRandomnessV2
    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 so far on the Witnet Oracle blockchain.
    bytes32 immutable public override witnetRadHash;

    constructor(
            WitnetOracle _witnet,
            address _operator
        )
        Ownable(_operator)
        UsingWitnet(_witnet)
    {
        _require(
            address(_witnet) == address(0)
                || _witnet.specs() == type(IWitnetOracle).interfaceId,
            "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("no transfers accepted");
    }

    fallback() virtual external payable { 
        _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))),
            Witnet.toHexString(uint8(bytes1(msg.sig << 24)))
        )));
    }

    function class() virtual override public pure returns (string memory) {
        return type(WitnetRandomnessV2).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, 
                    uint16(34)
                ) 
        ) / 100;
    }

    /// @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.
    /// @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)
    {
        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);
        }

        Randomize storage __randomize = __storage().randomize_[_blockNumber];
        uint256 _witnetQueryId = __randomize.witnetQueryId;
        _require(
            _witnetQueryId != 0, 
            "not randomized"
        );
        
        WitnetV2.ResponseStatus _status = __witnet.getQueryResponseStatus(_witnetQueryId);
        if (_status == WitnetV2.ResponseStatus.Ready) {
            return (
                __witnet.getQueryResultCborBytes(_witnetQueryId)
                    .toWitnetResult()
                    .asBytes32()
            );
        } else if (_status == WitnetV2.ResponseStatus.Error) {
            uint256 _nextRandomizeBlock = __randomize.nextBlock;
            _require(
                _nextRandomizeBlock != 0, 
                "faulty randomize"
            );
            return _fetchRandomnessAfter(_nextRandomizeBlock);
        
        } else {
            _revert("pending randomize");
        }
    }

    /// @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:
    /// @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 _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.
    function fetchRandomnessAfterProof(uint256 _blockNumber) 
        virtual override
        public view 
        returns (
            bytes32 _witnetResultRandomness,
            uint64  _witnetResultTimestamp,
            bytes32 _witnetResultTallyHash,
            uint256 _witnetResultFinalityBlock
        )
    {
        if (__storage().randomize_[_blockNumber].witnetQueryId == 0) {
            _blockNumber = getRandomizeNextBlock(_blockNumber);
        }

        Randomize storage __randomize = __storage().randomize_[_blockNumber];
        uint256 _witnetQueryId = __randomize.witnetQueryId;
        _require(
            _witnetQueryId != 0, 
            "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;
            _witnetResultRandomness = _witnetQueryResponse.resultCborBytes.toWitnetResult().asBytes32();

        } else if (_status == WitnetV2.ResponseStatus.Error) {
            uint256 _nextRandomizeBlock = __randomize.nextBlock;
            _require(
                _nextRandomizeBlock != 0, 
                "faulty randomize"
            );
            return fetchRandomnessAfterProof(_nextRandomizeBlock);
        
        } else {
            _revert("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.randomUniformUint32(
            _range,
            _nonce,
            keccak256(
                abi.encode(
                    msg.sender,
                    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. 
    /// @return _evmRandomizeFee Funds actually paid as randomize fee.
    function randomize()
        external payable
        virtual override
        returns (uint256 _evmRandomizeFee)
    {
        if (__storage().lastRandomizeBlock < block.number) {
            _evmRandomizeFee = msg.value;
            // Post the Witnet Randomness request:
            uint _witnetQueryId = __witnet.postRequest{
                value: _evmRandomizeFee
            }(
                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,
                tx.gasprice,
                _evmRandomizeFee,
                _witnetQueryId,
                __witnetDefaultSLA
            );
        }
        // Transfer back unused funds:
        if (_evmRandomizeFee < msg.value) {
            payable(msg.sender).transfer(msg.value - _evmRandomizeFee);
        }
    }

    /// @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(),
            "invalid SLA"
        );
        __witnetDefaultSLA = _witnetQuerySLA;
    }


    // ================================================================================================================
    // --- 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) {
        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)
        );
    }

    bytes32 private constant _STORAGE_SLOT = 
        // keccak256("io.witnet.apps.randomness.v20")
        0x643778935c57df947f6944f6a5242a3e91445f6337f4b2ec670c8642153b614f;

    function __storage() internal pure returns (Storage storage _ptr) {
        assembly {
            _ptr.slot := _STORAGE_SLOT
        }
    }
}
        

/Ownable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
          

/Context.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
          

/

// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0 <0.9.0;

import "./WitnetRequestBytecodes.sol";
import "./WitnetRequestFactory.sol";
import "./interfaces/IWitnetOracle.sol";
import "./interfaces/IWitnetOracleEvents.sol";

/// @title Witnet Request Board functionality base contract.
/// @author The Witnet Foundation.
abstract contract WitnetOracle
    is
        IWitnetOracle,
        IWitnetOracleEvents
{
    function class() virtual external view returns (string memory) {
        return type(WitnetOracle).name;
    }
    function channel() virtual external view returns (bytes4);
    function factory() virtual external view returns (WitnetRequestFactory);
    function registry() virtual external view returns (WitnetRequestBytecodes);
    function specs() virtual external view returns (bytes4);
}
          

/

// SPDX-License-Identifier: MIT

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,
        IWitnetRandomnessEvents
{
    function class() virtual external view returns (string memory);
    function specs() virtual external view returns (bytes4);
}
          

/

// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0 <0.9.0;
pragma experimental ABIEncoderV2;

import "./interfaces/IWitnetRequestBytecodes.sol";

abstract contract WitnetRequestBytecodes
    is
        IWitnetRequestBytecodes
{
    function class() virtual external view returns (string memory) {
        return type(WitnetRequestBytecodes).name;
    }   
    function specs() virtual external view returns (bytes4);
}
          

/

// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0 <0.9.0;
pragma experimental ABIEncoderV2;

import "./WitnetRequestBytecodes.sol";
import "./WitnetOracle.sol";
import "./interfaces/IWitnetRequestFactory.sol";

abstract contract WitnetRequestFactory
    is
        IWitnetRequestFactory
{
    function class() virtual external view returns (string memory);
    function registry() virtual external view returns (WitnetRequestBytecodes);
    function specs() virtual external view returns (bytes4);
    function witnet() virtual external view returns (WitnetOracle);
}
          

/UsingWitnet.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0 <0.9.0;
pragma experimental ABIEncoderV2;

import "../WitnetOracle.sol";

/// @title The UsingWitnet contract
/// @dev Witnet-aware contracts can inherit from this contract in order to interact with Witnet.
/// @author The Witnet Foundation.
abstract contract UsingWitnet
    is
        IWitnetOracleEvents
{
    /// @dev Immutable reference to the Witnet Request Board contract.
    WitnetOracle internal immutable __witnet;
    
    /// @dev Default Security-Level Agreement parameters to be fulfilled by the Witnet blockchain
    /// @dev when solving a data request.
    WitnetV2.RadonSLA internal __witnetDefaultSLA;

    /// @dev Percentage over base fee to pay on every data request, 
    /// @dev as to deal with volatility of evmGasPrice and evmWitPrice during the live time of 
    /// @dev a data request (since being posted until a result gets reported back), at both the EVM and 
    /// @dev the Witnet blockchain levels, respectivelly. 
    uint16 internal __witnetBaseFeeOverheadPercentage;

    /// @param _wrb Address of the WitnetOracle contract.
    constructor(WitnetOracle _wrb) {
        require(
            _wrb.specs() == type(IWitnetOracle).interfaceId,
            "UsingWitnet: uncompliant WitnetOracle"
        );
        __witnet = _wrb;
        __witnetDefaultSLA = WitnetV2.RadonSLA({
            // Number of nodes in the Witnet blockchain that will take part in solving the data request:
            committeeSize: 10,
            // Fee in $nanoWIT paid to every node in the Witnet blockchain involved in solving the data request:
            witnessingFeeNanoWit: 2 * 10 ** 8  // defaults to 0.2 $WIT
        });
        
        __witnetBaseFeeOverheadPercentage = 33; // defaults to 33%
    }

    /// @dev Provides a convenient way for client contracts extending this to block the execution of the main logic of the
    /// @dev contract until a particular request has been successfully solved and reported by Witnet,
    /// @dev either with an error or successfully.
    modifier witnetQuerySolved(uint256 _witnetQueryId) {
        require(_witnetCheckQueryResultAvailability(_witnetQueryId), "UsingWitnet: unsolved query");
        _;
    }

    function witnet() virtual public view returns (WitnetOracle) {
        return __witnet;
    }

    /// @notice Check if given query was already reported back from the Witnet oracle.
    /// @param _id The unique identifier of a previously posted data request.
    function _witnetCheckQueryResultAvailability(uint256 _id)
        internal view
        returns (bool)
    {
        return __witnet.getQueryStatus(_id) == WitnetV2.QueryStatus.Reported;
    }

    /// @notice Estimate the minimum reward required for posting a data request, using `tx.gasprice` as a reference.
    /// @dev Underestimates if the size of returned data is greater than `_resultMaxSize`. 
    /// @param _resultMaxSize Maximum expected size of returned data (in bytes).
    function _witnetEstimateEvmReward(uint16 _resultMaxSize)
        virtual internal view
        returns (uint256)
    {
        return (
            (100 + __witnetBaseFeeOverheadPercentage)
                * __witnet.estimateBaseFee(tx.gasprice, _resultMaxSize) 
        ) / 100;
    }

    function _witnetCheckQueryResponseStatus(uint256 _witnetQueryId)
        internal view
        returns (WitnetV2.ResponseStatus)
    {
        return __witnet.getQueryResponseStatus(_witnetQueryId);
    }

    function _witnetCheckQueryResultError(uint256 _witnetQueryId)
        internal view
        returns (Witnet.ResultError memory)
    {
        return __witnet.getQueryResultError(_witnetQueryId);
    }
}
          

/IWitnetOracle.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;

import "../libs/WitnetV2.sol";

interface IWitnetOracle {

    /// @notice Estimate the minimum reward required for posting a data request.
    /// @dev Underestimates if the size of returned data is greater than `resultMaxSize`. 
    /// @param gasPrice Expected gas price to pay upon posting the data request.
    /// @param resultMaxSize Maximum expected size of returned data (in bytes).  
    function estimateBaseFee(uint256 gasPrice, uint16 resultMaxSize) external view returns (uint256);

    /// @notice Estimate the minimum reward required for posting a data request.
    /// @dev Fails if the RAD hash was not previously verified on the WitnetRequestBytecodes registry.
    /// @param gasPrice Expected gas price to pay upon posting the data request.
    /// @param radHash The RAD hash of the data request to be solved by Witnet.
    function estimateBaseFee(uint256 gasPrice, bytes32 radHash) external view returns (uint256);
    
    /// @notice Estimate the minimum reward required for posting a data request with a callback.
    /// @param gasPrice Expected gas price to pay upon posting the data request.
    /// @param callbackGasLimit Maximum gas to be spent when reporting the data request result.
    function estimateBaseFeeWithCallback(uint256 gasPrice, uint24 callbackGasLimit) external view returns (uint256);
       
    /// @notice Retrieves a copy of all Witnet-provable data related to a previously posted request, 
    /// removing the whole query from the WRB storage.
    /// @dev Fails if the query was not in 'Reported' status, or called from an address different to
    /// @dev the one that actually posted the given request.
    /// @param queryId The unique query identifier.
    function fetchQueryResponse(uint256 queryId) external returns (WitnetV2.Response memory);
   
    /// @notice Gets the whole Query data contents, if any, no matter its current status.
    function getQuery(uint256 queryId) external view returns (WitnetV2.Query memory);

    /// @notice Gets the current EVM reward the report can claim, if not done yet.
    function getQueryEvmReward(uint256 queryId) external view returns (uint256);

    /// @notice Retrieves the RAD hash and SLA parameters of the given query.
    /// @param queryId The unique query identifier.
    function getQueryRequest(uint256 queryId) external view returns (WitnetV2.Request memory);

    /// @notice Retrieves the whole `Witnet.Response` record referred to a previously posted Witnet Data Request.
    /// @param queryId The unique query identifier.
    function getQueryResponse(uint256 queryId) external view returns (WitnetV2.Response memory);

    /// @notice Returns query's result current status from a requester's point of view:
    /// @notice   - 0 => Void: the query is either non-existent or deleted;
    /// @notice   - 1 => Awaiting: the query has not yet been reported;
    /// @notice   - 2 => Ready: the query response was finalized, and contains a result with no erros.
    /// @notice   - 3 => Error: the query response was finalized, and contains a result with errors.
    /// @param queryId The unique query identifier.
    function getQueryResponseStatus(uint256 queryId) external view returns (WitnetV2.ResponseStatus);

    /// @notice Retrieves the CBOR-encoded buffer containing the Witnet-provided result to the given query.
    /// @param queryId The unique query identifier.
    function getQueryResultCborBytes(uint256 queryId) external view returns (bytes memory);

    /// @notice Gets error code identifying some possible failure on the resolution of the given query.
    /// @param queryId The unique query identifier.
    function getQueryResultError(uint256 queryId) external view returns (Witnet.ResultError memory);

    /// @notice Gets current status of given query.
    function getQueryStatus(uint256 queryId) external view returns (WitnetV2.QueryStatus);
    
    /// @notice Get current status of all given query ids.
    function getQueryStatusBatch(uint256[] calldata queryIds) external view returns (WitnetV2.QueryStatus[] memory);

    /// @notice Returns next query id to be generated by the Witnet Request Board.
    function getNextQueryId() external view returns (uint256);

    /// @notice Requests the execution of the given Witnet Data Request, in expectation that it will be relayed and 
    /// @notice solved by the Witnet blockchain. A reward amount is escrowed by the Witnet Request Board that will be 
    /// @notice transferred to the reporter who relays back the Witnet-provable result to this request.
    /// @dev Reasons to fail:
    /// @dev - the RAD hash was not previously verified by the WitnetRequestBytecodes registry;
    /// @dev - invalid SLA parameters were provided;
    /// @dev - insufficient value is paid as reward.
    /// @param queryRAD The RAD hash of the data request to be solved by Witnet.
    /// @param querySLA The data query SLA to be fulfilled on the Witnet blockchain.
    /// @return queryId Unique query identifier.
    function postRequest(
            bytes32 queryRAD, 
            WitnetV2.RadonSLA calldata querySLA
        ) external payable returns (uint256 queryId);

    /// @notice Requests the execution of the given Witnet Data Request, in expectation that it will be relayed and solved by 
    /// @notice the Witnet blockchain. A reward amount is escrowed by the Witnet Request Board that will be transferred to the 
    /// @notice reporter who relays back the Witnet-provable result to this request. The Witnet-provable result will be reported
    /// @notice directly to the requesting contract. If the report callback fails for any reason, an `WitnetQueryResponseDeliveryFailed`
    /// @notice will be triggered, and the Witnet audit trail will be saved in storage, but not so the actual CBOR-encoded result.
    /// @dev Reasons to fail:
    /// @dev - the caller is not a contract implementing the IWitnetConsumer interface;
    /// @dev - the RAD hash was not previously verified by the WitnetRequestBytecodes registry;
    /// @dev - invalid SLA parameters were provided;
    /// @dev - insufficient value is paid as reward.
    /// @param queryRAD The RAD hash of the data request to be solved by Witnet.
    /// @param querySLA The data query SLA to be fulfilled on the Witnet blockchain.
    /// @param queryCallbackGasLimit Maximum gas to be spent when reporting the data request result.
    /// @return queryId Unique query identifier.
    function postRequestWithCallback(
            bytes32 queryRAD, 
            WitnetV2.RadonSLA calldata querySLA, 
            uint24 queryCallbackGasLimit
        ) external payable returns (uint256 queryId);

    /// @notice Requests the execution of the given Witnet Data Request, in expectation that it will be relayed and solved by 
    /// @notice the Witnet blockchain. A reward amount is escrowed by the Witnet Request Board that will be transferred to the 
    /// @notice reporter who relays back the Witnet-provable result to this request. The Witnet-provable result will be reported
    /// @notice directly to the requesting contract. If the report callback fails for any reason, a `WitnetQueryResponseDeliveryFailed`
    /// @notice event will be triggered, and the Witnet audit trail will be saved in storage, but not so the CBOR-encoded result.
    /// @dev Reasons to fail:
    /// @dev - the caller is not a contract implementing the IWitnetConsumer interface;
    /// @dev - the provided bytecode is empty;
    /// @dev - invalid SLA parameters were provided;
    /// @dev - insufficient value is paid as reward.
    /// @param queryUnverifiedBytecode The (unverified) bytecode containing the actual data request to be solved by the Witnet blockchain.
    /// @param querySLA The data query SLA to be fulfilled on the Witnet blockchain.
    /// @param queryCallbackGasLimit Maximum gas to be spent when reporting the data request result.
    /// @return queryId Unique query identifier.
    function postRequestWithCallback(
            bytes calldata queryUnverifiedBytecode,
            WitnetV2.RadonSLA calldata querySLA, 
            uint24 queryCallbackGasLimit
        ) external payable returns (uint256 queryId);

    /// @notice Increments the reward of a previously posted request by adding the transaction value to it.
    /// @param queryId The unique query identifier.
    function upgradeQueryEvmReward(uint256 queryId) external payable;

}
          

/IWitnetOracleEvents.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;

import "../libs/WitnetV2.sol";

interface IWitnetOracleEvents {
    
    /// Emitted every time a new query containing some verified data request is posted to the WRB.
    event WitnetQuery(
        uint256 id, 
        uint256 evmReward,
        WitnetV2.RadonSLA witnetSLA
    );

    /// Emitted when a query with no callback gets reported into the WRB.
    event WitnetQueryResponse(
        uint256 id, 
        uint256 evmGasPrice
    );

    /// Emitted when a query with a callback gets successfully reported into the WRB.
    event WitnetQueryResponseDelivered(
        uint256 id, 
        uint256 evmGasPrice, 
        uint256 evmCallbackGas
    );

    /// Emitted when a query with a callback cannot get reported into the WRB.
    event WitnetQueryResponseDeliveryFailed(
        uint256 id, 
        bytes   resultCborBytes,
        uint256 evmGasPrice, 
        uint256 evmCallbackActualGas, 
        string  evmCallbackRevertReason
    );

    /// Emitted when the reward of some not-yet reported query is upgraded.
    event WitnetQueryRewardUpgraded(
        uint256 id, 
        uint256 evmReward
    );

}
          

/IWitnetRandomness.sol

// 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 {
    
    /// @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 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.
    /// @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 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:
    /// @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 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.
    function fetchRandomnessAfterProof(uint256 blockNumber) external view returns (
            bytes32 witnetResultRandomness,
            uint64  witnetResultTimestamp, 
            bytes32 witnetResultTallyHash,
            uint256 witnetResultFinalityBlock
        ); 

    /// @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 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.
    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 the unique identifier of the Witnet-compliant data request being used for solving randomness.
    function witnetRadHash() external view returns (bytes32);
}
          

/IWitnetRandomnessAdmin.sol

// 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;
}
          

/IWitnetRandomnessEvents.sol

// 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
        );
}
          

/IWitnetRequestBytecodes.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;

import "../libs/WitnetV2.sol";

interface IWitnetRequestBytecodes {

    error UnknownRadonRetrieval(bytes32 hash);
    error UnknownRadonReducer(bytes32 hash);
    error UnknownRadonRequest(bytes32 hash);

    event NewDataProvider(uint256 index);
    event NewRadonRetrievalHash(bytes32 hash);
    event NewRadonReducerHash(bytes32 hash);
    event NewRadHash(bytes32 hash);

    function bytecodeOf(bytes32 radHash) external view returns (bytes memory);
    function bytecodeOf(bytes32 radHash, WitnetV2.RadonSLA calldata sla) external view returns (bytes memory);
    function bytecodeOf(bytes calldata radBytecode, WitnetV2.RadonSLA calldata sla) external view returns (bytes memory);
    
    function hashOf(bytes calldata) external view returns (bytes32);

    function lookupDataProvider(uint256 index) external view returns (string memory, uint);
    function lookupDataProviderIndex(string calldata authority) external view returns (uint);
    function lookupDataProviderSources(uint256 index, uint256 offset, uint256 length) external view returns (bytes32[] memory);

    function lookupRadonReducer(bytes32 hash) external view returns (Witnet.RadonReducer memory);
    
    function lookupRadonRetrieval(bytes32 hash) external view returns (Witnet.RadonRetrieval memory);
    function lookupRadonRetrievalArgsCount(bytes32 hash) external view returns (uint8);
    function lookupRadonRetrievalResultDataType(bytes32 hash) external view returns (Witnet.RadonDataTypes);
    
    function lookupRadonRequestAggregator(bytes32 radHash) external view returns (Witnet.RadonReducer memory);
    function lookupRadonRequestResultMaxSize(bytes32 radHash) external view returns (uint16);
    function lookupRadonRequestResultDataType(bytes32 radHash) external view returns (Witnet.RadonDataTypes);
    function lookupRadonRequestSources(bytes32 radHash) external view returns (bytes32[] memory);
    function lookupRadonRequestSourcesCount(bytes32 radHash) external view returns (uint);
    function lookupRadonRequestTally(bytes32 radHash) external view returns (Witnet.RadonReducer memory);
        
    function verifyRadonRetrieval(
            Witnet.RadonDataRequestMethods requestMethod,
            string calldata requestURL,
            string calldata requestBody,
            string[2][] calldata requestHeaders,
            bytes calldata requestRadonScript
        ) external returns (bytes32 hash);
    
    function verifyRadonReducer(Witnet.RadonReducer calldata reducer)
        external returns (bytes32 hash);
    
    function verifyRadonRequest(
            bytes32[] calldata sources,
            bytes32 aggregator,
            bytes32 tally,
            uint16 resultMaxSize,
            string[][] calldata args
        ) external returns (bytes32 radHash);

    function totalDataProviders() external view returns (uint);
}
          

/IWitnetRequestFactory.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0 <0.9.0;

interface IWitnetRequestFactory {
    
    event WitnetRequestTemplateBuilt(address template, bool parameterized);
    
    function buildRequestTemplate(
            bytes32[] memory sourcesIds,
            bytes32 aggregatorId,
            bytes32 tallyId,
            uint16  resultDataMaxSize
        ) external returns (address template);

}
          

/Witnet.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0 <0.9.0;
pragma experimental ABIEncoderV2;

import "./WitnetCBOR.sol";

library Witnet {

    using WitnetBuffer for WitnetBuffer.Buffer;
    using WitnetCBOR for WitnetCBOR.CBOR;
    using WitnetCBOR for WitnetCBOR.CBOR[];

    /// Struct containing both request and response data related to every query posted to the Witnet Request Board
    struct Query {
        Request request;
        Response response;
        address from;      // Address from which the request was posted.
    }

    /// Possible status of a Witnet query.
    enum QueryStatus {
        Unknown,
        Posted,
        Reported,
        Deleted
    }

    /// Data kept in EVM-storage for every Request posted to the Witnet Request Board.
    struct Request {
        address addr;       // Address of the (deprecated) IWitnetRequest contract containing Witnet data request raw bytecode.
        bytes32 slaHash;    // Radon SLA hash of the Witnet data request.
        bytes32 radHash;    // Radon radHash of the Witnet data request.
        uint256 gasprice;   // Minimum gas price the DR resolver should pay on the solving tx.
        uint256 reward;     // Escrowed reward to be paid to the DR resolver.
    }

    /// Data kept in EVM-storage containing the Witnet-provided response metadata and CBOR-encoded result.
    struct Response {
        address reporter;       // Address from which the result was reported.
        uint256 timestamp;      // Timestamp of the Witnet-provided result.
        bytes32 drTxHash;       // Hash of the Witnet transaction that solved the queried Data Request.
        bytes   cborBytes;      // Witnet-provided result CBOR-bytes to the queried Data Request.
    }

    /// Data struct containing the Witnet-provided result to a Data Request.
    struct Result {
        bool success;           // Flag stating whether the request could get solved successfully, or not.
        WitnetCBOR.CBOR value;  // Resulting value, in CBOR-serialized bytes.
    }

    /// Final query's result status from a requester's point of view.
    enum ResultStatus {
        Void,
        Awaiting,
        Ready,
        Error
    }

    /// Data struct describing an error when trying to fetch a Witnet-provided result to a Data Request.
    struct ResultError {
        ResultErrorCodes code;
        string reason;
    }

    enum ResultErrorCodes {
        /// 0x00: Unknown error. Something went really bad!
        Unknown, 
        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Source-specific format error sub-codes ============================================================================
        /// 0x01: At least one of the source scripts is not a valid CBOR-encoded value.
        SourceScriptNotCBOR, 
        /// 0x02: The CBOR value decoded from a source script is not an Array.
        SourceScriptNotArray,
        /// 0x03: The Array value decoded form a source script is not a valid Data Request.
        SourceScriptNotRADON,
        /// 0x04: The request body of at least one data source was not properly formated.
        SourceRequestBody,
        /// 0x05: The request headers of at least one data source was not properly formated.
        SourceRequestHeaders,
        /// 0x06: The request URL of at least one data source was not properly formated.
        SourceRequestURL,
        /// Unallocated
        SourceFormat0x07, SourceFormat0x08, SourceFormat0x09, SourceFormat0x0A, SourceFormat0x0B, SourceFormat0x0C,
        SourceFormat0x0D, SourceFormat0x0E, SourceFormat0x0F, 
        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Complexity error sub-codes ========================================================================================
        /// 0x10: The request contains too many sources.
        RequestTooManySources,
        /// 0x11: The script contains too many calls.
        ScriptTooManyCalls,
        /// Unallocated
        Complexity0x12, Complexity0x13, Complexity0x14, Complexity0x15, Complexity0x16, Complexity0x17, Complexity0x18,
        Complexity0x19, Complexity0x1A, Complexity0x1B, Complexity0x1C, Complexity0x1D, Complexity0x1E, Complexity0x1F,

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Lack of support error sub-codes ===================================================================================
        /// 0x20: Some Radon operator code was found that is not supported (1+ args).
        UnsupportedOperator,
        /// 0x21: Some Radon filter opcode is not currently supported (1+ args).
        UnsupportedFilter,
        /// 0x22: Some Radon request type is not currently supported (1+ args).
        UnsupportedHashFunction,
        /// 0x23: Some Radon reducer opcode is not currently supported (1+ args)
        UnsupportedReducer,
        /// 0x24: Some Radon hash function is not currently supported (1+ args).
        UnsupportedRequestType, 
        /// 0x25: Some Radon encoding function is not currently supported (1+ args).
        UnsupportedEncodingFunction,
        /// Unallocated
        Operator0x26, Operator0x27, 
        /// 0x28: Wrong number (or type) of arguments were passed to some Radon operator.
        WrongArguments,
        /// Unallocated
        Operator0x29, Operator0x2A, Operator0x2B, Operator0x2C, Operator0x2D, Operator0x2E, Operator0x2F,
        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Retrieve-specific circumstantial error sub-codes ================================================================================
        /// 0x30: A majority of data sources returned an HTTP status code other than 200 (1+ args):
        HttpErrors,
        /// 0x31: A majority of data sources timed out:
        RetrievalsTimeout,
        /// Unallocated
        RetrieveCircumstance0x32, RetrieveCircumstance0x33, RetrieveCircumstance0x34, RetrieveCircumstance0x35,
        RetrieveCircumstance0x36, RetrieveCircumstance0x37, RetrieveCircumstance0x38, RetrieveCircumstance0x39,
        RetrieveCircumstance0x3A, RetrieveCircumstance0x3B, RetrieveCircumstance0x3C, RetrieveCircumstance0x3D,
        RetrieveCircumstance0x3E, RetrieveCircumstance0x3F,
        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Scripting-specific runtime error sub-code =========================================================================
        /// 0x40: Math operator caused an underflow.
        MathUnderflow,
        /// 0x41: Math operator caused an overflow.
        MathOverflow,
        /// 0x42: Math operator tried to divide by zero.
        MathDivisionByZero,            
        /// 0x43:Wrong input to subscript call.
        WrongSubscriptInput,
        /// 0x44: Value cannot be extracted from input binary buffer.
        BufferIsNotValue,
        /// 0x45: Value cannot be decoded from expected type.
        Decode,
        /// 0x46: Unexpected empty array.
        EmptyArray,
        /// 0x47: Value cannot be encoded to expected type.
        Encode,
        /// 0x48: Failed to filter input values (1+ args).
        Filter,
        /// 0x49: Failed to hash input value.
        Hash,
        /// 0x4A: Mismatching array ranks.
        MismatchingArrays,
        /// 0x4B: Failed to process non-homogenous array.
        NonHomegeneousArray,
        /// 0x4C: Failed to parse syntax of some input value, or argument.
        Parse,
        /// 0x4E: Parsing logic limits were exceeded.
        ParseOverflow,
        /// 0x4F: Unallocated
        ScriptError0x4F,
    
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Actual first-order result error codes =============================================================================
        /// 0x50: Not enough reveals were received in due time:
        InsufficientReveals,
        /// 0x51: No actual reveal majority was reached on tally stage:
        InsufficientMajority,
        /// 0x52: Not enough commits were received before tally stage:
        InsufficientCommits,
        /// 0x53: Generic error during tally execution (to be deprecated after WIP #0028)
        TallyExecution,
        /// 0x54: A majority of data sources could either be temporarily unresponsive or failing to report the requested data:
        CircumstantialFailure,
        /// 0x55: At least one data source is inconsistent when queried through multiple transports at once:
        InconsistentSources,
        /// 0x56: Any one of the (multiple) Retrieve, Aggregate or Tally scripts were badly formated:
        MalformedDataRequest,
        /// 0x57: Values returned from a majority of data sources don't match the expected schema:
        MalformedResponses,
        /// Unallocated:    
        OtherError0x58, OtherError0x59, OtherError0x5A, OtherError0x5B, OtherError0x5C, OtherError0x5D, OtherError0x5E, 
        /// 0x5F: Size of serialized tally result exceeds allowance:
        OversizedTallyResult,

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Inter-stage runtime error sub-codes ===============================================================================
        /// 0x60: Data aggregation reveals could not get decoded on the tally stage:
        MalformedReveals,
        /// 0x61: The result to data aggregation could not get encoded:
        EncodeReveals,  
        /// 0x62: A mode tie ocurred when calculating some mode value on the aggregation or the tally stage:
        ModeTie, 
        /// Unallocated:
        OtherError0x63, OtherError0x64, OtherError0x65, OtherError0x66, OtherError0x67, OtherError0x68, OtherError0x69, 
        OtherError0x6A, OtherError0x6B, OtherError0x6C, OtherError0x6D, OtherError0x6E, OtherError0x6F,
        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Runtime access error sub-codes ====================================================================================
        /// 0x70: Tried to access a value from an array using an index that is out of bounds (1+ args):
        ArrayIndexOutOfBounds,
        /// 0x71: Tried to access a value from a map using a key that does not exist (1+ args):
        MapKeyNotFound,
        /// 0X72: Tried to extract value from a map using a JSON Path that returns no values (+1 args):
        JsonPathNotFound,
        /// Unallocated:
        OtherError0x73, OtherError0x74, OtherError0x75, OtherError0x76, OtherError0x77, OtherError0x78, 
        OtherError0x79, OtherError0x7A, OtherError0x7B, OtherError0x7C, OtherError0x7D, OtherError0x7E, OtherError0x7F, 
        OtherError0x80, OtherError0x81, OtherError0x82, OtherError0x83, OtherError0x84, OtherError0x85, OtherError0x86, 
        OtherError0x87, OtherError0x88, OtherError0x89, OtherError0x8A, OtherError0x8B, OtherError0x8C, OtherError0x8D, 
        OtherError0x8E, OtherError0x8F, OtherError0x90, OtherError0x91, OtherError0x92, OtherError0x93, OtherError0x94, 
        OtherError0x95, OtherError0x96, OtherError0x97, OtherError0x98, OtherError0x99, OtherError0x9A, OtherError0x9B,
        OtherError0x9C, OtherError0x9D, OtherError0x9E, OtherError0x9F, OtherError0xA0, OtherError0xA1, OtherError0xA2, 
        OtherError0xA3, OtherError0xA4, OtherError0xA5, OtherError0xA6, OtherError0xA7, OtherError0xA8, OtherError0xA9, 
        OtherError0xAA, OtherError0xAB, OtherError0xAC, OtherError0xAD, OtherError0xAE, OtherError0xAF, OtherError0xB0,
        OtherError0xB1, OtherError0xB2, OtherError0xB3, OtherError0xB4, OtherError0xB5, OtherError0xB6, OtherError0xB7,
        OtherError0xB8, OtherError0xB9, OtherError0xBA, OtherError0xBB, OtherError0xBC, OtherError0xBD, OtherError0xBE,
        OtherError0xBF, OtherError0xC0, OtherError0xC1, OtherError0xC2, OtherError0xC3, OtherError0xC4, OtherError0xC5,
        OtherError0xC6, OtherError0xC7, OtherError0xC8, OtherError0xC9, OtherError0xCA, OtherError0xCB, OtherError0xCC,
        OtherError0xCD, OtherError0xCE, OtherError0xCF, OtherError0xD0, OtherError0xD1, OtherError0xD2, OtherError0xD3,
        OtherError0xD4, OtherError0xD5, OtherError0xD6, OtherError0xD7, OtherError0xD8, OtherError0xD9, OtherError0xDA,
        OtherError0xDB, OtherError0xDC, OtherError0xDD, OtherError0xDE, OtherError0xDF,
        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Inter-client generic error codes ==================================================================================
        /// Data requests that cannot be relayed into the Witnet blockchain should be reported
        /// with one of these errors. 
        /// 0xE0: Requests that cannot be parsed must always get this error as their result.
        BridgeMalformedDataRequest,
        /// 0xE1: Witnesses exceeds 100
        BridgePoorIncentives,
        /// 0xE2: The request is rejected on the grounds that it may cause the submitter to spend or stake an
        /// amount of value that is unjustifiably high when compared with the reward they will be getting
        BridgeOversizedTallyResult,
        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Unallocated =======================================================================================================
        OtherError0xE3, OtherError0xE4, OtherError0xE5, OtherError0xE6, OtherError0xE7, OtherError0xE8, OtherError0xE9,
        OtherError0xEA, OtherError0xEB, OtherError0xEC, OtherError0xED, OtherError0xEE, OtherError0xEF, OtherError0xF0,
        OtherError0xF1, OtherError0xF2, OtherError0xF3, OtherError0xF4, OtherError0xF5, OtherError0xF6, OtherError0xF7,
        OtherError0xF8, OtherError0xF9, OtherError0xFA, OtherError0xFB, OtherError0xFC, OtherError0xFD, OtherError0xFE,
        
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// 0xFF: Some tally error is not intercepted but it should (0+ args)
        UnhandledIntercept
    }

    function isCircumstantial(ResultErrorCodes self) internal pure returns (bool) {
        return (self == ResultErrorCodes.CircumstantialFailure);
    }

    function lackOfConsensus(ResultErrorCodes self) internal pure returns (bool) {
        return (
            self == ResultErrorCodes.InsufficientCommits
                || self == ResultErrorCodes.InsufficientMajority
                || self == ResultErrorCodes.InsufficientReveals
        );
    }

    function isRetriable(ResultErrorCodes self) internal pure returns (bool) {
        return (
            lackOfConsensus(self)
                || isCircumstantial(self)
                || poorIncentives(self)
        );
    }

    function poorIncentives(ResultErrorCodes self) internal pure returns (bool) {
        return (
            self == ResultErrorCodes.OversizedTallyResult
                || self == ResultErrorCodes.InsufficientCommits
                || self == ResultErrorCodes.BridgePoorIncentives
                || self == ResultErrorCodes.BridgeOversizedTallyResult
        );
    }
    

    /// Possible Radon data request methods that can be used within a Radon Retrieval. 
    enum RadonDataRequestMethods {
        /* 0 */ Unknown,
        /* 1 */ HttpGet,
        /* 2 */ RNG,
        /* 3 */ HttpPost,
        /* 4 */ HttpHead
    }

    /// Possible types either processed by Witnet Radon Scripts or included within results to Witnet Data Requests.
    enum RadonDataTypes {
        /* 0x00 */ Any, 
        /* 0x01 */ Array,
        /* 0x02 */ Bool,
        /* 0x03 */ Bytes,
        /* 0x04 */ Integer,
        /* 0x05 */ Float,
        /* 0x06 */ Map,
        /* 0x07 */ String,
        Unused0x08, Unused0x09, Unused0x0A, Unused0x0B,
        Unused0x0C, Unused0x0D, Unused0x0E, Unused0x0F,
        /* 0x10 */ Same,
        /* 0x11 */ Inner,
        /* 0x12 */ Match,
        /* 0x13 */ Subscript
    }

    /// Structure defining some data filtering that can be applied at the Aggregation or the Tally stages
    /// within a Witnet Data Request resolution workflow.
    struct RadonFilter {
        RadonFilterOpcodes opcode;
        bytes args;
    }

    /// Filtering methods currently supported on the Witnet blockchain. 
    enum RadonFilterOpcodes {
        /* 0x00 */ Reserved0x00, //GreaterThan,
        /* 0x01 */ Reserved0x01, //LessThan,
        /* 0x02 */ Reserved0x02, //Equals,
        /* 0x03 */ Reserved0x03, //AbsoluteDeviation,
        /* 0x04 */ Reserved0x04, //RelativeDeviation
        /* 0x05 */ StandardDeviation,
        /* 0x06 */ Reserved0x06, //Top,
        /* 0x07 */ Reserved0x07, //Bottom,
        /* 0x08 */ Mode,
        /* 0x09 */ Reserved0x09  //LessOrEqualThan
    }

    /// Structure defining the array of filters and reducting function to be applied at either the Aggregation
    /// or the Tally stages within a Witnet Data Request resolution workflow.
    struct RadonReducer {
        RadonReducerOpcodes opcode;
        RadonFilter[] filters;
    }

    /// Reducting functions currently supported on the Witnet blockchain.
    enum RadonReducerOpcodes {
        /* 0x00 */ Reserved0x00, //Minimum,
        /* 0x01 */ Reserved0x01, //Maximum,
        /* 0x02 */ Mode,
        /* 0x03 */ AverageMean,
        /* 0x04 */ Reserved0x04, //AverageMeanWeighted,
        /* 0x05 */ AverageMedian,
        /* 0x06 */ Reserved0x06, //AverageMedianWeighted,
        /* 0x07 */ StandardDeviation,
        /* 0x08 */ Reserved0x08, //AverageDeviation,
        /* 0x09 */ Reserved0x09, //MedianDeviation,
        /* 0x0A */ Reserved0x10, //MaximumDeviation,
        /* 0x0B */ ConcatenateAndHash
    }

    /// Structure containing all the parameters that fully describe a Witnet Radon Retrieval within a Witnet Data Request.
    struct RadonRetrieval {
        uint8 argsCount;
        RadonDataRequestMethods method;
        RadonDataTypes resultDataType;
        string url;
        string body;
        string[2][] headers;
        bytes script;
    }

    /// Structure containing the Retrieve-Attestation-Delivery parts of a Witnet Data Request.
    struct RadonRAD {
        RadonRetrieval[] retrieve;
        RadonReducer aggregate;
        RadonReducer tally;
    }

    /// Structure containing the Service Level Aggreement parameters of a Witnet Data Request.
    struct RadonSLA {
        uint8 numWitnesses;
        uint8 minConsensusPercentage;
        uint64 witnessReward;
        uint64 witnessCollateral;
        uint64 minerCommitRevealFee;
    }


    /// ===============================================================================================================
    /// --- 'uint*' helper methods ------------------------------------------------------------------------------------

    /// @notice Convert a `uint8` into a 2 characters long `string` representing its two less significant hexadecimal values.
    function toHexString(uint8 _u)
        internal pure
        returns (string memory)
    {
        bytes memory b2 = new bytes(2);
        uint8 d0 = uint8(_u / 16) + 48;
        uint8 d1 = uint8(_u % 16) + 48;
        if (d0 > 57)
            d0 += 7;
        if (d1 > 57)
            d1 += 7;
        b2[0] = bytes1(d0);
        b2[1] = bytes1(d1);
        return string(b2);
    }

    /// @notice Convert a `uint8` into a 1, 2 or 3 characters long `string` representing its.
    /// three less significant decimal values.
    function toString(uint8 _u)
        internal pure
        returns (string memory)
    {
        if (_u < 10) {
            bytes memory b1 = new bytes(1);
            b1[0] = bytes1(uint8(_u) + 48);
            return string(b1);
        } else if (_u < 100) {
            bytes memory b2 = new bytes(2);
            b2[0] = bytes1(uint8(_u / 10) + 48);
            b2[1] = bytes1(uint8(_u % 10) + 48);
            return string(b2);
        } else {
            bytes memory b3 = new bytes(3);
            b3[0] = bytes1(uint8(_u / 100) + 48);
            b3[1] = bytes1(uint8(_u % 100 / 10) + 48);
            b3[2] = bytes1(uint8(_u % 10) + 48);
            return string(b3);
        }
    }

    /// @notice Convert a `uint` into a string` representing its value.
    function toString(uint v)
        internal pure 
        returns (string memory)
    {
        uint maxlength = 100;
        bytes memory reversed = new bytes(maxlength);
        uint i = 0;
        do {
            uint8 remainder = uint8(v % 10);
            v = v / 10;
            reversed[i ++] = bytes1(48 + remainder);
        } while (v != 0);
        bytes memory buf = new bytes(i);
        for (uint j = 1; j <= i; j ++) {
            buf[j - 1] = reversed[i - j];
        }
        return string(buf);
    }


    /// ===============================================================================================================
    /// --- 'bytes' helper methods ------------------------------------------------------------------------------------

    /// @dev Transform given bytes into a Witnet.Result instance.
    /// @param cborBytes Raw bytes representing a CBOR-encoded value.
    /// @return A `Witnet.Result` instance.
    function toWitnetResult(bytes memory cborBytes)
        internal pure
        returns (Witnet.Result memory)
    {
        WitnetCBOR.CBOR memory cborValue = WitnetCBOR.fromBytes(cborBytes);
        return _resultFromCborValue(cborValue);
    }

    function toAddress(bytes memory _value) internal pure returns (address) {
        return address(toBytes20(_value));
    }

    function toBytes4(bytes memory _value) internal pure returns (bytes4) {
        return bytes4(toFixedBytes(_value, 4));
    }
    
    function toBytes20(bytes memory _value) internal pure returns (bytes20) {
        return bytes20(toFixedBytes(_value, 20));
    }
    
    function toBytes32(bytes memory _value) internal pure returns (bytes32) {
        return toFixedBytes(_value, 32);
    }

    function toFixedBytes(bytes memory _value, uint8 _numBytes)
        internal pure
        returns (bytes32 _bytes32)
    {
        assert(_numBytes <= 32);
        unchecked {
            uint _len = _value.length > _numBytes ? _numBytes : _value.length;
            for (uint _i = 0; _i < _len; _i ++) {
                _bytes32 |= bytes32(_value[_i] & 0xff) >> (_i * 8);
            }
        }
    }


    /// ===============================================================================================================
    /// --- 'string' helper methods -----------------------------------------------------------------------------------

    function toLowerCase(string memory str)
        internal pure
        returns (string memory)
    {
        bytes memory lowered = new bytes(bytes(str).length);
        unchecked {
            for (uint i = 0; i < lowered.length; i ++) {
                uint8 char = uint8(bytes(str)[i]);
                if (char >= 65 && char <= 90) {
                    lowered[i] = bytes1(char + 32);
                } else {
                    lowered[i] = bytes1(char);
                }
            }
        }
        return string(lowered);
    }

    /// @notice Converts bytes32 into string.
    function toString(bytes32 _bytes32)
        internal pure
        returns (string memory)
    {
        bytes memory _bytes = new bytes(_toStringLength(_bytes32));
        for (uint _i = 0; _i < _bytes.length;) {
            _bytes[_i] = _bytes32[_i];
            unchecked {
                _i ++;
            }
        }
        return string(_bytes);
    }

    function tryUint(string memory str)
        internal pure
        returns (uint res, bool)
    {
        unchecked {
            for (uint256 i = 0; i < bytes(str).length; i++) {
                if (
                    (uint8(bytes(str)[i]) - 48) < 0
                        || (uint8(bytes(str)[i]) - 48) > 9
                ) {
                    return (0, false);
                }
                res += (uint8(bytes(str)[i]) - 48) * 10 ** (bytes(str).length - i - 1);
            }
            return (res, true);
        }
    }
    

    /// ===============================================================================================================
    /// --- 'Witnet.Result' helper methods ----------------------------------------------------------------------------

    modifier _isReady(Result memory result) {
        require(result.success, "Witnet: tried to decode value from errored result.");
        _;
    }

    /// @dev Decode an address from the Witnet.Result's CBOR value.
    function asAddress(Witnet.Result memory result)
        internal pure
        _isReady(result)
        returns (address)
    {
        if (result.value.majorType == uint8(WitnetCBOR.MAJOR_TYPE_BYTES)) {
            return toAddress(result.value.readBytes());
        } else {
            // TODO
            revert("WitnetLib: reading address from string not yet supported.");
        }
    }

    /// @dev Decode a `bool` value from the Witnet.Result's CBOR value.
    function asBool(Witnet.Result memory result)
        internal pure
        _isReady(result)
        returns (bool)
    {
        return result.value.readBool();
    }

    /// @dev Decode a `bytes` value from the Witnet.Result's CBOR value.
    function asBytes(Witnet.Result memory result)
        internal pure
        _isReady(result)
        returns(bytes memory)
    {
        return result.value.readBytes();
    }

    /// @dev Decode a `bytes4` value from the Witnet.Result's CBOR value.
    function asBytes4(Witnet.Result memory result)
        internal pure
        _isReady(result)
        returns (bytes4)
    {
        return toBytes4(asBytes(result));
    }

    /// @dev Decode a `bytes32` value from the Witnet.Result's CBOR value.
    function asBytes32(Witnet.Result memory result)
        internal pure
        _isReady(result)
        returns (bytes32)
    {
        return toBytes32(asBytes(result));
    }

    /// @notice Returns the Witnet.Result's unread CBOR value.
    function asCborValue(Witnet.Result memory result)
        internal pure
        _isReady(result)
        returns (WitnetCBOR.CBOR memory)
    {
        return result.value;
    }

    /// @notice Decode array of CBOR values from the Witnet.Result's CBOR value. 
    function asCborArray(Witnet.Result memory result)
        internal pure
        _isReady(result)
        returns (WitnetCBOR.CBOR[] memory)
    {
        return result.value.readArray();
    }

    /// @dev Decode a fixed16 (half-precision) numeric value from the Witnet.Result's CBOR value.
    /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values.
    /// by 5 decimal orders so as to get a fixed precision of 5 decimal positions, which should be OK for most `fixed16`.
    /// use cases. In other words, the output of this method is 10,000 times the actual value, encoded into an `int32`.
    function asFixed16(Witnet.Result memory result)
        internal pure
        _isReady(result)
        returns (int32)
    {
        return result.value.readFloat16();
    }

    /// @dev Decode an array of fixed16 values from the Witnet.Result's CBOR value.
    function asFixed16Array(Witnet.Result memory result)
        internal pure
        _isReady(result)
        returns (int32[] memory)
    {
        return result.value.readFloat16Array();
    }

    /// @dev Decode an `int64` value from the Witnet.Result's CBOR value.
    function asInt(Witnet.Result memory result)
        internal pure
        _isReady(result)
        returns (int)
    {
        return result.value.readInt();
    }

    /// @dev Decode an array of integer numeric values from a Witnet.Result as an `int[]` array.
    /// @param result An instance of Witnet.Result.
    /// @return The `int[]` decoded from the Witnet.Result.
    function asIntArray(Witnet.Result memory result)
        internal pure
        _isReady(result)
        returns (int[] memory)
    {
        return result.value.readIntArray();
    }

    /// @dev Decode a `string` value from the Witnet.Result's CBOR value.
    /// @param result An instance of Witnet.Result.
    /// @return The `string` decoded from the Witnet.Result.
    function asText(Witnet.Result memory result)
        internal pure
        _isReady(result)
        returns(string memory)
    {
        return result.value.readString();
    }

    /// @dev Decode an array of strings from the Witnet.Result's CBOR value.
    /// @param result An instance of Witnet.Result.
    /// @return The `string[]` decoded from the Witnet.Result.
    function asTextArray(Witnet.Result memory result)
        internal pure
        _isReady(result)
        returns (string[] memory)
    {
        return result.value.readStringArray();
    }

    /// @dev Decode a `uint64` value from the Witnet.Result's CBOR value.
    /// @param result An instance of Witnet.Result.
    /// @return The `uint` decoded from the Witnet.Result.
    function asUint(Witnet.Result memory result)
        internal pure
        _isReady(result)
        returns (uint)
    {
        return result.value.readUint();
    }

    /// @dev Decode an array of `uint64` values from the Witnet.Result's CBOR value.
    /// @param result An instance of Witnet.Result.
    /// @return The `uint[]` decoded from the Witnet.Result.
    function asUintArray(Witnet.Result memory result)
        internal pure
        returns (uint[] memory)
    {
        return result.value.readUintArray();
    }


    /// ===============================================================================================================
    /// --- Witnet library private methods ----------------------------------------------------------------------------

    /// @dev Decode a CBOR value into a Witnet.Result instance.
    function _resultFromCborValue(WitnetCBOR.CBOR memory cbor)
        private pure
        returns (Witnet.Result memory)    
    {
        // Witnet uses CBOR tag 39 to represent RADON error code identifiers.
        // [CBOR tag 39] Identifiers for CBOR: https://github.com/lucas-clemente/cbor-specs/blob/master/id.md
        bool success = cbor.tag != 39;
        return Witnet.Result(success, cbor);
    }

    /// @dev Calculate length of string-equivalent to given bytes32.
    function _toStringLength(bytes32 _bytes32)
        private pure
        returns (uint _length)
    {
        for (; _length < 32; ) {
            if (_bytes32[_length] == 0) {
                break;
            }
            unchecked {
                _length ++;
            }
        }
    }
}
          

/WitnetBuffer.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

/// @title A convenient wrapper around the `bytes memory` type that exposes a buffer-like interface
/// @notice The buffer has an inner cursor that tracks the final offset of every read, i.e. any subsequent read will
/// start with the byte that goes right after the last one in the previous read.
/// @dev `uint32` is used here for `cursor` because `uint16` would only enable seeking up to 8KB, which could in some
/// theoretical use cases be exceeded. Conversely, `uint32` supports up to 512MB, which cannot credibly be exceeded.
/// @author The Witnet Foundation.
library WitnetBuffer {

  error EmptyBuffer();
  error IndexOutOfBounds(uint index, uint range);
  error MissingArgs(uint expected, uint given);

  /// Iterable bytes buffer.
  struct Buffer {
      bytes data;
      uint cursor;
  }

  // Ensures we access an existing index in an array
  modifier withinRange(uint index, uint _range) {
    if (index > _range) {
      revert IndexOutOfBounds(index, _range);
    }
    _;
  }

  /// @notice Concatenate undefinite number of bytes chunks.
  /// @dev Faster than looping on `abi.encodePacked(output, _buffs[ix])`.
  function concat(bytes[] memory _buffs)
    internal pure
    returns (bytes memory output)
  {
    unchecked {
      uint destinationPointer;
      uint destinationLength;
      assembly {
        // get safe scratch location
        output := mload(0x40)
        // set starting destination pointer
        destinationPointer := add(output, 32)
      }      
      for (uint ix = 1; ix <= _buffs.length; ix ++) {  
        uint source;
        uint sourceLength;
        uint sourcePointer;        
        assembly {
          // load source length pointer
          source := mload(add(_buffs, mul(ix, 32)))
          // load source length
          sourceLength := mload(source)
          // sets source memory pointer
          sourcePointer := add(source, 32)
        }
        memcpy(
          destinationPointer,
          sourcePointer,
          sourceLength
        );
        assembly {          
          // increase total destination length
          destinationLength := add(destinationLength, sourceLength)
          // sets destination memory pointer
          destinationPointer := add(destinationPointer, sourceLength)
        }
      }
      assembly {
        // protect output bytes
        mstore(output, destinationLength)
        // set final output length
        mstore(0x40, add(mload(0x40), add(destinationLength, 32)))
      }
    }
  }

  function fork(WitnetBuffer.Buffer memory buffer)
    internal pure
    returns (WitnetBuffer.Buffer memory)
  {
    return Buffer(
      buffer.data,
      buffer.cursor
    );
  }

  function mutate(
      WitnetBuffer.Buffer memory buffer,
      uint length,
      bytes memory pokes
    )
    internal pure
    withinRange(length, buffer.data.length - buffer.cursor + 1)
  {
    bytes[] memory parts = new bytes[](3);
    parts[0] = peek(
      buffer,
      0,
      buffer.cursor
    );
    parts[1] = pokes;
    parts[2] = peek(
      buffer,
      buffer.cursor + length,
      buffer.data.length - buffer.cursor - length
    );
    buffer.data = concat(parts);
  }

  /// @notice Read and consume the next byte from the buffer.
  /// @param buffer An instance of `Buffer`.
  /// @return The next byte in the buffer counting from the cursor position.
  function next(Buffer memory buffer)
    internal pure
    withinRange(buffer.cursor, buffer.data.length)
    returns (bytes1)
  {
    // Return the byte at the position marked by the cursor and advance the cursor all at once
    return buffer.data[buffer.cursor ++];
  }

  function peek(
      WitnetBuffer.Buffer memory buffer,
      uint offset,
      uint length
    )
    internal pure
    withinRange(offset + length, buffer.data.length)
    returns (bytes memory)
  {
    bytes memory data = buffer.data;
    bytes memory peeks = new bytes(length);
    uint destinationPointer;
    uint sourcePointer;
    assembly {
      destinationPointer := add(peeks, 32)
      sourcePointer := add(add(data, 32), offset)
    }
    memcpy(
      destinationPointer,
      sourcePointer,
      length
    );
    return peeks;
  }

  // @notice Extract bytes array from buffer starting from current cursor.
  /// @param buffer An instance of `Buffer`.
  /// @param length How many bytes to peek from the Buffer.
  // solium-disable-next-line security/no-assign-params
  function peek(
      WitnetBuffer.Buffer memory buffer,
      uint length
    )
    internal pure
    withinRange(length, buffer.data.length - buffer.cursor)
    returns (bytes memory)
  {
    return peek(
      buffer,
      buffer.cursor,
      length
    );
  }

  /// @notice Read and consume a certain amount of bytes from the buffer.
  /// @param buffer An instance of `Buffer`.
  /// @param length How many bytes to read and consume from the buffer.
  /// @return output A `bytes memory` containing the first `length` bytes from the buffer, counting from the cursor position.
  function read(Buffer memory buffer, uint length)
    internal pure
    withinRange(buffer.cursor + length, buffer.data.length)
    returns (bytes memory output)
  {
    // Create a new `bytes memory destination` value
    output = new bytes(length);
    // Early return in case that bytes length is 0
    if (length > 0) {
      bytes memory input = buffer.data;
      uint offset = buffer.cursor;
      // Get raw pointers for source and destination
      uint sourcePointer;
      uint destinationPointer;
      assembly {
        sourcePointer := add(add(input, 32), offset)
        destinationPointer := add(output, 32)
      }
      // Copy `length` bytes from source to destination
      memcpy(
        destinationPointer,
        sourcePointer,
        length
      );
      // Move the cursor forward by `length` bytes
      seek(
        buffer,
        length,
        true
      );
    }
  }
  
  /// @notice Read and consume the next 2 bytes from the buffer as an IEEE 754-2008 floating point number enclosed in an
  /// `int32`.
  /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values
  /// by 5 decimal orders so as to get a fixed precision of 5 decimal positions, which should be OK for most `float16`
  /// use cases. In other words, the integer output of this method is 10,000 times the actual value. The input bytes are
  /// expected to follow the 16-bit base-2 format (a.k.a. `binary16`) in the IEEE 754-2008 standard.
  /// @param buffer An instance of `Buffer`.
  /// @return result The `int32` value of the next 4 bytes in the buffer counting from the cursor position.
  function readFloat16(Buffer memory buffer)
    internal pure
    returns (int32 result)
  {
    uint32 value = readUint16(buffer);
    // Get bit at position 0
    uint32 sign = value & 0x8000;
    // Get bits 1 to 5, then normalize to the [-15, 16] range so as to counterweight the IEEE 754 exponent bias
    int32 exponent = (int32(value & 0x7c00) >> 10) - 15;
    // Get bits 6 to 15
    int32 fraction = int32(value & 0x03ff);
    // Add 2^10 to the fraction if exponent is not -15
    if (exponent != -15) {
      fraction |= 0x400;
    } else if (exponent == 16) {
      revert(
        string(abi.encodePacked(
          "WitnetBuffer.readFloat16: ",
          sign != 0 ? "negative" : hex"",
          " infinity"
        ))
      );
    }
    // Compute `2 ^ exponent · (1 + fraction / 1024)`
    if (exponent >= 0) {
      result = int32(int(
        int(1 << uint256(int256(exponent)))
          * 10000
          * fraction
      ) >> 10);
    } else {
      result = int32(int(
        int(fraction)
          * 10000
          / int(1 << uint(int(- exponent)))
      ) >> 10);
    }
    // Make the result negative if the sign bit is not 0
    if (sign != 0) {
      result *= -1;
    }
  }

  /// @notice Consume the next 4 bytes from the buffer as an IEEE 754-2008 floating point number enclosed into an `int`.
  /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values
  /// by 9 decimal orders so as to get a fixed precision of 9 decimal positions, which should be OK for most `float32`
  /// use cases. In other words, the integer output of this method is 10^9 times the actual value. The input bytes are
  /// expected to follow the 64-bit base-2 format (a.k.a. `binary32`) in the IEEE 754-2008 standard.
  /// @param buffer An instance of `Buffer`.
  /// @return result The `int` value of the next 8 bytes in the buffer counting from the cursor position.
  function readFloat32(Buffer memory buffer)
    internal pure
    returns (int result)
  {
    uint value = readUint32(buffer);
    // Get bit at position 0
    uint sign = value & 0x80000000;
    // Get bits 1 to 8, then normalize to the [-127, 128] range so as to counterweight the IEEE 754 exponent bias
    int exponent = (int(value & 0x7f800000) >> 23) - 127;
    // Get bits 9 to 31
    int fraction = int(value & 0x007fffff);
    // Add 2^23 to the fraction if exponent is not -127
    if (exponent != -127) {
      fraction |= 0x800000;
    } else if (exponent == 128) {
      revert(
        string(abi.encodePacked(
          "WitnetBuffer.readFloat32: ",
          sign != 0 ? "negative" : hex"",
          " infinity"
        ))
      );
    }
    // Compute `2 ^ exponent · (1 + fraction / 2^23)`
    if (exponent >= 0) {
      result = (
        int(1 << uint(exponent))
          * (10 ** 9)
          * fraction
      ) >> 23;
    } else {
      result = (
        fraction 
          * (10 ** 9)
          / int(1 << uint(-exponent)) 
      ) >> 23;
    }
    // Make the result negative if the sign bit is not 0
    if (sign != 0) {
      result *= -1;
    }
  }

  /// @notice Consume the next 8 bytes from the buffer as an IEEE 754-2008 floating point number enclosed into an `int`.
  /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values
  /// by 15 decimal orders so as to get a fixed precision of 15 decimal positions, which should be OK for most `float64`
  /// use cases. In other words, the integer output of this method is 10^15 times the actual value. The input bytes are
  /// expected to follow the 64-bit base-2 format (a.k.a. `binary64`) in the IEEE 754-2008 standard.
  /// @param buffer An instance of `Buffer`.
  /// @return result The `int` value of the next 8 bytes in the buffer counting from the cursor position.
  function readFloat64(Buffer memory buffer)
    internal pure
    returns (int result)
  {
    uint value = readUint64(buffer);
    // Get bit at position 0
    uint sign = value & 0x8000000000000000;
    // Get bits 1 to 12, then normalize to the [-1023, 1024] range so as to counterweight the IEEE 754 exponent bias
    int exponent = (int(value & 0x7ff0000000000000) >> 52) - 1023;
    // Get bits 6 to 15
    int fraction = int(value & 0x000fffffffffffff);
    // Add 2^52 to the fraction if exponent is not -1023
    if (exponent != -1023) {
      fraction |= 0x10000000000000;
    } else if (exponent == 1024) {
      revert(
        string(abi.encodePacked(
          "WitnetBuffer.readFloat64: ",
          sign != 0 ? "negative" : hex"",
          " infinity"
        ))
      );
    }
    // Compute `2 ^ exponent · (1 + fraction / 1024)`
    if (exponent >= 0) {
      result = (
        int(1 << uint(exponent))
          * (10 ** 15)
          * fraction
      ) >> 52;
    } else {
      result = (
        fraction 
          * (10 ** 15)
          / int(1 << uint(-exponent)) 
      ) >> 52;
    }
    // Make the result negative if the sign bit is not 0
    if (sign != 0) {
      result *= -1;
    }
  }

  // Read a text string of a given length from a buffer. Returns a `bytes memory` value for the sake of genericness,
  /// but it can be easily casted into a string with `string(result)`.
  // solium-disable-next-line security/no-assign-params
  function readText(
      WitnetBuffer.Buffer memory buffer,
      uint64 length
    )
    internal pure
    returns (bytes memory text)
  {
    text = new bytes(length);
    unchecked {
      for (uint64 index = 0; index < length; index ++) {
        uint8 char = readUint8(buffer);
        if (char & 0x80 != 0) {
          if (char < 0xe0) {
            char = (char & 0x1f) << 6
              | (readUint8(buffer) & 0x3f);
            length -= 1;
          } else if (char < 0xf0) {
            char  = (char & 0x0f) << 12
              | (readUint8(buffer) & 0x3f) << 6
              | (readUint8(buffer) & 0x3f);
            length -= 2;
          } else {
            char = (char & 0x0f) << 18
              | (readUint8(buffer) & 0x3f) << 12
              | (readUint8(buffer) & 0x3f) << 6  
              | (readUint8(buffer) & 0x3f);
            length -= 3;
          }
        }
        text[index] = bytes1(char);
      }
      // Adjust text to actual length:
      assembly {
        mstore(text, length)
      }
    }
  }

  /// @notice Read and consume the next byte from the buffer as an `uint8`.
  /// @param buffer An instance of `Buffer`.
  /// @return value The `uint8` value of the next byte in the buffer counting from the cursor position.
  function readUint8(Buffer memory buffer)
    internal pure
    withinRange(buffer.cursor, buffer.data.length)
    returns (uint8 value)
  {
    bytes memory data = buffer.data;
    uint offset = buffer.cursor;
    assembly {
      value := mload(add(add(data, 1), offset))
    }
    buffer.cursor ++;
  }

  /// @notice Read and consume the next 2 bytes from the buffer as an `uint16`.
  /// @param buffer An instance of `Buffer`.
  /// @return value The `uint16` value of the next 2 bytes in the buffer counting from the cursor position.
  function readUint16(Buffer memory buffer)
    internal pure
    withinRange(buffer.cursor + 2, buffer.data.length)
    returns (uint16 value)
  {
    bytes memory data = buffer.data;
    uint offset = buffer.cursor;
    assembly {
      value := mload(add(add(data, 2), offset))
    }
    buffer.cursor += 2;
  }

  /// @notice Read and consume the next 4 bytes from the buffer as an `uint32`.
  /// @param buffer An instance of `Buffer`.
  /// @return value The `uint32` value of the next 4 bytes in the buffer counting from the cursor position.
  function readUint32(Buffer memory buffer)
    internal pure
    withinRange(buffer.cursor + 4, buffer.data.length)
    returns (uint32 value)
  {
    bytes memory data = buffer.data;
    uint offset = buffer.cursor;
    assembly {
      value := mload(add(add(data, 4), offset))
    }
    buffer.cursor += 4;
  }

  /// @notice Read and consume the next 8 bytes from the buffer as an `uint64`.
  /// @param buffer An instance of `Buffer`.
  /// @return value The `uint64` value of the next 8 bytes in the buffer counting from the cursor position.
  function readUint64(Buffer memory buffer)
    internal pure
    withinRange(buffer.cursor + 8, buffer.data.length)
    returns (uint64 value)
  {
    bytes memory data = buffer.data;
    uint offset = buffer.cursor;
    assembly {
      value := mload(add(add(data, 8), offset))
    }
    buffer.cursor += 8;
  }

  /// @notice Read and consume the next 16 bytes from the buffer as an `uint128`.
  /// @param buffer An instance of `Buffer`.
  /// @return value The `uint128` value of the next 16 bytes in the buffer counting from the cursor position.
  function readUint128(Buffer memory buffer)
    internal pure
    withinRange(buffer.cursor + 16, buffer.data.length)
    returns (uint128 value)
  {
    bytes memory data = buffer.data;
    uint offset = buffer.cursor;
    assembly {
      value := mload(add(add(data, 16), offset))
    }
    buffer.cursor += 16;
  }

  /// @notice Read and consume the next 32 bytes from the buffer as an `uint256`.
  /// @param buffer An instance of `Buffer`.
  /// @return value The `uint256` value of the next 32 bytes in the buffer counting from the cursor position.
  function readUint256(Buffer memory buffer)
    internal pure
    withinRange(buffer.cursor + 32, buffer.data.length)
    returns (uint256 value)
  {
    bytes memory data = buffer.data;
    uint offset = buffer.cursor;
    assembly {
      value := mload(add(add(data, 32), offset))
    }
    buffer.cursor += 32;
  }

  /// @notice Count number of required parameters for given bytes arrays
  /// @dev Wildcard format: "\#\", with # in ["0".."9"].
  /// @param input Bytes array containing strings.
  /// @param count Highest wildcard index found, plus 1.
  function argsCountOf(bytes memory input)
    internal pure
    returns (uint8 count)
  {
    if (input.length < 3) {
      return 0;
    }
    unchecked {
      uint ix = 0; 
      uint length = input.length - 2;
      for (; ix < length; ) {
        if (
          input[ix] == bytes1("\\")
            && input[ix + 2] == bytes1("\\")
            && input[ix + 1] >= bytes1("0")
            && input[ix + 1] <= bytes1("9")
        ) {
          uint8 ax = uint8(uint8(input[ix + 1]) - uint8(bytes1("0")) + 1);
          if (ax > count) {
            count = ax;
          }
          ix += 3;
        } else {
          ix ++;
        }
      }
    }
  }

  /// @notice Replace bytecode indexed wildcards by correspondent substrings.
  /// @dev Wildcard format: "\#\", with # in ["0".."9"].
  /// @param input Bytes array containing strings.
  /// @param args Array of substring values for replacing indexed wildcards.
  /// @return output Resulting bytes array after replacing all wildcards.
  /// @return hits Total number of replaced wildcards.
  function replace(bytes memory input, string[] memory args)
    internal pure
    returns (bytes memory output, uint hits)
  {
    uint ix = 0; uint lix = 0;
    uint inputLength;
    uint inputPointer;
    uint outputLength;
    uint outputPointer;    
    uint source;
    uint sourceLength;
    uint sourcePointer;

    if (input.length < 3) {
      return (input, 0);
    }
    
    assembly {
      // set starting input pointer
      inputPointer := add(input, 32)
      // get safe output location
      output := mload(0x40)
      // set starting output pointer
      outputPointer := add(output, 32)
    }         

    unchecked {
      uint length = input.length - 2;
      for (; ix < length; ) {
        if (
          input[ix] == bytes1("\\")
            && input[ix + 2] == bytes1("\\")
            && input[ix + 1] >= bytes1("0")
            && input[ix + 1] <= bytes1("9")
        ) {
          inputLength = (ix - lix);
          if (ix > lix) {
            memcpy(
              outputPointer,
              inputPointer,
              inputLength
            );
            inputPointer += inputLength + 3;
            outputPointer += inputLength;
          } else {
            inputPointer += 3;
          }
          uint ax = uint(uint8(input[ix + 1]) - uint8(bytes1("0")));
          if (ax >= args.length) {
            revert MissingArgs(ax + 1, args.length);
          }
          assembly {
            source := mload(add(args, mul(32, add(ax, 1))))
            sourceLength := mload(source)
            sourcePointer := add(source, 32)      
          }        
          memcpy(
            outputPointer,
            sourcePointer,
            sourceLength
          );
          outputLength += inputLength + sourceLength;
          outputPointer += sourceLength;
          ix += 3;
          lix = ix;
          hits ++;
        } else {
          ix ++;
        }
      }
      ix = input.length;    
    }
    if (outputLength > 0) {
      if (ix > lix ) {
        memcpy(
          outputPointer,
          inputPointer,
          ix - lix
        );
        outputLength += (ix - lix);
      }
      assembly {
        // set final output length
        mstore(output, outputLength)
        // protect output bytes
        mstore(0x40, add(mload(0x40), add(outputLength, 32)))
      }
    }
    else {
      return (input, 0);
    }
  }

  /// @notice Replace string indexed wildcards by correspondent substrings.
  /// @dev Wildcard format: "\#\", with # in ["0".."9"].
  /// @param input String potentially containing wildcards.
  /// @param args Array of substring values for replacing indexed wildcards.
  /// @return output Resulting string after replacing all wildcards.
  function replace(string memory input, string[] memory args)
    internal pure
    returns (string memory)
  {
    (bytes memory _outputBytes, ) = replace(bytes(input), args);
    return string(_outputBytes);
  }

  /// @notice Move the inner cursor of the buffer to a relative or absolute position.
  /// @param buffer An instance of `Buffer`.
  /// @param offset How many bytes to move the cursor forward.
  /// @param relative Whether to count `offset` from the last position of the cursor (`true`) or the beginning of the
  /// buffer (`true`).
  /// @return The final position of the cursor (will equal `offset` if `relative` is `false`).
  // solium-disable-next-line security/no-assign-params
  function seek(
      Buffer memory buffer,
      uint offset,
      bool relative
    )
    internal pure
    withinRange(offset, buffer.data.length)
    returns (uint)
  {
    // Deal with relative offsets
    if (relative) {
      offset += buffer.cursor;
    }
    buffer.cursor = offset;
    return offset;
  }

  /// @notice Move the inner cursor a number of bytes forward.
  /// @dev This is a simple wrapper around the relative offset case of `seek()`.
  /// @param buffer An instance of `Buffer`.
  /// @param relativeOffset How many bytes to move the cursor forward.
  /// @return The final position of the cursor.
  function seek(
      Buffer memory buffer,
      uint relativeOffset
    )
    internal pure
    returns (uint)
  {
    return seek(
      buffer,
      relativeOffset,
      true
    );
  }

  /// @notice Copy bytes from one memory address into another.
  /// @dev This function was borrowed from Nick Johnson's `solidity-stringutils` lib, and reproduced here under the terms
  /// of [Apache License 2.0](https://github.com/Arachnid/solidity-stringutils/blob/master/LICENSE).
  /// @param dest Address of the destination memory.
  /// @param src Address to the source memory.
  /// @param len How many bytes to copy.
  // solium-disable-next-line security/no-assign-params
  function memcpy(
      uint dest,
      uint src,
      uint len
    )
    private pure
  {
    unchecked {
      // Copy word-length chunks while possible
      for (; len >= 32; len -= 32) {
        assembly {
          mstore(dest, mload(src))
        }
        dest += 32;
        src += 32;
      }
      if (len > 0) {
        // Copy remaining bytes
        uint _mask = 256 ** (32 - len) - 1;
        assembly {
          let srcpart := and(mload(src), not(_mask))
          let destpart := and(mload(dest), _mask)
          mstore(dest, or(destpart, srcpart))
        }
      }
    }
  }

}
          

/WitnetCBOR.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

import "./WitnetBuffer.sol";

/// @title A minimalistic implementation of “RFC 7049 Concise Binary Object Representation”
/// @notice This library leverages a buffer-like structure for step-by-step decoding of bytes so as to minimize
/// the gas cost of decoding them into a useful native type.
/// @dev Most of the logic has been borrowed from Patrick Gansterer’s cbor.js library: https://github.com/paroga/cbor-js
/// @author The Witnet Foundation.

library WitnetCBOR {

  using WitnetBuffer for WitnetBuffer.Buffer;
  using WitnetCBOR for WitnetCBOR.CBOR;

  /// Data struct following the RFC-7049 standard: Concise Binary Object Representation.
  struct CBOR {
      WitnetBuffer.Buffer buffer;
      uint8 initialByte;
      uint8 majorType;
      uint8 additionalInformation;
      uint64 len;
      uint64 tag;
  }

  uint8 internal constant MAJOR_TYPE_INT = 0;
  uint8 internal constant MAJOR_TYPE_NEGATIVE_INT = 1;
  uint8 internal constant MAJOR_TYPE_BYTES = 2;
  uint8 internal constant MAJOR_TYPE_STRING = 3;
  uint8 internal constant MAJOR_TYPE_ARRAY = 4;
  uint8 internal constant MAJOR_TYPE_MAP = 5;
  uint8 internal constant MAJOR_TYPE_TAG = 6;
  uint8 internal constant MAJOR_TYPE_CONTENT_FREE = 7;

  uint32 internal constant UINT32_MAX = type(uint32).max;
  uint64 internal constant UINT64_MAX = type(uint64).max;
  
  error EmptyArray();
  error InvalidLengthEncoding(uint length);
  error UnexpectedMajorType(uint read, uint expected);
  error UnsupportedPrimitive(uint primitive);
  error UnsupportedMajorType(uint unexpected);  

  modifier isMajorType(
      WitnetCBOR.CBOR memory cbor,
      uint8 expected
  ) {
    if (cbor.majorType != expected) {
      revert UnexpectedMajorType(cbor.majorType, expected);
    }
    _;
  }

  modifier notEmpty(WitnetBuffer.Buffer memory buffer) {
    if (buffer.data.length == 0) {
      revert WitnetBuffer.EmptyBuffer();
    }
    _;
  }

  function eof(CBOR memory cbor)
    internal pure
    returns (bool)
  {
    return cbor.buffer.cursor >= cbor.buffer.data.length;
  }

  /// @notice Decode a CBOR structure from raw bytes.
  /// @dev This is the main factory for CBOR instances, which can be later decoded into native EVM types.
  /// @param bytecode Raw bytes representing a CBOR-encoded value.
  /// @return A `CBOR` instance containing a partially decoded value.
  function fromBytes(bytes memory bytecode)
    internal pure
    returns (CBOR memory)
  {
    WitnetBuffer.Buffer memory buffer = WitnetBuffer.Buffer(bytecode, 0);
    return fromBuffer(buffer);
  }

  /// @notice Decode a CBOR structure from raw bytes.
  /// @dev This is an alternate factory for CBOR instances, which can be later decoded into native EVM types.
  /// @param buffer A Buffer structure representing a CBOR-encoded value.
  /// @return A `CBOR` instance containing a partially decoded value.
  function fromBuffer(WitnetBuffer.Buffer memory buffer)
    internal pure
    notEmpty(buffer)
    returns (CBOR memory)
  {
    uint8 initialByte;
    uint8 majorType = 255;
    uint8 additionalInformation;
    uint64 tag = UINT64_MAX;
    uint256 len;
    bool isTagged = true;
    while (isTagged) {
      // Extract basic CBOR properties from input bytes
      initialByte = buffer.readUint8();
      len ++;
      majorType = initialByte >> 5;
      additionalInformation = initialByte & 0x1f;
      // Early CBOR tag parsing.
      if (majorType == MAJOR_TYPE_TAG) {
        uint _cursor = buffer.cursor;
        tag = readLength(buffer, additionalInformation);
        len += buffer.cursor - _cursor;
      } else {
        isTagged = false;
      }
    }
    if (majorType > MAJOR_TYPE_CONTENT_FREE) {
      revert UnsupportedMajorType(majorType);
    }
    return CBOR(
      buffer,
      initialByte,
      majorType,
      additionalInformation,
      uint64(len),
      tag
    );
  }

  function fork(WitnetCBOR.CBOR memory self)
    internal pure
    returns (WitnetCBOR.CBOR memory)
  {
    return CBOR({
      buffer: self.buffer.fork(),
      initialByte: self.initialByte,
      majorType: self.majorType,
      additionalInformation: self.additionalInformation,
      len: self.len,
      tag: self.tag
    });
  }

  function settle(CBOR memory self)
      internal pure
      returns (WitnetCBOR.CBOR memory)
  {
    if (!self.eof()) {
      return fromBuffer(self.buffer);
    } else {
      return self;
    }
  }

  function skip(CBOR memory self)
      internal pure
      returns (WitnetCBOR.CBOR memory)
  {
    if (
      self.majorType == MAJOR_TYPE_INT
        || self.majorType == MAJOR_TYPE_NEGATIVE_INT
        || (
          self.majorType == MAJOR_TYPE_CONTENT_FREE 
            && self.additionalInformation >= 25
            && self.additionalInformation <= 27
        )
    ) {
      self.buffer.cursor += self.peekLength();
    } else if (
        self.majorType == MAJOR_TYPE_STRING
          || self.majorType == MAJOR_TYPE_BYTES
    ) {
      uint64 len = readLength(self.buffer, self.additionalInformation);
      self.buffer.cursor += len;
    } else if (
      self.majorType == MAJOR_TYPE_ARRAY
        || self.majorType == MAJOR_TYPE_MAP
    ) { 
      self.len = readLength(self.buffer, self.additionalInformation);      
    } else if (
       self.majorType != MAJOR_TYPE_CONTENT_FREE
        || (
          self.additionalInformation != 20
            && self.additionalInformation != 21
        )
    ) {
      revert("WitnetCBOR.skip: unsupported major type");
    }
    return self;
  }

  function peekLength(CBOR memory self)
    internal pure
    returns (uint64)
  {
    if (self.additionalInformation < 24) {
      return 0;
    } else if (self.additionalInformation < 28) {
      return uint64(1 << (self.additionalInformation - 24));
    } else {
      revert InvalidLengthEncoding(self.additionalInformation);
    }
  }

  function readArray(CBOR memory self)
    internal pure
    isMajorType(self, MAJOR_TYPE_ARRAY)
    returns (CBOR[] memory items)
  {
    // read array's length and move self cursor forward to the first array element:
    uint64 len = readLength(self.buffer, self.additionalInformation);
    items = new CBOR[](len + 1);
    for (uint ix = 0; ix < len; ix ++) {
      // settle next element in the array:
      self = self.settle();
      // fork it and added to the list of items to be returned:
      items[ix] = self.fork();
      if (self.majorType == MAJOR_TYPE_ARRAY) {
        CBOR[] memory _subitems = self.readArray();
        // move forward to the first element after inner array:
        self = _subitems[_subitems.length - 1];
      } else if (self.majorType == MAJOR_TYPE_MAP) {
        CBOR[] memory _subitems = self.readMap();
        // move forward to the first element after inner map:
        self = _subitems[_subitems.length - 1];
      } else {
        // move forward to the next element:
        self.skip();
      }
    }
    // return self cursor as extra item at the end of the list,
    // as to optimize recursion when jumping over nested arrays:
    items[len] = self;
  }

  function readMap(CBOR memory self)
    internal pure
    isMajorType(self, MAJOR_TYPE_MAP)
    returns (CBOR[] memory items)
  {
    // read number of items within the map and move self cursor forward to the first inner element:
    uint64 len = readLength(self.buffer, self.additionalInformation) * 2;
    items = new CBOR[](len + 1);
    for (uint ix = 0; ix < len; ix ++) {
      // settle next element in the array:
      self = self.settle();
      // fork it and added to the list of items to be returned:
      items[ix] = self.fork();
      if (ix % 2 == 0 && self.majorType != MAJOR_TYPE_STRING) {
        revert UnexpectedMajorType(self.majorType, MAJOR_TYPE_STRING);
      } else if (self.majorType == MAJOR_TYPE_ARRAY || self.majorType == MAJOR_TYPE_MAP) {
        CBOR[] memory _subitems = (self.majorType == MAJOR_TYPE_ARRAY
            ? self.readArray()
            : self.readMap()
        );
        // move forward to the first element after inner array or map:
        self = _subitems[_subitems.length - 1];
      } else {
        // move forward to the next element:
        self.skip();
      }
    }
    // return self cursor as extra item at the end of the list,
    // as to optimize recursion when jumping over nested arrays:
    items[len] = self;
  }

  /// Reads the length of the settle CBOR item from a buffer, consuming a different number of bytes depending on the
  /// value of the `additionalInformation` argument.
  function readLength(
      WitnetBuffer.Buffer memory buffer,
      uint8 additionalInformation
    ) 
    internal pure
    returns (uint64)
  {
    if (additionalInformation < 24) {
      return additionalInformation;
    }
    if (additionalInformation == 24) {
      return buffer.readUint8();
    }
    if (additionalInformation == 25) {
      return buffer.readUint16();
    }
    if (additionalInformation == 26) {
      return buffer.readUint32();
    }
    if (additionalInformation == 27) {
      return buffer.readUint64();
    }
    if (additionalInformation == 31) {
      return UINT64_MAX;
    }
    revert InvalidLengthEncoding(additionalInformation);
  }

  /// @notice Read a `CBOR` structure into a native `bool` value.
  /// @param cbor An instance of `CBOR`.
  /// @return The value represented by the input, as a `bool` value.
  function readBool(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_CONTENT_FREE)
    returns (bool)
  {
    if (cbor.additionalInformation == 20) {
      return false;
    } else if (cbor.additionalInformation == 21) {
      return true;
    } else {
      revert UnsupportedPrimitive(cbor.additionalInformation);
    }
  }

  /// @notice Decode a `CBOR` structure into a native `bytes` value.
  /// @param cbor An instance of `CBOR`.
  /// @return output The value represented by the input, as a `bytes` value.   
  function readBytes(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_BYTES)
    returns (bytes memory output)
  {
    cbor.len = readLength(
      cbor.buffer,
      cbor.additionalInformation
    );
    if (cbor.len == UINT32_MAX) {
      // These checks look repetitive but the equivalent loop would be more expensive.
      uint32 length = uint32(_readIndefiniteStringLength(
        cbor.buffer,
        cbor.majorType
      ));
      if (length < UINT32_MAX) {
        output = abi.encodePacked(cbor.buffer.read(length));
        length = uint32(_readIndefiniteStringLength(
          cbor.buffer,
          cbor.majorType
        ));
        if (length < UINT32_MAX) {
          output = abi.encodePacked(
            output,
            cbor.buffer.read(length)
          );
        }
      }
    } else {
      return cbor.buffer.read(uint32(cbor.len));
    }
  }

  /// @notice Decode a `CBOR` structure into a `fixed16` value.
  /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values
  /// by 5 decimal orders so as to get a fixed precision of 5 decimal positions, which should be OK for most `fixed16`
  /// use cases. In other words, the output of this method is 10,000 times the actual value, encoded into an `int32`.
  /// @param cbor An instance of `CBOR`.
  /// @return The value represented by the input, as an `int128` value.
  function readFloat16(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_CONTENT_FREE)
    returns (int32)
  {
    if (cbor.additionalInformation == 25) {
      return cbor.buffer.readFloat16();
    } else {
      revert UnsupportedPrimitive(cbor.additionalInformation);
    }
  }

  /// @notice Decode a `CBOR` structure into a `fixed32` value.
  /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values
  /// by 9 decimal orders so as to get a fixed precision of 9 decimal positions, which should be OK for most `fixed64`
  /// use cases. In other words, the output of this method is 10^9 times the actual value, encoded into an `int`.
  /// @param cbor An instance of `CBOR`.
  /// @return The value represented by the input, as an `int` value.
  function readFloat32(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_CONTENT_FREE)
    returns (int)
  {
    if (cbor.additionalInformation == 26) {
      return cbor.buffer.readFloat32();
    } else {
      revert UnsupportedPrimitive(cbor.additionalInformation);
    }
  }

  /// @notice Decode a `CBOR` structure into a `fixed64` value.
  /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values
  /// by 15 decimal orders so as to get a fixed precision of 15 decimal positions, which should be OK for most `fixed64`
  /// use cases. In other words, the output of this method is 10^15 times the actual value, encoded into an `int`.
  /// @param cbor An instance of `CBOR`.
  /// @return The value represented by the input, as an `int` value.
  function readFloat64(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_CONTENT_FREE)
    returns (int)
  {
    if (cbor.additionalInformation == 27) {
      return cbor.buffer.readFloat64();
    } else {
      revert UnsupportedPrimitive(cbor.additionalInformation);
    }
  }

  /// @notice Decode a `CBOR` structure into a native `int128[]` value whose inner values follow the same convention 
  /// @notice as explained in `decodeFixed16`.
  /// @param cbor An instance of `CBOR`.
  function readFloat16Array(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_ARRAY)
    returns (int32[] memory values)
  {
    uint64 length = readLength(cbor.buffer, cbor.additionalInformation);
    if (length < UINT64_MAX) {
      values = new int32[](length);
      for (uint64 i = 0; i < length; ) {
        CBOR memory item = fromBuffer(cbor.buffer);
        values[i] = readFloat16(item);
        unchecked {
          i ++;
        }
      }
    } else {
      revert InvalidLengthEncoding(length);
    }
  }

  /// @notice Decode a `CBOR` structure into a native `int128` value.
  /// @param cbor An instance of `CBOR`.
  /// @return The value represented by the input, as an `int128` value.
  function readInt(CBOR memory cbor)
    internal pure
    returns (int)
  {
    if (cbor.majorType == 1) {
      uint64 _value = readLength(
        cbor.buffer,
        cbor.additionalInformation
      );
      return int(-1) - int(uint(_value));
    } else if (cbor.majorType == 0) {
      // Any `uint64` can be safely casted to `int128`, so this method supports majorType 1 as well so as to have offer
      // a uniform API for positive and negative numbers
      return int(readUint(cbor));
    }
    else {
      revert UnexpectedMajorType(cbor.majorType, 1);
    }
  }

  /// @notice Decode a `CBOR` structure into a native `int[]` value.
  /// @param cbor instance of `CBOR`.
  /// @return array The value represented by the input, as an `int[]` value.
  function readIntArray(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_ARRAY)
    returns (int[] memory array)
  {
    uint64 length = readLength(cbor.buffer, cbor.additionalInformation);
    if (length < UINT64_MAX) {
      array = new int[](length);
      for (uint i = 0; i < length; ) {
        CBOR memory item = fromBuffer(cbor.buffer);
        array[i] = readInt(item);
        unchecked {
          i ++;
        }
      }
    } else {
      revert InvalidLengthEncoding(length);
    }
  }

  /// @notice Decode a `CBOR` structure into a native `string` value.
  /// @param cbor An instance of `CBOR`.
  /// @return text The value represented by the input, as a `string` value.
  function readString(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_STRING)
    returns (string memory text)
  {
    cbor.len = readLength(cbor.buffer, cbor.additionalInformation);
    if (cbor.len == UINT64_MAX) {
      bool _done;
      while (!_done) {
        uint64 length = _readIndefiniteStringLength(
          cbor.buffer,
          cbor.majorType
        );
        if (length < UINT64_MAX) {
          text = string(abi.encodePacked(
            text,
            cbor.buffer.readText(length / 4)
          ));
        } else {
          _done = true;
        }
      }
    } else {
      return string(cbor.buffer.readText(cbor.len));
    }
  }

  /// @notice Decode a `CBOR` structure into a native `string[]` value.
  /// @param cbor An instance of `CBOR`.
  /// @return strings The value represented by the input, as an `string[]` value.
  function readStringArray(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_ARRAY)
    returns (string[] memory strings)
  {
    uint length = readLength(cbor.buffer, cbor.additionalInformation);
    if (length < UINT64_MAX) {
      strings = new string[](length);
      for (uint i = 0; i < length; ) {
        CBOR memory item = fromBuffer(cbor.buffer);
        strings[i] = readString(item);
        unchecked {
          i ++;
        }
      }
    } else {
      revert InvalidLengthEncoding(length);
    }
  }

  /// @notice Decode a `CBOR` structure into a native `uint64` value.
  /// @param cbor An instance of `CBOR`.
  /// @return The value represented by the input, as an `uint64` value.
  function readUint(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_INT)
    returns (uint)
  {
    return readLength(
      cbor.buffer,
      cbor.additionalInformation
    );
  }

  /// @notice Decode a `CBOR` structure into a native `uint64[]` value.
  /// @param cbor An instance of `CBOR`.
  /// @return values The value represented by the input, as an `uint64[]` value.
  function readUintArray(CBOR memory cbor)
    internal pure
    isMajorType(cbor, MAJOR_TYPE_ARRAY)
    returns (uint[] memory values)
  {
    uint64 length = readLength(cbor.buffer, cbor.additionalInformation);
    if (length < UINT64_MAX) {
      values = new uint[](length);
      for (uint ix = 0; ix < length; ) {
        CBOR memory item = fromBuffer(cbor.buffer);
        values[ix] = readUint(item);
        unchecked {
          ix ++;
        }
      }
    } else {
      revert InvalidLengthEncoding(length);
    }
  }  

  /// Read the length of a CBOR indifinite-length item (arrays, maps, byte strings and text) from a buffer, consuming
  /// as many bytes as specified by the first byte.
  function _readIndefiniteStringLength(
      WitnetBuffer.Buffer memory buffer,
      uint8 majorType
    )
    private pure
    returns (uint64 len)
  {
    uint8 initialByte = buffer.readUint8();
    if (initialByte == 0xff) {
      return UINT64_MAX;
    }
    len = readLength(
      buffer,
      initialByte & 0x1f
    );
    if (len >= UINT64_MAX) {
      revert InvalidLengthEncoding(len);
    } else if (majorType != (initialByte >> 5)) {
      revert UnexpectedMajorType((initialByte >> 5), majorType);
    }
  }
 
}
          

/WitnetV2.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

import "./Witnet.sol";

library WitnetV2 {

    /// Struct containing both request and response data related to every query posted to the Witnet Request Board
    struct Query {
        Request request;
        Response response;
    }

    /// Possible status of a Witnet query.
    enum QueryStatus {
        Unknown,
        Posted,
        Reported,
        Finalized
    }

    /// Data kept in EVM-storage for every Request posted to the Witnet Request Board.
    struct Request {
        address requester;              // EVM address from which the request was posted.
        uint24  gasCallback;            // Max callback gas limit upon response, if a callback is required.
        uint72  evmReward;              // EVM amount in wei eventually to be paid to the legit result reporter.
        bytes   witnetBytecode;         // Optional: Witnet Data Request bytecode to be solved by the Witnet blockchain.
        bytes32 witnetRAD;              // Optional: Previously verified hash of the Witnet Data Request to be solved.
        WitnetV2.RadonSLA witnetSLA;    // Minimum Service-Level parameters to be committed by the Witnet blockchain. 
    }

    /// Response metadata and result as resolved by the Witnet blockchain.
    struct Response {
        address reporter;               // EVM address from which the Data Request result was reported.
        uint64  finality;               // EVM block number at which the reported data will be considered to be finalized.
        uint32  resultTimestamp;        // Unix timestamp (seconds) at which the data request was resolved in the Witnet blockchain.
        bytes32 resultTallyHash;        // Unique hash of the commit/reveal act in the Witnet blockchain that resolved the data request.
        bytes   resultCborBytes;        // CBOR-encode result to the request, as resolved in the Witnet blockchain.
    }

    /// Response status from a requester's point of view.
    enum ResponseStatus {
        Void,
        Awaiting,
        Ready,
        Error,
        Finalizing,
        Delivered
    }

    struct RadonSLA {
        /// @notice Number of nodes in the Witnet blockchain that will take part in solving the data request. 
        uint8   committeeSize;
        
        /// @notice Fee in $nanoWIT paid to every node in the Witnet blockchain involved in solving the data request.
        /// @dev Witnet nodes participating as witnesses will have to stake as collateral 100x this amount.
        uint64  witnessingFeeNanoWit;
    }

    
    /// ===============================================================================================================
    /// --- 'WitnetV2.RadonSLA' helper methods ------------------------------------------------------------------------

    function equalOrGreaterThan(RadonSLA memory a, RadonSLA memory b) 
        internal pure returns (bool)
    {
        return (a.committeeSize >= b.committeeSize);
    }
     
    function isValid(RadonSLA calldata sla) internal pure returns (bool) {
        return (
            sla.witnessingFeeNanoWit > 0 
                && sla.committeeSize > 0 && sla.committeeSize <= 127
                // v1.7.x requires witnessing collateral to be greater or equal to 20 WIT:
                && sla.witnessingFeeNanoWit * 100 >= 20 * 10 ** 9 
        );
    }

    function toV1(RadonSLA memory self) internal pure returns (Witnet.RadonSLA memory) {
        return Witnet.RadonSLA({
            numWitnesses: self.committeeSize,
            minConsensusPercentage: 51,
            witnessReward: self.witnessingFeeNanoWit,
            witnessCollateral: self.witnessingFeeNanoWit * 100,
            minerCommitRevealFee: self.witnessingFeeNanoWit / self.committeeSize
        });
    }

    function nanoWitTotalFee(RadonSLA storage self) internal view returns (uint64) {
        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 randomUniformUint32(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);
    }
}
          

/Ownable.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
          

/Ownable2Step.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./Ownable.sol";

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is specified at deployment time in the constructor for `Ownable`. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private _pendingOwner;

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        if (pendingOwner() != sender) {
            revert("Ownable2Step: caller is not the new owner");
        }
        _transferOwnership(sender);
    }
}
          

Compiler Settings

{"remappings":[],"optimizer":{"runs":200,"enabled":true},"metadata":{"bytecodeHash":"ipfs"},"libraries":{},"evmVersion":"paris","compilationTarget":{"project:/contracts/apps/WitnetRandomnessV2.sol":"WitnetRandomnessV2"}}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_witnet","internalType":"contract WitnetOracle"},{"type":"address","name":"_operator","internalType":"address"}]},{"type":"error","name":"EmptyBuffer","inputs":[]},{"type":"error","name":"IndexOutOfBounds","inputs":[{"type":"uint256","name":"index","internalType":"uint256"},{"type":"uint256","name":"range","internalType":"uint256"}]},{"type":"error","name":"InvalidLengthEncoding","inputs":[{"type":"uint256","name":"length","internalType":"uint256"}]},{"type":"error","name":"OwnableInvalidOwner","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"error","name":"OwnableUnauthorizedAccount","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"error","name":"UnexpectedMajorType","inputs":[{"type":"uint256","name":"read","internalType":"uint256"},{"type":"uint256","name":"expected","internalType":"uint256"}]},{"type":"error","name":"UnsupportedMajorType","inputs":[{"type":"uint256","name":"unexpected","internalType":"uint256"}]},{"type":"event","name":"OwnershipTransferStarted","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Randomizing","inputs":[{"type":"uint256","name":"blockNumber","internalType":"uint256","indexed":false},{"type":"uint256","name":"evmTxGasPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"evmRandomizeFee","internalType":"uint256","indexed":false},{"type":"uint256","name":"witnetQueryId","internalType":"uint256","indexed":false},{"type":"tuple","name":"witnetQuerySLA","internalType":"struct WitnetV2.RadonSLA","indexed":false,"components":[{"type":"uint8","name":"committeeSize","internalType":"uint8"},{"type":"uint64","name":"witnessingFeeNanoWit","internalType":"uint64"}]}],"anonymous":false},{"type":"event","name":"WitnetQuery","inputs":[{"type":"uint256","name":"id","internalType":"uint256","indexed":false},{"type":"uint256","name":"evmReward","internalType":"uint256","indexed":false},{"type":"tuple","name":"witnetSLA","internalType":"struct WitnetV2.RadonSLA","indexed":false,"components":[{"type":"uint8","name":"committeeSize","internalType":"uint8"},{"type":"uint64","name":"witnessingFeeNanoWit","internalType":"uint64"}]}],"anonymous":false},{"type":"event","name":"WitnetQueryResponse","inputs":[{"type":"uint256","name":"id","internalType":"uint256","indexed":false},{"type":"uint256","name":"evmGasPrice","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"WitnetQueryResponseDelivered","inputs":[{"type":"uint256","name":"id","internalType":"uint256","indexed":false},{"type":"uint256","name":"evmGasPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"evmCallbackGas","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"WitnetQueryResponseDeliveryFailed","inputs":[{"type":"uint256","name":"id","internalType":"uint256","indexed":false},{"type":"bytes","name":"resultCborBytes","internalType":"bytes","indexed":false},{"type":"uint256","name":"evmGasPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"evmCallbackActualGas","internalType":"uint256","indexed":false},{"type":"string","name":"evmCallbackRevertReason","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"WitnetQueryRewardUpgraded","inputs":[{"type":"uint256","name":"id","internalType":"uint256","indexed":false},{"type":"uint256","name":"evmReward","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"fallback","stateMutability":"payable"},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"acceptOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint16","name":"","internalType":"uint16"}],"name":"baseFeeOverheadPercentage","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"class","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"estimateRandomizeFee","inputs":[{"type":"uint256","name":"_evmGasPrice","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"fetchRandomnessAfter","inputs":[{"type":"uint256","name":"_blockNumber","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"_witnetResultRandomness","internalType":"bytes32"},{"type":"uint64","name":"_witnetResultTimestamp","internalType":"uint64"},{"type":"bytes32","name":"_witnetResultTallyHash","internalType":"bytes32"},{"type":"uint256","name":"_witnetResultFinalityBlock","internalType":"uint256"}],"name":"fetchRandomnessAfterProof","inputs":[{"type":"uint256","name":"_blockNumber","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getLastRandomizeBlock","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_witnetQueryId","internalType":"uint256"},{"type":"uint256","name":"_prevRandomizeBlock","internalType":"uint256"},{"type":"uint256","name":"_nextRandomizeBlock","internalType":"uint256"}],"name":"getRandomizeData","inputs":[{"type":"uint256","name":"_blockNumber","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getRandomizeNextBlock","inputs":[{"type":"uint256","name":"_blockNumber","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getRandomizePrevBlock","inputs":[{"type":"uint256","name":"_blockNumber","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"enum WitnetV2.ResponseStatus"}],"name":"getRandomizeStatus","inputs":[{"type":"uint256","name":"_blockNumber","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isRandomized","inputs":[{"type":"uint256","name":"_blockNumber","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"pendingOwner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"random","inputs":[{"type":"uint32","name":"_range","internalType":"uint32"},{"type":"uint256","name":"_nonce","internalType":"uint256"},{"type":"uint256","name":"_blockNumber","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"uint256","name":"_evmRandomizeFee","internalType":"uint256"}],"name":"randomize","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"settleBaseFeeOverheadPercentage","inputs":[{"type":"uint16","name":"_baseFeeOverheadPercentage","internalType":"uint16"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"settleWitnetQuerySLA","inputs":[{"type":"tuple","name":"_witnetQuerySLA","internalType":"struct WitnetV2.RadonSLA","components":[{"type":"uint8","name":"committeeSize","internalType":"uint8"},{"type":"uint64","name":"witnessingFeeNanoWit","internalType":"uint64"}]}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes4","name":"","internalType":"bytes4"}],"name":"specs","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"_newOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract WitnetOracle"}],"name":"witnet","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct WitnetV2.RadonSLA","components":[{"type":"uint8","name":"committeeSize","internalType":"uint8"},{"type":"uint64","name":"witnessingFeeNanoWit","internalType":"uint64"}]}],"name":"witnetQuerySLA","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"witnetRadHash","inputs":[]},{"type":"receive","stateMutability":"payable"}]
              

Contract Creation Code

0x60c060405234801561001057600080fd5b5060405161306838038061306883398101604081905261002f916106de565b81816001600160a01b03811661006057604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b610069816105b3565b5063baeca88b60e01b6001600160e01b031916816001600160a01b031663adb7c3f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100de9190610718565b6001600160e01b031916146101435760405162461bcd60e51b815260206004820152602560248201527f5573696e675769746e65743a20756e636f6d706c69616e74205769746e65744f6044820152647261636c6560d81b6064820152608401610057565b6001600160a01b0390811660805260408051808201909152600a8152630bebc20060209091015260028054640bebc2000a6001600160481b03199091161790556003805461ffff19166021179055610257908316158061021e575063baeca88b60e01b6001600160e01b031916836001600160a01b031663adb7c3f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102129190610718565b6001600160e01b031916145b60408051808201909152601881527f756e636f6d706c69616e74205769746e65744f7261636c65000000000000000060208201526105cf565b60006102616105e1565b6001600160a01b0316637b1039996040518163ffffffff1660e01b8152600401602060405180830381865afa15801561029e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102c29190610749565b60408051600180825281830190925291925060009190602080830190803683375050604080516000808252602082019092529293506001600160a01b03851692639eb3ab1f925060029161032c565b6103196106a2565b8152602001906001900390816103115790505b506040518363ffffffff1660e01b815260040161034a9291906107e2565b6020604051808303816000875af1158015610369573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061038d91906108c5565b816000815181106103a0576103a06108de565b60200260200101818152505060606000836001600160a01b0316637f412e2360405180604001604052806002600b8111156103dd576103dd61077c565b8152602001858152506040518263ffffffff1660e01b815260040161040291906108f4565b6020604051808303816000875af1158015610421573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061044591906108c5565b90506000846001600160a01b0316637f412e236040518060400160405280600b808111156104755761047561077c565b8152602001868152506040518263ffffffff1660e01b815260040161049a91906108f4565b6020604051808303816000875af11580156104b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104dd91906108c5565b9050846001600160a01b031663a4a7cecd858484602089516001600160401b0381111561050c5761050c610766565b60405190808252806020026020018201604052801561053f57816020015b606081526020019060019003908161052a5790505b506040518663ffffffff1660e01b815260040161056095949392919061099b565b6020604051808303816000875af115801561057f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a391906108c5565b60a05250610ae095505050505050565b600180546001600160a01b03191690556105cc816105f1565b50565b816105dd576105dd81610641565b5050565b60006105ec60805190565b905090565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040805180820190915260128152712bb4ba3732ba2930b73237b6b732b9b9ab1960711b60208201528160405160200161067c929190610a90565b60408051601f198184030181529082905262461bcd60e51b825261005791600401610acd565b60405180604001604052806002905b60608152602001906001900390816106b15790505090565b6001600160a01b03811681146105cc57600080fd5b600080604083850312156106f157600080fd5b82516106fc816106c9565b602084015190925061070d816106c9565b809150509250929050565b60006020828403121561072a57600080fd5b81516001600160e01b03198116811461074257600080fd5b9392505050565b60006020828403121561075b57600080fd5b8151610742816106c9565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b60005b838110156107ad578181015183820152602001610795565b50506000910152565b600081518084526107ce816020860160208601610792565b601f01601f19169290920160200192915050565b6000600584106107f4576107f461077c565b838252602060a08184015260008060a0850152604060c06040860152600060c086015260e0850160e0606087015280875180835261010092508288019150828160051b890101925085890160005b8281101561089b5789850360ff19018452815185878101895b60028110156108865788820383526108748285516107b6565b938c0193928c0192915060010161085b565b50965050509287019290870190600101610842565b50505050858103608087015260018152600160ff1b60208201526040810198975050505050505050565b6000602082840312156108d757600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b60006020808352606083018451600c81106109115761091161077c565b828501528482015160408086018190528151928390526080600584901b8701810193928501929087019060005b8181101561098d57888603607f1901835284518051600a81106109635761096361077c565b875287015187870185905261097a858801826107b6565b965050938601939186019160010161093e565b509398975050505050505050565b60a0808252865190820181905260009060209060c0840190828a01845b828110156109d4578151845292840192908401906001016109b8565b505050878285015286604085015261ffff86166060850152838103608085015280855180835283830191506005848260051b85010185890160005b84811015610a7d57601f198784038101875282518051808652908a01908a86019080881b87018c0160005b82811015610a665785898303018452610a548286516107b6565b948e0194938e01939150600101610a3a565b50998c019996505050928901925050600101610a0f565b50909d9c50505050505050505050505050565b60008351610aa2818460208801610792565b6101d160f51b9083019081528351610ac1816002840160208801610792565b01600201949350505050565b60208152600061074260208301846107b6565b60805160a05161252b610b3d600039600081816102d20152610a84015260008181610288015281816107dc0152818161088301528181610a5401528181610c7701528181610e2e015281816112550152611309015261252b6000f3fe60806040526004361061014f5760003560e01c80639bc86fec116100b6578063c0248bf11161006f578063c0248bf11461051f578063d2bc459b1461053f578063de0958ac1461055f578063e30c39781461057f578063eb92b29b14610594578063f2fde38b146105b75761018c565b80639bc86fec14610411578063a3252f6814610441578063a60ee2681461047c578063adb7c3f71461049c578063b8d38c96146104be578063bff852fa146104de5761018c565b806376fa9d201161010857806376fa9d201461031f57806379ba50971461034c57806382b1c174146103615780638da5cb5b146103815780638f2616841461039f5780639353badd146103b45761018c565b806317f45487146101f757806324cbbfc11461024457806346d1d21a14610279578063613e9978146102c0578063699b328a14610302578063715018a61461030a5761018c565b3661018c5761018a604051806040016040528060158152602001741b9bc81d1c985b9cd9995c9cc81858d8d95c1d1959605a1b8152506105d7565b005b61018a61019d60003560f81c610641565b6101ae60ff60003560f01c16610641565b6101bf60ff60003560e81c16610641565b6101d060ff60003560e01c16610641565b6040516020016101e39493929190611e0c565b6040516020818303038152906040526105d7565b34801561020357600080fd5b50610217610212366004611e8b565b610733565b604080519485526001600160401b0390931660208501529183015260608201526080015b60405180910390f35b34801561025057600080fd5b5061026461025f366004611eb6565b6109e6565b60405163ffffffff909116815260200161023b565b34801561028557600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b03909116815260200161023b565b3480156102cc57600080fd5b506102f47f000000000000000000000000000000000000000000000000000000000000000081565b60405190815260200161023b565b6102f4610a3b565b34801561031657600080fd5b5061018a610bec565b34801561032b57600080fd5b5061033f61033a366004611e8b565b610c00565b60405161023b9190611f01565b34801561035857600080fd5b5061018a610d53565b34801561036d57600080fd5b506102f461037c366004611e8b565b610d5b565b34801561038d57600080fd5b506000546001600160a01b03166102a8565b3480156103ab57600080fd5b506102f4610d96565b3480156103c057600080fd5b5060408051808201825260008082526020918201528151808301835260025460ff81168083526001600160401b0361010090920482169284019283528451908152915116918101919091520161023b565b34801561041d57600080fd5b5061043161042c366004611e8b565b610da6565b604051901515815260200161023b565b34801561044d57600080fd5b5061046161045c366004611e8b565b610dcb565b6040805193845260208401929092529082015260600161023b565b34801561048857600080fd5b506102f4610497366004611e8b565b610e03565b3480156104a857600080fd5b5060405163124f910d60e01b815260200161023b565b3480156104ca57600080fd5b5061018a6104d9366004611f29565b610ec9565b3480156104ea57600080fd5b5060408051808201825260128152712bb4ba3732ba2930b73237b6b732b9b9ab1960711b6020820152905161023b9190611f4d565b34801561052b57600080fd5b506102f461053a366004611e8b565b610ee9565b34801561054b57600080fd5b5061018a61055a366004611f80565b610f37565b34801561056b57600080fd5b506102f461057a366004611e8b565b610f86565b34801561058b57600080fd5b506102a8610fdf565b3480156105a057600080fd5b5060035460405161ffff909116815260200161023b565b3480156105c357600080fd5b5061018a6105d2366004611fa7565b610ff3565b6040805180820190915260128152712bb4ba3732ba2930b73237b6b732b9b9ab1960711b602082015281604051602001610612929190611fc4565b60408051601f198184030181529082905262461bcd60e51b825261063891600401611f4d565b60405180910390fd5b604080516002808252818301909252606091600091906020820181803683370190505090506000610673601085612043565b61067e906030612065565b9050600061068d60108661207e565b610698906030612065565b905060398260ff1611156106b4576106b1600783612065565b91505b60398160ff1611156106ce576106cb600782612065565b90505b8160f81b836000815181106106e5576106e56120a0565b60200101906001600160f81b031916908160001a9053508060f81b83600181518110610713576107136120a0565b60200101906001600160f81b031916908160001a90535091949350505050565b600080600080610741611007565b6000868152600191909101602052604081205490036107665761076385610f86565b94505b6000610770611007565b600101600087815260200190815260200160002090506000816000015490506107c381600014156040518060400160405280600e81526020016d1b9bdd081c985b991bdb5a5e995960921b81525061102b565b60405163234fe6e360e01b8152600481018290526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063234fe6e390602401602060405180830381865afa15801561082b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061084f91906120b6565b9050600281600581111561086557610865611eeb565b0361093d57604051637b0c90d960e11b8152600481018390526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063f61921b290602401600060405180830381865afa1580156108d2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108fa9190810190612191565b9050806040015163ffffffff1696508060600151955080602001516001600160401b03169450610935610930826080015161103d565b61105b565b9750506109db565b600381600581111561095157610951611eeb565b036109a957600283015460408051808201909152601081526f6661756c74792072616e646f6d697a6560801b602082015261098f908215159061102b565b61099881610733565b9750975097509750505050506109df565b6109db6040518060400160405280601181526020017070656e64696e672072616e646f6d697a6560781b8152506105d7565b5050505b9193509193565b6000610a2c8484336109f786610d5b565b604080516001600160a01b03909316602084015282015260600160405160208183030381529060405280519060200120611090565b90505b9392505050565b905090565b600043610a46611007565b541015610ba95734905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633dc2b7a2837f000000000000000000000000000000000000000000000000000000000000000060026040518463ffffffff1660e01b8152600401610ac2929190612240565b60206040518083038185885af1158015610ae0573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610b05919061226a565b90506000610b11611007565b436000908152600191909101602052604081208381559150610b31611007565b5460018301819055905043610b44611007565b6000838152600191909101602052604090206002015543610b63611007565b556040517f8cb766b09215126141c41df86fd488fe4745f22f3c995c3ad9aaf4c07195b94690610b9d9043903a9088908890600290612283565b60405180910390a15050505b34811015610be957336108fc610bbf83346122c3565b6040518115909202916000818181858888f19350505050158015610be7573d6000803e3d6000fd5b505b90565b610bf46110ef565b610bfe600061111c565b565b6000610c0a611007565b600083815260019190910160205260408120549003610c2f57610c2c82610f86565b91505b6000610c39611007565b600084815260019190910160205260408120549150819003610c5e5750600092915050565b60405163234fe6e360e01b8152600481018290526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063234fe6e390602401602060405180830381865afa158015610cc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cea91906120b6565b90506003816005811115610d0057610d00611eeb565b03610a2f576000610d0f611007565b6000868152600191909101602052604090206002015490508015610d3f57610d3681610c00565b95945050505050565b506003949350505050565b505b5050919050565b610bfe611135565b600081610d67836111b0565b604080516020810193909352820152606001604051602081830303815290604052805190602001209050919050565b6000610da0611007565b54919050565b60006002610db383610c00565b6005811115610dc457610dc4611eeb565b1492915050565b600080600080610dd9611007565b60009586526001908101602052604090952080549581015460029091015495969095945092505050565b604051630f7b104360e31b815260048101829052602260248201526000906064906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690637bd8821890604401602060405180830381865afa158015610e75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e99919061226a565b600354610eab9061ffff1660646122d6565b61ffff16610eb991906122f1565b610ec39190612308565b92915050565b610ed16110ef565b6003805461ffff191661ffff92909216919091179055565b6000808211610efa57610efa61231c565b6000610f04611007565b549050808311610ec357610f3283610f1a611007565b60008481526001918201602052604090200154611414565b610a2f565b610f3f6110ef565b610f74610f4b82611447565b6040518060400160405280600b81526020016a696e76616c696420534c4160a81b81525061102b565b806002610f818282612341565b505050565b6000610f90611007565b600083815260019190910160205260408120549003610fc057610fbb82610fb5611007565b546114d4565b610ec3565b610fc8611007565b600092835260010160205250604090206002015490565b6000610a366001546001600160a01b031690565b610ffb6110ef565b61100481611523565b50565b7f643778935c57df947f6944f6a5242a3e91445f6337f4b2ec670c8642153b614f90565b8161103957611039816105d7565b5050565b611045611d80565b600061105083611555565b9050610a2f8161157a565b600081806000015161107f5760405162461bcd60e51b815260040161063890612393565b610a2f61108b846115ae565b6115df565b6000806001600160e01b0383856040516020016110b7929190918252602082015260400190565b60408051601f19818403018152919052805160209091012016905060e06110e463ffffffff8716836122f1565b901c95945050505050565b6000546001600160a01b03163314610bfe5760405163118cdaa760e01b8152336004820152602401610638565b600180546001600160a01b0319169055611004816115ec565b338061113f610fdf565b6001600160a01b0316146111a75760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610638565b6110048161111c565b60006111ba611007565b6000838152600191909101602052604081205490036111df576111dc82610f86565b91505b60006111e9611007565b6001016000848152602001908152602001600020905060008160000154905061123c81600014156040518060400160405280600e81526020016d1b9bdd081c985b991bdb5a5e995960921b81525061102b565b60405163234fe6e360e01b8152600481018290526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063234fe6e390602401602060405180830381865afa1580156112a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c891906120b6565b905060028160058111156112de576112de611eeb565b0361137d576040516311a7b16760e31b815260048101839052610d3690610930906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690638d3d8b3890602401600060405180830381865afa158015611350573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261137891908101906123e5565b61103d565b600381600581111561139157611391611eeb565b036113e257600283015460408051808201909152601081526f6661756c74792072616e646f6d697a6560801b60208201526113cf908215159061102b565b6113d8816111b0565b9695505050505050565b610d4a6040518060400160405280601181526020017070656e64696e672072616e646f6d697a6560781b8152506105d7565b600081831161144157610f3283611429611007565b60008581526001918201602052604090200154611414565b50919050565b60008061145a6040840160208501612421565b6001600160401b031611801561147f5750600061147a602084018461243e565b60ff16115b801561149b5750607f611495602084018461243e565b60ff1611155b8015610ec357506404a817c8006114b86040840160208501612421565b6114c390606461245b565b6001600160401b0316101592915050565b60008183101561150257610f32836114ea611007565b600085815260019182016020526040902001546114d4565b61150a611007565b6000928352600101602052506040902060020154919050565b61152b6110ef565b6001600160a01b0381166111a757604051631e4fbdf760e01b815260006004820152602401610638565b61155d611da1565b6040805180820190915282815260006020820152610a2f8161163c565b611582611d80565b5060a0810151604080518082019091526001600160401b03909116602714158152602081019190915290565b60608180600001516115d25760405162461bcd60e51b815260040161063890612393565b610a2f836020015161175c565b6000610ec38260206118a5565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b611644611da1565b8151518290600003611669576040516309036d4760e21b815260040160405180910390fd5b600060ff816001600160401b038160015b80156116ec576116898961191d565b9550816116958161247e565b6007600589901c169650601f8816955092505060051985016116e45760208901516116c08a8661197f565b9350808a602001516116d291906122c3565b6116dc9084612497565b92505061167a565b50600061167a565b600760ff861611156117165760405163bd2ac87960e01b815260ff86166004820152602401610638565b506040805160c08101825298895260ff95861660208a015293851693880193909352921660608601526001600160401b0390811660808601521660a08401525090919050565b60608160028060ff16826040015160ff161461179c57604080830151905161800560e51b815260ff91821660048201529082166024820152604401610638565b6117ae8460000151856060015161197f565b6001600160401b03166080850181905263fffffffe19016118845760006117dd85600001518660400151611a47565b905063ffffffff8082161015610d4a5784516118029063ffffffff80841690611af416565b60405160200161181291906124aa565b604051602081830303815290604052935061183585600001518660400151611a47565b905063ffffffff8082161015610d4a578451849061185c9063ffffffff80851690611af416565b60405160200161186d9291906124c6565b604051602081830303815290604052935050610d4c565b6080840151845161189e9163ffffffff90811690611af416565b9250610d4c565b600060208260ff1611156118bb576118bb61231c565b60008260ff168451116118cf5783516118d4565b8260ff165b905060005b8181101561191557806008028582815181106118f7576118f76120a0565b01602001516001600160f81b031916901c92909217916001016118d9565b505092915050565b6000816020015182600001515180821115611955576040516363a056dd60e01b81526004810183905260248101829052604401610638565b83516020850180518083016001015195509081906119728261247e565b8152505050505050919050565b600060188260ff161015611997575060ff8116610ec3565b8160ff166018036119b5576119ab8361191d565b60ff169050610ec3565b8160ff166019036119d4576119c983611bb4565b61ffff169050610ec3565b8160ff16601a036119f5576119e883611c20565b63ffffffff169050610ec3565b8160ff16601b03611a1057611a0983611c7f565b9050610ec3565b8160ff16601f03611a2957506001600160401b03610ec3565b604051636d785b1360e01b815260ff83166004820152602401610638565b600080611a538461191d565b90508060ff1660ff03611a70576001600160401b03915050610ec3565b611a7d8482601f1661197f565b91506001600160401b0380831610611ab357604051636d785b1360e01b81526001600160401b0383166004820152602401610638565b60ff83166007600583901c1614611aed5760405161800560e51b81526007600583901c16600482015260ff84166024820152604401610638565b5092915050565b6060818360200151611b069190612497565b83515180821115611b34576040516363a056dd60e01b81526004810183905260248101829052604401610638565b836001600160401b03811115611b4c57611b4c612001565b6040519080825280601f01601f191660200182016040528015611b76576020820181803683370190505b5092508315611915578451602080870151908183018101908601611b9b81838a611cde565b611ba789896001611d24565b5050505050505092915050565b600081602001516002611bc79190612497565b82515180821115611bf5576040516363a056dd60e01b81526004810183905260248101829052604401610638565b8351602085018051600281840181015196509091611c138284612497565b9052509395945050505050565b600081602001516004611c339190612497565b82515180821115611c61576040516363a056dd60e01b81526004810183905260248101829052604401610638565b8351602085018051600481840181015196509091611c138284612497565b600081602001516008611c929190612497565b82515180821115611cc0576040516363a056dd60e01b81526004810183905260248101829052604401610638565b8351602085018051600881840181015196509091611c138284612497565b5b60208110611cfe578151835260209283019290910190601f1901611cdf565b8015610f81578151835160208390036101000a6000190180199092169116178352505050565b60008284600001515180821115611d58576040516363a056dd60e01b81526004810183905260248101829052604401610638565b8315611d70576020860151611d6d9086612497565b94505b5050505060209190910181905290565b6040518060400160405280600015158152602001611d9c611da1565b905290565b604080516101008101909152606060c08201908152600060e08301528190815260006020820181905260408201819052606082018190526080820181905260a09091015290565b60005b83811015611e03578181015183820152602001611deb565b50506000910152565b720dcdee840d2dae0d8cadacadce8cac8744060f606b1b815260008551611e3a816013850160208a01611de8565b855190830190611e51816013840160208a01611de8565b8551910190611e67816013840160208901611de8565b8451910190611e7d816013840160208801611de8565b016013019695505050505050565b600060208284031215611e9d57600080fd5b5035919050565b63ffffffff8116811461100457600080fd5b600080600060608486031215611ecb57600080fd5b8335611ed681611ea4565b95602085013595506040909401359392505050565b634e487b7160e01b600052602160045260246000fd5b6020810160068310611f2357634e487b7160e01b600052602160045260246000fd5b91905290565b600060208284031215611f3b57600080fd5b813561ffff81168114610a2f57600080fd5b6020815260008251806020840152611f6c816040850160208701611de8565b601f01601f19169190910160400192915050565b60006040828403121561144157600080fd5b6001600160a01b038116811461100457600080fd5b600060208284031215611fb957600080fd5b8135610a2f81611f92565b60008351611fd6818460208801611de8565b6101d160f51b9083019081528351611ff5816002840160208801611de8565b01600201949350505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060ff83168061205657612056612017565b8060ff84160491505092915050565b60ff8181168382160190811115610ec357610ec361202d565b600060ff83168061209157612091612017565b8060ff84160691505092915050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156120c857600080fd5b815160068110610a2f57600080fd5b60405160a081016001600160401b03811182821017156120f9576120f9612001565b60405290565b6001600160401b038116811461100457600080fd5b600082601f83011261212557600080fd5b81516001600160401b038082111561213f5761213f612001565b604051601f8301601f19908116603f0116810190828211818310171561216757612167612001565b8160405283815286602085880101111561218057600080fd5b6113d8846020830160208901611de8565b6000602082840312156121a357600080fd5b81516001600160401b03808211156121ba57600080fd5b9083019060a082860312156121ce57600080fd5b6121d66120d7565b82516121e181611f92565b815260208301516121f1816120ff565b6020820152604083015161220481611ea4565b60408201526060838101519082015260808301518281111561222557600080fd5b61223187828601612114565b60808301525095945050505050565b82815260608101610a2f60208301845460ff8116825260081c6001600160401b0316602090910152565b60006020828403121561227c57600080fd5b5051919050565b600060c0820190508682528560208301528460408301528360608301526113d860808301845460ff8116825260081c6001600160401b0316602090910152565b81810381811115610ec357610ec361202d565b61ffff818116838216019080821115611aed57611aed61202d565b8082028115828204841417610ec357610ec361202d565b60008261231757612317612017565b500490565b634e487b7160e01b600052600160045260246000fd5b60ff8116811461100457600080fd5b813561234c81612332565b60ff8116905081548160ff198216178355602084013561236b816120ff565b68ffffffffffffffff008160081b168368ffffffffffffffffff198416171784555050505050565b60208082526032908201527f5769746e65743a20747269656420746f206465636f64652076616c756520667260408201527137b69032b93937b932b2103932b9bab63a1760711b606082015260800190565b6000602082840312156123f757600080fd5b81516001600160401b0381111561240d57600080fd5b61241984828501612114565b949350505050565b60006020828403121561243357600080fd5b8135610a2f816120ff565b60006020828403121561245057600080fd5b8135610a2f81612332565b6001600160401b038181168382160280821691908281146119155761191561202d565b6000600182016124905761249061202d565b5060010190565b80820180821115610ec357610ec361202d565b600082516124bc818460208701611de8565b9190910192915050565b600083516124d8818460208801611de8565b8351908301906124ec818360208801611de8565b0194935050505056fea2646970667358221220a7d132818b11585f7a3bfec2ecaa814d67803886db4209237c7caf9aaacd671564736f6c6343000819003300000000000000000000000077703ae126b971c9946d562f41dd47071da00777000000000000000000000000f121b71715e71dded592f1125a06d4ed06f0694d

Deployed ByteCode

0x60806040526004361061014f5760003560e01c80639bc86fec116100b6578063c0248bf11161006f578063c0248bf11461051f578063d2bc459b1461053f578063de0958ac1461055f578063e30c39781461057f578063eb92b29b14610594578063f2fde38b146105b75761018c565b80639bc86fec14610411578063a3252f6814610441578063a60ee2681461047c578063adb7c3f71461049c578063b8d38c96146104be578063bff852fa146104de5761018c565b806376fa9d201161010857806376fa9d201461031f57806379ba50971461034c57806382b1c174146103615780638da5cb5b146103815780638f2616841461039f5780639353badd146103b45761018c565b806317f45487146101f757806324cbbfc11461024457806346d1d21a14610279578063613e9978146102c0578063699b328a14610302578063715018a61461030a5761018c565b3661018c5761018a604051806040016040528060158152602001741b9bc81d1c985b9cd9995c9cc81858d8d95c1d1959605a1b8152506105d7565b005b61018a61019d60003560f81c610641565b6101ae60ff60003560f01c16610641565b6101bf60ff60003560e81c16610641565b6101d060ff60003560e01c16610641565b6040516020016101e39493929190611e0c565b6040516020818303038152906040526105d7565b34801561020357600080fd5b50610217610212366004611e8b565b610733565b604080519485526001600160401b0390931660208501529183015260608201526080015b60405180910390f35b34801561025057600080fd5b5061026461025f366004611eb6565b6109e6565b60405163ffffffff909116815260200161023b565b34801561028557600080fd5b507f00000000000000000000000077703ae126b971c9946d562f41dd47071da007775b6040516001600160a01b03909116815260200161023b565b3480156102cc57600080fd5b506102f47f65d6d4ee499b0bd13f0a96355ae30ede913555094a265b75305e904de1afbf3c81565b60405190815260200161023b565b6102f4610a3b565b34801561031657600080fd5b5061018a610bec565b34801561032b57600080fd5b5061033f61033a366004611e8b565b610c00565b60405161023b9190611f01565b34801561035857600080fd5b5061018a610d53565b34801561036d57600080fd5b506102f461037c366004611e8b565b610d5b565b34801561038d57600080fd5b506000546001600160a01b03166102a8565b3480156103ab57600080fd5b506102f4610d96565b3480156103c057600080fd5b5060408051808201825260008082526020918201528151808301835260025460ff81168083526001600160401b0361010090920482169284019283528451908152915116918101919091520161023b565b34801561041d57600080fd5b5061043161042c366004611e8b565b610da6565b604051901515815260200161023b565b34801561044d57600080fd5b5061046161045c366004611e8b565b610dcb565b6040805193845260208401929092529082015260600161023b565b34801561048857600080fd5b506102f4610497366004611e8b565b610e03565b3480156104a857600080fd5b5060405163124f910d60e01b815260200161023b565b3480156104ca57600080fd5b5061018a6104d9366004611f29565b610ec9565b3480156104ea57600080fd5b5060408051808201825260128152712bb4ba3732ba2930b73237b6b732b9b9ab1960711b6020820152905161023b9190611f4d565b34801561052b57600080fd5b506102f461053a366004611e8b565b610ee9565b34801561054b57600080fd5b5061018a61055a366004611f80565b610f37565b34801561056b57600080fd5b506102f461057a366004611e8b565b610f86565b34801561058b57600080fd5b506102a8610fdf565b3480156105a057600080fd5b5060035460405161ffff909116815260200161023b565b3480156105c357600080fd5b5061018a6105d2366004611fa7565b610ff3565b6040805180820190915260128152712bb4ba3732ba2930b73237b6b732b9b9ab1960711b602082015281604051602001610612929190611fc4565b60408051601f198184030181529082905262461bcd60e51b825261063891600401611f4d565b60405180910390fd5b604080516002808252818301909252606091600091906020820181803683370190505090506000610673601085612043565b61067e906030612065565b9050600061068d60108661207e565b610698906030612065565b905060398260ff1611156106b4576106b1600783612065565b91505b60398160ff1611156106ce576106cb600782612065565b90505b8160f81b836000815181106106e5576106e56120a0565b60200101906001600160f81b031916908160001a9053508060f81b83600181518110610713576107136120a0565b60200101906001600160f81b031916908160001a90535091949350505050565b600080600080610741611007565b6000868152600191909101602052604081205490036107665761076385610f86565b94505b6000610770611007565b600101600087815260200190815260200160002090506000816000015490506107c381600014156040518060400160405280600e81526020016d1b9bdd081c985b991bdb5a5e995960921b81525061102b565b60405163234fe6e360e01b8152600481018290526000907f00000000000000000000000077703ae126b971c9946d562f41dd47071da007776001600160a01b03169063234fe6e390602401602060405180830381865afa15801561082b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061084f91906120b6565b9050600281600581111561086557610865611eeb565b0361093d57604051637b0c90d960e11b8152600481018390526000907f00000000000000000000000077703ae126b971c9946d562f41dd47071da007776001600160a01b03169063f61921b290602401600060405180830381865afa1580156108d2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108fa9190810190612191565b9050806040015163ffffffff1696508060600151955080602001516001600160401b03169450610935610930826080015161103d565b61105b565b9750506109db565b600381600581111561095157610951611eeb565b036109a957600283015460408051808201909152601081526f6661756c74792072616e646f6d697a6560801b602082015261098f908215159061102b565b61099881610733565b9750975097509750505050506109df565b6109db6040518060400160405280601181526020017070656e64696e672072616e646f6d697a6560781b8152506105d7565b5050505b9193509193565b6000610a2c8484336109f786610d5b565b604080516001600160a01b03909316602084015282015260600160405160208183030381529060405280519060200120611090565b90505b9392505050565b905090565b600043610a46611007565b541015610ba95734905060007f00000000000000000000000077703ae126b971c9946d562f41dd47071da007776001600160a01b0316633dc2b7a2837f65d6d4ee499b0bd13f0a96355ae30ede913555094a265b75305e904de1afbf3c60026040518463ffffffff1660e01b8152600401610ac2929190612240565b60206040518083038185885af1158015610ae0573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610b05919061226a565b90506000610b11611007565b436000908152600191909101602052604081208381559150610b31611007565b5460018301819055905043610b44611007565b6000838152600191909101602052604090206002015543610b63611007565b556040517f8cb766b09215126141c41df86fd488fe4745f22f3c995c3ad9aaf4c07195b94690610b9d9043903a9088908890600290612283565b60405180910390a15050505b34811015610be957336108fc610bbf83346122c3565b6040518115909202916000818181858888f19350505050158015610be7573d6000803e3d6000fd5b505b90565b610bf46110ef565b610bfe600061111c565b565b6000610c0a611007565b600083815260019190910160205260408120549003610c2f57610c2c82610f86565b91505b6000610c39611007565b600084815260019190910160205260408120549150819003610c5e5750600092915050565b60405163234fe6e360e01b8152600481018290526000907f00000000000000000000000077703ae126b971c9946d562f41dd47071da007776001600160a01b03169063234fe6e390602401602060405180830381865afa158015610cc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cea91906120b6565b90506003816005811115610d0057610d00611eeb565b03610a2f576000610d0f611007565b6000868152600191909101602052604090206002015490508015610d3f57610d3681610c00565b95945050505050565b506003949350505050565b505b5050919050565b610bfe611135565b600081610d67836111b0565b604080516020810193909352820152606001604051602081830303815290604052805190602001209050919050565b6000610da0611007565b54919050565b60006002610db383610c00565b6005811115610dc457610dc4611eeb565b1492915050565b600080600080610dd9611007565b60009586526001908101602052604090952080549581015460029091015495969095945092505050565b604051630f7b104360e31b815260048101829052602260248201526000906064906001600160a01b037f00000000000000000000000077703ae126b971c9946d562f41dd47071da007771690637bd8821890604401602060405180830381865afa158015610e75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e99919061226a565b600354610eab9061ffff1660646122d6565b61ffff16610eb991906122f1565b610ec39190612308565b92915050565b610ed16110ef565b6003805461ffff191661ffff92909216919091179055565b6000808211610efa57610efa61231c565b6000610f04611007565b549050808311610ec357610f3283610f1a611007565b60008481526001918201602052604090200154611414565b610a2f565b610f3f6110ef565b610f74610f4b82611447565b6040518060400160405280600b81526020016a696e76616c696420534c4160a81b81525061102b565b806002610f818282612341565b505050565b6000610f90611007565b600083815260019190910160205260408120549003610fc057610fbb82610fb5611007565b546114d4565b610ec3565b610fc8611007565b600092835260010160205250604090206002015490565b6000610a366001546001600160a01b031690565b610ffb6110ef565b61100481611523565b50565b7f643778935c57df947f6944f6a5242a3e91445f6337f4b2ec670c8642153b614f90565b8161103957611039816105d7565b5050565b611045611d80565b600061105083611555565b9050610a2f8161157a565b600081806000015161107f5760405162461bcd60e51b815260040161063890612393565b610a2f61108b846115ae565b6115df565b6000806001600160e01b0383856040516020016110b7929190918252602082015260400190565b60408051601f19818403018152919052805160209091012016905060e06110e463ffffffff8716836122f1565b901c95945050505050565b6000546001600160a01b03163314610bfe5760405163118cdaa760e01b8152336004820152602401610638565b600180546001600160a01b0319169055611004816115ec565b338061113f610fdf565b6001600160a01b0316146111a75760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610638565b6110048161111c565b60006111ba611007565b6000838152600191909101602052604081205490036111df576111dc82610f86565b91505b60006111e9611007565b6001016000848152602001908152602001600020905060008160000154905061123c81600014156040518060400160405280600e81526020016d1b9bdd081c985b991bdb5a5e995960921b81525061102b565b60405163234fe6e360e01b8152600481018290526000907f00000000000000000000000077703ae126b971c9946d562f41dd47071da007776001600160a01b03169063234fe6e390602401602060405180830381865afa1580156112a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c891906120b6565b905060028160058111156112de576112de611eeb565b0361137d576040516311a7b16760e31b815260048101839052610d3690610930906001600160a01b037f00000000000000000000000077703ae126b971c9946d562f41dd47071da007771690638d3d8b3890602401600060405180830381865afa158015611350573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261137891908101906123e5565b61103d565b600381600581111561139157611391611eeb565b036113e257600283015460408051808201909152601081526f6661756c74792072616e646f6d697a6560801b60208201526113cf908215159061102b565b6113d8816111b0565b9695505050505050565b610d4a6040518060400160405280601181526020017070656e64696e672072616e646f6d697a6560781b8152506105d7565b600081831161144157610f3283611429611007565b60008581526001918201602052604090200154611414565b50919050565b60008061145a6040840160208501612421565b6001600160401b031611801561147f5750600061147a602084018461243e565b60ff16115b801561149b5750607f611495602084018461243e565b60ff1611155b8015610ec357506404a817c8006114b86040840160208501612421565b6114c390606461245b565b6001600160401b0316101592915050565b60008183101561150257610f32836114ea611007565b600085815260019182016020526040902001546114d4565b61150a611007565b6000928352600101602052506040902060020154919050565b61152b6110ef565b6001600160a01b0381166111a757604051631e4fbdf760e01b815260006004820152602401610638565b61155d611da1565b6040805180820190915282815260006020820152610a2f8161163c565b611582611d80565b5060a0810151604080518082019091526001600160401b03909116602714158152602081019190915290565b60608180600001516115d25760405162461bcd60e51b815260040161063890612393565b610a2f836020015161175c565b6000610ec38260206118a5565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b611644611da1565b8151518290600003611669576040516309036d4760e21b815260040160405180910390fd5b600060ff816001600160401b038160015b80156116ec576116898961191d565b9550816116958161247e565b6007600589901c169650601f8816955092505060051985016116e45760208901516116c08a8661197f565b9350808a602001516116d291906122c3565b6116dc9084612497565b92505061167a565b50600061167a565b600760ff861611156117165760405163bd2ac87960e01b815260ff86166004820152602401610638565b506040805160c08101825298895260ff95861660208a015293851693880193909352921660608601526001600160401b0390811660808601521660a08401525090919050565b60608160028060ff16826040015160ff161461179c57604080830151905161800560e51b815260ff91821660048201529082166024820152604401610638565b6117ae8460000151856060015161197f565b6001600160401b03166080850181905263fffffffe19016118845760006117dd85600001518660400151611a47565b905063ffffffff8082161015610d4a5784516118029063ffffffff80841690611af416565b60405160200161181291906124aa565b604051602081830303815290604052935061183585600001518660400151611a47565b905063ffffffff8082161015610d4a578451849061185c9063ffffffff80851690611af416565b60405160200161186d9291906124c6565b604051602081830303815290604052935050610d4c565b6080840151845161189e9163ffffffff90811690611af416565b9250610d4c565b600060208260ff1611156118bb576118bb61231c565b60008260ff168451116118cf5783516118d4565b8260ff165b905060005b8181101561191557806008028582815181106118f7576118f76120a0565b01602001516001600160f81b031916901c92909217916001016118d9565b505092915050565b6000816020015182600001515180821115611955576040516363a056dd60e01b81526004810183905260248101829052604401610638565b83516020850180518083016001015195509081906119728261247e565b8152505050505050919050565b600060188260ff161015611997575060ff8116610ec3565b8160ff166018036119b5576119ab8361191d565b60ff169050610ec3565b8160ff166019036119d4576119c983611bb4565b61ffff169050610ec3565b8160ff16601a036119f5576119e883611c20565b63ffffffff169050610ec3565b8160ff16601b03611a1057611a0983611c7f565b9050610ec3565b8160ff16601f03611a2957506001600160401b03610ec3565b604051636d785b1360e01b815260ff83166004820152602401610638565b600080611a538461191d565b90508060ff1660ff03611a70576001600160401b03915050610ec3565b611a7d8482601f1661197f565b91506001600160401b0380831610611ab357604051636d785b1360e01b81526001600160401b0383166004820152602401610638565b60ff83166007600583901c1614611aed5760405161800560e51b81526007600583901c16600482015260ff84166024820152604401610638565b5092915050565b6060818360200151611b069190612497565b83515180821115611b34576040516363a056dd60e01b81526004810183905260248101829052604401610638565b836001600160401b03811115611b4c57611b4c612001565b6040519080825280601f01601f191660200182016040528015611b76576020820181803683370190505b5092508315611915578451602080870151908183018101908601611b9b81838a611cde565b611ba789896001611d24565b5050505050505092915050565b600081602001516002611bc79190612497565b82515180821115611bf5576040516363a056dd60e01b81526004810183905260248101829052604401610638565b8351602085018051600281840181015196509091611c138284612497565b9052509395945050505050565b600081602001516004611c339190612497565b82515180821115611c61576040516363a056dd60e01b81526004810183905260248101829052604401610638565b8351602085018051600481840181015196509091611c138284612497565b600081602001516008611c929190612497565b82515180821115611cc0576040516363a056dd60e01b81526004810183905260248101829052604401610638565b8351602085018051600881840181015196509091611c138284612497565b5b60208110611cfe578151835260209283019290910190601f1901611cdf565b8015610f81578151835160208390036101000a6000190180199092169116178352505050565b60008284600001515180821115611d58576040516363a056dd60e01b81526004810183905260248101829052604401610638565b8315611d70576020860151611d6d9086612497565b94505b5050505060209190910181905290565b6040518060400160405280600015158152602001611d9c611da1565b905290565b604080516101008101909152606060c08201908152600060e08301528190815260006020820181905260408201819052606082018190526080820181905260a09091015290565b60005b83811015611e03578181015183820152602001611deb565b50506000910152565b720dcdee840d2dae0d8cadacadce8cac8744060f606b1b815260008551611e3a816013850160208a01611de8565b855190830190611e51816013840160208a01611de8565b8551910190611e67816013840160208901611de8565b8451910190611e7d816013840160208801611de8565b016013019695505050505050565b600060208284031215611e9d57600080fd5b5035919050565b63ffffffff8116811461100457600080fd5b600080600060608486031215611ecb57600080fd5b8335611ed681611ea4565b95602085013595506040909401359392505050565b634e487b7160e01b600052602160045260246000fd5b6020810160068310611f2357634e487b7160e01b600052602160045260246000fd5b91905290565b600060208284031215611f3b57600080fd5b813561ffff81168114610a2f57600080fd5b6020815260008251806020840152611f6c816040850160208701611de8565b601f01601f19169190910160400192915050565b60006040828403121561144157600080fd5b6001600160a01b038116811461100457600080fd5b600060208284031215611fb957600080fd5b8135610a2f81611f92565b60008351611fd6818460208801611de8565b6101d160f51b9083019081528351611ff5816002840160208801611de8565b01600201949350505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060ff83168061205657612056612017565b8060ff84160491505092915050565b60ff8181168382160190811115610ec357610ec361202d565b600060ff83168061209157612091612017565b8060ff84160691505092915050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156120c857600080fd5b815160068110610a2f57600080fd5b60405160a081016001600160401b03811182821017156120f9576120f9612001565b60405290565b6001600160401b038116811461100457600080fd5b600082601f83011261212557600080fd5b81516001600160401b038082111561213f5761213f612001565b604051601f8301601f19908116603f0116810190828211818310171561216757612167612001565b8160405283815286602085880101111561218057600080fd5b6113d8846020830160208901611de8565b6000602082840312156121a357600080fd5b81516001600160401b03808211156121ba57600080fd5b9083019060a082860312156121ce57600080fd5b6121d66120d7565b82516121e181611f92565b815260208301516121f1816120ff565b6020820152604083015161220481611ea4565b60408201526060838101519082015260808301518281111561222557600080fd5b61223187828601612114565b60808301525095945050505050565b82815260608101610a2f60208301845460ff8116825260081c6001600160401b0316602090910152565b60006020828403121561227c57600080fd5b5051919050565b600060c0820190508682528560208301528460408301528360608301526113d860808301845460ff8116825260081c6001600160401b0316602090910152565b81810381811115610ec357610ec361202d565b61ffff818116838216019080821115611aed57611aed61202d565b8082028115828204841417610ec357610ec361202d565b60008261231757612317612017565b500490565b634e487b7160e01b600052600160045260246000fd5b60ff8116811461100457600080fd5b813561234c81612332565b60ff8116905081548160ff198216178355602084013561236b816120ff565b68ffffffffffffffff008160081b168368ffffffffffffffffff198416171784555050505050565b60208082526032908201527f5769746e65743a20747269656420746f206465636f64652076616c756520667260408201527137b69032b93937b932b2103932b9bab63a1760711b606082015260800190565b6000602082840312156123f757600080fd5b81516001600160401b0381111561240d57600080fd5b61241984828501612114565b949350505050565b60006020828403121561243357600080fd5b8135610a2f816120ff565b60006020828403121561245057600080fd5b8135610a2f81612332565b6001600160401b038181168382160280821691908281146119155761191561202d565b6000600182016124905761249061202d565b5060010190565b80820180821115610ec357610ec361202d565b600082516124bc818460208701611de8565b9190910192915050565b600083516124d8818460208801611de8565b8351908301906124ec818360208801611de8565b0194935050505056fea2646970667358221220a7d132818b11585f7a3bfec2ecaa814d67803886db4209237c7caf9aaacd671564736f6c63430008190033