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
Transactions
Token Transfers
Tokens
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
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-06-16T09:42:05.632401Z
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 } } }
/@openzeppelin/contracts/access/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); } }
/@openzeppelin/contracts/utils/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; } }
/project:/contracts/WitnetOracle.sol
// 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); }
/project:/contracts/WitnetRandomness.sol
// 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); }
/project:/contracts/WitnetRequestBytecodes.sol
// 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); }
/project:/contracts/WitnetRequestFactory.sol
// 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); }
/project:/contracts/apps/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); } }
/project:/contracts/interfaces/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; }
/project:/contracts/interfaces/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 ); }
/project:/contracts/interfaces/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); }
/project:/contracts/interfaces/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; }
/project:/contracts/interfaces/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 ); }
/project:/contracts/interfaces/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); }
/project:/contracts/interfaces/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); }
/project:/contracts/libs/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 ++; } } } }
/project:/contracts/libs/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)) } } } } }
/project:/contracts/libs/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); } } }
/project:/contracts/libs/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); } }
/project:/contracts/patterns/Ownable.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/access/Ownable.sol";
/project:/contracts/patterns/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