Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- FluxAggregator
- Optimization enabled
- true
- Compiler version
- v0.8.6+commit.11564f7e
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2024-08-23T09:23:57.758777Z
Constructor Arguments
0x000000000000000000000000000000000000000000000000000009184e72a0000000000000000000000000000000000000000000000000000000000000000fa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008f0d180000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000145052494345204645454420546573742f54657374000000000000000000000000
Arg [0] (uint128) : 10000000000000
Arg [1] (uint32) : 4000
Arg [2] (int256) : 0
Arg [3] (int256) : 150000000
Arg [4] (uint8) : 8
Arg [5] (string) : PRICE FEED Test/Test
contracts/FluxAggregator.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.6; import "./interfaces/AggregatorValidatorInterface.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; import "./interfaces/AggregatorV2V3Interface.sol"; import "./Median.sol"; /** * @title The Prepaid Aggregator contract * @notice Handles aggregating data pushed in from off-chain, and unlocks * payment for oracles as they report. Oracles' submissions are gathered in * rounds, with each round aggregating the submissions for each oracle into a * single answer. The latest aggregated answer is exposed as well as historical * answers and their updated at timestamp. */ contract FluxAggregator is AggregatorV2V3Interface, AccessControl { struct Round { int256 answer; uint64 startedAt; uint64 updatedAt; uint32 answeredInRound; } struct RoundDetails { int256[] submissions; uint32 maxSubmissions; uint32 minSubmissions; uint32 timeout; uint128 paymentAmount; } struct OracleStatus { uint128 withdrawable; uint32 startingRound; uint32 endingRound; uint32 lastReportedRound; uint32 lastStartedRound; int256 latestSubmission; uint16 index; address admin; address pendingAdmin; } struct Requester { bool authorized; uint32 delay; uint32 lastStartedRound; } struct Funds { uint128 available; uint128 allocated; } AggregatorValidatorInterface public validator; // Round related params uint128 public paymentAmount; uint32 public maxSubmissionCount; uint32 public minSubmissionCount; uint32 public restartDelay; uint32 public timeout; uint8 public override decimals; string public override description; int256 immutable public minSubmissionValue; int256 immutable public maxSubmissionValue; uint256 constant public override version = 3; /** * @notice To ensure owner isn't withdrawing required funds as oracles are * submitting updates, we enforce that the contract maintains a minimum * reserve of RESERVE_ROUNDS * oracleCount() wFTN earmarked for payment to * oracles. (Of course, this doesn't prevent the contract from running out of * funds without the owner's intervention.) */ uint256 constant private RESERVE_ROUNDS = 2; uint256 constant private MAX_ORACLE_COUNT = 77; uint32 constant private ROUND_MAX = type(uint32).max; uint256 private constant VALIDATOR_GAS_LIMIT = 100000; // An error specific to the Aggregator V3 Interface, to prevent possible // confusion around accidentally reading unset values as reported values. string constant private V3_NO_DATA_ERROR = "No data present"; uint32 private reportingRoundId; uint32 internal latestRoundId; mapping(address => OracleStatus) private oracles; mapping(uint32 => Round) internal rounds; mapping(uint32 => RoundDetails) internal details; mapping(address => Requester) internal requesters; address[] private oracleAddresses; bytes32 public constant ADMIN_ROLE = 0xa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775; Funds private recordedFunds; event AvailableFundsUpdated( uint256 indexed amount ); event RoundDetailsUpdated( uint128 indexed paymentAmount, uint32 indexed minSubmissionCount, uint32 indexed maxSubmissionCount, uint32 restartDelay, uint32 timeout // measured in seconds ); event OraclePermissionsUpdated( address indexed oracle, bool indexed whitelisted ); event OracleAdminUpdated( address indexed oracle, address indexed newAdmin ); event OracleAdminUpdateRequested( address indexed oracle, address admin, address newAdmin ); event SubmissionReceived( int256 indexed submission, uint32 indexed round, address indexed oracle ); event RequesterPermissionsSet( address indexed requester, bool authorized, uint32 delay ); event ValidatorUpdated( address indexed previous, address indexed current ); /** * @notice set up the aggregator with initial configuration * @param _paymentAmount The amount paid of FTN paid to each oracle per submission, in wei (units of 10⁻¹⁸ wFTN) * @param _timeout is the number of seconds after the previous round that are * allowed to lapse before allowing an oracle to skip an unfinished round * _validator is an optional contract address for validating * external validation of answers * @param _minSubmissionValue is an immutable check for a lower bound of what * submission values are accepted from an oracle * @param _maxSubmissionValue is an immutable check for an upper bound of what * submission values are accepted from an oracle * @param _decimals represents the number of decimals to offset the answer by * @param _description a short description of what is being reported */ constructor( uint128 _paymentAmount, uint32 _timeout, int256 _minSubmissionValue, int256 _maxSubmissionValue, uint8 _decimals, string memory _description ) { _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); _setupRole(ADMIN_ROLE, msg.sender); updateFutureRounds(_paymentAmount, 0, 0, 0, _timeout); minSubmissionValue = _minSubmissionValue; maxSubmissionValue = _maxSubmissionValue; decimals = _decimals; description = _description; rounds[0].updatedAt = uint64(block.timestamp - (uint256(_timeout))); } /** * @notice called by oracles when they have witnessed a need to update * @param _roundId is the ID of the round this submission pertains to * @param _submission is the updated data that the oracle is submitting */ function submit(uint256 _roundId, int256 _submission) external { bytes memory error = validateOracleRound(msg.sender, uint32(_roundId)); require(_submission >= minSubmissionValue, "value below minSubmissionValue"); require(_submission <= maxSubmissionValue, "value above maxSubmissionValue"); require(error.length == 0, string(error)); oracleInitializeNewRound(uint32(_roundId)); recordSubmission(_submission, uint32(_roundId)); (bool updated, int256 newAnswer) = updateRoundAnswer(uint32(_roundId)); payOracle(uint32(_roundId)); deleteRoundDetails(uint32(_roundId)); } fallback() external payable{ updateAvailableFunds(); } receive() external payable{ updateAvailableFunds(); } /** * @notice called by the owner to remove and add new oracles as well as * update the round related parameters that pertain to total oracle count * @param _removed is the list of addresses for the new Oracles being removed * @param _added is the list of addresses for the new Oracles being added * @param _addedAdmins is the admin addresses for the new respective _added * list. Only this address is allowed to access the respective oracle's funds * @param _minSubmissions is the new minimum submission count for each round * @param _maxSubmissions is the new maximum submission count for each round * @param _restartDelay is the number of rounds an Oracle has to wait before * they can initiate a round */ function changeOracles( address[] calldata _removed, address[] calldata _added, address[] calldata _addedAdmins, uint32 _minSubmissions, uint32 _maxSubmissions, uint32 _restartDelay ) external onlyRole(ADMIN_ROLE) { for (uint256 i = 0; i < _removed.length; i++) { removeOracle(_removed[i]); } require(_added.length == _addedAdmins.length, "need same oracle and admin count"); require(uint256(oracleCount()) + (_added.length) <= MAX_ORACLE_COUNT, "max oracles allowed"); for (uint256 i = 0; i < _added.length; i++) { addOracle(_added[i], _addedAdmins[i]); } updateFutureRounds(paymentAmount, _minSubmissions, _maxSubmissions, _restartDelay, timeout); } /** * @notice update the round and payment related parameters for subsequent * rounds * @param _paymentAmount is the payment amount for subsequent rounds * @param _minSubmissions is the new minimum submission count for each round * @param _maxSubmissions is the new maximum submission count for each round * @param _restartDelay is the number of rounds an Oracle has to wait before * they can initiate a round */ function updateFutureRounds( uint128 _paymentAmount, uint32 _minSubmissions, uint32 _maxSubmissions, uint32 _restartDelay, uint32 _timeout ) public onlyRole(ADMIN_ROLE) { uint32 oracleNum = oracleCount(); // Save on storage reads require(_maxSubmissions >= _minSubmissions, "max must equal/exceed min"); require(oracleNum >= _maxSubmissions, "max cannot exceed total"); require(oracleNum == 0 || oracleNum > _restartDelay, "delay cannot exceed total"); require(recordedFunds.available >= requiredReserve(_paymentAmount), "insufficient funds for payment"); if (oracleCount() > 0) { require(_minSubmissions > 0, "min must be greater than 0"); } paymentAmount = _paymentAmount; minSubmissionCount = _minSubmissions; maxSubmissionCount = _maxSubmissions; restartDelay = _restartDelay; timeout = _timeout; emit RoundDetailsUpdated( paymentAmount, _minSubmissions, _maxSubmissions, _restartDelay, _timeout ); } /** * @notice the amount of payment yet to be withdrawn by oracles */ function allocatedFunds() external view returns (uint128) { return recordedFunds.allocated; } /** * @notice the amount of future funding available to oracles */ function availableFunds() external view returns (uint128) { return recordedFunds.available; } /** * @notice recalculate the amount of wFTN available for payouts */ function updateAvailableFunds() public { Funds memory funds = recordedFunds; uint256 nowAvailable = address(this).balance - (funds.allocated); if (funds.available != nowAvailable) { recordedFunds.available = uint128(nowAvailable); emit AvailableFundsUpdated(nowAvailable); } } /** * @notice returns the number of oracles */ function oracleCount() public view returns (uint8) { return uint8(oracleAddresses.length); } /** * @notice returns an array of addresses containing the oracles on contract */ function getOracles() external view returns (address[] memory) { return oracleAddresses; } /** * @notice get the most recently reported answer * * @dev #[deprecated] Use latestRoundData instead. This does not error if no * answer has been reached, it will simply return 0. Either wait to point to * an already answered Aggregator or use the recommended latestRoundData * instead which includes better verification information. */ function latestAnswer() public view virtual override returns (int256) { return rounds[latestRoundId].answer; } /** * @notice get the most recent updated at timestamp * * @dev #[deprecated] Use latestRoundData instead. This does not error if no * answer has been reached, it will simply return 0. Either wait to point to * an already answered Aggregator or use the recommended latestRoundData * instead which includes better verification information. */ function latestTimestamp() public view virtual override returns (uint256) { return rounds[latestRoundId].updatedAt; } /** * @notice get the ID of the last updated round * * @dev #[deprecated] Use latestRoundData instead. This does not error if no * answer has been reached, it will simply return 0. Either wait to point to * an already answered Aggregator or use the recommended latestRoundData * instead which includes better verification information. */ function latestRound() public view virtual override returns (uint256) { return latestRoundId; } /** * @notice get past rounds answers * @param _roundId the round number to retrieve the answer for * * @dev #[deprecated] Use getRoundData instead. This does not error if no * answer has been reached, it will simply return 0. Either wait to point to * an already answered Aggregator or use the recommended getRoundData * instead which includes better verification information. */ function getAnswer(uint256 _roundId) public view virtual override returns (int256) { if (validRoundId(_roundId)) { return rounds[uint32(_roundId)].answer; } return 0; } /** * @notice get timestamp when an answer was last updated * @param _roundId the round number to retrieve the updated timestamp for * * @dev #[deprecated] Use getRoundData instead. This does not error if no * answer has been reached, it will simply return 0. Either wait to point to * an already answered Aggregator or use the recommended getRoundData * instead which includes better verification information. */ function getTimestamp(uint256 _roundId) public view virtual override returns (uint256) { if (validRoundId(_roundId)) { return rounds[uint32(_roundId)].updatedAt; } return 0; } /** * @notice get data about a round. Consumers are encouraged to check * that they're receiving fresh data by inspecting the updatedAt and * answeredInRound return values. * @param _roundId the round ID to retrieve the round data for * @return roundId is the round ID for which data was retrieved * @return answer is the answer for the given round * @return startedAt is the timestamp when the round was started. This is 0 * if the round hasn't been started yet. * @return updatedAt is the timestamp when the round last was updated (i.e. * answer was last computed) * @return answeredInRound is the round ID of the round in which the answer * was computed. answeredInRound may be smaller than roundId when the round * timed out. answeredInRound is equal to roundId when the round didn't time out * and was completed regularly. * @dev Note that for in-progress rounds (i.e. rounds that haven't yet received * maxSubmissions) answer and updatedAt may change between queries. */ function getRoundData(uint80 _roundId) public view virtual override returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ) { Round memory r = rounds[uint32(_roundId)]; require(r.answeredInRound > 0 && validRoundId(_roundId), V3_NO_DATA_ERROR); return ( _roundId, r.answer, r.startedAt, r.updatedAt, r.answeredInRound ); } /** * @notice get data about the latest round. Consumers are encouraged to check * that they're receiving fresh data by inspecting the updatedAt and * answeredInRound return values. Consumers are encouraged to * use this more fully featured method over the "legacy" latestRound/ * latestAnswer/latestTimestamp functions. Consumers are encouraged to check * that they're receiving fresh data by inspecting the updatedAt and * answeredInRound return values. * @return roundId is the round ID for which data was retrieved * @return answer is the answer for the given round * @return startedAt is the timestamp when the round was started. This is 0 * if the round hasn't been started yet. * @return updatedAt is the timestamp when the round last was updated (i.e. * answer was last computed) * @return answeredInRound is the round ID of the round in which the answer * was computed. answeredInRound may be smaller than roundId when the round * timed out. answeredInRound is equal to roundId when the round didn't time * out and was completed regularly. * @dev Note that for in-progress rounds (i.e. rounds that haven't yet * received maxSubmissions) answer and updatedAt may change between queries. */ function latestRoundData() public view virtual override returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ) { return getRoundData(latestRoundId); } /** * @notice query the available amount of wFTN for an oracle to withdraw */ function withdrawablePayment(address _oracle) external view returns (uint256) { return oracles[_oracle].withdrawable; } /** * @notice Internal function to safely send FTN. * @param to Recipient address. * @param amount Amount of ETH to send. */ function _sendViaCall( address payable to, uint256 amount ) internal { (bool sent, ) = to.call{value: amount} (""); if (!sent) { revert(); } } /** * @notice transfers the oracle's wFTN to another address. Can only be called * by the oracle's admin. * @param _oracle is the oracle whose FTN is transferred * @param _recipient is the address to send the FTN to * @param _amount is the amount of FTN to send */ function withdrawPayment(address _oracle, address _recipient, uint256 _amount) external { require(oracles[_oracle].admin == msg.sender, "only callable by admin"); uint128 amount = uint128(_amount); uint128 available = oracles[_oracle].withdrawable; require(available >= amount, "insufficient withdrawable funds"); oracles[_oracle].withdrawable = available - (amount); recordedFunds.allocated = recordedFunds.allocated - (amount); _sendViaCall(payable(_recipient), uint256(amount)); } /** * @notice transfers the owner's wFTN to another address * @param _recipient is the address to send the wFTN to * @param _amount is the amount of wFTN to send */ function withdrawFunds(address _recipient, uint256 _amount) external onlyRole(ADMIN_ROLE) { uint256 available = uint256(recordedFunds.available); require(available - (requiredReserve(paymentAmount)) >= _amount, "insufficient reserve funds"); _sendViaCall(payable(_recipient), _amount); updateAvailableFunds(); } /** * @notice get the admin address of an oracle * @param _oracle is the address of the oracle whose admin is being queried */ function getAdmin(address _oracle) external view returns (address) { return oracles[_oracle].admin; } /** * @notice transfer the admin address for an oracle * @param _oracle is the address of the oracle whose admin is being transferred * @param _newAdmin is the new admin address */ function transferAdmin(address _oracle, address _newAdmin) external { require(oracles[_oracle].admin == msg.sender, "only callable by admin"); oracles[_oracle].pendingAdmin = _newAdmin; emit OracleAdminUpdateRequested(_oracle, msg.sender, _newAdmin); } /** * @notice accept the admin address transfer for an oracle * @param _oracle is the address of the oracle whose admin is being transferred */ function acceptAdmin(address _oracle) external { require(oracles[_oracle].pendingAdmin == msg.sender, "only callable by pending admin"); oracles[_oracle].pendingAdmin = address(0); oracles[_oracle].admin = msg.sender; emit OracleAdminUpdated(_oracle, msg.sender); } /** * @notice allows non-oracles to request a new round */ function requestNewRound() external returns (uint80) { require(requesters[msg.sender].authorized, "not authorized requester"); uint32 current = reportingRoundId; require(rounds[current].updatedAt > 0 || timedOut(current), "prev round must be supersedable"); uint32 newRoundId = current + 1; requesterInitializeNewRound(newRoundId); return newRoundId; } /** * @notice allows the owner to specify new non-oracles to start new rounds * @param _requester is the address to set permissions for * @param _authorized is a boolean specifying whether they can start new rounds or not * @param _delay is the number of rounds the requester must wait before starting another round */ function setRequesterPermissions(address _requester, bool _authorized, uint32 _delay) external onlyRole(ADMIN_ROLE) { if (requesters[_requester].authorized == _authorized) return; if (_authorized) { requesters[_requester].authorized = _authorized; requesters[_requester].delay = _delay; } else { delete requesters[_requester]; } emit RequesterPermissionsSet(_requester, _authorized, _delay); } /** * @notice a method to provide all current info oracles need. Intended only * only to be callable by oracles. Not for use by contracts to read state. * @param _oracle the address to look up information for. */ function oracleRoundState(address _oracle, uint32 _queriedRoundId) external view returns ( bool _eligibleToSubmit, uint32 _roundId, int256 _latestSubmission, uint64 _startedAt, uint64 _timeout, uint128 _availableFunds, uint8 _oracleCount, uint128 _paymentAmount ) { require(msg.sender == tx.origin, "off-chain reading only"); if (_queriedRoundId > 0) { Round storage round = rounds[_queriedRoundId]; RoundDetails storage details = details[_queriedRoundId]; return ( eligibleForSpecificRound(_oracle, _queriedRoundId), _queriedRoundId, oracles[_oracle].latestSubmission, round.startedAt, details.timeout, recordedFunds.available, oracleCount(), (round.startedAt > 0 ? details.paymentAmount : paymentAmount) ); } else { return oracleRoundStateSuggestRound(_oracle); } } /** * @notice method to update the address which does external data validation. * @param _newValidator designates the address of the new validation contract. */ function setValidator(address _newValidator) public onlyRole(ADMIN_ROLE) { address previous = address(validator); if (previous != _newValidator) { validator = AggregatorValidatorInterface(_newValidator); emit ValidatorUpdated(previous, _newValidator); } } /** * Private */ function initializeNewRound(uint32 _roundId) private { updateTimedOutRoundInfo(_roundId - 1); reportingRoundId = _roundId; RoundDetails memory nextDetails = RoundDetails( new int256[](0), maxSubmissionCount, minSubmissionCount, timeout, paymentAmount ); details[_roundId] = nextDetails; rounds[_roundId].startedAt = uint64(block.timestamp); emit NewRound(_roundId, msg.sender, rounds[_roundId].startedAt); } function oracleInitializeNewRound(uint32 _roundId) private { if (!newRound(_roundId)) return; uint256 lastStarted = oracles[msg.sender].lastStartedRound; // cache storage reads if (_roundId <= lastStarted + restartDelay && lastStarted != 0) return; initializeNewRound(_roundId); oracles[msg.sender].lastStartedRound = _roundId; } function requesterInitializeNewRound(uint32 _roundId) private { if (!newRound(_roundId)) return; uint256 lastStarted = requesters[msg.sender].lastStartedRound; // cache storage reads require(_roundId > lastStarted + requesters[msg.sender].delay || lastStarted == 0, "must delay requests"); initializeNewRound(_roundId); requesters[msg.sender].lastStartedRound = _roundId; } function updateTimedOutRoundInfo(uint32 _roundId) private { if (!timedOut(_roundId)) return; uint32 prevId = _roundId - 1; rounds[_roundId].answer = rounds[prevId].answer; rounds[_roundId].answeredInRound = rounds[prevId].answeredInRound; rounds[_roundId].updatedAt = uint64(block.timestamp); delete details[_roundId]; } function eligibleForSpecificRound(address _oracle, uint32 _queriedRoundId) private view returns (bool _eligible) { if (rounds[_queriedRoundId].startedAt > 0) { return acceptingSubmissions(_queriedRoundId) && validateOracleRound(_oracle, _queriedRoundId).length == 0; } else { return delayed(_oracle, _queriedRoundId) && validateOracleRound(_oracle, _queriedRoundId).length == 0; } } function oracleRoundStateSuggestRound(address _oracle) private view returns ( bool _eligibleToSubmit, uint32 _roundId, int256 _latestSubmission, uint64 _startedAt, uint64 _timeout, uint128 _availableFunds, uint8 _oracleCount, uint128 _paymentAmount ) { Round storage round = rounds[0]; OracleStatus storage oracle = oracles[_oracle]; bool shouldSupersede = oracle.lastReportedRound == reportingRoundId || !acceptingSubmissions(reportingRoundId); // Instead of nudging oracles to submit to the next round, the inclusion of // the shouldSupersede bool in the if condition pushes them towards // submitting in a currently open round. if (supersedable(reportingRoundId) && shouldSupersede) { _roundId = reportingRoundId + 1; round = rounds[_roundId]; _paymentAmount = paymentAmount; _eligibleToSubmit = delayed(_oracle, _roundId); } else { _roundId = reportingRoundId; round = rounds[_roundId]; _paymentAmount = details[_roundId].paymentAmount; _eligibleToSubmit = acceptingSubmissions(_roundId); } if (validateOracleRound(_oracle, _roundId).length != 0) { _eligibleToSubmit = false; } return ( _eligibleToSubmit, _roundId, oracle.latestSubmission, round.startedAt, details[_roundId].timeout, recordedFunds.available, oracleCount(), _paymentAmount ); } function updateRoundAnswer(uint32 _roundId) internal returns (bool, int256) { if (details[_roundId].submissions.length < details[_roundId].minSubmissions) { return (false, 0); } int256 newAnswer = Median.calculateInplace(details[_roundId].submissions); rounds[_roundId].answer = newAnswer; rounds[_roundId].updatedAt = uint64(block.timestamp); rounds[_roundId].answeredInRound = _roundId; latestRoundId = _roundId; emit AnswerUpdated(newAnswer, _roundId, block.timestamp); return (true, newAnswer); } function validateAnswer( uint32 _roundId, int256 _newAnswer ) private { AggregatorValidatorInterface av = validator; // cache storage reads if (address(av) == address(0)) return; uint32 prevRound = _roundId - 1; uint32 prevAnswerRoundId = rounds[prevRound].answeredInRound; int256 prevRoundAnswer = rounds[prevRound].answer; // We do not want the validator to ever prevent reporting, so we limit its // gas usage and catch any errors that may arise. try av.validate{gas: VALIDATOR_GAS_LIMIT}( prevAnswerRoundId, prevRoundAnswer, _roundId, _newAnswer ) {} catch {} } function payOracle(uint32 _roundId) private { uint128 payment = details[_roundId].paymentAmount; Funds memory funds = recordedFunds; funds.available = funds.available - payment; funds.allocated = funds.allocated + payment; recordedFunds = funds; oracles[msg.sender].withdrawable = oracles[msg.sender].withdrawable + payment; emit AvailableFundsUpdated(funds.available); } function recordSubmission(int256 _submission, uint32 _roundId) private { require(acceptingSubmissions(_roundId), "round not accepting submissions"); if(latestAnswer() > 0){ require(_submission <= 2 * latestAnswer(), "difference is too big"); } details[_roundId].submissions.push(_submission); oracles[msg.sender].lastReportedRound = _roundId; oracles[msg.sender].latestSubmission = _submission; emit SubmissionReceived(_submission, _roundId, msg.sender); } function deleteRoundDetails(uint32 _roundId) private { if (details[_roundId].submissions.length < details[_roundId].maxSubmissions) return; delete details[_roundId]; } function timedOut(uint32 _roundId) private view returns (bool) { uint64 startedAt = rounds[_roundId].startedAt; uint32 roundTimeout = details[_roundId].timeout; return startedAt > 0 && roundTimeout > 0 && startedAt + roundTimeout < block.timestamp; } function getStartingRound(address _oracle) private view returns (uint32) { uint32 currentRound = reportingRoundId; if (currentRound != 0 && currentRound == oracles[_oracle].endingRound) { return currentRound; } return currentRound + 1; } function previousAndCurrentUnanswered(uint32 _roundId, uint32 _rrId) private view returns (bool) { return _roundId + 1 == _rrId && rounds[_rrId].updatedAt == 0; } function requiredReserve(uint256 payment) private view returns (uint256) { return payment * oracleCount() * RESERVE_ROUNDS; } function addOracle( address _oracle, address _admin ) private { require(!oracleEnabled(_oracle), "oracle already enabled"); require(_admin != address(0), "cannot set admin to 0"); require(oracles[_oracle].admin == address(0) || oracles[_oracle].admin == _admin, "owner cannot overwrite admin"); oracles[_oracle].startingRound = getStartingRound(_oracle); oracles[_oracle].endingRound = ROUND_MAX; oracles[_oracle].index = uint16(oracleAddresses.length); oracleAddresses.push(_oracle); oracles[_oracle].admin = _admin; emit OraclePermissionsUpdated(_oracle, true); emit OracleAdminUpdated(_oracle, _admin); } function removeOracle( address _oracle ) private { require(oracleEnabled(_oracle), "oracle not enabled"); oracles[_oracle].endingRound = reportingRoundId + 1; address tail = oracleAddresses[uint256(oracleCount()) - 1]; uint16 index = oracles[_oracle].index; oracles[tail].index = index; delete oracles[_oracle].index; oracleAddresses[index] = tail; oracleAddresses.pop(); emit OraclePermissionsUpdated(_oracle, false); } function validateOracleRound(address _oracle, uint32 _roundId) private view returns (bytes memory) { // cache storage reads uint32 startingRound = oracles[_oracle].startingRound; uint32 rrId = reportingRoundId; if (startingRound == 0) return "not enabled oracle"; if (startingRound > _roundId) return "not yet enabled oracle"; if (oracles[_oracle].endingRound < _roundId) return "no longer allowed oracle"; if (oracles[_oracle].lastReportedRound >= _roundId) return "cannot report on previous rounds"; if (_roundId != rrId && _roundId != rrId + 1 && !previousAndCurrentUnanswered(_roundId, rrId)) return "invalid round to report"; if (_roundId != 1 && !supersedable(_roundId - 1)) return "previous round not supersedable"; } function supersedable(uint32 _roundId) private view returns (bool) { return rounds[_roundId].updatedAt > 0 || timedOut(_roundId); } function oracleEnabled(address _oracle) private view returns (bool) { return oracles[_oracle].endingRound == ROUND_MAX; } function acceptingSubmissions(uint32 _roundId) private view returns (bool) { return details[_roundId].maxSubmissions != 0; } function delayed(address _oracle, uint32 _roundId) private view returns (bool) { uint256 lastStarted = oracles[_oracle].lastStartedRound; return _roundId > lastStarted + restartDelay || lastStarted == 0; } function newRound(uint32 _roundId) private view returns (bool) { return _roundId == reportingRoundId + 1; } function validRoundId(uint256 _roundId) private pure returns (bool) { return _roundId <= ROUND_MAX; } }
@openzeppelin/contracts/access/AccessControl.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; import "../utils/Context.sol"; import "../utils/Strings.sol"; import "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(account), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
@openzeppelin/contracts/access/IAccessControl.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
@openzeppelin/contracts/utils/Context.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) pragma solidity ^0.8.0; /** * @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; } }
@openzeppelin/contracts/utils/Strings.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
@openzeppelin/contracts/utils/introspection/ERC165.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
@openzeppelin/contracts/utils/introspection/IERC165.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
@openzeppelin/contracts/utils/math/Math.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
@openzeppelin/contracts/utils/math/SignedMath.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
contracts/Median.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.6; // import "./vendor/SafeMathChainlink.sol"; import "./SignedSafeMath.sol"; library Median { using SignedSafeMath for int256; int256 constant INT_MAX = type(int256).max; /** * @notice Returns the sorted middle, or the average of the two middle indexed items if the * array has an even number of elements. * @dev The list passed as an argument isn't modified. * @dev This algorithm has expected runtime O(n), but for adversarially chosen inputs * the runtime is O(n^2). * @param list The list of elements to compare */ function calculate(int256[] memory list) internal pure returns (int256) { return calculateInplace(copy(list)); } /** * @notice See documentation for function calculate. * @dev The list passed as an argument may be permuted. */ function calculateInplace(int256[] memory list) internal pure returns (int256) { require(0 < list.length, "list must not be empty"); uint256 len = list.length; uint256 middleIndex = len / 2; if (len % 2 == 0) { int256 median1; int256 median2; (median1, median2) = quickselectTwo(list, 0, len - 1, middleIndex - 1, middleIndex); return SignedSafeMath.avg(median1, median2); } else { return quickselect(list, 0, len - 1, middleIndex); } } /** * @notice Maximum length of list that shortSelectTwo can handle */ uint256 constant SHORTSELECTTWO_MAX_LENGTH = 7; /** * @notice Select the k1-th and k2-th element from list of length at most 7 * @dev Uses an optimal sorting network */ function shortSelectTwo( int256[] memory list, uint256 lo, uint256 hi, uint256 k1, uint256 k2 ) private pure returns (int256 k1th, int256 k2th) { // Uses an optimal sorting network (https://en.wikipedia.org/wiki/Sorting_network) // for lists of length 7. Network layout is taken from // http://jgamble.ripco.net/cgi-bin/nw.cgi?inputs=7&algorithm=hibbard&output=svg uint256 len = hi + 1 - lo; int256 x0 = list[lo + 0]; int256 x1 = 1 < len ? list[lo + 1] : INT_MAX; int256 x2 = 2 < len ? list[lo + 2] : INT_MAX; int256 x3 = 3 < len ? list[lo + 3] : INT_MAX; int256 x4 = 4 < len ? list[lo + 4] : INT_MAX; int256 x5 = 5 < len ? list[lo + 5] : INT_MAX; int256 x6 = 6 < len ? list[lo + 6] : INT_MAX; if (x0 > x1) {(x0, x1) = (x1, x0);} if (x2 > x3) {(x2, x3) = (x3, x2);} if (x4 > x5) {(x4, x5) = (x5, x4);} if (x0 > x2) {(x0, x2) = (x2, x0);} if (x1 > x3) {(x1, x3) = (x3, x1);} if (x4 > x6) {(x4, x6) = (x6, x4);} if (x1 > x2) {(x1, x2) = (x2, x1);} if (x5 > x6) {(x5, x6) = (x6, x5);} if (x0 > x4) {(x0, x4) = (x4, x0);} if (x1 > x5) {(x1, x5) = (x5, x1);} if (x2 > x6) {(x2, x6) = (x6, x2);} if (x1 > x4) {(x1, x4) = (x4, x1);} if (x3 > x6) {(x3, x6) = (x6, x3);} if (x2 > x4) {(x2, x4) = (x4, x2);} if (x3 > x5) {(x3, x5) = (x5, x3);} if (x3 > x4) {(x3, x4) = (x4, x3);} uint256 index1 = k1 - lo; if (index1 == 0) {k1th = x0;} else if (index1 == 1) {k1th = x1;} else if (index1 == 2) {k1th = x2;} else if (index1 == 3) {k1th = x3;} else if (index1 == 4) {k1th = x4;} else if (index1 == 5) {k1th = x5;} else if (index1 == 6) {k1th = x6;} else {revert("k1 out of bounds");} uint256 index2 = k2 - lo; if (k1 == k2) {return (k1th, k1th);} else if (index2 == 0) {return (k1th, x0);} else if (index2 == 1) {return (k1th, x1);} else if (index2 == 2) {return (k1th, x2);} else if (index2 == 3) {return (k1th, x3);} else if (index2 == 4) {return (k1th, x4);} else if (index2 == 5) {return (k1th, x5);} else if (index2 == 6) {return (k1th, x6);} else {revert("k2 out of bounds");} } /** * @notice Selects the k-th ranked element from list, looking only at indices between lo and hi * (inclusive). Modifies list in-place. */ function quickselect(int256[] memory list, uint256 lo, uint256 hi, uint256 k) private pure returns (int256 kth) { require(lo <= k); require(k <= hi); while (lo < hi) { if (hi - lo < SHORTSELECTTWO_MAX_LENGTH) { int256 ignore; (kth, ignore) = shortSelectTwo(list, lo, hi, k, k); return kth; } uint256 pivotIndex = partition(list, lo, hi); if (k <= pivotIndex) { // since pivotIndex < (original hi passed to partition), // termination is guaranteed in this case hi = pivotIndex; } else { // since (original lo passed to partition) <= pivotIndex, // termination is guaranteed in this case lo = pivotIndex + 1; } } return list[lo]; } /** * @notice Selects the k1-th and k2-th ranked elements from list, looking only at indices between * lo and hi (inclusive). Modifies list in-place. */ function quickselectTwo( int256[] memory list, uint256 lo, uint256 hi, uint256 k1, uint256 k2 ) internal // for testing pure returns (int256 k1th, int256 k2th) { require(k1 < k2); require(lo <= k1 && k1 <= hi); require(lo <= k2 && k2 <= hi); while (true) { if (hi - lo < SHORTSELECTTWO_MAX_LENGTH) { return shortSelectTwo(list, lo, hi, k1, k2); } uint256 pivotIdx = partition(list, lo, hi); if (k2 <= pivotIdx) { hi = pivotIdx; } else if (pivotIdx < k1) { lo = pivotIdx + 1; } else { assert(k1 <= pivotIdx && pivotIdx < k2); k1th = quickselect(list, lo, pivotIdx, k1); k2th = quickselect(list, pivotIdx + 1, hi, k2); return (k1th, k2th); } } } /** * @notice Partitions list in-place using Hoare's partitioning scheme. * Only elements of list between indices lo and hi (inclusive) will be modified. * Returns an index i, such that: * - lo <= i < hi * - forall j in [lo, i]. list[j] <= list[i] * - forall j in [i, hi]. list[i] <= list[j] */ function partition(int256[] memory list, uint256 lo, uint256 hi) private pure returns (uint256) { // We don't care about overflow of the addition, because it would require a list // larger than any feasible computer's memory. int256 pivot = list[(lo + hi) / 2]; lo -= 1; // this can underflow. that's intentional. hi += 1; while (true) { do { lo += 1; } while (list[lo] < pivot); do { hi -= 1; } while (list[hi] > pivot); if (lo < hi) { (list[lo], list[hi]) = (list[hi], list[lo]); } else { // Let orig_lo and orig_hi be the original values of lo and hi passed to partition. // Then, hi < orig_hi, because hi decreases *strictly* monotonically // in each loop iteration and // - either list[orig_hi] > pivot, in which case the first loop iteration // will achieve hi < orig_hi; // - or list[orig_hi] <= pivot, in which case at least two loop iterations are // needed: // - lo will have to stop at least once in the interval // [orig_lo, (orig_lo + orig_hi)/2] // - (orig_lo + orig_hi)/2 < orig_hi return hi; } } } /** * @notice Makes an in-memory copy of the array passed in * @param list Reference to the array to be copied */ function copy(int256[] memory list) private pure returns(int256[] memory) { int256[] memory list2 = new int256[](list.length); for (uint256 i = 0; i < list.length; i++) { list2[i] = list[i]; } return list2; } }
contracts/SignedSafeMath.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.6; library SignedSafeMath { int256 private constant MIN_INT256 = type(int256).min; int256 private constant MAX_INT256 = type(int256).max; /** * @dev Multiplies two signed integers, reverts on overflow. */ function mul(int256 a, int256 b) internal pure returns (int256) { require(!(a == -1 && b == MIN_INT256), "SignedSafeMath: multiplication overflow"); int256 c = a * b; require(c / a == b, "SignedSafeMath: multiplication overflow"); return c; } /** * @dev Integer division of two signed integers truncating the quotient, reverts on division by zero. */ function div(int256 a, int256 b) internal pure returns (int256) { require(b != 0, "SignedSafeMath: division by zero"); require(!(b == -1 && a == MIN_INT256), "SignedSafeMath: division overflow"); int256 c = a / b; return c; } /** * @dev Subtracts two signed integers, reverts on overflow. */ function sub(int256 a, int256 b) internal pure returns (int256) { require((b >= 0 && a >= b) || (b < 0 && a > b), "SignedSafeMath: subtraction overflow"); int256 c = a - b; return c; } /** * @dev Adds two signed integers, reverts on overflow. */ function add(int256 a, int256 b) internal pure returns (int256) { require((b >= 0 && a <= MAX_INT256 - b) || (b < 0 && a >= MIN_INT256 - b), "SignedSafeMath: addition overflow"); int256 c = a + b; return c; } /** * @notice Computes average of two signed integers, ensuring that the computation * doesn't overflow. * @dev If the result is not an integer, it is rounded towards zero. For example, * avg(-3, -4) = -3 */ function avg(int256 _a, int256 _b) internal pure returns (int256) { if ((_a < 0 && _b > 0) || (_a > 0 && _b < 0)) { return add(_a, _b) / 2; } int256 remainder = (_a % 2 + _b % 2) / 2; return add(add(_a / 2, _b / 2), remainder); } }
contracts/interfaces/AggregatorInterface.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.6; interface AggregatorInterface { function latestAnswer() external view returns ( int256 ); function latestTimestamp() external view returns ( uint256 ); function latestRound() external view returns ( uint256 ); function getAnswer( uint256 roundId ) external view returns ( int256 ); function getTimestamp( uint256 roundId ) external view returns ( uint256 ); event AnswerUpdated( int256 indexed current, uint256 indexed roundId, uint256 updatedAt ); event NewRound( uint256 indexed roundId, address indexed startedBy, uint256 startedAt ); }
contracts/interfaces/AggregatorV2V3Interface.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.6; import "./AggregatorInterface.sol"; import "./AggregatorV3Interface.sol"; interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface { }
contracts/interfaces/AggregatorV3Interface.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.6; interface AggregatorV3Interface { function decimals() external view returns ( uint8 ); function description() external view returns ( string memory ); function version() external view returns ( uint256 ); function getRoundData( uint80 _roundId ) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); }
contracts/interfaces/AggregatorValidatorInterface.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.6; interface AggregatorValidatorInterface { function validate( uint256 previousRoundId, int256 previousAnswer, uint256 currentRoundId, int256 currentAnswer ) external returns (bool); }
Compiler Settings
{"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata","devdoc","userdoc","storageLayout","evm.gasEstimates"],"":["ast"]}},"optimizer":{"runs":200,"enabled":true},"metadata":{"useLiteralContent":true},"libraries":{}}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"uint128","name":"_paymentAmount","internalType":"uint128"},{"type":"uint32","name":"_timeout","internalType":"uint32"},{"type":"int256","name":"_minSubmissionValue","internalType":"int256"},{"type":"int256","name":"_maxSubmissionValue","internalType":"int256"},{"type":"uint8","name":"_decimals","internalType":"uint8"},{"type":"string","name":"_description","internalType":"string"}]},{"type":"event","name":"AnswerUpdated","inputs":[{"type":"int256","name":"current","internalType":"int256","indexed":true},{"type":"uint256","name":"roundId","internalType":"uint256","indexed":true},{"type":"uint256","name":"updatedAt","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"AvailableFundsUpdated","inputs":[{"type":"uint256","name":"amount","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"NewRound","inputs":[{"type":"uint256","name":"roundId","internalType":"uint256","indexed":true},{"type":"address","name":"startedBy","internalType":"address","indexed":true},{"type":"uint256","name":"startedAt","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OracleAdminUpdateRequested","inputs":[{"type":"address","name":"oracle","internalType":"address","indexed":true},{"type":"address","name":"admin","internalType":"address","indexed":false},{"type":"address","name":"newAdmin","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"OracleAdminUpdated","inputs":[{"type":"address","name":"oracle","internalType":"address","indexed":true},{"type":"address","name":"newAdmin","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OraclePermissionsUpdated","inputs":[{"type":"address","name":"oracle","internalType":"address","indexed":true},{"type":"bool","name":"whitelisted","internalType":"bool","indexed":true}],"anonymous":false},{"type":"event","name":"RequesterPermissionsSet","inputs":[{"type":"address","name":"requester","internalType":"address","indexed":true},{"type":"bool","name":"authorized","internalType":"bool","indexed":false},{"type":"uint32","name":"delay","internalType":"uint32","indexed":false}],"anonymous":false},{"type":"event","name":"RoleAdminChanged","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"previousAdminRole","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"newAdminRole","internalType":"bytes32","indexed":true}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RoundDetailsUpdated","inputs":[{"type":"uint128","name":"paymentAmount","internalType":"uint128","indexed":true},{"type":"uint32","name":"minSubmissionCount","internalType":"uint32","indexed":true},{"type":"uint32","name":"maxSubmissionCount","internalType":"uint32","indexed":true},{"type":"uint32","name":"restartDelay","internalType":"uint32","indexed":false},{"type":"uint32","name":"timeout","internalType":"uint32","indexed":false}],"anonymous":false},{"type":"event","name":"SubmissionReceived","inputs":[{"type":"int256","name":"submission","internalType":"int256","indexed":true},{"type":"uint32","name":"round","internalType":"uint32","indexed":true},{"type":"address","name":"oracle","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"ValidatorUpdated","inputs":[{"type":"address","name":"previous","internalType":"address","indexed":true},{"type":"address","name":"current","internalType":"address","indexed":true}],"anonymous":false},{"type":"fallback","stateMutability":"payable"},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"ADMIN_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"DEFAULT_ADMIN_ROLE","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"acceptAdmin","inputs":[{"type":"address","name":"_oracle","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint128","name":"","internalType":"uint128"}],"name":"allocatedFunds","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint128","name":"","internalType":"uint128"}],"name":"availableFunds","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"changeOracles","inputs":[{"type":"address[]","name":"_removed","internalType":"address[]"},{"type":"address[]","name":"_added","internalType":"address[]"},{"type":"address[]","name":"_addedAdmins","internalType":"address[]"},{"type":"uint32","name":"_minSubmissions","internalType":"uint32"},{"type":"uint32","name":"_maxSubmissions","internalType":"uint32"},{"type":"uint32","name":"_restartDelay","internalType":"uint32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"decimals","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"description","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"getAdmin","inputs":[{"type":"address","name":"_oracle","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"int256","name":"","internalType":"int256"}],"name":"getAnswer","inputs":[{"type":"uint256","name":"_roundId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getOracles","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getRoleAdmin","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint80","name":"roundId","internalType":"uint80"},{"type":"int256","name":"answer","internalType":"int256"},{"type":"uint256","name":"startedAt","internalType":"uint256"},{"type":"uint256","name":"updatedAt","internalType":"uint256"},{"type":"uint80","name":"answeredInRound","internalType":"uint80"}],"name":"getRoundData","inputs":[{"type":"uint80","name":"_roundId","internalType":"uint80"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTimestamp","inputs":[{"type":"uint256","name":"_roundId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"grantRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"int256","name":"","internalType":"int256"}],"name":"latestAnswer","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"latestRound","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint80","name":"roundId","internalType":"uint80"},{"type":"int256","name":"answer","internalType":"int256"},{"type":"uint256","name":"startedAt","internalType":"uint256"},{"type":"uint256","name":"updatedAt","internalType":"uint256"},{"type":"uint80","name":"answeredInRound","internalType":"uint80"}],"name":"latestRoundData","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"latestTimestamp","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"maxSubmissionCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"int256","name":"","internalType":"int256"}],"name":"maxSubmissionValue","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"minSubmissionCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"int256","name":"","internalType":"int256"}],"name":"minSubmissionValue","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"oracleCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"_eligibleToSubmit","internalType":"bool"},{"type":"uint32","name":"_roundId","internalType":"uint32"},{"type":"int256","name":"_latestSubmission","internalType":"int256"},{"type":"uint64","name":"_startedAt","internalType":"uint64"},{"type":"uint64","name":"_timeout","internalType":"uint64"},{"type":"uint128","name":"_availableFunds","internalType":"uint128"},{"type":"uint8","name":"_oracleCount","internalType":"uint8"},{"type":"uint128","name":"_paymentAmount","internalType":"uint128"}],"name":"oracleRoundState","inputs":[{"type":"address","name":"_oracle","internalType":"address"},{"type":"uint32","name":"_queriedRoundId","internalType":"uint32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint128","name":"","internalType":"uint128"}],"name":"paymentAmount","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint80","name":"","internalType":"uint80"}],"name":"requestNewRound","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"restartDelay","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revokeRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRequesterPermissions","inputs":[{"type":"address","name":"_requester","internalType":"address"},{"type":"bool","name":"_authorized","internalType":"bool"},{"type":"uint32","name":"_delay","internalType":"uint32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setValidator","inputs":[{"type":"address","name":"_newValidator","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"submit","inputs":[{"type":"uint256","name":"_roundId","internalType":"uint256"},{"type":"int256","name":"_submission","internalType":"int256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"supportsInterface","inputs":[{"type":"bytes4","name":"interfaceId","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"timeout","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferAdmin","inputs":[{"type":"address","name":"_oracle","internalType":"address"},{"type":"address","name":"_newAdmin","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateAvailableFunds","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateFutureRounds","inputs":[{"type":"uint128","name":"_paymentAmount","internalType":"uint128"},{"type":"uint32","name":"_minSubmissions","internalType":"uint32"},{"type":"uint32","name":"_maxSubmissions","internalType":"uint32"},{"type":"uint32","name":"_restartDelay","internalType":"uint32"},{"type":"uint32","name":"_timeout","internalType":"uint32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract AggregatorValidatorInterface"}],"name":"validator","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"version","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawFunds","inputs":[{"type":"address","name":"_recipient","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawPayment","inputs":[{"type":"address","name":"_oracle","internalType":"address"},{"type":"address","name":"_recipient","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"withdrawablePayment","inputs":[{"type":"address","name":"_oracle","internalType":"address"}]},{"type":"receive","stateMutability":"payable"}]
Contract Creation Code
0x60c06040523480156200001157600080fd5b5060405162005096380380620050968339810160408190526200003491620008fe565b6200004160003362000112565b6200005c600080516020620050768339815191523362000112565b6200006c86600080808962000122565b608084905260a08390526003805460ff191660ff841617905580516200009a906004906020840190620007c7565b50620000ad63ffffffff86164262000a95565b6000805260076020527f6d5257204ebe7d88fd91ae87941cb2dd9d8062b64ae5a2bd2d28ec40b9fbf6e080546001600160401b03929092166801000000000000000002600160401b600160801b03199092169190911790555062000b7b945050505050565b6200011e828262000486565b5050565b600080516020620050768339815191526200013d8162000526565b600062000149600a5490565b60ff1690508563ffffffff168563ffffffff161015620001b05760405162461bcd60e51b815260206004820152601960248201527f6d6178206d75737420657175616c2f657863656564206d696e0000000000000060448201526064015b60405180910390fd5b8463ffffffff168163ffffffff1610156200020e5760405162461bcd60e51b815260206004820152601760248201527f6d61782063616e6e6f742065786365656420746f74616c0000000000000000006044820152606401620001a7565b63ffffffff811615806200022d57508363ffffffff168163ffffffff16115b6200027b5760405162461bcd60e51b815260206004820152601960248201527f64656c61792063616e6e6f742065786365656420746f74616c000000000000006044820152606401620001a7565b6200028f6001600160801b03881662000535565b600b546001600160801b03161015620002eb5760405162461bcd60e51b815260206004820152601e60248201527f696e73756666696369656e742066756e647320666f72207061796d656e7400006044820152606401620001a7565b6000620002f7600a5490565b60ff161115620003595760008663ffffffff1611620003595760405162461bcd60e51b815260206004820152601a60248201527f6d696e206d7573742062652067726561746572207468616e20300000000000006044820152606401620001a7565b86600260006101000a8154816001600160801b0302191690836001600160801b0316021790555085600260146101000a81548163ffffffff021916908363ffffffff16021790555084600260106101000a81548163ffffffff021916908363ffffffff16021790555083600260186101000a81548163ffffffff021916908363ffffffff160217905550826002601c6101000a81548163ffffffff021916908363ffffffff1602179055508463ffffffff168663ffffffff16600260009054906101000a90046001600160801b03166001600160801b03167f56800c9d1ed723511246614d15e58cfcde15b6a33c245b5c961b689c1890fd8f87876040516200047592919063ffffffff92831681529116602082015260400190565b60405180910390a450505050505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff166200011e576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620004e23390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b62000532813362000564565b50565b6000600262000543600a5490565b620005529060ff168462000a73565b6200055e919062000a73565b92915050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff166200011e57620005a381620005f460201b62001c0c1760201c565b620005b983602062001c1e62000607821b17811c565b604051602001620005cc929190620009aa565b60408051601f198184030181529082905262461bcd60e51b8252620001a79160040162000a23565b60606200055e6001600160a01b03831660145b606060006200061883600262000a73565b6200062590600262000a58565b6001600160401b038111156200063f576200063f62000b65565b6040519080825280601f01601f1916602001820160405280156200066a576020820181803683370190505b509050600360fc1b8160008151811062000688576200068862000b4f565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110620006ba57620006ba62000b4f565b60200101906001600160f81b031916908160001a9053506000620006e084600262000a73565b620006ed90600162000a58565b90505b60018111156200076f576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811062000725576200072562000b4f565b1a60f81b8282815181106200073e576200073e62000b4f565b60200101906001600160f81b031916908160001a90535060049490941c93620007678162000ae2565b9050620006f0565b508315620007c05760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401620001a7565b9392505050565b828054620007d59062000afc565b90600052602060002090601f016020900481019282620007f9576000855562000844565b82601f106200081457805160ff191683800117855562000844565b8280016001018555821562000844579182015b828111156200084457825182559160200191906001019062000827565b506200085292915062000856565b5090565b5b8082111562000852576000815560010162000857565b600082601f8301126200087f57600080fd5b81516001600160401b03808211156200089c576200089c62000b65565b604051601f8301601f19908116603f01168101908282118183101715620008c757620008c762000b65565b81604052838152866020858801011115620008e157600080fd5b620008f484602083016020890162000aaf565b9695505050505050565b60008060008060008060c087890312156200091857600080fd5b86516001600160801b03811681146200093057600080fd5b602088015190965063ffffffff811681146200094b57600080fd5b809550506040870151935060608701519250608087015160ff811681146200097257600080fd5b60a08801519092506001600160401b038111156200098f57600080fd5b6200099d89828a016200086d565b9150509295509295509295565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351620009e481601785016020880162000aaf565b7001034b99036b4b9b9b4b733903937b6329607d1b601791840191820152835162000a1781602884016020880162000aaf565b01602801949350505050565b602081526000825180602084015262000a4481604085016020870162000aaf565b601f01601f19169190910160400192915050565b6000821982111562000a6e5762000a6e62000b39565b500190565b600081600019048311821515161562000a905762000a9062000b39565b500290565b60008282101562000aaa5762000aaa62000b39565b500390565b60005b8381101562000acc57818101518382015260200162000ab2565b8381111562000adc576000848401525b50505050565b60008162000af45762000af462000b39565b506000190190565b600181811c9082168062000b1157607f821691505b6020821081141562000b3357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b60805160a0516144c762000baf600039600081816103290152610b7c0152600081816106ac0152610b0701526144c76000f3fe60806040526004361061026b5760003560e01c806364efb22b11610144578063a217fddf116100b6578063c93745001161007a578063c9374500146108cb578063d4cc54e4146108ef578063d547741f14610914578063e2e4031714610934578063e9ee6eeb14610973578063feaf968c146109935761027a565b8063a217fddf14610836578063b5ab58dc1461084b578063b633620c1461086b578063c10753291461088b578063c35905c6146108ab5761027a565b80637c2b0b21116101085780637c2b0b211461069a5780638205bf6a146106ce57806388aa80e71461071257806391d148541461078f57806398e5b12a146107af5780639a6fc8f5146107df5761027a565b806364efb22b146105ce578063668a0f021461061057806370dea79a146106325780637284e4161461065657806375b238fc146106785761027a565b80633969c20f116101dd5780634f8fc3b5116101a15780634f8fc3b51461051a57806350d25bcd1461052f57806354fd4d501461056057806358609e4414610575578063613d8fcc14610599578063628806ef146105ae5761027a565b80633969c20f1461044e5780633a5381b51461046e5780633d3d7714146104a657806340884c52146104c657806346fcff4c146104e85761027a565b8063248a9ca31161022f578063248a9ca3146103595780632f2ff15d14610389578063313ce567146103a9578063357ebb02146103d557806336568abe1461040e57806338aa4c721461042e5761027a565b806301ffc9a7146102825780631327d3d8146102b7578063202ee0ed146102d757806320ed0275146102f757806323ca2903146103175761027a565b3661027a576102786109a8565b005b6102786109a8565b34801561028e57600080fd5b506102a261029d366004613f06565b610a3e565b60405190151581526020015b60405180910390f35b3480156102c357600080fd5b506102786102d2366004613cd8565b610a75565b3480156102e357600080fd5b506102786102f2366004613fa3565b610af7565b34801561030357600080fd5b50610278610312366004613d62565b610c49565b34801561032357600080fd5b5061034b7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016102ae565b34801561036557600080fd5b5061034b610374366004613eca565b60009081526020819052604090206001015490565b34801561039557600080fd5b506102786103a4366004613ee3565b610d4f565b3480156103b557600080fd5b506003546103c39060ff1681565b60405160ff90911681526020016102ae565b3480156103e157600080fd5b506002546103f990600160c01b900463ffffffff1681565b60405163ffffffff90911681526020016102ae565b34801561041a57600080fd5b50610278610429366004613ee3565b610d74565b34801561043a57600080fd5b50610278610449366004613f30565b610dee565b34801561045a57600080fd5b50610278610469366004613e00565b61113a565b34801561047a57600080fd5b5060015461048e906001600160a01b031681565b6040516001600160a01b0390911681526020016102ae565b3480156104b257600080fd5b506102786104c1366004613d26565b6112f5565b3480156104d257600080fd5b506104db611452565b6040516102ae9190614066565b3480156104f457600080fd5b50600b546001600160801b03165b6040516001600160801b0390911681526020016102ae565b34801561052657600080fd5b506102786109a8565b34801561053b57600080fd5b50600554600160201b900463ffffffff1660009081526007602052604090205461034b565b34801561056c57600080fd5b5061034b600381565b34801561058157600080fd5b506002546103f990600160801b900463ffffffff1681565b3480156105a557600080fd5b50600a546103c3565b3480156105ba57600080fd5b506102786105c9366004613cd8565b6114b4565b3480156105da57600080fd5b5061048e6105e9366004613cd8565b6001600160a01b039081166000908152600660205260409020600201546201000090041690565b34801561061c57600080fd5b50600554600160201b900463ffffffff1661034b565b34801561063e57600080fd5b506002546103f990600160e01b900463ffffffff1681565b34801561066257600080fd5b5061066b611595565b6040516102ae91906140b3565b34801561068457600080fd5b5061034b60008051602061447283398151915281565b3480156106a657600080fd5b5061034b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156106da57600080fd5b50600554600160201b900463ffffffff16600090815260076020526040902060010154600160401b90046001600160401b031661034b565b34801561071e57600080fd5b5061073261072d366004613dd6565b611623565b60408051981515895263ffffffff9097166020890152958701949094526001600160401b039283166060870152911660808501526001600160801b0390811660a085015260ff90911660c08401521660e0820152610100016102ae565b34801561079b57600080fd5b506102a26107aa366004613ee3565b611780565b3480156107bb57600080fd5b506107c46117a9565b60405169ffffffffffffffffffff90911681526020016102ae565b3480156107eb57600080fd5b506107ff6107fa366004613fc5565b6118b4565b6040805169ffffffffffffffffffff968716815260208101959095528401929092526060830152909116608082015260a0016102ae565b34801561084257600080fd5b5061034b600081565b34801561085757600080fd5b5061034b610866366004613eca565b6119ba565b34801561087757600080fd5b5061034b610886366004613eca565b6119f0565b34801561089757600080fd5b506102786108a6366004613dac565b611a31565b3480156108b757600080fd5b50600254610502906001600160801b031681565b3480156108d757600080fd5b506002546103f990600160a01b900463ffffffff1681565b3480156108fb57600080fd5b50600b54600160801b90046001600160801b0316610502565b34801561092057600080fd5b5061027861092f366004613ee3565b611ad1565b34801561094057600080fd5b5061034b61094f366004613cd8565b6001600160a01b03166000908152600660205260409020546001600160801b031690565b34801561097f57600080fd5b5061027861098e366004613cf3565b611af6565b34801561099f57600080fd5b506107ff611bd2565b60408051808201909152600b546001600160801b038082168352600160801b90910416602082018190526000906109df90476142f8565b82519091506001600160801b03168114610a3a57600b80546001600160801b0319166001600160801b03831617905560405181907ffe25c73e3b9089fac37d55c4c7efcba6f04af04cebd2fc4d6d7dbb07e1e5234f90600090a25b5050565b60006001600160e01b03198216637965db0b60e01b1480610a6f57506301ffc9a760e01b6001600160e01b03198316145b92915050565b600080516020614472833981519152610a8d81611dc0565b6001546001600160a01b039081169083168114610af257600180546001600160a01b0319166001600160a01b0385811691821790925560405190918316907fcfac5dc75b8d9a7e074162f59d9adcd33da59f0fe8dfb21580db298fc0fdad0d90600090a35b505050565b6000610b033384611dcd565b90507f0000000000000000000000000000000000000000000000000000000000000000821215610b7a5760405162461bcd60e51b815260206004820152601e60248201527f76616c75652062656c6f77206d696e5375626d697373696f6e56616c7565000060448201526064015b60405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000821315610bea5760405162461bcd60e51b815260206004820152601e60248201527f76616c75652061626f7665206d61785375626d697373696f6e56616c756500006044820152606401610b71565b8051819015610c0c5760405162461bcd60e51b8152600401610b7191906140b3565b50610c168361205b565b610c2082846120f9565b600080610c2c85612275565b91509150610c39856123d1565b610c42856124e7565b5050505050565b600080516020614472833981519152610c6181611dc0565b6001600160a01b03841660009081526009602052604090205460ff1615158315151415610c8d57610d49565b8215610cd4576001600160a01b0384166000908152600960205260409020805464ffffffffff191684151564ffffffff0019161761010063ffffffff851602179055610cfd565b6001600160a01b0384166000908152600960205260409020805468ffffffffffffffffff191690555b60408051841515815263ffffffff841660208201526001600160a01b038616917fc3df5a754e002718f2e10804b99e6605e7c701d95cec9552c7680ca2b6f2820a910160405180910390a25b50505050565b600082815260208190526040902060010154610d6a81611dc0565b610af28383612544565b6001600160a01b0381163314610de45760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610b71565b610a3a82826125c8565b600080516020614472833981519152610e0681611dc0565b6000610e11600a5490565b60ff1690508563ffffffff168563ffffffff161015610e725760405162461bcd60e51b815260206004820152601960248201527f6d6178206d75737420657175616c2f657863656564206d696e000000000000006044820152606401610b71565b8463ffffffff168163ffffffff161015610ece5760405162461bcd60e51b815260206004820152601760248201527f6d61782063616e6e6f742065786365656420746f74616c0000000000000000006044820152606401610b71565b63ffffffff81161580610eec57508363ffffffff168163ffffffff16115b610f385760405162461bcd60e51b815260206004820152601960248201527f64656c61792063616e6e6f742065786365656420746f74616c000000000000006044820152606401610b71565b610f4a876001600160801b031661262d565b600b546001600160801b03161015610fa45760405162461bcd60e51b815260206004820152601e60248201527f696e73756666696369656e742066756e647320666f72207061796d656e7400006044820152606401610b71565b6000610faf600a5490565b60ff16111561100e5760008663ffffffff161161100e5760405162461bcd60e51b815260206004820152601a60248201527f6d696e206d7573742062652067726561746572207468616e20300000000000006044820152606401610b71565b86600260006101000a8154816001600160801b0302191690836001600160801b0316021790555085600260146101000a81548163ffffffff021916908363ffffffff16021790555084600260106101000a81548163ffffffff021916908363ffffffff16021790555083600260186101000a81548163ffffffff021916908363ffffffff160217905550826002601c6101000a81548163ffffffff021916908363ffffffff1602179055508463ffffffff168663ffffffff16600260009054906101000a90046001600160801b03166001600160801b03167f56800c9d1ed723511246614d15e58cfcde15b6a33c245b5c961b689c1890fd8f878760405161112992919063ffffffff92831681529116602082015260400190565b60405180910390a450505050505050565b60008051602061447283398151915261115281611dc0565b60005b8981101561119e5761118c8b8b8381811061117257611172614445565b90506020020160208101906111879190613cd8565b612651565b80611196816143aa565b915050611155565b508685146111ee5760405162461bcd60e51b815260206004820181905260248201527f6e6565642073616d65206f7261636c6520616e642061646d696e20636f756e746044820152606401610b71565b604d876111fa600a5490565b60ff166112079190614152565b111561124b5760405162461bcd60e51b81526020600482015260136024820152721b585e081bdc9858db195cc8185b1b1bddd959606a1b6044820152606401610b71565b60005b878110156112be576112ac89898381811061126b5761126b614445565b90506020020160208101906112809190613cd8565b88888481811061129257611292614445565b90506020020160208101906112a79190613cd8565b612823565b806112b6816143aa565b91505061124e565b506002546112e9906001600160801b03811690869086908690600160e01b900463ffffffff16610dee565b50505050505050505050565b6001600160a01b038381166000908152600660205260409020600201546201000090041633146113605760405162461bcd60e51b815260206004820152601660248201527537b7363c9031b0b63630b1363290313c9030b236b4b760511b6044820152606401610b71565b6001600160a01b03831660009081526006602052604090205481906001600160801b039081169082168110156113d85760405162461bcd60e51b815260206004820152601f60248201527f696e73756666696369656e7420776974686472617761626c652066756e6473006044820152606401610b71565b6113e282826142d0565b6001600160a01b038616600090815260066020526040902080546001600160801b0319166001600160801b03928316179055600b5461142a918491600160801b9004166142d0565b600b80546001600160801b03928316600160801b02908316179055610c429085908416612aa8565b6060600a8054806020026020016040519081016040528092919081815260200182805480156114aa57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161148c575b5050505050905090565b6001600160a01b038181166000908152600660205260409020600301541633146115205760405162461bcd60e51b815260206004820152601e60248201527f6f6e6c792063616c6c61626c652062792070656e64696e672061646d696e00006044820152606401610b71565b6001600160a01b0381166000818152600660205260408082206003810180546001600160a01b0319169055600201805462010000600160b01b031916336201000081029190911790915590519092917f0c5055390645c15a4be9a21b3f8d019153dcb4a0c125685da6eb84048e2fe90491a350565b600480546115a29061436f565b80601f01602080910402602001604051908101604052809291908181526020018280546115ce9061436f565b801561161b5780601f106115f05761010080835404028352916020019161161b565b820191906000526020600020905b8154815290600101906020018083116115fe57829003601f168201915b505050505081565b6000808080808080803332146116745760405162461bcd60e51b81526020600482015260166024820152756f66662d636861696e2072656164696e67206f6e6c7960501b6044820152606401610b71565b63ffffffff8916156117595763ffffffff8916600090815260076020908152604080832060089092529091206116aa8c8c612b08565b6001600160a01b038d1660009081526006602052604090206001908101548482015491840154600b548f936001600160401b03169163ffffffff600160401b90910416906001600160801b0316611700600a5490565b60018901546001600160401b0316611723576002546001600160801b0316611739565b6001880154600160601b90046001600160801b03165b8363ffffffff169350995099509950995099509950995099505050611773565b6117628a612b72565b975097509750975097509750975097505b9295985092959890939650565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3360009081526009602052604081205460ff166118085760405162461bcd60e51b815260206004820152601860248201527f6e6f7420617574686f72697a65642072657175657374657200000000000000006044820152606401610b71565b60055463ffffffff16600081815260076020526040902060010154600160401b90046001600160401b0316151580611844575061184481612d40565b6118905760405162461bcd60e51b815260206004820152601f60248201527f7072657620726f756e64206d75737420626520737570657273656461626c65006044820152606401610b71565b600061189d82600161416a565b90506118a881612dbf565b63ffffffff1692915050565b63ffffffff80821660009081526007602090815260408083208151608081018352815481526001909101546001600160401b0380821694830194909452600160401b810490931691810191909152600160801b9091049092166060830181905290918291829182918291901580159061193d575069ffffffffffffffffffff871663ffffffff10155b6040518060400160405280600f81526020016e139bc819185d18481c1c995cd95b9d608a1b815250906119835760405162461bcd60e51b8152600401610b7191906140b3565b50805160208201516040830151606090930151989991986001600160401b0391821698509216955063ffffffff9091169350915050565b60006119ca8263ffffffff101590565b156119e8575063ffffffff1660009081526007602052604090205490565b506000919050565b6000611a008263ffffffff101590565b156119e8575063ffffffff16600090815260076020526040902060010154600160401b90046001600160401b031690565b600080516020614472833981519152611a4981611dc0565b600b546002546001600160801b03918216918491611a67911661262d565b611a7190836142f8565b1015611abf5760405162461bcd60e51b815260206004820152601a60248201527f696e73756666696369656e7420726573657276652066756e64730000000000006044820152606401610b71565b611ac98484612aa8565b610d496109a8565b600082815260208190526040902060010154611aec81611dc0565b610af283836125c8565b6001600160a01b03828116600090815260066020526040902060020154620100009004163314611b615760405162461bcd60e51b815260206004820152601660248201527537b7363c9031b0b63630b1363290313c9030b236b4b760511b6044820152606401610b71565b6001600160a01b0382811660008181526006602090815260409182902060030180546001600160a01b031916948616948517905581513381529081019390935290917fb79bf2e89c2d70dde91d2991fb1ea69b7e478061ad7c04ed5b02b96bc52b8104910160405180910390a25050565b6000806000806000611bfb600560049054906101000a900463ffffffff1663ffffffff166118b4565b945094509450945094509091929394565b6060610a6f6001600160a01b03831660145b60606000611c2d836002614272565b611c38906002614152565b6001600160401b03811115611c4f57611c4f61445b565b6040519080825280601f01601f191660200182016040528015611c79576020820181803683370190505b509050600360fc1b81600081518110611c9457611c94614445565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110611cc357611cc3614445565b60200101906001600160f81b031916908160001a9053506000611ce7846002614272565b611cf2906001614152565b90505b6001811115611d6a576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110611d2657611d26614445565b1a60f81b828281518110611d3c57611d3c614445565b60200101906001600160f81b031916908160001a90535060049490941c93611d6381614358565b9050611cf5565b508315611db95760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610b71565b9392505050565b611dca8133612e95565b50565b6001600160a01b03821660009081526006602052604090205460055460609163ffffffff600160801b9091048116911681611e3657604051806040016040528060128152602001716e6f7420656e61626c6564206f7261636c6560701b81525092505050610a6f565b8363ffffffff168263ffffffff161115611e8257604051806040016040528060168152602001756e6f742079657420656e61626c6564206f7261636c6560501b81525092505050610a6f565b6001600160a01b03851660009081526006602052604090205463ffffffff808616600160a01b909204161015611ef1576040518060400160405280601881526020017f6e6f206c6f6e67657220616c6c6f776564206f7261636c65000000000000000081525092505050610a6f565b6001600160a01b03851660009081526006602052604090205463ffffffff808616600160c01b9092041610611f5f576040518060400160405280602081526020017f63616e6e6f74207265706f7274206f6e2070726576696f757320726f756e647381525092505050610a6f565b8063ffffffff168463ffffffff1614158015611f915750611f8181600161416a565b63ffffffff168463ffffffff1614155b8015611fa45750611fa28482612eee565b155b15611fe8576040518060400160405280601781526020017f696e76616c696420726f756e6420746f207265706f727400000000000000000081525092505050610a6f565b8363ffffffff1660011415801561200f575061200d61200860018661430f565b612f3f565b155b15612053576040518060400160405280601f81526020017f70726576696f757320726f756e64206e6f7420737570657273656461626c650081525092505050610a6f565b505092915050565b61206481612f79565b61206b5750565b3360009081526006602052604090205460025463ffffffff600160e01b9092048216916120a091600160c01b90041682614152565b8263ffffffff16111580156120b457508015155b156120bd575050565b6120c682612fa5565b50336000908152600660205260409020805463ffffffff909216600160e01b026001600160e01b03909216919091179055565b63ffffffff808216600090815260086020526040902060010154166121605760405162461bcd60e51b815260206004820152601f60248201527f726f756e64206e6f7420616363657074696e67207375626d697373696f6e73006044820152606401610b71565b600554600160201b900463ffffffff1660009081526007602052604081205413156121f657600554600160201b900463ffffffff166000908152600760205260409020546121af9060026141ed565b8213156121f65760405162461bcd60e51b8152602060048201526015602482015274646966666572656e636520697320746f6f2062696760581b6044820152606401610b71565b63ffffffff8116600081815260086020908152604080832080546001808201835591855283852001879055338085526006909352818420805463ffffffff60c01b1916600160c01b8702178155018690555190929185917f92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c9190a45050565b63ffffffff80821660009081526008602052604081206001810154905491928392600160201b9092041611156122b057506000928392509050565b63ffffffff8316600090815260086020908152604080832080548251818502810185019093528083526123169383018282801561230c57602002820191906000526020600020905b8154815260200190600101908083116122f8575b505050505061312f565b63ffffffff851660008181526007602090815260409182902084815560010180546bffffffffffffffffffffffff60401b1916600160401b426001600160401b0381169190910263ffffffff60801b191691909117600160801b8602179091556005805467ffffffff000000001916600160201b86021790559151918252929350909183917f0559884fd3a460db3073b7fc896cc77986f16e378210ded43186175bf646fc5f910160405180910390a3600194909350915050565b63ffffffff8116600090815260086020908152604091829020600101548251808401909352600b546001600160801b03808216808652600160801b909204811693850193909352600160601b90910490911691906124309083906142d0565b6001600160801b03168152602081015161244b908390614127565b6001600160801b03908116602083810182905283518316600160801b90920291909117600b553360009081526006909152604090205461248d91849116614127565b3360009081526006602052604080822080546001600160801b0319166001600160801b03948516179055835190519216917ffe25c73e3b9089fac37d55c4c7efcba6f04af04cebd2fc4d6d7dbb07e1e5234f9190a2505050565b63ffffffff8082166000908152600860205260409020600181015490549116111561250f5750565b63ffffffff811660009081526008602052604081209061252f8282613bdf565b5060010180546001600160e01b031916905550565b61254e8282611780565b610a3a576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556125843390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6125d28282611780565b15610a3a576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000600261263a600a5490565b6126479060ff1684614272565b610a6f9190614272565b61265a816131ef565b61269b5760405162461bcd60e51b81526020600482015260126024820152711bdc9858db19481b9bdd08195b98589b195960721b6044820152606401610b71565b6005546126af9063ffffffff16600161416a565b6001600160a01b0382166000908152600660205260408120805463ffffffff93909316600160a01b0263ffffffff60a01b1990931692909217909155600a60016126f8600a5490565b60ff1661270591906142f8565b8154811061271557612715614445565b6000918252602080832091909101546001600160a01b0385811680855260069093526040808520600290810180549390941680875291862001805461ffff90931661ffff199384168117909155939094528154169055600a805492935090918391908390811061278757612787614445565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600a8054806127c6576127c661442f565b600082815260208120820160001990810180546001600160a01b03191690559091019091556040516001600160a01b038516907f18dd09695e4fbdae8d1a5edb11221eb04564269c29a089b9753a6535c54ba92e908390a3505050565b61282c826131ef565b156128725760405162461bcd60e51b81526020600482015260166024820152751bdc9858db1948185b1c9958591e48195b98589b195960521b6044820152606401610b71565b6001600160a01b0381166128c05760405162461bcd60e51b8152602060048201526015602482015274063616e6e6f74207365742061646d696e20746f203605c1b6044820152606401610b71565b6001600160a01b0382811660009081526006602052604090206002015462010000900416158061291557506001600160a01b038281166000908152600660205260409020600201546201000090048116908216145b6129615760405162461bcd60e51b815260206004820152601c60248201527f6f776e65722063616e6e6f74206f76657277726974652061646d696e000000006044820152606401610b71565b61296a8261321a565b6001600160a01b03838116600081815260066020526040808220805463ffffffff60a01b1963ffffffff97909716600160801b029690961667ffffffffffffffff60801b199096169590951763ffffffff60a01b178555600a80546002909601805461ffff90971661ffff19909716969096178655805460018181019092557fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a80180546001600160a01b031916851790558554948716620100000262010000600160b01b0319909516949094179094559251919290917f18dd09695e4fbdae8d1a5edb11221eb04564269c29a089b9753a6535c54ba92e9190a3806001600160a01b0316826001600160a01b03167f0c5055390645c15a4be9a21b3f8d019153dcb4a0c125685da6eb84048e2fe90460405160405180910390a35050565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612af5576040519150601f19603f3d011682016040523d82523d6000602084013e612afa565b606091505b5050905080610af257600080fd5b63ffffffff81166000908152600760205260408120600101546001600160401b031615612b685763ffffffff8083166000908152600860205260409020600101541615155b8015612b615750612b5e8383611dcd565b51155b9050610a6f565b612b4d8383613272565b6001600160a01b0381166000908152600660205260408120600554815483928392839283928392839283927f6d5257204ebe7d88fd91ae87941cb2dd9d8062b64ae5a2bd2d28ec40b9fbf6df929091849163ffffffff908116600160c01b909204161480612bfb575060055463ffffffff90811660009081526008602052604090206001015416155b600554909150612c109063ffffffff16612f3f565b8015612c195750805b15612c6d57600554612c329063ffffffff16600161416a565b63ffffffff81166000908152600760205260409020600254919b506001600160801b0390911694509250612c668c8b613272565b9a50612cb2565b60055463ffffffff9081166000818152600760209081526040808320600890925290912060010154919c50600160601b82046001600160801b0316965094501615159a505b612cbc8c8b611dcd565b5115612cc75760009a505b6001808301548482015463ffffffff808e16600090815260086020526040902090930154600b548f948f94936001600160401b031692600160401b900416906001600160801b0316612d18600a5490565b8a8363ffffffff1693509a509a509a509a509a509a509a509a50505050919395975091939597565b63ffffffff80821660009081526007602090815260408083206001908101546008909352908320015491926001600160401b0390911691600160401b9004168115801590612d94575060008163ffffffff16115b8015612db7575042612dac63ffffffff831684614189565b6001600160401b0316105b949350505050565b612dc881612f79565b612dcf5750565b3360009081526009602052604090205463ffffffff650100000000008204811691612e01916101009091041682614152565b8263ffffffff161180612e12575080155b612e545760405162461bcd60e51b81526020600482015260136024820152726d7573742064656c617920726571756573747360681b6044820152606401610b71565b612e5d82612fa5565b50336000908152600960205260409020805463ffffffff909216650100000000000268ffffffff000000000019909216919091179055565b612e9f8282611780565b610a3a57612eac81611c0c565b612eb7836020611c1e565b604051602001612ec8929190613ff1565b60408051601f198184030181529082905262461bcd60e51b8252610b71916004016140b3565b600063ffffffff8216612f0284600161416a565b63ffffffff16148015611db957505063ffffffff16600090815260076020526040902060010154600160401b90046001600160401b031615919050565b63ffffffff8116600090815260076020526040812060010154600160401b90046001600160401b0316151580610a6f5750610a6f82612d40565b600554600090612f909063ffffffff16600161416a565b63ffffffff168263ffffffff16149050919050565b612fb8612fb360018361430f565b6132c6565b6005805463ffffffff191663ffffffff83811691821790925560408051600060a0820181815260c0830184528252600254600160801b81048616602080850191909152600160a01b8204871684860152600160e01b820490961660608401526001600160801b0316608083015292835260088452912081518051929384936130439284920190613bfd565b506020828101516001928301805460408087015160608801516080909801516001600160801b0316600160601b026fffffffffffffffffffffffffffffffff60601b1963ffffffff998a16600160401b021668010000000000000000600160e01b0319928a16600160201b0267ffffffffffffffff19958616978b16979097179690961791909116949094179390931790915593861660008181526007845282902090930180546001600160401b0342169516851790555192835233927f0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271910160405180910390a35050565b6000815160001061317b5760405162461bcd60e51b81526020600482015260166024820152756c697374206d757374206e6f7420626520656d70747960501b6044820152606401610b71565b8151600061318a6002836141d9565b90506131976002836143d9565b6131d8576000806131bf86826131ae6001886142f8565b6131b96001886142f8565b87613389565b90925090506131ce8282613481565b9695505050505050565b612db78460006131e96001866142f8565b84613519565b6001600160a01b0316600090815260066020526040902054600160a01b900463ffffffff9081161490565b60055460009063ffffffff16801580159061325c57506001600160a01b03831660009081526006602052604090205463ffffffff828116600160a01b90920416145b156132675792915050565b611db981600161416a565b6001600160a01b03821660009081526006602052604081205460025463ffffffff600160e01b9092048216916132b091600160c01b90041682614152565b8363ffffffff161180612db75750159392505050565b6132cf81612d40565b6132d65750565b60006132e360018361430f565b63ffffffff818116600090815260076020908152604080832080548886168552828520908155600191820154910180546bffffffffffffffffffffffff60401b1916600160801b928390049096169091026fffffffffffffffff0000000000000000191694909417600160401b426001600160401b03160217909355600890529081209192506133738282613bdf565b5060010180546001600160e01b03191690555050565b60008082841061339857600080fd5b8386111580156133a85750848411155b6133b157600080fd5b8286111580156133c15750848311155b6133ca57600080fd5b60076133d687876142f8565b10156133f2576133e987878787876135be565b91509150613477565b60006133ff888888613a08565b905080841161341057809550613471565b8481101561342a57613423816001614152565b9650613471565b80851115801561343957508381105b613445576134456143ed565b61345188888388613519565b925061346988613462836001614152565b8887613519565b915050613477565b506133ca565b9550959350505050565b600080831280156134925750600082135b806134a857506000831380156134a85750600082125b156134c35760026134b98484613b38565b612b6191906141ab565b600060026134d181856143c5565b6134dc6002876143c5565b6134e691906140e6565b6134f091906141ab565b9050612db76135136135036002876141ab565b61350e6002876141ab565b613b38565b82613b38565b60008184111561352857600080fd5b8282111561353557600080fd5b8284101561359a57600761354985856142f8565b101561356857600061355e86868686876135be565b509150612db79050565b6000613575868686613a08565b905080831161358657809350613594565b613591816001614152565b94505b50613535565b8484815181106135ac576135ac614445565b60200260200101519050949350505050565b60008080866135ce876001614152565b6135d891906142f8565b90506000886135e78983614152565b815181106135f7576135f7614445565b60200260200101519050600082600110613618576001600160ff1b0361363d565b896136248a6001614152565b8151811061363457613634614445565b60200260200101515b9050600083600210613656576001600160ff1b0361367b565b8a6136628b6002614152565b8151811061367257613672614445565b60200260200101515b9050600084600310613694576001600160ff1b036136b9565b8b6136a08c6003614152565b815181106136b0576136b0614445565b60200260200101515b90506000856004106136d2576001600160ff1b036136f7565b8c6136de8d6004614152565b815181106136ee576136ee614445565b60200260200101515b9050600086600510613710576001600160ff1b03613735565b8d61371c8e6005614152565b8151811061372c5761372c614445565b60200260200101515b905060008760061061374e576001600160ff1b03613773565b8e61375a8f6006614152565b8151811061376a5761376a614445565b60200260200101515b905085871315613781579495945b8385131561378d579293925b81831315613799579091905b848713156137a5579395935b838613156137b1579294925b808313156137bb57915b848613156137c7579394935b808213156137d157905b828713156137dd579195915b818613156137e9579094905b808513156137f357935b828613156137ff579194915b8084131561380957925b82851315613815579193915b81841315613821579092905b8284131561382d579192915b60006138398f8e6142f8565b90508061384857879a506138e9565b806001141561385957869a506138e9565b806002141561386a57859a506138e9565b806003141561387b57849a506138e9565b806004141561388c57839a506138e9565b806005141561389d57829a506138e9565b80600614156138ae57819a506138e9565b60405162461bcd60e51b815260206004820152601060248201526f6b31206f7574206f6620626f756e647360801b6044820152606401610b71565b60008f8d6138f791906142f8565b90508c8e141561391457508a995061347798505050505050505050565b8061392b5750969850613477975050505050505050565b80600114156139465750959850613477975050505050505050565b80600214156139615750949850613477975050505050505050565b806003141561397c5750939850613477975050505050505050565b80600414156139975750929850613477975050505050505050565b80600514156139b25750919850613477975050505050505050565b80600614156139cd5750909850613477975050505050505050565b60405162461bcd60e51b815260206004820152601060248201526f6b32206f7574206f6620626f756e647360801b6044820152606401610b71565b600080846002613a188587614152565b613a2291906141d9565b81518110613a3257613a32614445565b60200260200101519050600184613a4991906142f8565b9350613a56600184614152565b92505b613a64600185614152565b935080858581518110613a7957613a79614445565b602002602001015112613a59575b613a926001846142f8565b925080858481518110613aa757613aa7614445565b602002602001015113613a875782841015613b2f57848381518110613ace57613ace614445565b6020026020010151858581518110613ae857613ae8614445565b6020026020010151868681518110613b0257613b02614445565b60200260200101878681518110613b1b57613b1b614445565b602090810291909101019190915252613a59565b50909392505050565b6000808212158015613b5a5750613b56826001600160ff1b03614291565b8313155b80613b7d5750600082128015613b7d5750613b7982600160ff1b614291565b8312155b613bd35760405162461bcd60e51b815260206004820152602160248201527f5369676e6564536166654d6174683a206164646974696f6e206f766572666c6f6044820152607760f81b6064820152608401610b71565b6000612db783856140e6565b5080546000825590600052602060002090810190611dca9190613c48565b828054828255906000526020600020908101928215613c38579160200282015b82811115613c38578251825591602001919060010190613c1d565b50613c44929150613c48565b5090565b5b80821115613c445760008155600101613c49565b80356001600160a01b0381168114613c7457600080fd5b919050565b60008083601f840112613c8b57600080fd5b5081356001600160401b03811115613ca257600080fd5b6020830191508360208260051b8501011115613cbd57600080fd5b9250929050565b803563ffffffff81168114613c7457600080fd5b600060208284031215613cea57600080fd5b611db982613c5d565b60008060408385031215613d0657600080fd5b613d0f83613c5d565b9150613d1d60208401613c5d565b90509250929050565b600080600060608486031215613d3b57600080fd5b613d4484613c5d565b9250613d5260208501613c5d565b9150604084013590509250925092565b600080600060608486031215613d7757600080fd5b613d8084613c5d565b925060208401358015158114613d9557600080fd5b9150613da360408501613cc4565b90509250925092565b60008060408385031215613dbf57600080fd5b613dc883613c5d565b946020939093013593505050565b60008060408385031215613de957600080fd5b613df283613c5d565b9150613d1d60208401613cc4565b600080600080600080600080600060c08a8c031215613e1e57600080fd5b89356001600160401b0380821115613e3557600080fd5b613e418d838e01613c79565b909b50995060208c0135915080821115613e5a57600080fd5b613e668d838e01613c79565b909950975060408c0135915080821115613e7f57600080fd5b50613e8c8c828d01613c79565b9096509450613e9f905060608b01613cc4565b9250613ead60808b01613cc4565b9150613ebb60a08b01613cc4565b90509295985092959850929598565b600060208284031215613edc57600080fd5b5035919050565b60008060408385031215613ef657600080fd5b82359150613d1d60208401613c5d565b600060208284031215613f1857600080fd5b81356001600160e01b031981168114611db957600080fd5b600080600080600060a08688031215613f4857600080fd5b85356001600160801b0381168114613f5f57600080fd5b9450613f6d60208701613cc4565b9350613f7b60408701613cc4565b9250613f8960608701613cc4565b9150613f9760808701613cc4565b90509295509295909350565b60008060408385031215613fb657600080fd5b50508035926020909101359150565b600060208284031215613fd757600080fd5b813569ffffffffffffffffffff81168114611db957600080fd5b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161402981601785016020880161432c565b7001034b99036b4b9b9b4b733903937b6329607d1b601791840191820152835161405a81602884016020880161432c565b01602801949350505050565b6020808252825182820181905260009190848201906040850190845b818110156140a75783516001600160a01b031683529284019291840191600101614082565b50909695505050505050565b60208152600082518060208401526140d281604085016020870161432c565b601f01601f19169190910160400192915050565b600080821280156001600160ff1b038490038513161561410857614108614403565b600160ff1b839003841281161561412157614121614403565b50500190565b60006001600160801b0380831681851680830382111561414957614149614403565b01949350505050565b6000821982111561416557614165614403565b500190565b600063ffffffff80831681851680830382111561414957614149614403565b60006001600160401b0380831681851680830382111561414957614149614403565b6000826141ba576141ba614419565b600160ff1b8214600019841416156141d4576141d4614403565b500590565b6000826141e8576141e8614419565b500490565b60006001600160ff1b038184138284138082168684048611161561421357614213614403565b600160ff1b600087128281168783058912161561423257614232614403565b6000871292508782058712848416161561424e5761424e614403565b8785058712818416161561426457614264614403565b505050929093029392505050565b600081600019048311821515161561428c5761428c614403565b500290565b60008083128015600160ff1b8501841216156142af576142af614403565b6001600160ff1b03840183138116156142ca576142ca614403565b50500390565b60006001600160801b03838116908316818110156142f0576142f0614403565b039392505050565b60008282101561430a5761430a614403565b500390565b600063ffffffff838116908316818110156142f0576142f0614403565b60005b8381101561434757818101518382015260200161432f565b83811115610d495750506000910152565b60008161436757614367614403565b506000190190565b600181811c9082168061438357607f821691505b602082108114156143a457634e487b7160e01b600052602260045260246000fd5b50919050565b60006000198214156143be576143be614403565b5060010190565b6000826143d4576143d4614419565b500790565b6000826143e8576143e8614419565b500690565b634e487b7160e01b600052600160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfea49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775a26469706673582212204eec107119481f1f7592d75f10a67dd69eefc6e01211e3f963ae657cafce919264736f6c63430008060033a49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775000000000000000000000000000000000000000000000000000009184e72a0000000000000000000000000000000000000000000000000000000000000000fa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008f0d180000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000145052494345204645454420546573742f54657374000000000000000000000000
Deployed ByteCode
0x60806040526004361061026b5760003560e01c806364efb22b11610144578063a217fddf116100b6578063c93745001161007a578063c9374500146108cb578063d4cc54e4146108ef578063d547741f14610914578063e2e4031714610934578063e9ee6eeb14610973578063feaf968c146109935761027a565b8063a217fddf14610836578063b5ab58dc1461084b578063b633620c1461086b578063c10753291461088b578063c35905c6146108ab5761027a565b80637c2b0b21116101085780637c2b0b211461069a5780638205bf6a146106ce57806388aa80e71461071257806391d148541461078f57806398e5b12a146107af5780639a6fc8f5146107df5761027a565b806364efb22b146105ce578063668a0f021461061057806370dea79a146106325780637284e4161461065657806375b238fc146106785761027a565b80633969c20f116101dd5780634f8fc3b5116101a15780634f8fc3b51461051a57806350d25bcd1461052f57806354fd4d501461056057806358609e4414610575578063613d8fcc14610599578063628806ef146105ae5761027a565b80633969c20f1461044e5780633a5381b51461046e5780633d3d7714146104a657806340884c52146104c657806346fcff4c146104e85761027a565b8063248a9ca31161022f578063248a9ca3146103595780632f2ff15d14610389578063313ce567146103a9578063357ebb02146103d557806336568abe1461040e57806338aa4c721461042e5761027a565b806301ffc9a7146102825780631327d3d8146102b7578063202ee0ed146102d757806320ed0275146102f757806323ca2903146103175761027a565b3661027a576102786109a8565b005b6102786109a8565b34801561028e57600080fd5b506102a261029d366004613f06565b610a3e565b60405190151581526020015b60405180910390f35b3480156102c357600080fd5b506102786102d2366004613cd8565b610a75565b3480156102e357600080fd5b506102786102f2366004613fa3565b610af7565b34801561030357600080fd5b50610278610312366004613d62565b610c49565b34801561032357600080fd5b5061034b7f0000000000000000000000000000000000000000000000000000000008f0d18081565b6040519081526020016102ae565b34801561036557600080fd5b5061034b610374366004613eca565b60009081526020819052604090206001015490565b34801561039557600080fd5b506102786103a4366004613ee3565b610d4f565b3480156103b557600080fd5b506003546103c39060ff1681565b60405160ff90911681526020016102ae565b3480156103e157600080fd5b506002546103f990600160c01b900463ffffffff1681565b60405163ffffffff90911681526020016102ae565b34801561041a57600080fd5b50610278610429366004613ee3565b610d74565b34801561043a57600080fd5b50610278610449366004613f30565b610dee565b34801561045a57600080fd5b50610278610469366004613e00565b61113a565b34801561047a57600080fd5b5060015461048e906001600160a01b031681565b6040516001600160a01b0390911681526020016102ae565b3480156104b257600080fd5b506102786104c1366004613d26565b6112f5565b3480156104d257600080fd5b506104db611452565b6040516102ae9190614066565b3480156104f457600080fd5b50600b546001600160801b03165b6040516001600160801b0390911681526020016102ae565b34801561052657600080fd5b506102786109a8565b34801561053b57600080fd5b50600554600160201b900463ffffffff1660009081526007602052604090205461034b565b34801561056c57600080fd5b5061034b600381565b34801561058157600080fd5b506002546103f990600160801b900463ffffffff1681565b3480156105a557600080fd5b50600a546103c3565b3480156105ba57600080fd5b506102786105c9366004613cd8565b6114b4565b3480156105da57600080fd5b5061048e6105e9366004613cd8565b6001600160a01b039081166000908152600660205260409020600201546201000090041690565b34801561061c57600080fd5b50600554600160201b900463ffffffff1661034b565b34801561063e57600080fd5b506002546103f990600160e01b900463ffffffff1681565b34801561066257600080fd5b5061066b611595565b6040516102ae91906140b3565b34801561068457600080fd5b5061034b60008051602061447283398151915281565b3480156106a657600080fd5b5061034b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156106da57600080fd5b50600554600160201b900463ffffffff16600090815260076020526040902060010154600160401b90046001600160401b031661034b565b34801561071e57600080fd5b5061073261072d366004613dd6565b611623565b60408051981515895263ffffffff9097166020890152958701949094526001600160401b039283166060870152911660808501526001600160801b0390811660a085015260ff90911660c08401521660e0820152610100016102ae565b34801561079b57600080fd5b506102a26107aa366004613ee3565b611780565b3480156107bb57600080fd5b506107c46117a9565b60405169ffffffffffffffffffff90911681526020016102ae565b3480156107eb57600080fd5b506107ff6107fa366004613fc5565b6118b4565b6040805169ffffffffffffffffffff968716815260208101959095528401929092526060830152909116608082015260a0016102ae565b34801561084257600080fd5b5061034b600081565b34801561085757600080fd5b5061034b610866366004613eca565b6119ba565b34801561087757600080fd5b5061034b610886366004613eca565b6119f0565b34801561089757600080fd5b506102786108a6366004613dac565b611a31565b3480156108b757600080fd5b50600254610502906001600160801b031681565b3480156108d757600080fd5b506002546103f990600160a01b900463ffffffff1681565b3480156108fb57600080fd5b50600b54600160801b90046001600160801b0316610502565b34801561092057600080fd5b5061027861092f366004613ee3565b611ad1565b34801561094057600080fd5b5061034b61094f366004613cd8565b6001600160a01b03166000908152600660205260409020546001600160801b031690565b34801561097f57600080fd5b5061027861098e366004613cf3565b611af6565b34801561099f57600080fd5b506107ff611bd2565b60408051808201909152600b546001600160801b038082168352600160801b90910416602082018190526000906109df90476142f8565b82519091506001600160801b03168114610a3a57600b80546001600160801b0319166001600160801b03831617905560405181907ffe25c73e3b9089fac37d55c4c7efcba6f04af04cebd2fc4d6d7dbb07e1e5234f90600090a25b5050565b60006001600160e01b03198216637965db0b60e01b1480610a6f57506301ffc9a760e01b6001600160e01b03198316145b92915050565b600080516020614472833981519152610a8d81611dc0565b6001546001600160a01b039081169083168114610af257600180546001600160a01b0319166001600160a01b0385811691821790925560405190918316907fcfac5dc75b8d9a7e074162f59d9adcd33da59f0fe8dfb21580db298fc0fdad0d90600090a35b505050565b6000610b033384611dcd565b90507f0000000000000000000000000000000000000000000000000000000000000000821215610b7a5760405162461bcd60e51b815260206004820152601e60248201527f76616c75652062656c6f77206d696e5375626d697373696f6e56616c7565000060448201526064015b60405180910390fd5b7f0000000000000000000000000000000000000000000000000000000008f0d180821315610bea5760405162461bcd60e51b815260206004820152601e60248201527f76616c75652061626f7665206d61785375626d697373696f6e56616c756500006044820152606401610b71565b8051819015610c0c5760405162461bcd60e51b8152600401610b7191906140b3565b50610c168361205b565b610c2082846120f9565b600080610c2c85612275565b91509150610c39856123d1565b610c42856124e7565b5050505050565b600080516020614472833981519152610c6181611dc0565b6001600160a01b03841660009081526009602052604090205460ff1615158315151415610c8d57610d49565b8215610cd4576001600160a01b0384166000908152600960205260409020805464ffffffffff191684151564ffffffff0019161761010063ffffffff851602179055610cfd565b6001600160a01b0384166000908152600960205260409020805468ffffffffffffffffff191690555b60408051841515815263ffffffff841660208201526001600160a01b038616917fc3df5a754e002718f2e10804b99e6605e7c701d95cec9552c7680ca2b6f2820a910160405180910390a25b50505050565b600082815260208190526040902060010154610d6a81611dc0565b610af28383612544565b6001600160a01b0381163314610de45760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610b71565b610a3a82826125c8565b600080516020614472833981519152610e0681611dc0565b6000610e11600a5490565b60ff1690508563ffffffff168563ffffffff161015610e725760405162461bcd60e51b815260206004820152601960248201527f6d6178206d75737420657175616c2f657863656564206d696e000000000000006044820152606401610b71565b8463ffffffff168163ffffffff161015610ece5760405162461bcd60e51b815260206004820152601760248201527f6d61782063616e6e6f742065786365656420746f74616c0000000000000000006044820152606401610b71565b63ffffffff81161580610eec57508363ffffffff168163ffffffff16115b610f385760405162461bcd60e51b815260206004820152601960248201527f64656c61792063616e6e6f742065786365656420746f74616c000000000000006044820152606401610b71565b610f4a876001600160801b031661262d565b600b546001600160801b03161015610fa45760405162461bcd60e51b815260206004820152601e60248201527f696e73756666696369656e742066756e647320666f72207061796d656e7400006044820152606401610b71565b6000610faf600a5490565b60ff16111561100e5760008663ffffffff161161100e5760405162461bcd60e51b815260206004820152601a60248201527f6d696e206d7573742062652067726561746572207468616e20300000000000006044820152606401610b71565b86600260006101000a8154816001600160801b0302191690836001600160801b0316021790555085600260146101000a81548163ffffffff021916908363ffffffff16021790555084600260106101000a81548163ffffffff021916908363ffffffff16021790555083600260186101000a81548163ffffffff021916908363ffffffff160217905550826002601c6101000a81548163ffffffff021916908363ffffffff1602179055508463ffffffff168663ffffffff16600260009054906101000a90046001600160801b03166001600160801b03167f56800c9d1ed723511246614d15e58cfcde15b6a33c245b5c961b689c1890fd8f878760405161112992919063ffffffff92831681529116602082015260400190565b60405180910390a450505050505050565b60008051602061447283398151915261115281611dc0565b60005b8981101561119e5761118c8b8b8381811061117257611172614445565b90506020020160208101906111879190613cd8565b612651565b80611196816143aa565b915050611155565b508685146111ee5760405162461bcd60e51b815260206004820181905260248201527f6e6565642073616d65206f7261636c6520616e642061646d696e20636f756e746044820152606401610b71565b604d876111fa600a5490565b60ff166112079190614152565b111561124b5760405162461bcd60e51b81526020600482015260136024820152721b585e081bdc9858db195cc8185b1b1bddd959606a1b6044820152606401610b71565b60005b878110156112be576112ac89898381811061126b5761126b614445565b90506020020160208101906112809190613cd8565b88888481811061129257611292614445565b90506020020160208101906112a79190613cd8565b612823565b806112b6816143aa565b91505061124e565b506002546112e9906001600160801b03811690869086908690600160e01b900463ffffffff16610dee565b50505050505050505050565b6001600160a01b038381166000908152600660205260409020600201546201000090041633146113605760405162461bcd60e51b815260206004820152601660248201527537b7363c9031b0b63630b1363290313c9030b236b4b760511b6044820152606401610b71565b6001600160a01b03831660009081526006602052604090205481906001600160801b039081169082168110156113d85760405162461bcd60e51b815260206004820152601f60248201527f696e73756666696369656e7420776974686472617761626c652066756e6473006044820152606401610b71565b6113e282826142d0565b6001600160a01b038616600090815260066020526040902080546001600160801b0319166001600160801b03928316179055600b5461142a918491600160801b9004166142d0565b600b80546001600160801b03928316600160801b02908316179055610c429085908416612aa8565b6060600a8054806020026020016040519081016040528092919081815260200182805480156114aa57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161148c575b5050505050905090565b6001600160a01b038181166000908152600660205260409020600301541633146115205760405162461bcd60e51b815260206004820152601e60248201527f6f6e6c792063616c6c61626c652062792070656e64696e672061646d696e00006044820152606401610b71565b6001600160a01b0381166000818152600660205260408082206003810180546001600160a01b0319169055600201805462010000600160b01b031916336201000081029190911790915590519092917f0c5055390645c15a4be9a21b3f8d019153dcb4a0c125685da6eb84048e2fe90491a350565b600480546115a29061436f565b80601f01602080910402602001604051908101604052809291908181526020018280546115ce9061436f565b801561161b5780601f106115f05761010080835404028352916020019161161b565b820191906000526020600020905b8154815290600101906020018083116115fe57829003601f168201915b505050505081565b6000808080808080803332146116745760405162461bcd60e51b81526020600482015260166024820152756f66662d636861696e2072656164696e67206f6e6c7960501b6044820152606401610b71565b63ffffffff8916156117595763ffffffff8916600090815260076020908152604080832060089092529091206116aa8c8c612b08565b6001600160a01b038d1660009081526006602052604090206001908101548482015491840154600b548f936001600160401b03169163ffffffff600160401b90910416906001600160801b0316611700600a5490565b60018901546001600160401b0316611723576002546001600160801b0316611739565b6001880154600160601b90046001600160801b03165b8363ffffffff169350995099509950995099509950995099505050611773565b6117628a612b72565b975097509750975097509750975097505b9295985092959890939650565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3360009081526009602052604081205460ff166118085760405162461bcd60e51b815260206004820152601860248201527f6e6f7420617574686f72697a65642072657175657374657200000000000000006044820152606401610b71565b60055463ffffffff16600081815260076020526040902060010154600160401b90046001600160401b0316151580611844575061184481612d40565b6118905760405162461bcd60e51b815260206004820152601f60248201527f7072657620726f756e64206d75737420626520737570657273656461626c65006044820152606401610b71565b600061189d82600161416a565b90506118a881612dbf565b63ffffffff1692915050565b63ffffffff80821660009081526007602090815260408083208151608081018352815481526001909101546001600160401b0380821694830194909452600160401b810490931691810191909152600160801b9091049092166060830181905290918291829182918291901580159061193d575069ffffffffffffffffffff871663ffffffff10155b6040518060400160405280600f81526020016e139bc819185d18481c1c995cd95b9d608a1b815250906119835760405162461bcd60e51b8152600401610b7191906140b3565b50805160208201516040830151606090930151989991986001600160401b0391821698509216955063ffffffff9091169350915050565b60006119ca8263ffffffff101590565b156119e8575063ffffffff1660009081526007602052604090205490565b506000919050565b6000611a008263ffffffff101590565b156119e8575063ffffffff16600090815260076020526040902060010154600160401b90046001600160401b031690565b600080516020614472833981519152611a4981611dc0565b600b546002546001600160801b03918216918491611a67911661262d565b611a7190836142f8565b1015611abf5760405162461bcd60e51b815260206004820152601a60248201527f696e73756666696369656e7420726573657276652066756e64730000000000006044820152606401610b71565b611ac98484612aa8565b610d496109a8565b600082815260208190526040902060010154611aec81611dc0565b610af283836125c8565b6001600160a01b03828116600090815260066020526040902060020154620100009004163314611b615760405162461bcd60e51b815260206004820152601660248201527537b7363c9031b0b63630b1363290313c9030b236b4b760511b6044820152606401610b71565b6001600160a01b0382811660008181526006602090815260409182902060030180546001600160a01b031916948616948517905581513381529081019390935290917fb79bf2e89c2d70dde91d2991fb1ea69b7e478061ad7c04ed5b02b96bc52b8104910160405180910390a25050565b6000806000806000611bfb600560049054906101000a900463ffffffff1663ffffffff166118b4565b945094509450945094509091929394565b6060610a6f6001600160a01b03831660145b60606000611c2d836002614272565b611c38906002614152565b6001600160401b03811115611c4f57611c4f61445b565b6040519080825280601f01601f191660200182016040528015611c79576020820181803683370190505b509050600360fc1b81600081518110611c9457611c94614445565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110611cc357611cc3614445565b60200101906001600160f81b031916908160001a9053506000611ce7846002614272565b611cf2906001614152565b90505b6001811115611d6a576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110611d2657611d26614445565b1a60f81b828281518110611d3c57611d3c614445565b60200101906001600160f81b031916908160001a90535060049490941c93611d6381614358565b9050611cf5565b508315611db95760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610b71565b9392505050565b611dca8133612e95565b50565b6001600160a01b03821660009081526006602052604090205460055460609163ffffffff600160801b9091048116911681611e3657604051806040016040528060128152602001716e6f7420656e61626c6564206f7261636c6560701b81525092505050610a6f565b8363ffffffff168263ffffffff161115611e8257604051806040016040528060168152602001756e6f742079657420656e61626c6564206f7261636c6560501b81525092505050610a6f565b6001600160a01b03851660009081526006602052604090205463ffffffff808616600160a01b909204161015611ef1576040518060400160405280601881526020017f6e6f206c6f6e67657220616c6c6f776564206f7261636c65000000000000000081525092505050610a6f565b6001600160a01b03851660009081526006602052604090205463ffffffff808616600160c01b9092041610611f5f576040518060400160405280602081526020017f63616e6e6f74207265706f7274206f6e2070726576696f757320726f756e647381525092505050610a6f565b8063ffffffff168463ffffffff1614158015611f915750611f8181600161416a565b63ffffffff168463ffffffff1614155b8015611fa45750611fa28482612eee565b155b15611fe8576040518060400160405280601781526020017f696e76616c696420726f756e6420746f207265706f727400000000000000000081525092505050610a6f565b8363ffffffff1660011415801561200f575061200d61200860018661430f565b612f3f565b155b15612053576040518060400160405280601f81526020017f70726576696f757320726f756e64206e6f7420737570657273656461626c650081525092505050610a6f565b505092915050565b61206481612f79565b61206b5750565b3360009081526006602052604090205460025463ffffffff600160e01b9092048216916120a091600160c01b90041682614152565b8263ffffffff16111580156120b457508015155b156120bd575050565b6120c682612fa5565b50336000908152600660205260409020805463ffffffff909216600160e01b026001600160e01b03909216919091179055565b63ffffffff808216600090815260086020526040902060010154166121605760405162461bcd60e51b815260206004820152601f60248201527f726f756e64206e6f7420616363657074696e67207375626d697373696f6e73006044820152606401610b71565b600554600160201b900463ffffffff1660009081526007602052604081205413156121f657600554600160201b900463ffffffff166000908152600760205260409020546121af9060026141ed565b8213156121f65760405162461bcd60e51b8152602060048201526015602482015274646966666572656e636520697320746f6f2062696760581b6044820152606401610b71565b63ffffffff8116600081815260086020908152604080832080546001808201835591855283852001879055338085526006909352818420805463ffffffff60c01b1916600160c01b8702178155018690555190929185917f92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c9190a45050565b63ffffffff80821660009081526008602052604081206001810154905491928392600160201b9092041611156122b057506000928392509050565b63ffffffff8316600090815260086020908152604080832080548251818502810185019093528083526123169383018282801561230c57602002820191906000526020600020905b8154815260200190600101908083116122f8575b505050505061312f565b63ffffffff851660008181526007602090815260409182902084815560010180546bffffffffffffffffffffffff60401b1916600160401b426001600160401b0381169190910263ffffffff60801b191691909117600160801b8602179091556005805467ffffffff000000001916600160201b86021790559151918252929350909183917f0559884fd3a460db3073b7fc896cc77986f16e378210ded43186175bf646fc5f910160405180910390a3600194909350915050565b63ffffffff8116600090815260086020908152604091829020600101548251808401909352600b546001600160801b03808216808652600160801b909204811693850193909352600160601b90910490911691906124309083906142d0565b6001600160801b03168152602081015161244b908390614127565b6001600160801b03908116602083810182905283518316600160801b90920291909117600b553360009081526006909152604090205461248d91849116614127565b3360009081526006602052604080822080546001600160801b0319166001600160801b03948516179055835190519216917ffe25c73e3b9089fac37d55c4c7efcba6f04af04cebd2fc4d6d7dbb07e1e5234f9190a2505050565b63ffffffff8082166000908152600860205260409020600181015490549116111561250f5750565b63ffffffff811660009081526008602052604081209061252f8282613bdf565b5060010180546001600160e01b031916905550565b61254e8282611780565b610a3a576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556125843390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6125d28282611780565b15610a3a576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000600261263a600a5490565b6126479060ff1684614272565b610a6f9190614272565b61265a816131ef565b61269b5760405162461bcd60e51b81526020600482015260126024820152711bdc9858db19481b9bdd08195b98589b195960721b6044820152606401610b71565b6005546126af9063ffffffff16600161416a565b6001600160a01b0382166000908152600660205260408120805463ffffffff93909316600160a01b0263ffffffff60a01b1990931692909217909155600a60016126f8600a5490565b60ff1661270591906142f8565b8154811061271557612715614445565b6000918252602080832091909101546001600160a01b0385811680855260069093526040808520600290810180549390941680875291862001805461ffff90931661ffff199384168117909155939094528154169055600a805492935090918391908390811061278757612787614445565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600a8054806127c6576127c661442f565b600082815260208120820160001990810180546001600160a01b03191690559091019091556040516001600160a01b038516907f18dd09695e4fbdae8d1a5edb11221eb04564269c29a089b9753a6535c54ba92e908390a3505050565b61282c826131ef565b156128725760405162461bcd60e51b81526020600482015260166024820152751bdc9858db1948185b1c9958591e48195b98589b195960521b6044820152606401610b71565b6001600160a01b0381166128c05760405162461bcd60e51b8152602060048201526015602482015274063616e6e6f74207365742061646d696e20746f203605c1b6044820152606401610b71565b6001600160a01b0382811660009081526006602052604090206002015462010000900416158061291557506001600160a01b038281166000908152600660205260409020600201546201000090048116908216145b6129615760405162461bcd60e51b815260206004820152601c60248201527f6f776e65722063616e6e6f74206f76657277726974652061646d696e000000006044820152606401610b71565b61296a8261321a565b6001600160a01b03838116600081815260066020526040808220805463ffffffff60a01b1963ffffffff97909716600160801b029690961667ffffffffffffffff60801b199096169590951763ffffffff60a01b178555600a80546002909601805461ffff90971661ffff19909716969096178655805460018181019092557fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a80180546001600160a01b031916851790558554948716620100000262010000600160b01b0319909516949094179094559251919290917f18dd09695e4fbdae8d1a5edb11221eb04564269c29a089b9753a6535c54ba92e9190a3806001600160a01b0316826001600160a01b03167f0c5055390645c15a4be9a21b3f8d019153dcb4a0c125685da6eb84048e2fe90460405160405180910390a35050565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612af5576040519150601f19603f3d011682016040523d82523d6000602084013e612afa565b606091505b5050905080610af257600080fd5b63ffffffff81166000908152600760205260408120600101546001600160401b031615612b685763ffffffff8083166000908152600860205260409020600101541615155b8015612b615750612b5e8383611dcd565b51155b9050610a6f565b612b4d8383613272565b6001600160a01b0381166000908152600660205260408120600554815483928392839283928392839283927f6d5257204ebe7d88fd91ae87941cb2dd9d8062b64ae5a2bd2d28ec40b9fbf6df929091849163ffffffff908116600160c01b909204161480612bfb575060055463ffffffff90811660009081526008602052604090206001015416155b600554909150612c109063ffffffff16612f3f565b8015612c195750805b15612c6d57600554612c329063ffffffff16600161416a565b63ffffffff81166000908152600760205260409020600254919b506001600160801b0390911694509250612c668c8b613272565b9a50612cb2565b60055463ffffffff9081166000818152600760209081526040808320600890925290912060010154919c50600160601b82046001600160801b0316965094501615159a505b612cbc8c8b611dcd565b5115612cc75760009a505b6001808301548482015463ffffffff808e16600090815260086020526040902090930154600b548f948f94936001600160401b031692600160401b900416906001600160801b0316612d18600a5490565b8a8363ffffffff1693509a509a509a509a509a509a509a509a50505050919395975091939597565b63ffffffff80821660009081526007602090815260408083206001908101546008909352908320015491926001600160401b0390911691600160401b9004168115801590612d94575060008163ffffffff16115b8015612db7575042612dac63ffffffff831684614189565b6001600160401b0316105b949350505050565b612dc881612f79565b612dcf5750565b3360009081526009602052604090205463ffffffff650100000000008204811691612e01916101009091041682614152565b8263ffffffff161180612e12575080155b612e545760405162461bcd60e51b81526020600482015260136024820152726d7573742064656c617920726571756573747360681b6044820152606401610b71565b612e5d82612fa5565b50336000908152600960205260409020805463ffffffff909216650100000000000268ffffffff000000000019909216919091179055565b612e9f8282611780565b610a3a57612eac81611c0c565b612eb7836020611c1e565b604051602001612ec8929190613ff1565b60408051601f198184030181529082905262461bcd60e51b8252610b71916004016140b3565b600063ffffffff8216612f0284600161416a565b63ffffffff16148015611db957505063ffffffff16600090815260076020526040902060010154600160401b90046001600160401b031615919050565b63ffffffff8116600090815260076020526040812060010154600160401b90046001600160401b0316151580610a6f5750610a6f82612d40565b600554600090612f909063ffffffff16600161416a565b63ffffffff168263ffffffff16149050919050565b612fb8612fb360018361430f565b6132c6565b6005805463ffffffff191663ffffffff83811691821790925560408051600060a0820181815260c0830184528252600254600160801b81048616602080850191909152600160a01b8204871684860152600160e01b820490961660608401526001600160801b0316608083015292835260088452912081518051929384936130439284920190613bfd565b506020828101516001928301805460408087015160608801516080909801516001600160801b0316600160601b026fffffffffffffffffffffffffffffffff60601b1963ffffffff998a16600160401b021668010000000000000000600160e01b0319928a16600160201b0267ffffffffffffffff19958616978b16979097179690961791909116949094179390931790915593861660008181526007845282902090930180546001600160401b0342169516851790555192835233927f0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271910160405180910390a35050565b6000815160001061317b5760405162461bcd60e51b81526020600482015260166024820152756c697374206d757374206e6f7420626520656d70747960501b6044820152606401610b71565b8151600061318a6002836141d9565b90506131976002836143d9565b6131d8576000806131bf86826131ae6001886142f8565b6131b96001886142f8565b87613389565b90925090506131ce8282613481565b9695505050505050565b612db78460006131e96001866142f8565b84613519565b6001600160a01b0316600090815260066020526040902054600160a01b900463ffffffff9081161490565b60055460009063ffffffff16801580159061325c57506001600160a01b03831660009081526006602052604090205463ffffffff828116600160a01b90920416145b156132675792915050565b611db981600161416a565b6001600160a01b03821660009081526006602052604081205460025463ffffffff600160e01b9092048216916132b091600160c01b90041682614152565b8363ffffffff161180612db75750159392505050565b6132cf81612d40565b6132d65750565b60006132e360018361430f565b63ffffffff818116600090815260076020908152604080832080548886168552828520908155600191820154910180546bffffffffffffffffffffffff60401b1916600160801b928390049096169091026fffffffffffffffff0000000000000000191694909417600160401b426001600160401b03160217909355600890529081209192506133738282613bdf565b5060010180546001600160e01b03191690555050565b60008082841061339857600080fd5b8386111580156133a85750848411155b6133b157600080fd5b8286111580156133c15750848311155b6133ca57600080fd5b60076133d687876142f8565b10156133f2576133e987878787876135be565b91509150613477565b60006133ff888888613a08565b905080841161341057809550613471565b8481101561342a57613423816001614152565b9650613471565b80851115801561343957508381105b613445576134456143ed565b61345188888388613519565b925061346988613462836001614152565b8887613519565b915050613477565b506133ca565b9550959350505050565b600080831280156134925750600082135b806134a857506000831380156134a85750600082125b156134c35760026134b98484613b38565b612b6191906141ab565b600060026134d181856143c5565b6134dc6002876143c5565b6134e691906140e6565b6134f091906141ab565b9050612db76135136135036002876141ab565b61350e6002876141ab565b613b38565b82613b38565b60008184111561352857600080fd5b8282111561353557600080fd5b8284101561359a57600761354985856142f8565b101561356857600061355e86868686876135be565b509150612db79050565b6000613575868686613a08565b905080831161358657809350613594565b613591816001614152565b94505b50613535565b8484815181106135ac576135ac614445565b60200260200101519050949350505050565b60008080866135ce876001614152565b6135d891906142f8565b90506000886135e78983614152565b815181106135f7576135f7614445565b60200260200101519050600082600110613618576001600160ff1b0361363d565b896136248a6001614152565b8151811061363457613634614445565b60200260200101515b9050600083600210613656576001600160ff1b0361367b565b8a6136628b6002614152565b8151811061367257613672614445565b60200260200101515b9050600084600310613694576001600160ff1b036136b9565b8b6136a08c6003614152565b815181106136b0576136b0614445565b60200260200101515b90506000856004106136d2576001600160ff1b036136f7565b8c6136de8d6004614152565b815181106136ee576136ee614445565b60200260200101515b9050600086600510613710576001600160ff1b03613735565b8d61371c8e6005614152565b8151811061372c5761372c614445565b60200260200101515b905060008760061061374e576001600160ff1b03613773565b8e61375a8f6006614152565b8151811061376a5761376a614445565b60200260200101515b905085871315613781579495945b8385131561378d579293925b81831315613799579091905b848713156137a5579395935b838613156137b1579294925b808313156137bb57915b848613156137c7579394935b808213156137d157905b828713156137dd579195915b818613156137e9579094905b808513156137f357935b828613156137ff579194915b8084131561380957925b82851315613815579193915b81841315613821579092905b8284131561382d579192915b60006138398f8e6142f8565b90508061384857879a506138e9565b806001141561385957869a506138e9565b806002141561386a57859a506138e9565b806003141561387b57849a506138e9565b806004141561388c57839a506138e9565b806005141561389d57829a506138e9565b80600614156138ae57819a506138e9565b60405162461bcd60e51b815260206004820152601060248201526f6b31206f7574206f6620626f756e647360801b6044820152606401610b71565b60008f8d6138f791906142f8565b90508c8e141561391457508a995061347798505050505050505050565b8061392b5750969850613477975050505050505050565b80600114156139465750959850613477975050505050505050565b80600214156139615750949850613477975050505050505050565b806003141561397c5750939850613477975050505050505050565b80600414156139975750929850613477975050505050505050565b80600514156139b25750919850613477975050505050505050565b80600614156139cd5750909850613477975050505050505050565b60405162461bcd60e51b815260206004820152601060248201526f6b32206f7574206f6620626f756e647360801b6044820152606401610b71565b600080846002613a188587614152565b613a2291906141d9565b81518110613a3257613a32614445565b60200260200101519050600184613a4991906142f8565b9350613a56600184614152565b92505b613a64600185614152565b935080858581518110613a7957613a79614445565b602002602001015112613a59575b613a926001846142f8565b925080858481518110613aa757613aa7614445565b602002602001015113613a875782841015613b2f57848381518110613ace57613ace614445565b6020026020010151858581518110613ae857613ae8614445565b6020026020010151868681518110613b0257613b02614445565b60200260200101878681518110613b1b57613b1b614445565b602090810291909101019190915252613a59565b50909392505050565b6000808212158015613b5a5750613b56826001600160ff1b03614291565b8313155b80613b7d5750600082128015613b7d5750613b7982600160ff1b614291565b8312155b613bd35760405162461bcd60e51b815260206004820152602160248201527f5369676e6564536166654d6174683a206164646974696f6e206f766572666c6f6044820152607760f81b6064820152608401610b71565b6000612db783856140e6565b5080546000825590600052602060002090810190611dca9190613c48565b828054828255906000526020600020908101928215613c38579160200282015b82811115613c38578251825591602001919060010190613c1d565b50613c44929150613c48565b5090565b5b80821115613c445760008155600101613c49565b80356001600160a01b0381168114613c7457600080fd5b919050565b60008083601f840112613c8b57600080fd5b5081356001600160401b03811115613ca257600080fd5b6020830191508360208260051b8501011115613cbd57600080fd5b9250929050565b803563ffffffff81168114613c7457600080fd5b600060208284031215613cea57600080fd5b611db982613c5d565b60008060408385031215613d0657600080fd5b613d0f83613c5d565b9150613d1d60208401613c5d565b90509250929050565b600080600060608486031215613d3b57600080fd5b613d4484613c5d565b9250613d5260208501613c5d565b9150604084013590509250925092565b600080600060608486031215613d7757600080fd5b613d8084613c5d565b925060208401358015158114613d9557600080fd5b9150613da360408501613cc4565b90509250925092565b60008060408385031215613dbf57600080fd5b613dc883613c5d565b946020939093013593505050565b60008060408385031215613de957600080fd5b613df283613c5d565b9150613d1d60208401613cc4565b600080600080600080600080600060c08a8c031215613e1e57600080fd5b89356001600160401b0380821115613e3557600080fd5b613e418d838e01613c79565b909b50995060208c0135915080821115613e5a57600080fd5b613e668d838e01613c79565b909950975060408c0135915080821115613e7f57600080fd5b50613e8c8c828d01613c79565b9096509450613e9f905060608b01613cc4565b9250613ead60808b01613cc4565b9150613ebb60a08b01613cc4565b90509295985092959850929598565b600060208284031215613edc57600080fd5b5035919050565b60008060408385031215613ef657600080fd5b82359150613d1d60208401613c5d565b600060208284031215613f1857600080fd5b81356001600160e01b031981168114611db957600080fd5b600080600080600060a08688031215613f4857600080fd5b85356001600160801b0381168114613f5f57600080fd5b9450613f6d60208701613cc4565b9350613f7b60408701613cc4565b9250613f8960608701613cc4565b9150613f9760808701613cc4565b90509295509295909350565b60008060408385031215613fb657600080fd5b50508035926020909101359150565b600060208284031215613fd757600080fd5b813569ffffffffffffffffffff81168114611db957600080fd5b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161402981601785016020880161432c565b7001034b99036b4b9b9b4b733903937b6329607d1b601791840191820152835161405a81602884016020880161432c565b01602801949350505050565b6020808252825182820181905260009190848201906040850190845b818110156140a75783516001600160a01b031683529284019291840191600101614082565b50909695505050505050565b60208152600082518060208401526140d281604085016020870161432c565b601f01601f19169190910160400192915050565b600080821280156001600160ff1b038490038513161561410857614108614403565b600160ff1b839003841281161561412157614121614403565b50500190565b60006001600160801b0380831681851680830382111561414957614149614403565b01949350505050565b6000821982111561416557614165614403565b500190565b600063ffffffff80831681851680830382111561414957614149614403565b60006001600160401b0380831681851680830382111561414957614149614403565b6000826141ba576141ba614419565b600160ff1b8214600019841416156141d4576141d4614403565b500590565b6000826141e8576141e8614419565b500490565b60006001600160ff1b038184138284138082168684048611161561421357614213614403565b600160ff1b600087128281168783058912161561423257614232614403565b6000871292508782058712848416161561424e5761424e614403565b8785058712818416161561426457614264614403565b505050929093029392505050565b600081600019048311821515161561428c5761428c614403565b500290565b60008083128015600160ff1b8501841216156142af576142af614403565b6001600160ff1b03840183138116156142ca576142ca614403565b50500390565b60006001600160801b03838116908316818110156142f0576142f0614403565b039392505050565b60008282101561430a5761430a614403565b500390565b600063ffffffff838116908316818110156142f0576142f0614403565b60005b8381101561434757818101518382015260200161432f565b83811115610d495750506000910152565b60008161436757614367614403565b506000190190565b600181811c9082168061438357607f821691505b602082108114156143a457634e487b7160e01b600052602260045260246000fd5b50919050565b60006000198214156143be576143be614403565b5060010190565b6000826143d4576143d4614419565b500790565b6000826143e8576143e8614419565b500690565b634e487b7160e01b600052600160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfea49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775a26469706673582212204eec107119481f1f7592d75f10a67dd69eefc6e01211e3f963ae657cafce919264736f6c63430008060033