Source Code
Overview
ETH Balance
0 ETH
Token Holdings
More Info
ContractCreator
Multichain Info
N/A
Loading...
Loading
Contract Name:
AccessControlledOCR2Aggregator
Compiler Version
v0.8.19+commit.7dd6d404
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./OCR2Aggregator.sol"; import "./SimpleReadAccessController.sol"; /** * @notice Wrapper of OCR2Aggregator which checks read access on Aggregator-interface methods */ contract AccessControlledOCR2Aggregator is OCR2Aggregator, SimpleReadAccessController { constructor( LinkTokenInterface _link, int192 _minAnswer, int192 _maxAnswer, AccessControllerInterface _billingAccessController, AccessControllerInterface _requesterAccessController, uint8 _decimals, string memory description ) OCR2Aggregator( _link, _minAnswer, _maxAnswer, _billingAccessController, _requesterAccessController, _decimals, description ) { } /* * Versioning */ function typeAndVersion() external override pure virtual returns (string memory) { return "AccessControlledOCR2Aggregator 1.0.0-alpha"; } /* * v2 Aggregator interface */ /// @inheritdoc OCR2Aggregator function latestAnswer() public override view checkAccess() returns (int256) { return super.latestAnswer(); } /// @inheritdoc OCR2Aggregator function latestTimestamp() public override view checkAccess() returns (uint256) { return super.latestTimestamp(); } /// @inheritdoc OCR2Aggregator function latestRound() public override view checkAccess() returns (uint256) { return super.latestRound(); } /// @inheritdoc OCR2Aggregator function getAnswer(uint256 _roundId) public override view checkAccess() returns (int256) { return super.getAnswer(_roundId); } /// @inheritdoc OCR2Aggregator function getTimestamp(uint256 _roundId) public override view checkAccess() returns (uint256) { return super.getTimestamp(_roundId); } /* * v3 Aggregator interface */ /// @inheritdoc OCR2Aggregator function description() public override view checkAccess() returns (string memory) { return super.description(); } /// @inheritdoc OCR2Aggregator function getRoundData(uint80 _roundId) public override view checkAccess() returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ) { return super.getRoundData(_roundId); } /// @inheritdoc OCR2Aggregator function latestRoundData() public override view checkAccess() returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ) { return super.latestRoundData(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./AccessControlledOCR2Aggregator.sol"; contract AccessControlTestHelper { event Dummy(); // Used to silence warning that these methods are pure function readGetRoundData(address _aggregator, uint80 _roundID) external { AccessControlledOCR2Aggregator(_aggregator).getRoundData(_roundID); emit Dummy(); } function readLatestRoundData(address _aggregator) external { AccessControlledOCR2Aggregator(_aggregator).latestRoundData(); emit Dummy(); } function readLatestAnswer(address _aggregator) external { AccessControlledOCR2Aggregator(_aggregator).latestAnswer(); emit Dummy(); } function readLatestTimestamp(address _aggregator) external { AccessControlledOCR2Aggregator(_aggregator).latestTimestamp(); emit Dummy(); } function readLatestRound(address _aggregator) external { AccessControlledOCR2Aggregator(_aggregator).latestRound(); emit Dummy(); } function readGetAnswer(address _aggregator, uint256 _roundID) external { AccessControlledOCR2Aggregator(_aggregator).getAnswer(_roundID); emit Dummy(); } function readGetTimestamp(address _aggregator, uint256 _roundID) external { AccessControlledOCR2Aggregator(_aggregator).getTimestamp(_roundID); emit Dummy(); } function testLatestTransmissionDetails(address _aggregator) external view { OCR2Aggregator(_aggregator).latestTransmissionDetails(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./ConfirmedOwnerWithProposal.sol"; /** * @title The ConfirmedOwner contract * @notice A contract with helpers for basic contract ownership. */ contract ConfirmedOwner is ConfirmedOwnerWithProposal { constructor( address newOwner ) ConfirmedOwnerWithProposal( newOwner, address(0) ) { } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./interfaces/OwnableInterface.sol"; /** * @title The ConfirmedOwner contract * @notice A contract with helpers for basic contract ownership. */ contract ConfirmedOwnerWithProposal is OwnableInterface { address private s_owner; address private s_pendingOwner; event OwnershipTransferRequested( address indexed from, address indexed to ); event OwnershipTransferred( address indexed from, address indexed to ); constructor( address newOwner, address pendingOwner ) { require(newOwner != address(0), "Cannot set owner to zero"); s_owner = newOwner; if (pendingOwner != address(0)) { _transferOwnership(pendingOwner); } } /** * @notice Allows an owner to begin transferring ownership to a new address, * pending. */ function transferOwnership( address to ) public override onlyOwner() { _transferOwnership(to); } /** * @notice Allows an ownership transfer to be completed by the recipient. */ function acceptOwnership() external override { require(msg.sender == s_pendingOwner, "Must be proposed owner"); address oldOwner = s_owner; s_owner = msg.sender; s_pendingOwner = address(0); emit OwnershipTransferred(oldOwner, msg.sender); } /** * @notice Get the current owner */ function owner() public view override returns ( address ) { return s_owner; } /** * @notice validate, transfer ownership, and emit relevant events */ function _transferOwnership( address to ) private { require(to != msg.sender, "Cannot transfer to self"); s_pendingOwner = to; emit OwnershipTransferRequested(s_owner, to); } /** * @notice validate access */ function _validateOwnership() internal view { require(msg.sender == s_owner, "Only callable by owner"); } /** * @notice Reverts if called by anyone other than the contract owner. */ modifier onlyOwner() { _validateOwnership(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./OCR2Aggregator.sol"; // ExposedOCR2Aggregator exposes certain internal OCR2Aggregator // methods/structures so that golang code can access them, and we get // reliable type checking on their usage contract ExposedOCR2Aggregator is OCR2Aggregator { constructor() OCR2Aggregator( LinkTokenInterface(address(0)), 0, 0, AccessControllerInterface(address(0)), AccessControllerInterface(address(0)), 0, "" ) {} function exposedConfigDigestFromConfigData( uint256 _chainId, address _contractAddress, uint64 _configCount, address[] memory _signers, address[] memory _transmitters, uint8 _f, bytes calldata _onchainConfig, uint64 _encodedConfigVersion, bytes memory _encodedConfig ) public view returns (bytes32) { return _configDigestFromConfigData(_chainId, _contractAddress, _configCount, _signers, _transmitters, _f, _onchainConfig, _encodedConfigVersion, _encodedConfig); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./interfaces/TypeAndVersionInterface.sol"; abstract contract OCR2Abstract is TypeAndVersionInterface { // Maximum number of oracles the offchain reporting protocol is designed for uint256 constant internal maxNumOracles = 31; /** * @notice triggers a new run of the offchain reporting protocol * @param previousConfigBlockNumber block in which the previous config was set, to simplify historic analysis * @param configDigest configDigest of this configuration * @param configCount ordinal number of this config setting among all config settings over the life of this contract * @param signers ith element is address ith oracle uses to sign a report * @param transmitters ith element is address ith oracle uses to transmit a report via the transmit method * @param f maximum number of faulty/dishonest oracles the protocol can tolerate while still working correctly * @param onchainConfig serialized configuration used by the contract (and possibly oracles) * @param offchainConfigVersion version of the serialization format used for "offchainConfig" parameter * @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract */ event ConfigSet( uint32 previousConfigBlockNumber, bytes32 configDigest, uint64 configCount, address[] signers, address[] transmitters, uint8 f, bytes onchainConfig, uint64 offchainConfigVersion, bytes offchainConfig ); /** * @notice sets offchain reporting protocol configuration incl. participating oracles * @param signers addresses with which oracles sign the reports * @param transmitters addresses oracles use to transmit the reports * @param f number of faulty oracles the system can tolerate * @param onchainConfig serialized configuration used by the contract (and possibly oracles) * @param offchainConfigVersion version number for offchainEncoding schema * @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract */ function setConfig( address[] memory signers, address[] memory transmitters, uint8 f, bytes memory onchainConfig, uint64 offchainConfigVersion, bytes memory offchainConfig ) external virtual; /** * @notice information about current offchain reporting protocol configuration * @return configCount ordinal number of current config, out of all configs applied to this contract so far * @return blockNumber block at which this config was set * @return configDigest domain-separation tag for current config (see _configDigestFromConfigData) */ function latestConfigDetails() external view virtual returns ( uint32 configCount, uint32 blockNumber, bytes32 configDigest ); function _configDigestFromConfigData( uint256 chainId, address contractAddress, uint64 configCount, address[] memory signers, address[] memory transmitters, uint8 f, bytes memory onchainConfig, uint64 offchainConfigVersion, bytes memory offchainConfig ) internal pure returns (bytes32) { uint256 h = uint256(keccak256(abi.encode(chainId, contractAddress, configCount, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig ))); uint256 prefixMask = type(uint256).max << (256-16); // 0xFFFF00..00 uint256 prefix = 0x0001 << (256-16); // 0x000100..00 return bytes32((prefix & prefixMask) | (h & ~prefixMask)); } /** * @notice optionally emitted to indicate the latest configDigest and epoch for which a report was successfully transmitted. Alternatively, the contract may use latestConfigDigestAndEpoch with scanLogs set to false. */ event Transmitted( bytes32 configDigest, uint32 epoch ); /** * @notice optionally returns the latest configDigest and epoch for which a report was successfully transmitted. Alternatively, the contract may return scanLogs set to true and use Transmitted events to provide this information to offchain watchers. * @return scanLogs indicates whether to rely on the configDigest and epoch returned or whether to scan logs for the Transmitted event instead. * @return configDigest * @return epoch */ function latestConfigDigestAndEpoch() external view virtual returns( bool scanLogs, bytes32 configDigest, uint32 epoch ); /** * @notice transmit is called to post a new report to the contract * @param reportContext serialized report context containing configDigest, epoch, round, extraHash * @param report serialized report, which the signatures are signing * @param rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries * @param ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries * @param rawVs ith element is the the V component of the ith signature */ function transmit( // NOTE: If these parameters are changed, expectedMsgDataLength and/or // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly bytes32[3] calldata reportContext, bytes calldata report, bytes32[] calldata rs, bytes32[] calldata ss, bytes32 rawVs // signatures ) external virtual; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./interfaces/AccessControllerInterface.sol"; import "./interfaces/AggregatorV2V3Interface.sol"; import "./interfaces/AggregatorValidatorInterface.sol"; import "./interfaces/LinkTokenInterface.sol"; import "./interfaces/TypeAndVersionInterface.sol"; import "./OCR2Abstract.sol"; import "./OwnerIsCreator.sol"; /** * @notice OCR2Aggregator for numerical data with billing support. * @dev * If you read or change this, be sure to read or adjust the comments. They * track the units of the values under consideration, and are crucial to * the readability of the operations it specifies. * @notice * Billing Trust Model: * Nothing in this contract prevents a billing admin from setting insane * values for the billing parameters in setBilling. Oracles * participating in this contract should regularly check that the * parameters make sense. Similarly, the outstanding obligations of this * contract to the oracles can exceed the funds held by the contract. * Oracles participating in this contract should regularly check that it * holds sufficient funds and stop interacting with it if funding runs * out. * This still leaves oracles with some risk due to TOCTOU issues. * However, since the sums involved are pretty small (Ethereum * transactions aren't that expensive in the end) and an oracle would * likely stop participating in a contract it repeatedly lost money on, * this risk is deemed acceptable. Oracles should also regularly * withdraw any funds in the contract to prevent issues where the * contract becomes underfunded at a later time, and different oracles * are competing for the left-over funds. * Finally, note that any change to the set of oracles or to the billing * parameters will trigger payout of all oracles first (using the old * parameters), a billing admin cannot take away funds that are already * marked for payment. */ contract OCR2Aggregator is OCR2Abstract, OwnerIsCreator, AggregatorV2V3Interface { // This contract is divided into sections. Each section defines a set of // variables, events, and functions that belong together. /*************************************************************************** * Section: Variables used in multiple other sections **************************************************************************/ struct Transmitter { bool active; // Index of oracle in s_signersList/s_transmittersList uint8 index; // juels-denominated payment for transmitters, covering gas costs incurred // by the transmitter plus additional rewards. The entire LINK supply (1e9 // LINK = 1e27 Juels) will always fit into a uint96. uint96 paymentJuels; } mapping (address /* transmitter address */ => Transmitter) internal s_transmitters; struct Signer { bool active; // Index of oracle in s_signersList/s_transmittersList uint8 index; } mapping (address /* signer address */ => Signer) internal s_signers; // s_signersList contains the signing address of each oracle address[] internal s_signersList; // s_transmittersList contains the transmission address of each oracle, // i.e. the address the oracle actually sends transactions to the contract from address[] internal s_transmittersList; // We assume that all oracles contribute observations to all rounds. this // variable tracks (per-oracle) from what round an oracle should be rewarded, // i.e. the oracle gets (latestAggregatorRoundId - // rewardFromAggregatorRoundId) * reward uint32[maxNumOracles] internal s_rewardFromAggregatorRoundId; bytes32 s_latestConfigDigest; // Storing these fields used on the hot path in a HotVars variable reduces the // retrieval of all of them to a single SLOAD. struct HotVars { // maximum number of faulty oracles uint8 f; // epoch and round from OCR protocol. // 32 most sig bits for epoch, 8 least sig bits for round uint40 latestEpochAndRound; // Chainlink Aggregators expose a roundId to consumers. The offchain reporting // protocol does not use this id anywhere. We increment it whenever a new // transmission is made to provide callers with contiguous ids for successive // reports. uint32 latestAggregatorRoundId; // Highest compensated gas price, in gwei uints uint32 maximumGasPriceGwei; // If gas price is less (in gwei units), transmitter gets half the savings uint32 reasonableGasPriceGwei; // Fixed LINK reward for each observer uint32 observationPaymentGjuels; // Fixed reward for transmitter uint32 transmissionPaymentGjuels; // Overhead incurred by accounting logic uint24 accountingGas; } HotVars internal s_hotVars; // Transmission records the median answer from the transmit transaction at // time timestamp struct Transmission { int192 answer; // 192 bits ought to be enough for anyone uint32 observationsTimestamp; // when were observations made offchain uint32 transmissionTimestamp; // when was report received onchain } mapping(uint32 /* aggregator round ID */ => Transmission) internal s_transmissions; // Lowest answer the system is allowed to report in response to transmissions int192 immutable public minAnswer; // Highest answer the system is allowed to report in response to transmissions int192 immutable public maxAnswer; /*************************************************************************** * Section: Constructor **************************************************************************/ /** * @param link address of the LINK contract * @param minAnswer_ lowest answer the median of a report is allowed to be * @param maxAnswer_ highest answer the median of a report is allowed to be * @param requesterAccessController access controller for requesting new rounds * @param decimals_ answers are stored in fixed-point format, with this many digits of precision * @param description_ short human-readable description of observable this contract's answers pertain to */ constructor( LinkTokenInterface link, int192 minAnswer_, int192 maxAnswer_, AccessControllerInterface billingAccessController, AccessControllerInterface requesterAccessController, uint8 decimals_, string memory description_ ) { s_linkToken = link; emit LinkTokenSet(LinkTokenInterface(address(0)), link); _setBillingAccessController(billingAccessController); decimals = decimals_; s_description = description_; setRequesterAccessController(requesterAccessController); setValidatorConfig(AggregatorValidatorInterface(address(0x0)), 0); minAnswer = minAnswer_; maxAnswer = maxAnswer_; } /*************************************************************************** * Section: OCR2Abstract Configuration **************************************************************************/ // incremented each time a new config is posted. This count is incorporated // into the config digest to prevent replay attacks. uint32 internal s_configCount; // makes it easier for offchain systems to extract config from logs uint32 internal s_latestConfigBlockNumber; // left as a function so this check can be disabled in derived contracts function _requirePositiveF ( uint256 f ) internal pure virtual { require(0 < f, "f must be positive"); } struct SetConfigArgs { address[] signers; address[] transmitters; uint8 f; bytes onchainConfig; uint64 offchainConfigVersion; bytes offchainConfig; } /// @inheritdoc OCR2Abstract function setConfig( address[] memory signers, address[] memory transmitters, uint8 f, bytes memory onchainConfig, uint64 offchainConfigVersion, bytes memory offchainConfig ) external override onlyOwner() { require(signers.length <= maxNumOracles, "too many oracles"); require(signers.length == transmitters.length, "oracle length mismatch"); require(3*f < signers.length, "faulty-oracle f too high"); _requirePositiveF(f); require(keccak256(onchainConfig) == keccak256(abi.encodePacked(uint8(1) /*version*/, minAnswer, maxAnswer)), "invalid onchainConfig"); SetConfigArgs memory args = SetConfigArgs({ signers: signers, transmitters: transmitters, f: f, onchainConfig: onchainConfig, offchainConfigVersion: offchainConfigVersion, offchainConfig: offchainConfig }); s_hotVars.latestEpochAndRound = 0; _payOracles(); // remove any old signer/transmitter addresses uint256 oldLength = s_signersList.length; for (uint256 i = 0; i < oldLength; i++) { address signer = s_signersList[i]; address transmitter = s_transmittersList[i]; delete s_signers[signer]; delete s_transmitters[transmitter]; } delete s_signersList; delete s_transmittersList; // add new signer/transmitter addresses for (uint i = 0; i < args.signers.length; i++) { require( !s_signers[args.signers[i]].active, "repeated signer address" ); s_signers[args.signers[i]] = Signer({ active: true, index: uint8(i) }); require( !s_transmitters[args.transmitters[i]].active, "repeated transmitter address" ); s_transmitters[args.transmitters[i]] = Transmitter({ active: true, index: uint8(i), paymentJuels: 0 }); } s_signersList = args.signers; s_transmittersList = args.transmitters; s_hotVars.f = args.f; uint32 previousConfigBlockNumber = s_latestConfigBlockNumber; s_latestConfigBlockNumber = uint32(block.number); s_configCount += 1; s_latestConfigDigest = _configDigestFromConfigData( block.chainid, address(this), s_configCount, args.signers, args.transmitters, args.f, args.onchainConfig, args.offchainConfigVersion, args.offchainConfig ); emit ConfigSet( previousConfigBlockNumber, s_latestConfigDigest, s_configCount, args.signers, args.transmitters, args.f, args.onchainConfig, args.offchainConfigVersion, args.offchainConfig ); uint32 latestAggregatorRoundId = s_hotVars.latestAggregatorRoundId; for (uint256 i = 0; i < args.signers.length; i++) { s_rewardFromAggregatorRoundId[i] = latestAggregatorRoundId; } } /// @inheritdoc OCR2Abstract function latestConfigDetails() external override view returns ( uint32 configCount, uint32 blockNumber, bytes32 configDigest ) { return (s_configCount, s_latestConfigBlockNumber, s_latestConfigDigest); } /** * @return list of addresses permitted to transmit reports to this contract * @dev The list will match the order used to specify the transmitter during setConfig */ function getTransmitters() external view returns(address[] memory) { return s_transmittersList; } /*************************************************************************** * Section: Onchain Validation **************************************************************************/ // Configuration for validator struct ValidatorConfig { AggregatorValidatorInterface validator; uint32 gasLimit; } ValidatorConfig private s_validatorConfig; /** * @notice indicates that the validator configuration has been set * @param previousValidator previous validator contract * @param previousGasLimit previous gas limit for validate calls * @param currentValidator current validator contract * @param currentGasLimit current gas limit for validate calls */ event ValidatorConfigSet( AggregatorValidatorInterface indexed previousValidator, uint32 previousGasLimit, AggregatorValidatorInterface indexed currentValidator, uint32 currentGasLimit ); /** * @notice validator configuration * @return validator validator contract * @return gasLimit gas limit for validate calls */ function getValidatorConfig() external view returns (AggregatorValidatorInterface validator, uint32 gasLimit) { ValidatorConfig memory vc = s_validatorConfig; return (vc.validator, vc.gasLimit); } /** * @notice sets validator configuration * @dev set newValidator to 0x0 to disable validate calls * @param newValidator address of the new validator contract * @param newGasLimit new gas limit for validate calls */ function setValidatorConfig( AggregatorValidatorInterface newValidator, uint32 newGasLimit ) public onlyOwner() { ValidatorConfig memory previous = s_validatorConfig; if (previous.validator != newValidator || previous.gasLimit != newGasLimit) { s_validatorConfig = ValidatorConfig({ validator: newValidator, gasLimit: newGasLimit }); emit ValidatorConfigSet(previous.validator, previous.gasLimit, newValidator, newGasLimit); } } function _validateAnswer( uint32 aggregatorRoundId, int256 answer ) private { ValidatorConfig memory vc = s_validatorConfig; if (address(vc.validator) == address(0)) { return; } uint32 prevAggregatorRoundId = aggregatorRoundId - 1; int256 prevAggregatorRoundAnswer = s_transmissions[prevAggregatorRoundId].answer; require( _callWithExactGasEvenIfTargetIsNoContract( vc.gasLimit, address(vc.validator), abi.encodeWithSignature( "validate(uint256,int256,uint256,int256)", uint256(prevAggregatorRoundId), prevAggregatorRoundAnswer, uint256(aggregatorRoundId), answer ) ), "insufficient gas" ); } uint256 private constant CALL_WITH_EXACT_GAS_CUSHION = 5_000; /** * @dev calls target address with exactly gasAmount gas and data as calldata * or reverts if at least gasAmount gas is not available. */ function _callWithExactGasEvenIfTargetIsNoContract( uint256 gasAmount, address target, bytes memory data ) private returns (bool sufficientGas) { // solhint-disable-next-line no-inline-assembly assembly { let g := gas() // Compute g -= CALL_WITH_EXACT_GAS_CUSHION and check for underflow. We // need the cushion since the logic following the above call to gas also // costs gas which we cannot account for exactly. So cushion is a // conservative upper bound for the cost of this logic. if iszero(lt(g, CALL_WITH_EXACT_GAS_CUSHION)) { g := sub(g, CALL_WITH_EXACT_GAS_CUSHION) // If g - g//64 <= gasAmount, we don't have enough gas. (We subtract g//64 // because of EIP-150.) if gt(sub(g, div(g, 64)), gasAmount) { // Call and ignore success/return data. Note that we did not check // whether a contract actually exists at the target address. pop(call(gasAmount, target, 0, add(data, 0x20), mload(data), 0, 0)) sufficientGas := true } } } } /*************************************************************************** * Section: RequestNewRound **************************************************************************/ AccessControllerInterface internal s_requesterAccessController; /** * @notice emitted when a new requester access controller contract is set * @param old the address prior to the current setting * @param current the address of the new access controller contract */ event RequesterAccessControllerSet(AccessControllerInterface old, AccessControllerInterface current); /** * @notice emitted to immediately request a new round * @param requester the address of the requester * @param configDigest the latest transmission's configDigest * @param epoch the latest transmission's epoch * @param round the latest transmission's round */ event RoundRequested(address indexed requester, bytes32 configDigest, uint32 epoch, uint8 round); /** * @notice address of the requester access controller contract * @return requester access controller address */ function getRequesterAccessController() external view returns (AccessControllerInterface) { return s_requesterAccessController; } /** * @notice sets the requester access controller * @param requesterAccessController designates the address of the new requester access controller */ function setRequesterAccessController(AccessControllerInterface requesterAccessController) public onlyOwner() { AccessControllerInterface oldController = s_requesterAccessController; if (requesterAccessController != oldController) { s_requesterAccessController = AccessControllerInterface(requesterAccessController); emit RequesterAccessControllerSet(oldController, requesterAccessController); } } /** * @notice immediately requests a new round * @return the aggregatorRoundId of the next round. Note: The report for this round may have been * transmitted (but not yet mined) *before* requestNewRound() was even called. There is *no* * guarantee of causality between the request and the report at aggregatorRoundId. */ function requestNewRound() external returns (uint80) { require(msg.sender == owner() || s_requesterAccessController.hasAccess(msg.sender, msg.data), "Only owner&requester can call"); uint40 latestEpochAndRound = s_hotVars.latestEpochAndRound; uint32 latestAggregatorRoundId = s_hotVars.latestAggregatorRoundId; emit RoundRequested( msg.sender, s_latestConfigDigest, uint32(latestEpochAndRound >> 8), uint8(latestEpochAndRound) ); return latestAggregatorRoundId + 1; } /*************************************************************************** * Section: Transmission **************************************************************************/ /** * @notice indicates that a new report was transmitted * @param aggregatorRoundId the round to which this report was assigned * @param answer median of the observations attached to this report * @param transmitter address from which the report was transmitted * @param observationsTimestamp when were observations made offchain * @param observations observations transmitted with this report * @param observers i-th element is the oracle id of the oracle that made the i-th observation * @param juelsPerFeeCoin exchange rate between feeCoin (e.g. ETH on Ethereum) and LINK, denominated in juels * @param configDigest configDigest of transmission * @param epochAndRound least-significant byte is the OCR protocol round number, the other bytes give the big-endian OCR protocol epoch number */ event NewTransmission( uint32 indexed aggregatorRoundId, int192 answer, address transmitter, uint32 observationsTimestamp, int192[] observations, bytes observers, int192 juelsPerFeeCoin, bytes32 configDigest, uint40 epochAndRound ); // Used to relieve stack pressure in transmit struct Report { uint32 observationsTimestamp; bytes observers; // ith element is the index of the ith observer int192[] observations; // ith element is the ith observation int192 juelsPerFeeCoin; } // _decodeReport decodes a serialized report into a Report struct function _decodeReport(bytes memory rawReport) internal pure returns ( Report memory ) { uint32 observationsTimestamp; bytes32 rawObservers; int192[] memory observations; int192 juelsPerFeeCoin; (observationsTimestamp, rawObservers, observations, juelsPerFeeCoin) = abi.decode(rawReport, (uint32, bytes32, int192[], int192)); _requireExpectedReportLength(rawReport, observations); uint256 numObservations = observations.length; bytes memory observers = abi.encodePacked(rawObservers); assembly { // we truncate observers from length 32 to the number of observations mstore(observers, numObservations) } return Report({ observationsTimestamp: observationsTimestamp, observers: observers, observations: observations, juelsPerFeeCoin: juelsPerFeeCoin }); } // The constant-length components of the msg.data sent to transmit. // See the "If we wanted to call sam" example on for example reasoning // https://solidity.readthedocs.io/en/v0.7.2/abi-spec.html uint256 private constant TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT = 4 + // function selector 32 * 3 + // 3 words containing reportContext 32 + // word containing start location of abiencoded report value 32 + // word containing location start of abiencoded rs value 32 + // word containing start location of abiencoded ss value 32 + // rawVs value 32 + // word containing length of report 32 + // word containing length rs 32 + // word containing length of ss 0; // placeholder // Make sure the calldata length matches the inputs. Otherwise, the // transmitter could append an arbitrarily long (up to gas-block limit) // string of 0 bytes, which we would reimburse at a rate of 16 gas/byte, but // which would only cost the transmitter 4 gas/byte. function _requireExpectedMsgDataLength( bytes calldata report, bytes32[] calldata rs, bytes32[] calldata ss ) private pure { // calldata will never be big enough to make this overflow uint256 expected = TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT + report.length + // one byte pure entry in report rs.length * 32 + // 32 bytes per entry in rs ss.length * 32 + // 32 bytes per entry in ss 0; // placeholder require(msg.data.length == expected, "calldata length mismatch"); } /// @inheritdoc OCR2Abstract function transmit( // reportContext consists of: // reportContext[0]: ConfigDigest // reportContext[1]: 27 byte padding, 4-byte epoch and 1-byte round // reportContext[2]: ExtraHash bytes32[3] calldata reportContext, bytes calldata report, // ECDSA signatures bytes32[] calldata rs, bytes32[] calldata ss, bytes32 rawVs ) external override { // NOTE: If the arguments to this function are changed, _requireExpectedMsgDataLength and/or // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly uint256 initialGas = gasleft(); // This line must come first HotVars memory hotVars = s_hotVars; uint40 epochAndRound = uint40(uint256(reportContext[1])); require(hotVars.latestEpochAndRound < epochAndRound, "stale report"); require(s_transmitters[msg.sender].active, "unauthorized transmitter"); require(s_latestConfigDigest == reportContext[0], "configDigest mismatch"); _requireExpectedMsgDataLength(report, rs, ss); require(rs.length == hotVars.f + 1, "wrong number of signatures"); require(rs.length == ss.length, "signatures out of registration"); // Verify signatures attached to report { bytes32 h = keccak256(abi.encode(keccak256(report), reportContext)); // i-th byte counts number of sigs made by i-th signer uint256 signedCount = 0; Signer memory signer; for (uint i = 0; i < rs.length; i++) { address signerAddress = ecrecover(h, uint8(rawVs[i])+27, rs[i], ss[i]); signer = s_signers[signerAddress]; require(signer.active, "signature error"); unchecked{ signedCount += 1 << (8 * signer.index); } } // The first byte of the mask can be 0, because we only ever have 31 oracles require(signedCount & 0x0001010101010101010101010101010101010101010101010101010101010101 == signedCount, "duplicate signer"); } int192 juelsPerFeeCoin = _report(hotVars, reportContext[0], epochAndRound, report); _payTransmitter(hotVars, juelsPerFeeCoin, uint32(initialGas), msg.sender); } /** * @notice details about the most recent report * @return configDigest domain separation tag for the latest report * @return epoch epoch in which the latest report was generated * @return round OCR round in which the latest report was generated * @return latestAnswer_ median value from latest report * @return latestTimestamp_ when the latest report was transmitted */ function latestTransmissionDetails() external view returns ( bytes32 configDigest, uint32 epoch, uint8 round, int192 latestAnswer_, uint64 latestTimestamp_ ) { require(msg.sender == tx.origin, "Only callable by EOA"); return ( s_latestConfigDigest, uint32(s_hotVars.latestEpochAndRound >> 8), uint8(s_hotVars.latestEpochAndRound), s_transmissions[s_hotVars.latestAggregatorRoundId].answer, s_transmissions[s_hotVars.latestAggregatorRoundId].transmissionTimestamp ); } /// @inheritdoc OCR2Abstract function latestConfigDigestAndEpoch() external override view virtual returns( bool scanLogs, bytes32 configDigest, uint32 epoch ) { return (false, s_latestConfigDigest, uint32(s_hotVars.latestEpochAndRound >> 8)); } function _requireExpectedReportLength( bytes memory report, int192[] memory observations ) private pure { uint256 expected = 32 + // observationsTimestamp 32 + // rawObservers 32 + // observations offset 32 + // juelsPerFeeCoin 32 + // observations length 32 * observations.length + // observations payload 0; require(report.length == expected, "report length mismatch"); } function _report( HotVars memory hotVars, bytes32 configDigest, uint40 epochAndRound, bytes memory rawReport ) internal returns (int192 juelsPerFeeCoin) { Report memory report = _decodeReport(rawReport); require(report.observations.length <= maxNumOracles, "num observations out of bounds"); require(hotVars.f < report.observations.length, "too few values to trust median"); hotVars.latestEpochAndRound = epochAndRound; // get median, validate its range, store it in new aggregator round int192 median = report.observations[report.observations.length/2]; require(minAnswer <= median && median <= maxAnswer, "median is out of min-max range"); hotVars.latestAggregatorRoundId++; s_transmissions[hotVars.latestAggregatorRoundId] = Transmission({ answer: median, observationsTimestamp: report.observationsTimestamp, transmissionTimestamp: uint32(block.timestamp) }); // persist updates to hotVars s_hotVars = hotVars; emit NewTransmission( hotVars.latestAggregatorRoundId, median, msg.sender, report.observationsTimestamp, report.observations, report.observers, report.juelsPerFeeCoin, configDigest, epochAndRound ); // Emit these for backwards compatibility with offchain consumers // that only support legacy events emit NewRound( hotVars.latestAggregatorRoundId, address(0x0), // use zero address since we don't have anybody "starting" the round here report.observationsTimestamp ); emit AnswerUpdated( median, hotVars.latestAggregatorRoundId, block.timestamp ); _validateAnswer(hotVars.latestAggregatorRoundId, median); return report.juelsPerFeeCoin; } /*************************************************************************** * Section: v2 AggregatorInterface **************************************************************************/ /** * @notice median from the most recent report */ function latestAnswer() public override view virtual returns (int256) { return s_transmissions[s_hotVars.latestAggregatorRoundId].answer; } /** * @notice timestamp of block in which last report was transmitted */ function latestTimestamp() public override view virtual returns (uint256) { return s_transmissions[s_hotVars.latestAggregatorRoundId].transmissionTimestamp; } /** * @notice Aggregator round (NOT OCR round) in which last report was transmitted */ function latestRound() public override view virtual returns (uint256) { return s_hotVars.latestAggregatorRoundId; } /** * @notice median of report from given aggregator round (NOT OCR round) * @param roundId the aggregator round of the target report */ function getAnswer(uint256 roundId) public override view virtual returns (int256) { if (roundId > 0xFFFFFFFF) { return 0; } return s_transmissions[uint32(roundId)].answer; } /** * @notice timestamp of block in which report from given aggregator round was transmitted * @param roundId aggregator round (NOT OCR round) of target report */ function getTimestamp(uint256 roundId) public override view virtual returns (uint256) { if (roundId > 0xFFFFFFFF) { return 0; } return s_transmissions[uint32(roundId)].transmissionTimestamp; } /*************************************************************************** * Section: v3 AggregatorInterface **************************************************************************/ /** * @return answers are stored in fixed-point format, with this many digits of precision */ uint8 immutable public override decimals; /** * @notice aggregator contract version */ uint256 constant public override version = 6; string internal s_description; /** * @notice human-readable description of observable this contract is reporting on */ function description() public override view virtual returns (string memory) { return s_description; } /** * @notice details for the given aggregator round * @param roundId target aggregator round (NOT OCR round). Must fit in uint32 * @return roundId_ roundId * @return answer median of report from given roundId * @return startedAt timestamp of when observations were made offchain * @return updatedAt timestamp of block in which report from given roundId was transmitted * @return answeredInRound roundId */ function getRoundData(uint80 roundId) public override view virtual returns ( uint80 roundId_, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ) { if(roundId > type(uint32).max) { return (0, 0, 0, 0, 0); } Transmission memory transmission = s_transmissions[uint32(roundId)]; return ( roundId, transmission.answer, transmission.observationsTimestamp, transmission.transmissionTimestamp, roundId ); } /** * @notice aggregator details for the most recently transmitted report * @return roundId aggregator round of latest report (NOT OCR round) * @return answer median of latest report * @return startedAt timestamp of when observations were made offchain * @return updatedAt timestamp of block containing latest report * @return answeredInRound aggregator round of latest report */ function latestRoundData() public override view virtual returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ) { uint32 latestAggregatorRoundId = s_hotVars.latestAggregatorRoundId; Transmission memory transmission = s_transmissions[latestAggregatorRoundId]; return ( latestAggregatorRoundId, transmission.answer, transmission.observationsTimestamp, transmission.transmissionTimestamp, latestAggregatorRoundId ); } /*************************************************************************** * Section: Configurable LINK Token **************************************************************************/ // We assume that the token contract is correct. This contract is not written // to handle misbehaving ERC20 tokens! LinkTokenInterface internal s_linkToken; /* * @notice emitted when the LINK token contract is set * @param oldLinkToken the address of the old LINK token contract * @param newLinkToken the address of the new LINK token contract */ event LinkTokenSet( LinkTokenInterface indexed oldLinkToken, LinkTokenInterface indexed newLinkToken ); /** * @notice sets the LINK token contract used for paying oracles * @param linkToken the address of the LINK token contract * @param recipient remaining funds from the previous token contract are transferred * here * @dev this function will return early (without an error) without changing any state * if linkToken equals getLinkToken(). * @dev this will trigger a payout so that a malicious owner cannot take from oracles * what is already owed to them. * @dev we assume that the token contract is correct. This contract is not written * to handle misbehaving ERC20 tokens! */ function setLinkToken( LinkTokenInterface linkToken, address recipient ) external onlyOwner() { LinkTokenInterface oldLinkToken = s_linkToken; if (linkToken == oldLinkToken) { // No change, nothing to be done return; } // call balanceOf as a sanity check on whether we're talking to a token // contract linkToken.balanceOf(address(this)); // we break CEI here, but that's okay because we're dealing with a correct // token contract (by assumption). _payOracles(); uint256 remainingBalance = oldLinkToken.balanceOf(address(this)); require(oldLinkToken.transfer(recipient, remainingBalance), "transfer remaining funds failed"); s_linkToken = linkToken; emit LinkTokenSet(oldLinkToken, linkToken); } /* * @notice gets the LINK token contract used for paying oracles * @return linkToken the address of the LINK token contract */ function getLinkToken() external view returns(LinkTokenInterface linkToken) { return s_linkToken; } /*************************************************************************** * Section: BillingAccessController Management **************************************************************************/ // Controls who can change billing parameters. A billingAdmin is not able to // affect any OCR protocol settings and therefore cannot tamper with the // liveness or integrity of a data feed. However, a billingAdmin can set // faulty billing parameters causing oracles to be underpaid, or causing them // to be paid so much that further calls to setConfig, setBilling, // setLinkToken will always fail due to the contract being underfunded. AccessControllerInterface internal s_billingAccessController; /** * @notice emitted when a new access-control contract is set * @param old the address prior to the current setting * @param current the address of the new access-control contract */ event BillingAccessControllerSet(AccessControllerInterface old, AccessControllerInterface current); function _setBillingAccessController(AccessControllerInterface billingAccessController) internal { AccessControllerInterface oldController = s_billingAccessController; if (billingAccessController != oldController) { s_billingAccessController = billingAccessController; emit BillingAccessControllerSet( oldController, billingAccessController ); } } /** * @notice sets billingAccessController * @param _billingAccessController new billingAccessController contract address * @dev only owner can call this */ function setBillingAccessController(AccessControllerInterface _billingAccessController) external onlyOwner { _setBillingAccessController(_billingAccessController); } /** * @notice gets billingAccessController * @return address of billingAccessController contract */ function getBillingAccessController() external view returns (AccessControllerInterface) { return s_billingAccessController; } /*************************************************************************** * Section: Billing Configuration **************************************************************************/ /** * @notice emitted when billing parameters are set * @param maximumGasPriceGwei highest gas price for which transmitter will be compensated * @param reasonableGasPriceGwei transmitter will receive reward for gas prices under this value * @param observationPaymentGjuels reward to oracle for contributing an observation to a successfully transmitted report * @param transmissionPaymentGjuels reward to transmitter of a successful report * @param accountingGas gas overhead incurred by accounting logic */ event BillingSet( uint32 maximumGasPriceGwei, uint32 reasonableGasPriceGwei, uint32 observationPaymentGjuels, uint32 transmissionPaymentGjuels, uint24 accountingGas ); /** * @notice sets billing parameters * @param maximumGasPriceGwei highest gas price for which transmitter will be compensated * @param reasonableGasPriceGwei transmitter will receive reward for gas prices under this value * @param observationPaymentGjuels reward to oracle for contributing an observation to a successfully transmitted report * @param transmissionPaymentGjuels reward to transmitter of a successful report * @param accountingGas gas overhead incurred by accounting logic * @dev access control provided by billingAccessController */ function setBilling( uint32 maximumGasPriceGwei, uint32 reasonableGasPriceGwei, uint32 observationPaymentGjuels, uint32 transmissionPaymentGjuels, uint24 accountingGas ) external { AccessControllerInterface access = s_billingAccessController; require(msg.sender == owner() || access.hasAccess(msg.sender, msg.data), "Only owner&billingAdmin can call"); _payOracles(); s_hotVars.maximumGasPriceGwei = maximumGasPriceGwei; s_hotVars.reasonableGasPriceGwei = reasonableGasPriceGwei; s_hotVars.observationPaymentGjuels = observationPaymentGjuels; s_hotVars.transmissionPaymentGjuels = transmissionPaymentGjuels; s_hotVars.accountingGas = accountingGas; emit BillingSet(maximumGasPriceGwei, reasonableGasPriceGwei, observationPaymentGjuels, transmissionPaymentGjuels, accountingGas); } /** * @notice gets billing parameters * @param maximumGasPriceGwei highest gas price for which transmitter will be compensated * @param reasonableGasPriceGwei transmitter will receive reward for gas prices under this value * @param observationPaymentGjuels reward to oracle for contributing an observation to a successfully transmitted report * @param transmissionPaymentGjuels reward to transmitter of a successful report * @param accountingGas gas overhead of the accounting logic */ function getBilling() external view returns ( uint32 maximumGasPriceGwei, uint32 reasonableGasPriceGwei, uint32 observationPaymentGjuels, uint32 transmissionPaymentGjuels, uint24 accountingGas ) { return ( s_hotVars.maximumGasPriceGwei, s_hotVars.reasonableGasPriceGwei, s_hotVars.observationPaymentGjuels, s_hotVars.transmissionPaymentGjuels, s_hotVars.accountingGas ); } /*************************************************************************** * Section: Payments and Withdrawals **************************************************************************/ /** * @notice withdraws an oracle's payment from the contract * @param transmitter the transmitter address of the oracle * @dev must be called by oracle's payee address */ function withdrawPayment(address transmitter) external { require(msg.sender == s_payees[transmitter], "Only payee can withdraw"); _payOracle(transmitter); } /** * @notice query an oracle's payment amount, denominated in juels * @param transmitterAddress the transmitter address of the oracle */ function owedPayment(address transmitterAddress) public view returns (uint256) { Transmitter memory transmitter = s_transmitters[transmitterAddress]; if (!transmitter.active) { return 0; } // safe from overflow: // s_hotVars.latestAggregatorRoundId - s_rewardFromAggregatorRoundId[transmitter.index] <= 2**32 // s_hotVars.observationPaymentGjuels <= 2**32 // 1 gwei <= 2**32 // hence juelsAmount <= 2**96 uint256 juelsAmount = uint256(s_hotVars.latestAggregatorRoundId - s_rewardFromAggregatorRoundId[transmitter.index]) * uint256(s_hotVars.observationPaymentGjuels) * (1 gwei); juelsAmount += transmitter.paymentJuels; return juelsAmount; } /** * @notice emitted when an oracle has been paid LINK * @param transmitter address from which the oracle sends reports to the transmit method * @param payee address to which the payment is sent * @param amount amount of LINK sent * @param linkToken address of the LINK token contract */ event OraclePaid( address indexed transmitter, address indexed payee, uint256 amount, LinkTokenInterface indexed linkToken ); // _payOracle pays out transmitter's balance to the corresponding payee, and zeros it out function _payOracle(address transmitterAddress) internal { Transmitter memory transmitter = s_transmitters[transmitterAddress]; if (!transmitter.active) { return; } uint256 juelsAmount = owedPayment(transmitterAddress); if (juelsAmount > 0) { address payee = s_payees[transmitterAddress]; // Poses no re-entrancy issues, because LINK.transfer does not yield // control flow. require(s_linkToken.transfer(payee, juelsAmount), "insufficient funds"); s_rewardFromAggregatorRoundId[transmitter.index] = s_hotVars.latestAggregatorRoundId; s_transmitters[transmitterAddress].paymentJuels = 0; emit OraclePaid(transmitterAddress, payee, juelsAmount, s_linkToken); } } // _payOracles pays out all transmitters, and zeros out their balances. // // It's much more gas-efficient to do this as a single operation, to avoid // hitting storage too much. function _payOracles() internal { unchecked { LinkTokenInterface linkToken = s_linkToken; uint32 latestAggregatorRoundId = s_hotVars.latestAggregatorRoundId; uint32[maxNumOracles] memory rewardFromAggregatorRoundId = s_rewardFromAggregatorRoundId; address[] memory transmitters = s_transmittersList; for (uint transmitteridx = 0; transmitteridx < transmitters.length; transmitteridx++) { uint256 reimbursementAmountJuels = s_transmitters[transmitters[transmitteridx]].paymentJuels; s_transmitters[transmitters[transmitteridx]].paymentJuels = 0; uint256 obsCount = latestAggregatorRoundId - rewardFromAggregatorRoundId[transmitteridx]; uint256 juelsAmount = obsCount * uint256(s_hotVars.observationPaymentGjuels) * (1 gwei) + reimbursementAmountJuels; if (juelsAmount > 0) { address payee = s_payees[transmitters[transmitteridx]]; // Poses no re-entrancy issues, because LINK.transfer does not yield // control flow. require(linkToken.transfer(payee, juelsAmount), "insufficient funds"); rewardFromAggregatorRoundId[transmitteridx] = latestAggregatorRoundId; emit OraclePaid(transmitters[transmitteridx], payee, juelsAmount, linkToken); } } // "Zero" the accounting storage variables s_rewardFromAggregatorRoundId = rewardFromAggregatorRoundId; } } /** * @notice withdraw any available funds left in the contract, up to amount, after accounting for the funds due to participants in past reports * @param recipient address to send funds to * @param amount maximum amount to withdraw, denominated in LINK-wei. * @dev access control provided by billingAccessController */ function withdrawFunds( address recipient, uint256 amount ) external { require(msg.sender == owner() || s_billingAccessController.hasAccess(msg.sender, msg.data), "Only owner&billingAdmin can call"); uint256 linkDue = _totalLinkDue(); uint256 linkBalance = s_linkToken.balanceOf(address(this)); require(linkBalance >= linkDue, "insufficient balance"); require(s_linkToken.transfer(recipient, _min(linkBalance - linkDue, amount)), "insufficient funds"); } // Total LINK due to participants in past reports (denominated in Juels). function _totalLinkDue() internal view returns (uint256 linkDue) { // Argument for overflow safety: We do all computations in // uint256s. The inputs to linkDue are: // - the <= 31 observation rewards each of which has less than // 64 bits (32 bits for observationPaymentGjuels, 32 bits // for wei/gwei conversion). Hence 69 bits are sufficient for this part. // - the <= 31 gas reimbursements, each of which consists of at most 96 // bits. Hence 101 bits are sufficient for this part. // So we never need more than 102 bits. address[] memory transmitters = s_transmittersList; uint256 n = transmitters.length; uint32 latestAggregatorRoundId = s_hotVars.latestAggregatorRoundId; uint32[maxNumOracles] memory rewardFromAggregatorRoundId = s_rewardFromAggregatorRoundId; for (uint i = 0; i < n; i++) { linkDue += latestAggregatorRoundId - rewardFromAggregatorRoundId[i]; } // Convert observationPaymentGjuels to uint256, or this overflows! linkDue *= uint256(s_hotVars.observationPaymentGjuels) * (1 gwei); for (uint i = 0; i < n; i++) { linkDue += uint256(s_transmitters[transmitters[i]].paymentJuels); } } /** * @notice allows oracles to check that sufficient LINK balance is available * @return availableBalance LINK available on this contract, after accounting for outstanding obligations. can become negative */ function linkAvailableForPayment() external view returns (int256 availableBalance) { // there are at most one billion LINK, so this cast is safe int256 balance = int256(s_linkToken.balanceOf(address(this))); // according to the argument in the definition of _totalLinkDue, // _totalLinkDue is never greater than 2**102, so this cast is safe int256 due = int256(_totalLinkDue()); // safe from overflow according to above sizes return int256(balance) - int256(due); } /** * @notice number of observations oracle is due to be reimbursed for * @param transmitterAddress address used by oracle for signing or transmitting reports */ function oracleObservationCount(address transmitterAddress) external view returns (uint32) { Transmitter memory transmitter = s_transmitters[transmitterAddress]; if (!transmitter.active) { return 0; } return s_hotVars.latestAggregatorRoundId - s_rewardFromAggregatorRoundId[transmitter.index]; } /*************************************************************************** * Section: Transmitter Payment **************************************************************************/ // Gas price at which the transmitter should be reimbursed, in gwei/gas function _reimbursementGasPriceGwei( uint256 txGasPriceGwei, uint256 reasonableGasPriceGwei, uint256 maximumGasPriceGwei ) internal pure returns (uint256) { // this happens on the path for transmissions. we'd rather pay out // a wrong reward than risk a liveness failure due to a revert. unchecked { // Reward the transmitter for choosing an efficient gas price: if they manage // to come in lower than considered reasonable, give them half the savings. uint256 gasPriceGwei = txGasPriceGwei; if (txGasPriceGwei < reasonableGasPriceGwei) { // Give transmitter half the savings for coming in under the reasonable gas price gasPriceGwei += (reasonableGasPriceGwei - txGasPriceGwei) / 2; } // Don't reimburse a gas price higher than maximumGasPriceGwei return _min(gasPriceGwei, maximumGasPriceGwei); } } // gas reimbursement due the transmitter, in wei function _transmitterGasCostWei( uint256 initialGas, uint256 gasPriceGwei, uint256 callDataGas, uint256 accountingGas, uint256 leftGas ) internal pure returns (uint256) { // this happens on the path for transmissions. we'd rather pay out // a wrong reward than risk a liveness failure due to a revert. unchecked { require(initialGas >= leftGas, "leftGas cannot exceed initialGas"); uint256 usedGas = initialGas - leftGas + // observed gas usage callDataGas + accountingGas; // estimated gas usage uint256 fullGasCostWei = usedGas * gasPriceGwei * (1 gwei); return fullGasCostWei; } } function _payTransmitter( HotVars memory hotVars, int192 juelsPerFeeCoin, uint32 initialGas, address transmitter ) internal virtual { // this happens on the path for transmissions. we'd rather pay out // a wrong reward than risk a liveness failure due to a revert. unchecked { // we can't deal with negative juelsPerFeeCoin, better to just not pay if (juelsPerFeeCoin < 0) { return; } // Reimburse transmitter of the report for gas usage uint256 gasPriceGwei = _reimbursementGasPriceGwei( tx.gasprice / (1 gwei), // convert to ETH-gwei units hotVars.reasonableGasPriceGwei, hotVars.maximumGasPriceGwei ); // The following is only an upper bound, as it ignores the cheaper cost for // 0 bytes. Safe from overflow, because calldata just isn't that long. uint256 callDataGasCost = 16 * msg.data.length; uint256 gasLeft = gasleft(); uint256 gasCostEthWei = _transmitterGasCostWei( uint256(initialGas), gasPriceGwei, callDataGasCost, hotVars.accountingGas, gasLeft ); // Even if we assume absurdly large values, this still does not overflow. With // - usedGas <= 1'000'000 gas <= 2**20 gas // - weiPerGas <= 1'000'000 gwei <= 2**50 wei // - hence gasCostEthWei <= 2**70 // - juelsPerFeeCoin <= 2**96 (more than the entire supply) // we still fit into 166 bits uint256 gasCostJuels = (gasCostEthWei * uint192(juelsPerFeeCoin))/1e18; uint96 oldTransmitterPaymentJuels = s_transmitters[transmitter].paymentJuels; uint96 newTransmitterPaymentJuels = uint96(uint256(oldTransmitterPaymentJuels) + gasCostJuels + uint256(hotVars.transmissionPaymentGjuels) * (1 gwei)); // overflow *should* never happen, but if it does, let's not persist it. if (newTransmitterPaymentJuels < oldTransmitterPaymentJuels) { return; } s_transmitters[transmitter].paymentJuels = newTransmitterPaymentJuels; } } /*************************************************************************** * Section: Payee Management **************************************************************************/ // Addresses at which oracles want to receive payments, by transmitter address mapping (address /* transmitter */ => address /* payment address */) internal s_payees; // Payee addresses which must be approved by the owner mapping (address /* transmitter */ => address /* payment address */) internal s_proposedPayees; /** * @notice emitted when a transfer of an oracle's payee address has been initiated * @param transmitter address from which the oracle sends reports to the transmit method * @param current the payee address for the oracle, prior to this setting * @param proposed the proposed new payee address for the oracle */ event PayeeshipTransferRequested( address indexed transmitter, address indexed current, address indexed proposed ); /** * @notice emitted when a transfer of an oracle's payee address has been completed * @param transmitter address from which the oracle sends reports to the transmit method * @param current the payee address for the oracle, prior to this setting */ event PayeeshipTransferred( address indexed transmitter, address indexed previous, address indexed current ); /** * @notice sets the payees for transmitting addresses * @param transmitters addresses oracles use to transmit the reports * @param payees addresses of payees corresponding to list of transmitters * @dev must be called by owner * @dev cannot be used to change payee addresses, only to initially populate them */ function setPayees( address[] calldata transmitters, address[] calldata payees ) external onlyOwner() { require(transmitters.length == payees.length, "transmitters.size != payees.size"); for (uint i = 0; i < transmitters.length; i++) { address transmitter = transmitters[i]; address payee = payees[i]; address currentPayee = s_payees[transmitter]; bool zeroedOut = currentPayee == address(0); require(zeroedOut || currentPayee == payee, "payee already set"); s_payees[transmitter] = payee; if (currentPayee != payee) { emit PayeeshipTransferred(transmitter, currentPayee, payee); } } } /** * @notice first step of payeeship transfer (safe transfer pattern) * @param transmitter transmitter address of oracle whose payee is changing * @param proposed new payee address * @dev can only be called by payee address */ function transferPayeeship( address transmitter, address proposed ) external { require(msg.sender == s_payees[transmitter], "only current payee can update"); require(msg.sender != proposed, "cannot transfer to self"); address previousProposed = s_proposedPayees[transmitter]; s_proposedPayees[transmitter] = proposed; if (previousProposed != proposed) { emit PayeeshipTransferRequested(transmitter, msg.sender, proposed); } } /** * @notice second step of payeeship transfer (safe transfer pattern) * @param transmitter transmitter address of oracle whose payee is changing * @dev can only be called by proposed new payee address */ function acceptPayeeship( address transmitter ) external { require(msg.sender == s_proposedPayees[transmitter], "only proposed payees can accept"); address currentPayee = s_payees[transmitter]; s_payees[transmitter] = msg.sender; s_proposedPayees[transmitter] = address(0); emit PayeeshipTransferred(transmitter, currentPayee, msg.sender); } /*************************************************************************** * Section: TypeAndVersionInterface **************************************************************************/ function typeAndVersion() external override pure virtual returns (string memory) { return "OCR2Aggregator 1.0.0-alpha"; } /*************************************************************************** * Section: Helper Functions **************************************************************************/ function _min( uint256 a, uint256 b ) internal pure returns (uint256) { unchecked { if (a < b) { return a; } return b; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./OwnerIsCreator.sol"; import "./OCR2Abstract.sol"; /** * @notice Onchain verification of reports from the offchain reporting protocol * @dev For details on its operation, see the offchain reporting protocol design * doc, which refers to this contract as simply the "contract". * @dev This contract is meant to aid rapid development of new applications based on OCR2. * However, for actual production contracts, it is expected that most of the logic of this contract * will be folded directly into the application contract. Inheritance prevents us from doing lots * of juicy storage layout optimizations, leading to a substantial increase in gas cost. * @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD */ abstract contract OCR2Base is OwnerIsCreator, OCR2Abstract { bool immutable internal UNIQUE_REPORTS; constructor(bool uniqueReports) { UNIQUE_REPORTS = uniqueReports; } uint256 constant private maxUint32 = (1 << 32) - 1; // Storing these fields used on the hot path in a ConfigInfo variable reduces the // retrieval of all of them to a single SLOAD. If any further fields are // added, make sure that storage of the struct still takes at most 32 bytes. struct ConfigInfo { bytes32 latestConfigDigest; uint8 f; // TODO: could be optimized by squeezing into one slot uint8 n; } ConfigInfo internal s_configInfo; // incremented each time a new config is posted. This count is incorporated // into the config digest, to prevent replay attacks. uint32 internal s_configCount; uint32 internal s_latestConfigBlockNumber; // makes it easier for offchain systems // to extract config from logs. // Used for s_oracles[a].role, where a is an address, to track the purpose // of the address, or to indicate that the address is unset. enum Role { // No oracle role has been set for address a Unset, // Signing address for the s_oracles[a].index'th oracle. I.e., report // signatures from this oracle should ecrecover back to address a. Signer, // Transmission address for the s_oracles[a].index'th oracle. I.e., if a // report is received by OCR2Aggregator.transmit in which msg.sender is // a, it is attributed to the s_oracles[a].index'th oracle. Transmitter } struct Oracle { uint8 index; // Index of oracle in s_signers/s_transmitters Role role; // Role of the address which mapped to this struct } mapping (address /* signer OR transmitter address */ => Oracle) internal s_oracles; // s_signers contains the signing address of each oracle address[] internal s_signers; // s_transmitters contains the transmission address of each oracle, // i.e. the address the oracle actually sends transactions to the contract from address[] internal s_transmitters; /* * Config logic */ // Reverts transaction if config args are invalid modifier checkConfigValid ( uint256 _numSigners, uint256 _numTransmitters, uint256 _f ) { require(_numSigners <= maxNumOracles, "too many signers"); require(_f > 0, "f must be positive"); require( _numSigners == _numTransmitters, "oracle addresses out of registration" ); require(_numSigners > 3*_f, "faulty-oracle f too high"); _; } struct SetConfigArgs { address[] signers; address[] transmitters; uint8 f; bytes onchainConfig; uint64 offchainConfigVersion; bytes offchainConfig; } /** * @notice sets offchain reporting protocol configuration incl. participating oracles * @param _signers addresses with which oracles sign the reports * @param _transmitters addresses oracles use to transmit the reports * @param _f number of faulty oracles the system can tolerate * @param _onchainConfig encoded on-chain contract configuration * @param _offchainConfigVersion version number for offchainEncoding schema * @param _offchainConfig encoded off-chain oracle configuration */ function setConfig( address[] memory _signers, address[] memory _transmitters, uint8 _f, bytes memory _onchainConfig, uint64 _offchainConfigVersion, bytes memory _offchainConfig ) external override checkConfigValid(_signers.length, _transmitters.length, _f) onlyOwner() { SetConfigArgs memory args = SetConfigArgs({ signers: _signers, transmitters: _transmitters, f: _f, onchainConfig: _onchainConfig, offchainConfigVersion: _offchainConfigVersion, offchainConfig: _offchainConfig }); _beforeSetConfig( args.f, args.onchainConfig ); while (s_signers.length != 0) { // remove any old signer/transmitter addresses uint lastIdx = s_signers.length - 1; address signer = s_signers[lastIdx]; address transmitter = s_transmitters[lastIdx]; delete s_oracles[signer]; delete s_oracles[transmitter]; s_signers.pop(); s_transmitters.pop(); } for (uint i = 0; i < args.signers.length; i++) { // add new signer/transmitter addresses require( s_oracles[args.signers[i]].role == Role.Unset, "repeated signer address" ); s_oracles[args.signers[i]] = Oracle(uint8(i), Role.Signer); require( s_oracles[args.transmitters[i]].role == Role.Unset, "repeated transmitter address" ); s_oracles[args.transmitters[i]] = Oracle(uint8(i), Role.Transmitter); s_signers.push(args.signers[i]); s_transmitters.push(args.transmitters[i]); } s_configInfo.f = args.f; uint32 previousConfigBlockNumber = s_latestConfigBlockNumber; s_latestConfigBlockNumber = uint32(block.number); s_configCount += 1; { s_configInfo.latestConfigDigest = configDigestFromConfigData( block.chainid, address(this), s_configCount, args.signers, args.transmitters, args.f, args.onchainConfig, args.offchainConfigVersion, args.offchainConfig ); } s_configInfo.n = uint8(args.signers.length); emit ConfigSet( previousConfigBlockNumber, s_configInfo.latestConfigDigest, s_configCount, args.signers, args.transmitters, args.f, args.onchainConfig, args.offchainConfigVersion, args.offchainConfig ); _afterSetConfig( args.f, args.onchainConfig ); } function configDigestFromConfigData( uint256 _chainId, address _contractAddress, uint64 _configCount, address[] memory _signers, address[] memory _transmitters, uint8 _f, bytes memory _onchainConfig, uint64 _encodedConfigVersion, bytes memory _encodedConfig ) internal pure returns (bytes32) { uint256 h = uint256(keccak256(abi.encode(_chainId, _contractAddress, _configCount, _signers, _transmitters, _f, _onchainConfig, _encodedConfigVersion, _encodedConfig ))); uint256 prefixMask = type(uint256).max << (256-16); // 0xFFFF00..00 uint256 prefix = 0x0001 << (256-16); // 0x000100..00 return bytes32((prefix & prefixMask) | (h & ~prefixMask)); } /** * @notice information about current offchain reporting protocol configuration * @return configCount ordinal number of current config, out of all configs applied to this contract so far * @return blockNumber block at which this config was set * @return configDigest domain-separation tag for current config (see configDigestFromConfigData) */ function latestConfigDetails() external override view returns ( uint32 configCount, uint32 blockNumber, bytes32 configDigest ) { return (s_configCount, s_latestConfigBlockNumber, s_configInfo.latestConfigDigest); } /** * @return list of addresses permitted to transmit reports to this contract * @dev The list will match the order used to specify the transmitter during setConfig */ function transmitters() external view returns(address[] memory) { return s_transmitters; } function _beforeSetConfig( uint8 _f, bytes memory _onchainConfig ) internal virtual; function _afterSetConfig( uint8 _f, bytes memory _onchainConfig ) internal virtual; function _report( bytes32 configDigest, uint40 epochAndRound, bytes memory report ) internal virtual; function _payTransmitter( uint32 initialGas, address transmitter ) internal virtual; // The constant-length components of the msg.data sent to transmit. // See the "If we wanted to call sam" example on for example reasoning // https://solidity.readthedocs.io/en/v0.7.2/abi-spec.html uint16 private constant TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT = 4 + // function selector 32 * 3 + // 3 words containing reportContext 32 + // word containing start location of abiencoded report value 32 + // word containing location start of abiencoded rs value 32 + // word containing start location of abiencoded ss value 32 + // rawVs value 32 + // word containing length of report 32 + // word containing length rs 32 + // word containing length of ss 0; // placeholder function requireExpectedMsgDataLength( bytes calldata report, bytes32[] calldata rs, bytes32[] calldata ss ) private pure { // calldata will never be big enough to make this overflow uint256 expected = uint256(TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT) + report.length + // one byte pure entry in _report rs.length * 32 + // 32 bytes per entry in _rs ss.length * 32 + // 32 bytes per entry in _ss 0; // placeholder require(msg.data.length == expected, "calldata length mismatch"); } /** * @notice transmit is called to post a new report to the contract * @param report serialized report, which the signatures are signing. * @param rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries * @param ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries * @param rawVs ith element is the the V component of the ith signature */ function transmit( // NOTE: If these parameters are changed, expectedMsgDataLength and/or // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly bytes32[3] calldata reportContext, bytes calldata report, bytes32[] calldata rs, bytes32[] calldata ss, bytes32 rawVs // signatures ) external override { uint256 initialGas = gasleft(); // This line must come first { // reportContext consists of: // reportContext[0]: ConfigDigest // reportContext[1]: 27 byte padding, 4-byte epoch and 1-byte round // reportContext[2]: ExtraHash bytes32 configDigest = reportContext[0]; uint40 epochAndRound = uint40(uint256(reportContext[1])); _report(configDigest, epochAndRound, report); emit Transmitted(configDigest, uint32(epochAndRound >> 8)); ConfigInfo memory configInfo = s_configInfo; require(configInfo.latestConfigDigest == configDigest, "configDigest mismatch"); requireExpectedMsgDataLength(report, rs, ss); uint256 expectedNumSignatures; if (UNIQUE_REPORTS) { expectedNumSignatures = (configInfo.n + configInfo.f)/2 + 1; } else { expectedNumSignatures = configInfo.f + 1; } require(rs.length == expectedNumSignatures, "wrong number of signatures"); require(rs.length == ss.length, "signatures out of registration"); Oracle memory transmitter = s_oracles[msg.sender]; require( // Check that sender is authorized to report transmitter.role == Role.Transmitter && msg.sender == s_transmitters[transmitter.index], "unauthorized transmitter" ); } { // Verify signatures attached to report bytes32 h = keccak256(abi.encode(keccak256(report), reportContext)); bool[maxNumOracles] memory signed; Oracle memory o; for (uint i = 0; i < rs.length; i++) { address signer = ecrecover(h, uint8(rawVs[i])+27, rs[i], ss[i]); o = s_oracles[signer]; require(o.role == Role.Signer, "address not authorized to sign"); require(!signed[o.index], "non-unique signature"); signed[o.index] = true; } } assert(initialGas < maxUint32); _payTransmitter(uint32(initialGas), msg.sender); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./OCR2Base.sol"; contract OCR2TitleRequest is OCR2Base { event TitleRequest(bytes32 requestId, string url); event TitleFulfillment(bytes32 requestId, string title); uint256 internal s_requestCount; mapping(bytes32 => bool) internal s_fulfilled; constructor() OCR2Base(false) { // We generate a bunch of requests in the constructor for easy testing // Not what you would do in a real implementation! ;-) request("https://blog.chain.link/what-is-chainlink/"); request("https://www.coindesk.com/mark-cuban-backed-nft-marketplace-mintable-raises-13m"); request("https://www.bloomberg.com/opinion/articles/2021-06-24/fidelity-manager-owned-gamestop-but-lacked-diamond-hands"); } function request(string memory url) public { bytes32 requestId = keccak256(bytes(url)); // abi.encodePacked is fine here because we're dealing with fixed size // elements only requestId = keccak256(abi.encodePacked(requestId, s_requestCount)); s_requestCount++; emit TitleRequest(requestId, url); } function fulfilled(bytes32 requestId) external view returns (bool) { return s_fulfilled[requestId]; } function _beforeSetConfig( uint8 _f, bytes memory _onchainConfig ) internal override { // We don't need to do any configuration for this contract } function _afterSetConfig( uint8 /* f */, bytes memory /* onchainConfig */ ) internal override { // We don't need to do any configuration for this contract } function _report( bytes32 /*configDigest*/, uint40 /*epochAndRound*/, bytes memory report ) internal override { (bytes32 requestId, string memory title) = abi.decode(report, (bytes32, string)); require(!s_fulfilled[requestId], "already fulfilled"); s_fulfilled[requestId] = true; emit TitleFulfillment(requestId, title); // In a real request-model contract, we'd perform a callback here } function _payTransmitter( uint32 initialGas, address transmitter ) internal override { // TODO } /// @inheritdoc OCR2Abstract function latestConfigDigestAndEpoch() external override view virtual returns( bool scanLogs, bytes32 configDigest, uint32 epoch ) { return (true, bytes32(0), 0); } function typeAndVersion() external override pure returns (string memory) { return "OCR2TitleRequest 1.0.0-alpha"; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./interfaces/TypeAndVersionInterface.sol"; import "./lib/ConfigDigestUtilEVMSimple.sol"; import "./OwnerIsCreator.sol"; import "./OCR2Abstract.sol"; /// @title OCRConfigurationStoreEVMSimple /// @notice This contract stores configurations for protocol versions OCR2 and /// above in contract storage. It uses the "EVMSimple" config digester. contract OCRConfigurationStoreEVMSimple is TypeAndVersionInterface { struct ConfigurationEVMSimple { address[] signers; address[] transmitters; bytes onchainConfig; bytes offchainConfig; address contractAddress; uint64 offchainConfigVersion; uint32 configCount; uint8 f; } /// @notice a list of configurations keyed by their digest mapping(bytes32 => ConfigurationEVMSimple) internal s_configurations; /// @notice emitted when a new configuration is added event NewConfiguration(bytes32 indexed configDigest); /// @notice adds a new configuration to the store function addConfig(ConfigurationEVMSimple calldata configuration) external returns (bytes32) { bytes32 configDigest = ConfigDigestUtilEVMSimple.configDigestFromConfigData( block.chainid, configuration.contractAddress, configuration.configCount, configuration.signers, configuration.transmitters, configuration.f, configuration.onchainConfig, configuration.offchainConfigVersion, configuration.offchainConfig ); s_configurations[configDigest] = configuration; emit NewConfiguration(configDigest); return configDigest; } /// @notice reads a configuration from the store function readConfig(bytes32 configDigest) external view returns (ConfigurationEVMSimple memory) { return s_configurations[configDigest]; } /// @inheritdoc TypeAndVersionInterface function typeAndVersion() external override pure virtual returns (string memory) { return "OCRConfigurationStoreEVMSimple 1.0.0"; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./ConfirmedOwner.sol"; /** * @title The OwnerIsCreator contract * @notice A contract with helpers for basic contract ownership. */ contract OwnerIsCreator is ConfirmedOwner { constructor( ) ConfirmedOwner( msg.sender ) { } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./SimpleWriteAccessController.sol"; /** * @title SimpleReadAccessController * @notice Gives access to: * - any externally owned account (note that offchain actors can always read * any contract storage regardless of onchain access control measures, so this * does not weaken the access control while improving usability) * - accounts explicitly added to an access list * @dev SimpleReadAccessController is not suitable for access controlling writes * since it grants any externally owned account access! See * SimpleWriteAccessController for that. */ contract SimpleReadAccessController is SimpleWriteAccessController { /** * @notice Returns the access of an address * @param _user The address to query */ function hasAccess( address _user, bytes memory _calldata ) public view virtual override returns (bool) { return super.hasAccess(_user, _calldata) || _user == tx.origin; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./OwnerIsCreator.sol"; import "./interfaces/AccessControllerInterface.sol"; /** * @title SimpleWriteAccessController * @notice Gives access to accounts explicitly added to an access list by the * controller's owner. * @dev does not make any special permissions for externally, see * SimpleReadAccessController for that. */ contract SimpleWriteAccessController is AccessControllerInterface, OwnerIsCreator { bool public checkEnabled; mapping(address => bool) internal accessList; event AddedAccess(address user); event RemovedAccess(address user); event CheckAccessEnabled(); event CheckAccessDisabled(); constructor() // TODO // this is modified from the version in the Chainlink monorepo // OwnerIsCreator() { checkEnabled = true; } /** * @notice Returns the access of an address * @param _user The address to query */ function hasAccess( address _user, bytes memory ) public view virtual override returns (bool) { return accessList[_user] || !checkEnabled; } /** * @notice Adds an address to the access list * @param _user The address to add */ function addAccess(address _user) external onlyOwner() { if (!accessList[_user]) { accessList[_user] = true; emit AddedAccess(_user); } } /** * @notice Removes an address from the access list * @param _user The address to remove */ function removeAccess(address _user) external onlyOwner() { if (accessList[_user]) { accessList[_user] = false; emit RemovedAccess(_user); } } /** * @notice makes the access check enforced */ function enableAccessCheck() external onlyOwner() { if (!checkEnabled) { checkEnabled = true; emit CheckAccessEnabled(); } } /** * @notice makes the access check unenforced */ function disableAccessCheck() external onlyOwner() { if (checkEnabled) { checkEnabled = false; emit CheckAccessDisabled(); } } /** * @dev reverts if the caller does not have access */ modifier checkAccess() { require(hasAccess(msg.sender, msg.data), "No access"); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract TestAccess { function testLatestTransmissionDetails(address oca) external returns (bool, bytes memory) { return oca.call("latestTransmissionDetails"); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./AccessControlledOCR2Aggregator.sol"; import "./AccessControlTestHelper.sol"; contract TestOCR2Aggregator is AccessControlledOCR2Aggregator { function testDecodeReport( bytes memory report ) public pure returns (uint32, bytes memory, int192[] memory) { Report memory decoded = _decodeReport(report); return (decoded.observationsTimestamp, decoded.observers, decoded.observations); } constructor( LinkTokenInterface _link, int192 _minAnswer, int192 _maxAnswer, AccessControllerInterface _billingAccessController, AccessControllerInterface _requesterAdminAccessController ) AccessControlledOCR2Aggregator( _link, _minAnswer, _maxAnswer, _billingAccessController, _requesterAdminAccessController, 0, "TEST" ) {} function testPayee( address _transmitter ) external view returns (address) { return s_payees[_transmitter]; } function getConfigDigest() public view returns (bytes32) { return s_latestConfigDigest; } function testBurnLink(uint256 amount) external { require(s_linkToken.transfer(address(1), amount), "transfer failed"); } function testReimbursementGasPriceGwei(uint256 txGasPrice, uint256 reasonableGasPrice, uint256 maximumGasPrice ) external pure returns (uint256) { return _reimbursementGasPriceGwei(txGasPrice, reasonableGasPrice, maximumGasPrice); } function testTransmitterGasCostWei(uint256 initialGas, uint256 gasPriceGwei, uint256 callDataGas, uint256 accountingGas, uint256 leftGas ) external pure returns (uint256) { return _transmitterGasCostWei( initialGas, gasPriceGwei, callDataGas, accountingGas, leftGas ); } function testTotalLinkDue() external view returns (uint256 linkDue) { return _totalLinkDue(); } function testSetTransmitterPayment(address transmitter, uint96 paymentJuels) external { require(s_transmitters[transmitter].active, "invalid transmitter"); s_transmitters[transmitter].paymentJuels = paymentJuels; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./interfaces/AggregatorValidatorInterface.sol"; contract TestValidator is AggregatorValidatorInterface { uint32 s_minGasUse; uint256 s_latestRoundId; event Validated( uint256 previousRoundId, int256 previousAnswer, uint256 currentRoundId, int256 currentAnswer, uint256 initialGas ); function validate( uint256 previousRoundId, int256 previousAnswer, uint256 currentRoundId, int256 currentAnswer ) external override returns (bool) { uint256 initialGas = gasleft(); emit Validated( previousRoundId, previousAnswer, currentRoundId, currentAnswer, initialGas ); s_latestRoundId = currentRoundId; uint256 minGasUse = s_minGasUse; while (initialGas - gasleft() < minGasUse) {} return true; } function setMinGasUse(uint32 minGasUse) external { s_minGasUse = minGasUse; } function latestRoundId() external view returns (uint256) { return s_latestRoundId; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface AccessControllerInterface { function hasAccess(address user, bytes calldata data) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; 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); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./AggregatorInterface.sol"; import "./AggregatorV3Interface.sol"; interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface { }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; 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 ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface AggregatorValidatorInterface { function validate( uint256 previousRoundId, int256 previousAnswer, uint256 currentRoundId, int256 currentAnswer ) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface LinkTokenInterface { function allowance(address owner, address spender) external view returns (uint256 remaining); function approve(address spender, uint256 value) external returns (bool success); function balanceOf(address owner) external view returns (uint256 balance); function decimals() external view returns (uint8 decimalPlaces); function decreaseApproval(address spender, uint256 addedValue) external returns (bool success); function increaseApproval(address spender, uint256 subtractedValue) external; function name() external view returns (string memory tokenName); function symbol() external view returns (string memory tokenSymbol); function totalSupply() external view returns (uint256 totalTokensIssued); function transfer(address to, uint256 value) external returns (bool success); function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool success); function transferFrom(address from, address to, uint256 value) external returns (bool success); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface OwnableInterface { function owner() external returns ( address ); function transferOwnership( address recipient ) external; function acceptOwnership() external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface TypeAndVersionInterface{ function typeAndVersion() external pure returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title ConfigDigestUtilEVMSimple /// @notice ConfigDigest related utility functions for "EVMSimple" config /// digester library ConfigDigestUtilEVMSimple { function configDigestFromConfigData( uint256 chainId, address contractAddress, uint64 configCount, address[] memory signers, address[] memory transmitters, uint8 f, bytes memory onchainConfig, uint64 offchainConfigVersion, bytes memory offchainConfig ) internal pure returns (bytes32) { uint256 hash = uint256( keccak256( abi.encode( chainId, contractAddress, configCount, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig ))); uint256 prefixMask = type(uint256).max << (256-16); // 0xFFFF00..00 uint256 prefix = 0x0001 << (256-16); // 0x000100..00 return bytes32((prefix & prefixMask) | (hash & ~prefixMask)); } }
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": {} }
[{"inputs":[{"internalType":"contract LinkTokenInterface","name":"_link","type":"address"},{"internalType":"int192","name":"_minAnswer","type":"int192"},{"internalType":"int192","name":"_maxAnswer","type":"int192"},{"internalType":"contract AccessControllerInterface","name":"_billingAccessController","type":"address"},{"internalType":"contract AccessControllerInterface","name":"_requesterAccessController","type":"address"},{"internalType":"uint8","name":"_decimals","type":"uint8"},{"internalType":"string","name":"description","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"}],"name":"AddedAccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"int256","name":"current","type":"int256"},{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"updatedAt","type":"uint256"}],"name":"AnswerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract AccessControllerInterface","name":"old","type":"address"},{"indexed":false,"internalType":"contract AccessControllerInterface","name":"current","type":"address"}],"name":"BillingAccessControllerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"maximumGasPriceGwei","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"reasonableGasPriceGwei","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"observationPaymentGjuels","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"transmissionPaymentGjuels","type":"uint32"},{"indexed":false,"internalType":"uint24","name":"accountingGas","type":"uint24"}],"name":"BillingSet","type":"event"},{"anonymous":false,"inputs":[],"name":"CheckAccessDisabled","type":"event"},{"anonymous":false,"inputs":[],"name":"CheckAccessEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"previousConfigBlockNumber","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"configCount","type":"uint64"},{"indexed":false,"internalType":"address[]","name":"signers","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"transmitters","type":"address[]"},{"indexed":false,"internalType":"uint8","name":"f","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"onchainConfig","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"ConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract LinkTokenInterface","name":"oldLinkToken","type":"address"},{"indexed":true,"internalType":"contract LinkTokenInterface","name":"newLinkToken","type":"address"}],"name":"LinkTokenSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":true,"internalType":"address","name":"startedBy","type":"address"},{"indexed":false,"internalType":"uint256","name":"startedAt","type":"uint256"}],"name":"NewRound","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"aggregatorRoundId","type":"uint32"},{"indexed":false,"internalType":"int192","name":"answer","type":"int192"},{"indexed":false,"internalType":"address","name":"transmitter","type":"address"},{"indexed":false,"internalType":"uint32","name":"observationsTimestamp","type":"uint32"},{"indexed":false,"internalType":"int192[]","name":"observations","type":"int192[]"},{"indexed":false,"internalType":"bytes","name":"observers","type":"bytes"},{"indexed":false,"internalType":"int192","name":"juelsPerFeeCoin","type":"int192"},{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint40","name":"epochAndRound","type":"uint40"}],"name":"NewTransmission","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"address","name":"payee","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"contract LinkTokenInterface","name":"linkToken","type":"address"}],"name":"OraclePaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"address","name":"current","type":"address"},{"indexed":true,"internalType":"address","name":"proposed","type":"address"}],"name":"PayeeshipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"address","name":"previous","type":"address"},{"indexed":true,"internalType":"address","name":"current","type":"address"}],"name":"PayeeshipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"}],"name":"RemovedAccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract AccessControllerInterface","name":"old","type":"address"},{"indexed":false,"internalType":"contract AccessControllerInterface","name":"current","type":"address"}],"name":"RequesterAccessControllerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"requester","type":"address"},{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"epoch","type":"uint32"},{"indexed":false,"internalType":"uint8","name":"round","type":"uint8"}],"name":"RoundRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"epoch","type":"uint32"}],"name":"Transmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract AggregatorValidatorInterface","name":"previousValidator","type":"address"},{"indexed":false,"internalType":"uint32","name":"previousGasLimit","type":"uint32"},{"indexed":true,"internalType":"contract AggregatorValidatorInterface","name":"currentValidator","type":"address"},{"indexed":false,"internalType":"uint32","name":"currentGasLimit","type":"uint32"}],"name":"ValidatorConfigSet","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"}],"name":"acceptPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"addAccess","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"checkEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"description","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disableAccessCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableAccessCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_roundId","type":"uint256"}],"name":"getAnswer","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBilling","outputs":[{"internalType":"uint32","name":"maximumGasPriceGwei","type":"uint32"},{"internalType":"uint32","name":"reasonableGasPriceGwei","type":"uint32"},{"internalType":"uint32","name":"observationPaymentGjuels","type":"uint32"},{"internalType":"uint32","name":"transmissionPaymentGjuels","type":"uint32"},{"internalType":"uint24","name":"accountingGas","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBillingAccessController","outputs":[{"internalType":"contract AccessControllerInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkToken","outputs":[{"internalType":"contract LinkTokenInterface","name":"linkToken","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRequesterAccessController","outputs":[{"internalType":"contract AccessControllerInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint80","name":"_roundId","type":"uint80"}],"name":"getRoundData","outputs":[{"internalType":"uint80","name":"roundId","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_roundId","type":"uint256"}],"name":"getTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransmitters","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getValidatorConfig","outputs":[{"internalType":"contract AggregatorValidatorInterface","name":"validator","type":"address"},{"internalType":"uint32","name":"gasLimit","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"bytes","name":"_calldata","type":"bytes"}],"name":"hasAccess","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestAnswer","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestConfigDetails","outputs":[{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestConfigDigestAndEpoch","outputs":[{"internalType":"bool","name":"scanLogs","type":"bool"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"internalType":"uint32","name":"epoch","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestRound","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestRoundData","outputs":[{"internalType":"uint80","name":"roundId","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestTransmissionDetails","outputs":[{"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"internalType":"uint32","name":"epoch","type":"uint32"},{"internalType":"uint8","name":"round","type":"uint8"},{"internalType":"int192","name":"latestAnswer_","type":"int192"},{"internalType":"uint64","name":"latestTimestamp_","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"linkAvailableForPayment","outputs":[{"internalType":"int256","name":"availableBalance","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxAnswer","outputs":[{"internalType":"int192","name":"","type":"int192"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minAnswer","outputs":[{"internalType":"int192","name":"","type":"int192"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"transmitterAddress","type":"address"}],"name":"oracleObservationCount","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"transmitterAddress","type":"address"}],"name":"owedPayment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"removeAccess","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestNewRound","outputs":[{"internalType":"uint80","name":"","type":"uint80"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"maximumGasPriceGwei","type":"uint32"},{"internalType":"uint32","name":"reasonableGasPriceGwei","type":"uint32"},{"internalType":"uint32","name":"observationPaymentGjuels","type":"uint32"},{"internalType":"uint32","name":"transmissionPaymentGjuels","type":"uint32"},{"internalType":"uint24","name":"accountingGas","type":"uint24"}],"name":"setBilling","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract AccessControllerInterface","name":"_billingAccessController","type":"address"}],"name":"setBillingAccessController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"internalType":"bytes","name":"onchainConfig","type":"bytes"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract LinkTokenInterface","name":"linkToken","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"setLinkToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"address[]","name":"payees","type":"address[]"}],"name":"setPayees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract AccessControllerInterface","name":"requesterAccessController","type":"address"}],"name":"setRequesterAccessController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract AggregatorValidatorInterface","name":"newValidator","type":"address"},{"internalType":"uint32","name":"newGasLimit","type":"uint32"}],"name":"setValidatorConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"},{"internalType":"address","name":"proposed","type":"address"}],"name":"transferPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[3]","name":"reportContext","type":"bytes32[3]"},{"internalType":"bytes","name":"report","type":"bytes"},{"internalType":"bytes32[]","name":"rs","type":"bytes32[]"},{"internalType":"bytes32[]","name":"ss","type":"bytes32[]"},{"internalType":"bytes32","name":"rawVs","type":"bytes32"}],"name":"transmit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"}],"name":"withdrawPayment","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60e06040523480156200001157600080fd5b5060405162005437380380620054378339810160408190526200003491620004a4565b868686868686863380600081620000925760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c557620000c58162000179565b5050601180546001600160a01b0319166001600160a01b038a169081179091556040519091506000907f4966a50c93f855342ccf6c5c0d358b85b91335b2acedc7da0932f691f351711a908290a36200011e8462000224565b60ff821660c052601062000133828262000686565b506200013f836200029d565b6200014c60008062000318565b50505050601791820b608052900b60a05250506015805460ff191660011790555062000752945050505050565b336001600160a01b03821603620001d35760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000089565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6012546001600160a01b0390811690821681146200029957601280546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f793cb73064f3c8cde7e187ae515511e6e56d1ee89bf08b82fa60fb70f8d4891291015b60405180910390a15b5050565b620002a7620003ff565b600f546001600160a01b0390811690821681146200029957600f80546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f27b89aede8b560578baaa25ee5ce3852c5eecad1e114b941bbd89e1eb4bae634910162000290565b62000322620003ff565b60408051808201909152600e546001600160a01b03808216808452600160a01b90920463ffffffff16602084015284161415806200037057508163ffffffff16816020015163ffffffff1614155b15620003fa576040805180820182526001600160a01b0385811680835263ffffffff8681166020948501819052600e80546001600160c01b0319168417600160a01b830217905586518786015187519316835294820152909392909116917fb04e3a37abe9c0fcdfebdeae019a8e2b12ddf53f5d55ffb0caccc1bedaca1541910160405180910390a35b505050565b6000546001600160a01b031633146200045b5760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000089565b565b6001600160a01b03811681146200047357600080fd5b50565b8051601781900b81146200048957600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600080600080600080600060e0888a031215620004c057600080fd5b8751620004cd816200045d565b96506020620004de89820162000476565b9650620004ee60408a0162000476565b9550606089015162000500816200045d565b60808a015190955062000513816200045d565b60a08a015190945060ff811681146200052b57600080fd5b60c08a01519093506001600160401b03808211156200054957600080fd5b818b0191508b601f8301126200055e57600080fd5b8151818111156200057357620005736200048e565b604051601f8201601f19908116603f011681019083821181831017156200059e576200059e6200048e565b816040528281528e86848701011115620005b757600080fd5b600093505b82841015620005db5784840186015181850187015292850192620005bc565b600086848301015280965050505050505092959891949750929550565b600181811c908216806200060d57607f821691505b6020821081036200062e57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620003fa57600081815260208120601f850160051c810160208610156200065d5750805b601f850160051c820191505b818110156200067e5782815560010162000669565b505050505050565b81516001600160401b03811115620006a257620006a26200048e565b620006ba81620006b38454620005f8565b8462000634565b602080601f831160018114620006f25760008415620006d95750858301515b600019600386901b1c1916600185901b1785556200067e565b600085815260208120601f198616915b82811015620007235788860151825594840194600190910190840162000702565b5085821015620007425787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c051614c996200079e600039600061039d01526000818161044c015281816120b501526133d30152600081816102e40152818161208d01526133a60152614c996000f3fe608060405234801561001057600080fd5b50600436106102955760003560e01c80639a6fc8f511610167578063d09dc339116100ce578063e76d516811610087578063e76d51681461073b578063eb4571631461074c578063eb5dcd6c1461075f578063f2fde38b14610772578063fbffd2c114610785578063feaf968c1461079857600080fd5b8063d09dc33914610691578063daffc4b514610699578063dc7f0124146106aa578063e3d0e712146106b7578063e4902f82146106ca578063e5fe4577146106f257600080fd5b8063b121e14711610120578063b121e14714610621578063b1dc65a414610634578063b5ab58dc14610647578063b633620c1461065a578063c10753291461066d578063c4c92b371461068057600080fd5b80639a6fc8f51461052c5780639bd2c0b1146105765780639c849b30146105b75780639e3ceeab146105ca578063a118f249146105dd578063afcb95d7146105f057600080fd5b8063668a0f021161020b57806381ff7048116101c457806381ff7048146104865780638205bf6a146104b65780638823da6c146104be5780638ac28d5a146104d15780638da5cb5b146104e457806398e5b12a1461050957600080fd5b8063668a0f021461041c5780636b14daf81461042457806370da2f67146104475780637284e4161461046e57806379ba5097146104765780638038e4a11461047e57600080fd5b8063313ce5671161025d578063313ce567146103985780634fb17470146103d157806350d25bcd146103e457806354fd4d50146103ec578063643dc105146103f4578063666cab8d1461040757600080fd5b80630a7569831461029a5780630eafb25b146102a4578063181f5a77146102ca57806322adbc78146102df5780632993726814610319575b600080fd5b6102a26107a0565b005b6102b76102b23660046140c0565b6107e9565b6040519081526020015b60405180910390f35b6102d26108ee565b6040516102c19190614123565b6103067f000000000000000000000000000000000000000000000000000000000000000081565b60405160179190910b81526020016102c1565b61035c600b54600160501b810463ffffffff90811692600160701b8304821692600160901b8104831692600160b01b82041691600160d01b90910462ffffff1690565b6040805163ffffffff9687168152948616602086015292851692840192909252909216606082015262ffffff909116608082015260a0016102c1565b6103bf7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016102c1565b6102a26103df366004614136565b61090e565b6102b7610b2b565b6102b7600681565b6102a2610402366004614181565b610bb6565b61040f610d9c565b6040516102c1919061423e565b6102b7610dfe565b610437610432366004614306565b610e72565b60405190151581526020016102c1565b6103067f000000000000000000000000000000000000000000000000000000000000000081565b6102d2610e9a565b6102a2610f01565b6102a2610fab565b600d54600a546040805163ffffffff808516825264010000000090940490931660208401528201526060016102c1565b6102b7610ff5565b6102a26104cc3660046140c0565b611081565b6102a26104df3660046140c0565b611103565b6000546001600160a01b03165b6040516001600160a01b0390911681526020016102c1565b610511611175565b60405169ffffffffffffffffffff90911681526020016102c1565b61053f61053a366004614355565b6112d0565b6040805169ffffffffffffffffffff968716815260208101959095528401929092526060830152909116608082015260a0016102c1565b604080518082018252600e546001600160a01b038116808352600160a01b90910463ffffffff166020928301819052835191825291810191909152016102c1565b6102a26105c53660046143cc565b611352565b6102a26105d83660046140c0565b611524565b6102a26105eb3660046140c0565b6115a3565b600a54600b546040805160008152602081019390935261010090910460081c63ffffffff16908201526060016102c1565b6102a261062f3660046140c0565b61161f565b6102a2610642366004614437565b6116fb565b6102b761065536600461451b565b611bc4565b6102b761066836600461451b565b611c34565b6102a261067b366004614534565b611c9c565b6012546001600160a01b03166104f1565b6102b7611eed565b600f546001600160a01b03166104f1565b6015546104379060ff1681565b6102a26106c536600461461f565b611f7d565b6106dd6106d83660046140c0565b6126ad565b60405163ffffffff90911681526020016102c1565b6106fa612763565b6040805195865263ffffffff909416602086015260ff9092169284019290925260179190910b60608301526001600160401b0316608082015260a0016102c1565b6011546001600160a01b03166104f1565b6102a261075a3660046146eb565b612803565b6102a261076d366004614136565b6128e6565b6102a26107803660046140c0565b612a1e565b6102a26107933660046140c0565b612a2f565b61053f612a40565b6107a8612b14565b60155460ff16156107e7576015805460ff191690556040517f3be8a977a014527b50ae38adda80b56911c267328965c98ddc385d248f53963890600090a15b565b6001600160a01b03811660009081526002602090815260408083208151606081018352905460ff80821615158084526101008304909116948301949094526201000090046001600160601b0316918101919091529061084b5750600092915050565b600b546020820151600091600160901b900463ffffffff169060069060ff16601f811061087a5761087a614719565b600881049190910154600b546108ad926007166004026101000a90910463ffffffff90811691600160301b900416614745565b63ffffffff166108bd9190614769565b6108cb90633b9aca00614769565b905081604001516001600160601b0316816108e69190614780565b949350505050565b60606040518060600160405280602a8152602001614c3a602a9139905090565b610916612b14565b6011546001600160a01b0390811690831681900361093357505050565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610977573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099b9190614793565b506109a4612b67565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156109eb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0f9190614793565b60405163a9059cbb60e01b81526001600160a01b038581166004830152602482018390529192509083169063a9059cbb906044016020604051808303816000875af1158015610a62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8691906147ac565b610ad75760405162461bcd60e51b815260206004820152601f60248201527f7472616e736665722072656d61696e696e672066756e6473206661696c65640060448201526064015b60405180910390fd5b601180546001600160a01b0319166001600160a01b0386811691821790925560405190918416907f4966a50c93f855342ccf6c5c0d358b85b91335b2acedc7da0932f691f351711a90600090a350505b5050565b6000610b6e336000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e7292505050565b610b8a5760405162461bcd60e51b8152600401610ace906147ce565b600b54600160301b900463ffffffff166000908152600c602052604090205460170b905090565b905090565b6012546001600160a01b0316610bd46000546001600160a01b031690565b6001600160a01b0316336001600160a01b03161480610c605750604051630d629b5f60e31b81526001600160a01b03821690636b14daf890610c1f90339060009036906004016147f1565b602060405180830381865afa158015610c3c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c6091906147ac565b610cac5760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79206f776e65722662696c6c696e6741646d696e2063616e2063616c6c6044820152606401610ace565b610cb4612b67565b600b805467ffffffffffffffff60501b1916600160501b63ffffffff89811691820263ffffffff60701b191692909217600160701b8984169081029190911767ffffffffffffffff60901b1916600160901b89851690810263ffffffff60b01b191691909117600160b01b9489169485021762ffffff60d01b1916600160d01b62ffffff89169081029190911790955560408051938452602084019290925290820152606081019190915260808101919091527f0bf184bf1bba9699114bdceddaf338a1b364252c5e497cc01918dde92031713f9060a00160405180910390a1505050505050565b60606005805480602002602001604051908101604052809291908181526020018280548015610df457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610dd6575b5050505050905090565b6000610e41336000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e7292505050565b610e5d5760405162461bcd60e51b8152600401610ace906147ce565b600b54600160301b900463ffffffff16905090565b6000610e7e8383612edc565b80610e9157506001600160a01b03831632145b90505b92915050565b6060610edd336000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e7292505050565b610ef95760405162461bcd60e51b8152600401610ace906147ce565b610bb1612f0c565b6001546001600160a01b03163314610f545760405162461bcd60e51b815260206004820152601660248201527526bab9ba10313290383937b837b9b2b21037bbb732b960511b6044820152606401610ace565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610fb3612b14565b60155460ff166107e7576015805460ff191660011790556040517faebf329500988c6488a0074e5a0a9ff304561fc5c6fc877aeb1d59c8282c348090600090a1565b6000611038336000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e7292505050565b6110545760405162461bcd60e51b8152600401610ace906147ce565b50600b5463ffffffff600160301b90910481166000908152600c6020526040902054600160e01b90041690565b611089612b14565b6001600160a01b03811660009081526016602052604090205460ff1615611100576001600160a01b038116600081815260166020908152604091829020805460ff1916905590519182527f3d68a6fce901d20453d1a7aa06bf3950302a735948037deb182a8db66df2a0d191015b60405180910390a15b50565b6001600160a01b0381811660009081526013602052604090205416331461116c5760405162461bcd60e51b815260206004820152601760248201527f4f6e6c792070617965652063616e2077697468647261770000000000000000006044820152606401610ace565b61110081612f95565b600080546001600160a01b03163314806112005750600f54604051630d629b5f60e31b81526001600160a01b0390911690636b14daf8906111bf90339060009036906004016147f1565b602060405180830381865afa1580156111dc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120091906147ac565b61124c5760405162461bcd60e51b815260206004820152601d60248201527f4f6e6c79206f776e6572267265717565737465722063616e2063616c6c0000006044820152606401610ace565b600b54600a546040805191825263ffffffff6101008404600881901c8216602085015260ff811684840152915164ffffffffff90921693600160301b9004169133917f41e3990591fd372502daa15842da15bc7f41c75309ab3ff4f56f1848c178825c9181900360600190a26112c3816001614831565b63ffffffff169250505090565b6000806000806000611319336000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e7292505050565b6113355760405162461bcd60e51b8152600401610ace906147ce565b61133e8661317d565b945094509450945094505b91939590929450565b61135a612b14565b8281146113a95760405162461bcd60e51b815260206004820181905260248201527f7472616e736d6974746572732e73697a6520213d207061796565732e73697a656044820152606401610ace565b60005b8381101561151d5760008585838181106113c8576113c8614719565b90506020020160208101906113dd91906140c0565b905060008484848181106113f3576113f3614719565b905060200201602081019061140891906140c0565b6001600160a01b0380841660009081526013602052604090205491925016801580806114455750826001600160a01b0316826001600160a01b0316145b6114855760405162461bcd60e51b81526020600482015260116024820152701c185e595948185b1c9958591e481cd95d607a1b6044820152606401610ace565b6001600160a01b03848116600090815260136020526040902080546001600160a01b0319168583169081179091559083161461150657826001600160a01b0316826001600160a01b0316856001600160a01b03167f78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b360405160405180910390a45b5050505080806115159061484e565b9150506113ac565b5050505050565b61152c612b14565b600f546001600160a01b039081169082168114610b2757600f80546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f27b89aede8b560578baaa25ee5ce3852c5eecad1e114b941bbd89e1eb4bae63491015b60405180910390a15050565b6115ab612b14565b6001600160a01b03811660009081526016602052604090205460ff16611100576001600160a01b038116600081815260166020908152604091829020805460ff1916600117905590519182527f87286ad1f399c8e82bf0c4ef4fcdc570ea2e1e92176e5c848b6413545b885db491016110f7565b6001600160a01b038181166000908152601460205260409020541633146116885760405162461bcd60e51b815260206004820152601f60248201527f6f6e6c792070726f706f736564207061796565732063616e20616363657074006044820152606401610ace565b6001600160a01b0381811660008181526013602090815260408083208054336001600160a01b031980831682179093556014909452828520805490921690915590519416939092849290917f78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b39190a45050565b60005a604080516101008082018352600b5460ff8116835290810464ffffffffff9081166020808501829052600160301b840463ffffffff90811696860196909652600160501b840486166060860152600160701b840486166080860152600160901b8404861660a0860152600160b01b840490951660c0850152600160d01b90920462ffffff1660e08401529394509092918c0135918216116117d05760405162461bcd60e51b815260206004820152600c60248201526b1cdd185b19481c995c1bdc9d60a21b6044820152606401610ace565b3360009081526002602052604090205460ff1661182f5760405162461bcd60e51b815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610ace565b600a548b35146118795760405162461bcd60e51b81526020600482015260156024820152740c6dedcccd2ce88d2cecae6e840dad2e6dac2e8c6d605b1b6044820152606401610ace565b6118878a8a8a8a8a8a613209565b8151611894906001614867565b60ff1687146118e55760405162461bcd60e51b815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610ace565b8685146119345760405162461bcd60e51b815260206004820152601e60248201527f7369676e617475726573206f7574206f6620726567697374726174696f6e00006044820152606401610ace565b60008a8a604051611946929190614880565b60405190819003812061195d918e90602001614890565b60408051601f19818403018152828252805160209182012083830190925260008084529083018190529092509060005b8a811015611af55760006001858a84602081106119ac576119ac614719565b6119b991901a601b614867565b8f8f868181106119cb576119cb614719565b905060200201358e8e878181106119e4576119e4614719565b9050602002013560405160008152602001604052604051611a21949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611a43573d6000803e3d6000fd5b505060408051601f198101516001600160a01b03811660009081526003602090815290849020838501909452925460ff8082161515808552610100909204169383019390935290955092509050611ace5760405162461bcd60e51b815260206004820152600f60248201526e39b4b3b730ba3ab9329032b93937b960891b6044820152606401610ace565b826020015160080260ff166001901b84019350508080611aed9061484e565b91505061198d565b5081827e010101010101010101010101010101010101010101010101010101010101011614611b595760405162461bcd60e51b815260206004820152601060248201526f323ab83634b1b0ba329039b4b3b732b960811b6044820152606401610ace565b5060009150611ba89050838d836020020135848e8e8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506132a692505050565b9050611bb683828633613781565b505050505050505050505050565b6000611c07336000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e7292505050565b611c235760405162461bcd60e51b8152600401610ace906147ce565b611c2c8261389b565b90505b919050565b6000611c77336000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e7292505050565b611c935760405162461bcd60e51b8152600401610ace906147ce565b611c2c826138cd565b6000546001600160a01b0316331480611d265750601254604051630d629b5f60e31b81526001600160a01b0390911690636b14daf890611ce590339060009036906004016147f1565b602060405180830381865afa158015611d02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d2691906147ac565b611d725760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79206f776e65722662696c6c696e6741646d696e2063616e2063616c6c6044820152606401610ace565b6000611d7c613906565b6011546040516370a0823160e01b81523060048201529192506000916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611dca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dee9190614793565b905081811015611e375760405162461bcd60e51b8152602060048201526014602482015273696e73756666696369656e742062616c616e636560601b6044820152606401610ace565b6011546001600160a01b031663a9059cbb85611e5c611e5686866148a6565b87613ad0565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015611ea7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ecb91906147ac565b611ee75760405162461bcd60e51b8152600401610ace906148b9565b50505050565b6011546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611f3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5e9190614793565b90506000611f6a613906565b9050611f7681836148e5565b9250505090565b611f85612b14565b601f86511115611fca5760405162461bcd60e51b815260206004820152601060248201526f746f6f206d616e79206f7261636c657360801b6044820152606401610ace565b84518651146120145760405162461bcd60e51b81526020600482015260166024820152750dee4c2c6d8ca40d8cadccee8d040dad2e6dac2e8c6d60531b6044820152606401610ace565b8551612021856003614905565b60ff16106120715760405162461bcd60e51b815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610ace565b61207d8460ff16613ae7565b60408051600160f81b60208201527f0000000000000000000000000000000000000000000000000000000000000000821b60218201527f000000000000000000000000000000000000000000000000000000000000000090911b6039820152605101604051602081830303815290604052805190602001208380519060200120146121425760405162461bcd60e51b8152602060048201526015602482015274696e76616c6964206f6e636861696e436f6e66696760581b6044820152606401610ace565b6040805160c0810182528781526020810187905260ff861691810191909152606081018490526001600160401b038316608082015260a08101829052600b805465ffffffffff0019169055612195612b67565b60045460005b81811015612246576000600482815481106121b8576121b8614719565b6000918252602082200154600580546001600160a01b03909216935090849081106121e5576121e5614719565b60009182526020808320909101546001600160a01b039485168352600382526040808420805461ffff1916905594168252600290529190912080546dffffffffffffffffffffffffffff19169055508061223e8161484e565b91505061219b565b5061225360046000613f80565b61225f60056000613f80565b60005b8251518110156124d857600360008460000151838151811061228657612286614719565b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff16156122fa5760405162461bcd60e51b815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610ace565b604080518082019091526001815260ff82166020820152835180516003916000918590811061232b5761232b614719565b6020908102919091018101516001600160a01b03168252818101929092526040016000908120835181549484015161ffff1990951690151561ff0019161761010060ff9095169490940293909317909255840151805160029291908490811061239657612396614719565b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff161561240a5760405162461bcd60e51b815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610ace565b60405180606001604052806001151581526020018260ff16815260200160006001600160601b0316815250600260008560200151848151811061244f5761244f614719565b6020908102919091018101516001600160a01b03168252818101929092526040908101600020835181549385015194909201516001600160601b0316620100000262010000600160701b031960ff959095166101000261ff00199315159390931661ffff19909416939093179190911792909216179055806124d08161484e565b915050612262565b50815180516124ef91600491602090910190613f9e565b506020808301518051612506926005920190613f9e565b506040820151600b805460ff191660ff909216919091179055600d805467ffffffff0000000019811664010000000063ffffffff438116820292831785559083048116936001939092600092612563928692908216911617614831565b92506101000a81548163ffffffff021916908363ffffffff1602179055506125c24630600d60009054906101000a900463ffffffff1663ffffffff1686600001518760200151886040015189606001518a608001518b60a00151613b2c565b600a819055600d5484516020860151604080880151606089015160808a015160a08b015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e059861262b988b98919763ffffffff909116969195909490939092909190614921565b60405180910390a1600b54600160301b900463ffffffff1660005b8451518110156126a05781600682601f811061266457612664614719565b600891828204019190066004026101000a81548163ffffffff021916908363ffffffff16021790555080806126989061484e565b915050612646565b5050505050505050505050565b6001600160a01b03811660009081526002602090815260408083208151606081018352905460ff80821615158084526101008304909116948301949094526201000090046001600160601b0316918101919091529061270f5750600092915050565b6006816020015160ff16601f811061272957612729614719565b600881049190910154600b5461275c926007166004026101000a90910463ffffffff90811691600160301b900416614745565b9392505050565b6000808080803332146127af5760405162461bcd60e51b81526020600482015260146024820152734f6e6c792063616c6c61626c6520627920454f4160601b6044820152606401610ace565b5050600a54600b5463ffffffff600160301b820481166000908152600c60205260409020549296610100909204600881901c8216965064ffffffffff169450601783900b9350600160e01b90920490911690565b61280b612b14565b60408051808201909152600e546001600160a01b03808216808452600160a01b90920463ffffffff166020840152841614158061285857508163ffffffff16816020015163ffffffff1614155b156128e1576040805180820182526001600160a01b0385811680835263ffffffff8681166020948501819052600e80546001600160c01b0319168417600160a01b830217905586518786015187519316835294820152909392909116917fb04e3a37abe9c0fcdfebdeae019a8e2b12ddf53f5d55ffb0caccc1bedaca1541910160405180910390a35b505050565b6001600160a01b0382811660009081526013602052604090205416331461294f5760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c792063757272656e742070617965652063616e207570646174650000006044820152606401610ace565b6001600160a01b03811633036129a75760405162461bcd60e51b815260206004820152601760248201527f63616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610ace565b6001600160a01b03808316600090815260146020526040902080548383166001600160a01b0319821681179092559091169081146128e1576040516001600160a01b038084169133918616907f84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e3836790600090a4505050565b612a26612b14565b61110081613b88565b612a37612b14565b61110081613c31565b6000806000806000612a89336000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e7292505050565b612aa55760405162461bcd60e51b8152600401610ace906147ce565b612b03600b54600160301b900463ffffffff9081166000818152600c602090815260409182902082516060810184529054601781900b808352600160c01b82048716938301849052600160e01b909104909516920182905291938490565b945094509450945094509091929394565b6000546001600160a01b031633146107e75760405162461bcd60e51b815260206004820152601660248201527527b7363c9031b0b63630b1363290313c9037bbb732b960511b6044820152606401610ace565b601154600b54604080516103e08101918290526001600160a01b0390931692600160301b90920463ffffffff1691600091600690601f908285855b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411612ba25790505050505050905060006005805480602002602001604051908101604052809291908181526020018280548015612c3d57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612c1f575b5050505050905060005b8151811015612ece57600060026000848481518110612c6857612c68614719565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060000160029054906101000a90046001600160601b03166001600160601b03169050600060026000858581518110612cca57612cca614719565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060000160026101000a8154816001600160601b0302191690836001600160601b0316021790555060008483601f8110612d2d57612d2d614719565b6020020151600b5490870363ffffffff9081169250600160901b909104168102633b9aca000282018015612ec357600060136000878781518110612d7357612d73614719565b6020908102919091018101516001600160a01b03908116835290820192909252604090810160002054905163a9059cbb60e01b815290821660048201819052602482018590529250908a169063a9059cbb906044016020604051808303816000875af1158015612de7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e0b91906147ac565b612e275760405162461bcd60e51b8152600401610ace906148b9565b878786601f8110612e3a57612e3a614719565b602002019063ffffffff16908163ffffffff1681525050886001600160a01b0316816001600160a01b0316878781518110612e7757612e77614719565b60200260200101516001600160a01b03167fd0b1dac935d85bd54cf0a33b0d41d39f8cf53a968465fc7ea2377526b8ac712c85604051612eb991815260200190565b60405180910390a4505b505050600101612c47565b5061151d600683601f614003565b6001600160a01b03821660009081526016602052604081205460ff1680610e9157505060155460ff161592915050565b606060108054612f1b906149b6565b80601f0160208091040260200160405190810160405280929190818152602001828054612f47906149b6565b8015610df45780601f10612f6957610100808354040283529160200191610df4565b820191906000526020600020905b815481529060010190602001808311612f7757509395945050505050565b6001600160a01b0381166000908152600260209081526040918290208251606081018452905460ff80821615158084526101008304909116938301939093526201000090046001600160601b031692810192909252612ff2575050565b6000612ffd836107e9565b905080156128e1576001600160a01b038381166000908152601360205260409081902054601154915163a9059cbb60e01b8152908316600482018190526024820185905292919091169063a9059cbb906044016020604051808303816000875af115801561306f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061309391906147ac565b6130af5760405162461bcd60e51b8152600401610ace906148b9565b600b60000160069054906101000a900463ffffffff166006846020015160ff16601f81106130df576130df614719565b6008810491909101805460079092166004026101000a63ffffffff8181021990931693909216919091029190911790556001600160a01b03848116600081815260026020908152604091829020805462010000600160701b0319169055601154915186815291841693851692917fd0b1dac935d85bd54cf0a33b0d41d39f8cf53a968465fc7ea2377526b8ac712c910160405180910390a450505050565b60008080808063ffffffff69ffffffffffffffffffff871611156131af57506000935083925082915081905080611349565b5050505063ffffffff8281166000908152600c602090815260409182902082516060810184529054601781900b808352600160c01b82048616938301849052600160e01b9091049094169201829052939491939250908490565b6000613216826020614769565b613221856020614769565b61322d88610144614780565b6132379190614780565b6132419190614780565b61324c906000614780565b905036811461329d5760405162461bcd60e51b815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610ace565b50505050505050565b6000806132b283613ca0565b9050601f816040015151111561330a5760405162461bcd60e51b815260206004820152601e60248201527f6e756d206f62736572766174696f6e73206f7574206f6620626f756e647300006044820152606401610ace565b604081015151865160ff16106133625760405162461bcd60e51b815260206004820152601e60248201527f746f6f206665772076616c75657320746f207472757374206d656469616e00006044820152606401610ace565b64ffffffffff841660208701526040810151805160009190613386906002906149ea565b8151811061339657613396614719565b602002602001015190508060170b7f000000000000000000000000000000000000000000000000000000000000000060170b131580156133fc57507f000000000000000000000000000000000000000000000000000000000000000060170b8160170b13155b6134485760405162461bcd60e51b815260206004820152601e60248201527f6d656469616e206973206f7574206f66206d696e2d6d61782072616e676500006044820152606401610ace565b6040870180519061345882614a0c565b63ffffffff1663ffffffff168152505060405180606001604052808260170b8152602001836000015163ffffffff1681526020014263ffffffff16815250600c6000896040015163ffffffff1663ffffffff16815260200190815260200160002060008201518160000160006101000a8154816001600160c01b03021916908360170b6001600160c01b0316021790555060208201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550604082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555090505086600b60008201518160000160006101000a81548160ff021916908360ff16021790555060208201518160000160016101000a81548164ffffffffff021916908364ffffffffff16021790555060408201518160000160066101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001600a6101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600e6101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160000160126101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160000160166101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600001601a6101000a81548162ffffff021916908362ffffff160217905550905050866040015163ffffffff167fc797025feeeaf2cd924c99e9205acb8ec04d5cad21c41ce637a38fb6dee6016a823385600001518660400151876020015188606001518d8d6040516136ca989796959493929190614a2f565b60405180910390a26040808801518351915163ffffffff9283168152600092909116907f0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac602719060200160405180910390a3866040015163ffffffff168160170b7f0559884fd3a460db3073b7fc896cc77986f16e378210ded43186175bf646fc5f4260405161375a91815260200190565b60405180910390a361377387604001518260170b613d45565b506060015195945050505050565b60008360170b12611ee75760006137b3633b9aca003a04866080015163ffffffff16876060015163ffffffff16613e49565b90506010360260005a905060006137dc8663ffffffff1685858b60e0015162ffffff1686613e6f565b90506000670de0b6b3a76400006001600160c01b03891683026001600160a01b03881660009081526002602052604090205460c08c01519290910492506201000090046001600160601b039081169163ffffffff16633b9aca0002828401019081168211156138515750505050505050611ee7565b6001600160a01b038816600090815260026020526040902080546001600160601b03909216620100000262010000600160701b031990921691909117905550505050505050505050565b600063ffffffff8211156138b157506000919050565b5063ffffffff166000908152600c602052604090205460170b90565b600063ffffffff8211156138e357506000919050565b5063ffffffff9081166000908152600c6020526040902054600160e01b90041690565b600080600580548060200260200160405190810160405280929190818152602001828054801561395f57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613941575b50508351600b54604080516103e08101918290529697509195600160301b90910463ffffffff169450600093509150600690601f908285855b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116139985790505050505050905060005b83811015613a2b578181601f81106139f8576139f8614719565b6020020151613a079084614745565b613a179063ffffffff1687614780565b955080613a238161484e565b9150506139de565b50600b54613a4a90600160901b900463ffffffff16633b9aca00614769565b613a549086614769565b945060005b83811015613ac85760026000868381518110613a7757613a77614719565b6020908102919091018101516001600160a01b0316825281019190915260400160002054613ab4906201000090046001600160601b031687614780565b955080613ac08161484e565b915050613a59565b505050505090565b600081831015613ae1575081610e94565b50919050565b806000106111005760405162461bcd60e51b815260206004820152601260248201527166206d75737420626520706f73697469766560701b6044820152606401610ace565b6000808a8a8a8a8a8a8a8a8a604051602001613b5099989796959493929190614ad6565b60408051601f1981840301815291905280516020909101206001600160f01b0316600160f01b179150505b9998505050505050505050565b336001600160a01b03821603613be05760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610ace565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6012546001600160a01b039081169082168114610b2757601280546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f793cb73064f3c8cde7e187ae515511e6e56d1ee89bf08b82fa60fb70f8d489129101611597565b613cd46040518060800160405280600063ffffffff1681526020016060815260200160608152602001600060170b81525090565b6000806060600085806020019051810190613cef9190614b71565b92965090945092509050613d038683613ed3565b81516040805160208082019690965281519082018252918252805160808101825263ffffffff969096168652938501529183015260170b606082015292915050565b60408051808201909152600e546001600160a01b038116808352600160a01b90910463ffffffff166020830152613d7b57505050565b6000613d88600185614745565b63ffffffff8181166000818152600c6020908152604091829020549087015187519251602481019490945260179190910b60448401819052898516606485015260848401899052949550613e0a93169160a40160408051601f198184030181529190526020810180516001600160e01b031663beed9b5160e01b179052613f44565b61151d5760405162461bcd60e51b815260206004820152601060248201526f696e73756666696369656e742067617360801b6044820152606401610ace565b60008383811015613e5c57600285850304015b613e668184613ad0565b95945050505050565b600081861015613ec15760405162461bcd60e51b815260206004820181905260248201527f6c6566744761732063616e6e6f742065786365656420696e697469616c4761736044820152606401610ace565b50633b9aca0094039190910101020290565b600081516020613ee39190614769565b613eee9060a0614780565b613ef9906000614780565b9050808351146128e15760405162461bcd60e51b81526020600482015260166024820152750e4cae0dee4e840d8cadccee8d040dad2e6dac2e8c6d60531b6044820152606401610ace565b60005a6113888110613f785761138881039050846040820482031115613f78576000808451602086016000888af150600191505b509392505050565b50805460008255906000526020600020908101906111009190614096565b828054828255906000526020600020908101928215613ff3579160200282015b82811115613ff357825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613fbe565b50613fff929150614096565b5090565b600483019183908215613ff35791602002820160005b8382111561405d57835183826101000a81548163ffffffff021916908363ffffffff1602179055509260200192600401602081600301049283019260010302614019565b801561408d5782816101000a81549063ffffffff021916905560040160208160030104928301926001030261405d565b5050613fff9291505b5b80821115613fff5760008155600101614097565b6001600160a01b038116811461110057600080fd5b6000602082840312156140d257600080fd5b813561275c816140ab565b6000815180845260005b81811015614103576020818501810151868301820152016140e7565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000610e9160208301846140dd565b6000806040838503121561414957600080fd5b8235614154816140ab565b91506020830135614164816140ab565b809150509250929050565b63ffffffff8116811461110057600080fd5b600080600080600060a0868803121561419957600080fd5b85356141a48161416f565b945060208601356141b48161416f565b935060408601356141c48161416f565b925060608601356141d48161416f565b9150608086013562ffffff811681146141ec57600080fd5b809150509295509295909350565b600081518084526020808501945080840160005b838110156142335781516001600160a01b03168752958201959082019060010161420e565b509495945050505050565b602081526000610e9160208301846141fa565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561428f5761428f614251565b604052919050565b600082601f8301126142a857600080fd5b81356001600160401b038111156142c1576142c1614251565b6142d4601f8201601f1916602001614267565b8181528460208386010111156142e957600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561431957600080fd5b8235614324816140ab565b915060208301356001600160401b0381111561433f57600080fd5b61434b85828601614297565b9150509250929050565b60006020828403121561436757600080fd5b813569ffffffffffffffffffff8116811461275c57600080fd5b60008083601f84011261439357600080fd5b5081356001600160401b038111156143aa57600080fd5b6020830191508360208260051b85010111156143c557600080fd5b9250929050565b600080600080604085870312156143e257600080fd5b84356001600160401b03808211156143f957600080fd5b61440588838901614381565b9096509450602087013591508082111561441e57600080fd5b5061442b87828801614381565b95989497509550505050565b60008060008060008060008060e0898b03121561445357600080fd5b606089018a81111561446457600080fd5b899850356001600160401b038082111561447d57600080fd5b818b0191508b601f83011261449157600080fd5b8135818111156144a057600080fd5b8c60208285010111156144b257600080fd5b6020830199508098505060808b01359150808211156144d057600080fd5b6144dc8c838d01614381565b909750955060a08b01359150808211156144f557600080fd5b506145028b828c01614381565b999c989b50969995989497949560c00135949350505050565b60006020828403121561452d57600080fd5b5035919050565b6000806040838503121561454757600080fd5b8235614552816140ab565b946020939093013593505050565b60006001600160401b0382111561457957614579614251565b5060051b60200190565b600082601f83011261459457600080fd5b813560206145a96145a483614560565b614267565b82815260059290921b840181019181810190868411156145c857600080fd5b8286015b848110156145ec5780356145df816140ab565b83529183019183016145cc565b509695505050505050565b803560ff81168114611c2f57600080fd5b80356001600160401b0381168114611c2f57600080fd5b60008060008060008060c0878903121561463857600080fd5b86356001600160401b038082111561464f57600080fd5b61465b8a838b01614583565b9750602089013591508082111561467157600080fd5b61467d8a838b01614583565b965061468b60408a016145f7565b955060608901359150808211156146a157600080fd5b6146ad8a838b01614297565b94506146bb60808a01614608565b935060a08901359150808211156146d157600080fd5b506146de89828a01614297565b9150509295509295509295565b600080604083850312156146fe57600080fd5b8235614709816140ab565b915060208301356141648161416f565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b63ffffffff8281168282160390808211156147625761476261472f565b5092915050565b8082028115828204841417610e9457610e9461472f565b80820180821115610e9457610e9461472f565b6000602082840312156147a557600080fd5b5051919050565b6000602082840312156147be57600080fd5b8151801515811461275c57600080fd5b6020808252600990820152684e6f2061636365737360b81b604082015260600190565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b63ffffffff8181168382160190808211156147625761476261472f565b6000600182016148605761486061472f565b5060010190565b60ff8181168382160190811115610e9457610e9461472f565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b81810381811115610e9457610e9461472f565b602080825260129082015271696e73756666696369656e742066756e647360701b604082015260600190565b81810360008312801583831316838312821617156147625761476261472f565b60ff81811683821602908116908181146147625761476261472f565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526149518184018a6141fa565b9050828103608084015261496581896141fa565b905060ff871660a084015282810360c084015261498281876140dd565b90506001600160401b03851660e08401528281036101008401526149a681856140dd565b9c9b505050505050505050505050565b600181811c908216806149ca57607f821691505b602082108103613ae157634e487b7160e01b600052602260045260246000fd5b600082614a0757634e487b7160e01b600052601260045260246000fd5b500490565b600063ffffffff808316818103614a2557614a2561472f565b6001019392505050565b601789810b82526001600160a01b03891660208084019190915263ffffffff891660408401526101006060840181905288519084018190526000926101208501928a810192855b81811015614a94578451840b86529482019493820193600101614a76565b50505050508281036080840152614aab81886140dd565b915050614abd60a083018660170b9052565b8360c0830152613b7b60e083018464ffffffffff169052565b8981526001600160a01b03891660208201526001600160401b03888116604083015261012060608301819052600091614b118483018b6141fa565b91508382036080850152614b25828a6141fa565b915060ff881660a085015283820360c0850152614b4282886140dd565b90861660e085015283810361010085015290506149a681856140dd565b8051601781900b8114611c2f57600080fd5b60008060008060808587031215614b8757600080fd5b8451614b928161416f565b80945050602080860151935060408601516001600160401b03811115614bb757600080fd5b8601601f81018813614bc857600080fd5b8051614bd66145a482614560565b81815260059190911b8201830190838101908a831115614bf557600080fd5b928401925b82841015614c1a57614c0b84614b5f565b82529284019290840190614bfa565b8096505050505050614c2e60608601614b5f565b90509295919450925056fe416363657373436f6e74726f6c6c65644f43523241676772656761746f7220312e302e302d616c706861a26469706673582212201645cfb8ed2a0d111e7ffa313a8264260a72335f33fbad27406436ee9de87c3a64736f6c63430008130033000000000000000000000000779877a7b0d9e8603169ddbd7836e478b4624789000000000000000000000000000000000000000000000000000000000000000100000000000000000000ffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000a4c494e4b202f2055534400000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102955760003560e01c80639a6fc8f511610167578063d09dc339116100ce578063e76d516811610087578063e76d51681461073b578063eb4571631461074c578063eb5dcd6c1461075f578063f2fde38b14610772578063fbffd2c114610785578063feaf968c1461079857600080fd5b8063d09dc33914610691578063daffc4b514610699578063dc7f0124146106aa578063e3d0e712146106b7578063e4902f82146106ca578063e5fe4577146106f257600080fd5b8063b121e14711610120578063b121e14714610621578063b1dc65a414610634578063b5ab58dc14610647578063b633620c1461065a578063c10753291461066d578063c4c92b371461068057600080fd5b80639a6fc8f51461052c5780639bd2c0b1146105765780639c849b30146105b75780639e3ceeab146105ca578063a118f249146105dd578063afcb95d7146105f057600080fd5b8063668a0f021161020b57806381ff7048116101c457806381ff7048146104865780638205bf6a146104b65780638823da6c146104be5780638ac28d5a146104d15780638da5cb5b146104e457806398e5b12a1461050957600080fd5b8063668a0f021461041c5780636b14daf81461042457806370da2f67146104475780637284e4161461046e57806379ba5097146104765780638038e4a11461047e57600080fd5b8063313ce5671161025d578063313ce567146103985780634fb17470146103d157806350d25bcd146103e457806354fd4d50146103ec578063643dc105146103f4578063666cab8d1461040757600080fd5b80630a7569831461029a5780630eafb25b146102a4578063181f5a77146102ca57806322adbc78146102df5780632993726814610319575b600080fd5b6102a26107a0565b005b6102b76102b23660046140c0565b6107e9565b6040519081526020015b60405180910390f35b6102d26108ee565b6040516102c19190614123565b6103067f000000000000000000000000000000000000000000000000000000000000000181565b60405160179190910b81526020016102c1565b61035c600b54600160501b810463ffffffff90811692600160701b8304821692600160901b8104831692600160b01b82041691600160d01b90910462ffffff1690565b6040805163ffffffff9687168152948616602086015292851692840192909252909216606082015262ffffff909116608082015260a0016102c1565b6103bf7f000000000000000000000000000000000000000000000000000000000000000881565b60405160ff90911681526020016102c1565b6102a26103df366004614136565b61090e565b6102b7610b2b565b6102b7600681565b6102a2610402366004614181565b610bb6565b61040f610d9c565b6040516102c1919061423e565b6102b7610dfe565b610437610432366004614306565b610e72565b60405190151581526020016102c1565b6103067f00000000000000000000ffffffffffffffffffffffffffffffffffffffffffff81565b6102d2610e9a565b6102a2610f01565b6102a2610fab565b600d54600a546040805163ffffffff808516825264010000000090940490931660208401528201526060016102c1565b6102b7610ff5565b6102a26104cc3660046140c0565b611081565b6102a26104df3660046140c0565b611103565b6000546001600160a01b03165b6040516001600160a01b0390911681526020016102c1565b610511611175565b60405169ffffffffffffffffffff90911681526020016102c1565b61053f61053a366004614355565b6112d0565b6040805169ffffffffffffffffffff968716815260208101959095528401929092526060830152909116608082015260a0016102c1565b604080518082018252600e546001600160a01b038116808352600160a01b90910463ffffffff166020928301819052835191825291810191909152016102c1565b6102a26105c53660046143cc565b611352565b6102a26105d83660046140c0565b611524565b6102a26105eb3660046140c0565b6115a3565b600a54600b546040805160008152602081019390935261010090910460081c63ffffffff16908201526060016102c1565b6102a261062f3660046140c0565b61161f565b6102a2610642366004614437565b6116fb565b6102b761065536600461451b565b611bc4565b6102b761066836600461451b565b611c34565b6102a261067b366004614534565b611c9c565b6012546001600160a01b03166104f1565b6102b7611eed565b600f546001600160a01b03166104f1565b6015546104379060ff1681565b6102a26106c536600461461f565b611f7d565b6106dd6106d83660046140c0565b6126ad565b60405163ffffffff90911681526020016102c1565b6106fa612763565b6040805195865263ffffffff909416602086015260ff9092169284019290925260179190910b60608301526001600160401b0316608082015260a0016102c1565b6011546001600160a01b03166104f1565b6102a261075a3660046146eb565b612803565b6102a261076d366004614136565b6128e6565b6102a26107803660046140c0565b612a1e565b6102a26107933660046140c0565b612a2f565b61053f612a40565b6107a8612b14565b60155460ff16156107e7576015805460ff191690556040517f3be8a977a014527b50ae38adda80b56911c267328965c98ddc385d248f53963890600090a15b565b6001600160a01b03811660009081526002602090815260408083208151606081018352905460ff80821615158084526101008304909116948301949094526201000090046001600160601b0316918101919091529061084b5750600092915050565b600b546020820151600091600160901b900463ffffffff169060069060ff16601f811061087a5761087a614719565b600881049190910154600b546108ad926007166004026101000a90910463ffffffff90811691600160301b900416614745565b63ffffffff166108bd9190614769565b6108cb90633b9aca00614769565b905081604001516001600160601b0316816108e69190614780565b949350505050565b60606040518060600160405280602a8152602001614c3a602a9139905090565b610916612b14565b6011546001600160a01b0390811690831681900361093357505050565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610977573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099b9190614793565b506109a4612b67565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156109eb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0f9190614793565b60405163a9059cbb60e01b81526001600160a01b038581166004830152602482018390529192509083169063a9059cbb906044016020604051808303816000875af1158015610a62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8691906147ac565b610ad75760405162461bcd60e51b815260206004820152601f60248201527f7472616e736665722072656d61696e696e672066756e6473206661696c65640060448201526064015b60405180910390fd5b601180546001600160a01b0319166001600160a01b0386811691821790925560405190918416907f4966a50c93f855342ccf6c5c0d358b85b91335b2acedc7da0932f691f351711a90600090a350505b5050565b6000610b6e336000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e7292505050565b610b8a5760405162461bcd60e51b8152600401610ace906147ce565b600b54600160301b900463ffffffff166000908152600c602052604090205460170b905090565b905090565b6012546001600160a01b0316610bd46000546001600160a01b031690565b6001600160a01b0316336001600160a01b03161480610c605750604051630d629b5f60e31b81526001600160a01b03821690636b14daf890610c1f90339060009036906004016147f1565b602060405180830381865afa158015610c3c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c6091906147ac565b610cac5760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79206f776e65722662696c6c696e6741646d696e2063616e2063616c6c6044820152606401610ace565b610cb4612b67565b600b805467ffffffffffffffff60501b1916600160501b63ffffffff89811691820263ffffffff60701b191692909217600160701b8984169081029190911767ffffffffffffffff60901b1916600160901b89851690810263ffffffff60b01b191691909117600160b01b9489169485021762ffffff60d01b1916600160d01b62ffffff89169081029190911790955560408051938452602084019290925290820152606081019190915260808101919091527f0bf184bf1bba9699114bdceddaf338a1b364252c5e497cc01918dde92031713f9060a00160405180910390a1505050505050565b60606005805480602002602001604051908101604052809291908181526020018280548015610df457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610dd6575b5050505050905090565b6000610e41336000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e7292505050565b610e5d5760405162461bcd60e51b8152600401610ace906147ce565b600b54600160301b900463ffffffff16905090565b6000610e7e8383612edc565b80610e9157506001600160a01b03831632145b90505b92915050565b6060610edd336000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e7292505050565b610ef95760405162461bcd60e51b8152600401610ace906147ce565b610bb1612f0c565b6001546001600160a01b03163314610f545760405162461bcd60e51b815260206004820152601660248201527526bab9ba10313290383937b837b9b2b21037bbb732b960511b6044820152606401610ace565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610fb3612b14565b60155460ff166107e7576015805460ff191660011790556040517faebf329500988c6488a0074e5a0a9ff304561fc5c6fc877aeb1d59c8282c348090600090a1565b6000611038336000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e7292505050565b6110545760405162461bcd60e51b8152600401610ace906147ce565b50600b5463ffffffff600160301b90910481166000908152600c6020526040902054600160e01b90041690565b611089612b14565b6001600160a01b03811660009081526016602052604090205460ff1615611100576001600160a01b038116600081815260166020908152604091829020805460ff1916905590519182527f3d68a6fce901d20453d1a7aa06bf3950302a735948037deb182a8db66df2a0d191015b60405180910390a15b50565b6001600160a01b0381811660009081526013602052604090205416331461116c5760405162461bcd60e51b815260206004820152601760248201527f4f6e6c792070617965652063616e2077697468647261770000000000000000006044820152606401610ace565b61110081612f95565b600080546001600160a01b03163314806112005750600f54604051630d629b5f60e31b81526001600160a01b0390911690636b14daf8906111bf90339060009036906004016147f1565b602060405180830381865afa1580156111dc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120091906147ac565b61124c5760405162461bcd60e51b815260206004820152601d60248201527f4f6e6c79206f776e6572267265717565737465722063616e2063616c6c0000006044820152606401610ace565b600b54600a546040805191825263ffffffff6101008404600881901c8216602085015260ff811684840152915164ffffffffff90921693600160301b9004169133917f41e3990591fd372502daa15842da15bc7f41c75309ab3ff4f56f1848c178825c9181900360600190a26112c3816001614831565b63ffffffff169250505090565b6000806000806000611319336000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e7292505050565b6113355760405162461bcd60e51b8152600401610ace906147ce565b61133e8661317d565b945094509450945094505b91939590929450565b61135a612b14565b8281146113a95760405162461bcd60e51b815260206004820181905260248201527f7472616e736d6974746572732e73697a6520213d207061796565732e73697a656044820152606401610ace565b60005b8381101561151d5760008585838181106113c8576113c8614719565b90506020020160208101906113dd91906140c0565b905060008484848181106113f3576113f3614719565b905060200201602081019061140891906140c0565b6001600160a01b0380841660009081526013602052604090205491925016801580806114455750826001600160a01b0316826001600160a01b0316145b6114855760405162461bcd60e51b81526020600482015260116024820152701c185e595948185b1c9958591e481cd95d607a1b6044820152606401610ace565b6001600160a01b03848116600090815260136020526040902080546001600160a01b0319168583169081179091559083161461150657826001600160a01b0316826001600160a01b0316856001600160a01b03167f78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b360405160405180910390a45b5050505080806115159061484e565b9150506113ac565b5050505050565b61152c612b14565b600f546001600160a01b039081169082168114610b2757600f80546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f27b89aede8b560578baaa25ee5ce3852c5eecad1e114b941bbd89e1eb4bae63491015b60405180910390a15050565b6115ab612b14565b6001600160a01b03811660009081526016602052604090205460ff16611100576001600160a01b038116600081815260166020908152604091829020805460ff1916600117905590519182527f87286ad1f399c8e82bf0c4ef4fcdc570ea2e1e92176e5c848b6413545b885db491016110f7565b6001600160a01b038181166000908152601460205260409020541633146116885760405162461bcd60e51b815260206004820152601f60248201527f6f6e6c792070726f706f736564207061796565732063616e20616363657074006044820152606401610ace565b6001600160a01b0381811660008181526013602090815260408083208054336001600160a01b031980831682179093556014909452828520805490921690915590519416939092849290917f78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b39190a45050565b60005a604080516101008082018352600b5460ff8116835290810464ffffffffff9081166020808501829052600160301b840463ffffffff90811696860196909652600160501b840486166060860152600160701b840486166080860152600160901b8404861660a0860152600160b01b840490951660c0850152600160d01b90920462ffffff1660e08401529394509092918c0135918216116117d05760405162461bcd60e51b815260206004820152600c60248201526b1cdd185b19481c995c1bdc9d60a21b6044820152606401610ace565b3360009081526002602052604090205460ff1661182f5760405162461bcd60e51b815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610ace565b600a548b35146118795760405162461bcd60e51b81526020600482015260156024820152740c6dedcccd2ce88d2cecae6e840dad2e6dac2e8c6d605b1b6044820152606401610ace565b6118878a8a8a8a8a8a613209565b8151611894906001614867565b60ff1687146118e55760405162461bcd60e51b815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610ace565b8685146119345760405162461bcd60e51b815260206004820152601e60248201527f7369676e617475726573206f7574206f6620726567697374726174696f6e00006044820152606401610ace565b60008a8a604051611946929190614880565b60405190819003812061195d918e90602001614890565b60408051601f19818403018152828252805160209182012083830190925260008084529083018190529092509060005b8a811015611af55760006001858a84602081106119ac576119ac614719565b6119b991901a601b614867565b8f8f868181106119cb576119cb614719565b905060200201358e8e878181106119e4576119e4614719565b9050602002013560405160008152602001604052604051611a21949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611a43573d6000803e3d6000fd5b505060408051601f198101516001600160a01b03811660009081526003602090815290849020838501909452925460ff8082161515808552610100909204169383019390935290955092509050611ace5760405162461bcd60e51b815260206004820152600f60248201526e39b4b3b730ba3ab9329032b93937b960891b6044820152606401610ace565b826020015160080260ff166001901b84019350508080611aed9061484e565b91505061198d565b5081827e010101010101010101010101010101010101010101010101010101010101011614611b595760405162461bcd60e51b815260206004820152601060248201526f323ab83634b1b0ba329039b4b3b732b960811b6044820152606401610ace565b5060009150611ba89050838d836020020135848e8e8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506132a692505050565b9050611bb683828633613781565b505050505050505050505050565b6000611c07336000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e7292505050565b611c235760405162461bcd60e51b8152600401610ace906147ce565b611c2c8261389b565b90505b919050565b6000611c77336000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e7292505050565b611c935760405162461bcd60e51b8152600401610ace906147ce565b611c2c826138cd565b6000546001600160a01b0316331480611d265750601254604051630d629b5f60e31b81526001600160a01b0390911690636b14daf890611ce590339060009036906004016147f1565b602060405180830381865afa158015611d02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d2691906147ac565b611d725760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79206f776e65722662696c6c696e6741646d696e2063616e2063616c6c6044820152606401610ace565b6000611d7c613906565b6011546040516370a0823160e01b81523060048201529192506000916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611dca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dee9190614793565b905081811015611e375760405162461bcd60e51b8152602060048201526014602482015273696e73756666696369656e742062616c616e636560601b6044820152606401610ace565b6011546001600160a01b031663a9059cbb85611e5c611e5686866148a6565b87613ad0565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015611ea7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ecb91906147ac565b611ee75760405162461bcd60e51b8152600401610ace906148b9565b50505050565b6011546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611f3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5e9190614793565b90506000611f6a613906565b9050611f7681836148e5565b9250505090565b611f85612b14565b601f86511115611fca5760405162461bcd60e51b815260206004820152601060248201526f746f6f206d616e79206f7261636c657360801b6044820152606401610ace565b84518651146120145760405162461bcd60e51b81526020600482015260166024820152750dee4c2c6d8ca40d8cadccee8d040dad2e6dac2e8c6d60531b6044820152606401610ace565b8551612021856003614905565b60ff16106120715760405162461bcd60e51b815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610ace565b61207d8460ff16613ae7565b60408051600160f81b60208201527f0000000000000000000000000000000000000000000000000000000000000001821b60218201527f00000000000000000000ffffffffffffffffffffffffffffffffffffffffffff90911b6039820152605101604051602081830303815290604052805190602001208380519060200120146121425760405162461bcd60e51b8152602060048201526015602482015274696e76616c6964206f6e636861696e436f6e66696760581b6044820152606401610ace565b6040805160c0810182528781526020810187905260ff861691810191909152606081018490526001600160401b038316608082015260a08101829052600b805465ffffffffff0019169055612195612b67565b60045460005b81811015612246576000600482815481106121b8576121b8614719565b6000918252602082200154600580546001600160a01b03909216935090849081106121e5576121e5614719565b60009182526020808320909101546001600160a01b039485168352600382526040808420805461ffff1916905594168252600290529190912080546dffffffffffffffffffffffffffff19169055508061223e8161484e565b91505061219b565b5061225360046000613f80565b61225f60056000613f80565b60005b8251518110156124d857600360008460000151838151811061228657612286614719565b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff16156122fa5760405162461bcd60e51b815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610ace565b604080518082019091526001815260ff82166020820152835180516003916000918590811061232b5761232b614719565b6020908102919091018101516001600160a01b03168252818101929092526040016000908120835181549484015161ffff1990951690151561ff0019161761010060ff9095169490940293909317909255840151805160029291908490811061239657612396614719565b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff161561240a5760405162461bcd60e51b815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610ace565b60405180606001604052806001151581526020018260ff16815260200160006001600160601b0316815250600260008560200151848151811061244f5761244f614719565b6020908102919091018101516001600160a01b03168252818101929092526040908101600020835181549385015194909201516001600160601b0316620100000262010000600160701b031960ff959095166101000261ff00199315159390931661ffff19909416939093179190911792909216179055806124d08161484e565b915050612262565b50815180516124ef91600491602090910190613f9e565b506020808301518051612506926005920190613f9e565b506040820151600b805460ff191660ff909216919091179055600d805467ffffffff0000000019811664010000000063ffffffff438116820292831785559083048116936001939092600092612563928692908216911617614831565b92506101000a81548163ffffffff021916908363ffffffff1602179055506125c24630600d60009054906101000a900463ffffffff1663ffffffff1686600001518760200151886040015189606001518a608001518b60a00151613b2c565b600a819055600d5484516020860151604080880151606089015160808a015160a08b015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e059861262b988b98919763ffffffff909116969195909490939092909190614921565b60405180910390a1600b54600160301b900463ffffffff1660005b8451518110156126a05781600682601f811061266457612664614719565b600891828204019190066004026101000a81548163ffffffff021916908363ffffffff16021790555080806126989061484e565b915050612646565b5050505050505050505050565b6001600160a01b03811660009081526002602090815260408083208151606081018352905460ff80821615158084526101008304909116948301949094526201000090046001600160601b0316918101919091529061270f5750600092915050565b6006816020015160ff16601f811061272957612729614719565b600881049190910154600b5461275c926007166004026101000a90910463ffffffff90811691600160301b900416614745565b9392505050565b6000808080803332146127af5760405162461bcd60e51b81526020600482015260146024820152734f6e6c792063616c6c61626c6520627920454f4160601b6044820152606401610ace565b5050600a54600b5463ffffffff600160301b820481166000908152600c60205260409020549296610100909204600881901c8216965064ffffffffff169450601783900b9350600160e01b90920490911690565b61280b612b14565b60408051808201909152600e546001600160a01b03808216808452600160a01b90920463ffffffff166020840152841614158061285857508163ffffffff16816020015163ffffffff1614155b156128e1576040805180820182526001600160a01b0385811680835263ffffffff8681166020948501819052600e80546001600160c01b0319168417600160a01b830217905586518786015187519316835294820152909392909116917fb04e3a37abe9c0fcdfebdeae019a8e2b12ddf53f5d55ffb0caccc1bedaca1541910160405180910390a35b505050565b6001600160a01b0382811660009081526013602052604090205416331461294f5760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c792063757272656e742070617965652063616e207570646174650000006044820152606401610ace565b6001600160a01b03811633036129a75760405162461bcd60e51b815260206004820152601760248201527f63616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610ace565b6001600160a01b03808316600090815260146020526040902080548383166001600160a01b0319821681179092559091169081146128e1576040516001600160a01b038084169133918616907f84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e3836790600090a4505050565b612a26612b14565b61110081613b88565b612a37612b14565b61110081613c31565b6000806000806000612a89336000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e7292505050565b612aa55760405162461bcd60e51b8152600401610ace906147ce565b612b03600b54600160301b900463ffffffff9081166000818152600c602090815260409182902082516060810184529054601781900b808352600160c01b82048716938301849052600160e01b909104909516920182905291938490565b945094509450945094509091929394565b6000546001600160a01b031633146107e75760405162461bcd60e51b815260206004820152601660248201527527b7363c9031b0b63630b1363290313c9037bbb732b960511b6044820152606401610ace565b601154600b54604080516103e08101918290526001600160a01b0390931692600160301b90920463ffffffff1691600091600690601f908285855b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411612ba25790505050505050905060006005805480602002602001604051908101604052809291908181526020018280548015612c3d57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612c1f575b5050505050905060005b8151811015612ece57600060026000848481518110612c6857612c68614719565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060000160029054906101000a90046001600160601b03166001600160601b03169050600060026000858581518110612cca57612cca614719565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060000160026101000a8154816001600160601b0302191690836001600160601b0316021790555060008483601f8110612d2d57612d2d614719565b6020020151600b5490870363ffffffff9081169250600160901b909104168102633b9aca000282018015612ec357600060136000878781518110612d7357612d73614719565b6020908102919091018101516001600160a01b03908116835290820192909252604090810160002054905163a9059cbb60e01b815290821660048201819052602482018590529250908a169063a9059cbb906044016020604051808303816000875af1158015612de7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e0b91906147ac565b612e275760405162461bcd60e51b8152600401610ace906148b9565b878786601f8110612e3a57612e3a614719565b602002019063ffffffff16908163ffffffff1681525050886001600160a01b0316816001600160a01b0316878781518110612e7757612e77614719565b60200260200101516001600160a01b03167fd0b1dac935d85bd54cf0a33b0d41d39f8cf53a968465fc7ea2377526b8ac712c85604051612eb991815260200190565b60405180910390a4505b505050600101612c47565b5061151d600683601f614003565b6001600160a01b03821660009081526016602052604081205460ff1680610e9157505060155460ff161592915050565b606060108054612f1b906149b6565b80601f0160208091040260200160405190810160405280929190818152602001828054612f47906149b6565b8015610df45780601f10612f6957610100808354040283529160200191610df4565b820191906000526020600020905b815481529060010190602001808311612f7757509395945050505050565b6001600160a01b0381166000908152600260209081526040918290208251606081018452905460ff80821615158084526101008304909116938301939093526201000090046001600160601b031692810192909252612ff2575050565b6000612ffd836107e9565b905080156128e1576001600160a01b038381166000908152601360205260409081902054601154915163a9059cbb60e01b8152908316600482018190526024820185905292919091169063a9059cbb906044016020604051808303816000875af115801561306f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061309391906147ac565b6130af5760405162461bcd60e51b8152600401610ace906148b9565b600b60000160069054906101000a900463ffffffff166006846020015160ff16601f81106130df576130df614719565b6008810491909101805460079092166004026101000a63ffffffff8181021990931693909216919091029190911790556001600160a01b03848116600081815260026020908152604091829020805462010000600160701b0319169055601154915186815291841693851692917fd0b1dac935d85bd54cf0a33b0d41d39f8cf53a968465fc7ea2377526b8ac712c910160405180910390a450505050565b60008080808063ffffffff69ffffffffffffffffffff871611156131af57506000935083925082915081905080611349565b5050505063ffffffff8281166000908152600c602090815260409182902082516060810184529054601781900b808352600160c01b82048616938301849052600160e01b9091049094169201829052939491939250908490565b6000613216826020614769565b613221856020614769565b61322d88610144614780565b6132379190614780565b6132419190614780565b61324c906000614780565b905036811461329d5760405162461bcd60e51b815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610ace565b50505050505050565b6000806132b283613ca0565b9050601f816040015151111561330a5760405162461bcd60e51b815260206004820152601e60248201527f6e756d206f62736572766174696f6e73206f7574206f6620626f756e647300006044820152606401610ace565b604081015151865160ff16106133625760405162461bcd60e51b815260206004820152601e60248201527f746f6f206665772076616c75657320746f207472757374206d656469616e00006044820152606401610ace565b64ffffffffff841660208701526040810151805160009190613386906002906149ea565b8151811061339657613396614719565b602002602001015190508060170b7f000000000000000000000000000000000000000000000000000000000000000160170b131580156133fc57507f00000000000000000000ffffffffffffffffffffffffffffffffffffffffffff60170b8160170b13155b6134485760405162461bcd60e51b815260206004820152601e60248201527f6d656469616e206973206f7574206f66206d696e2d6d61782072616e676500006044820152606401610ace565b6040870180519061345882614a0c565b63ffffffff1663ffffffff168152505060405180606001604052808260170b8152602001836000015163ffffffff1681526020014263ffffffff16815250600c6000896040015163ffffffff1663ffffffff16815260200190815260200160002060008201518160000160006101000a8154816001600160c01b03021916908360170b6001600160c01b0316021790555060208201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550604082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555090505086600b60008201518160000160006101000a81548160ff021916908360ff16021790555060208201518160000160016101000a81548164ffffffffff021916908364ffffffffff16021790555060408201518160000160066101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001600a6101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600e6101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160000160126101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160000160166101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600001601a6101000a81548162ffffff021916908362ffffff160217905550905050866040015163ffffffff167fc797025feeeaf2cd924c99e9205acb8ec04d5cad21c41ce637a38fb6dee6016a823385600001518660400151876020015188606001518d8d6040516136ca989796959493929190614a2f565b60405180910390a26040808801518351915163ffffffff9283168152600092909116907f0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac602719060200160405180910390a3866040015163ffffffff168160170b7f0559884fd3a460db3073b7fc896cc77986f16e378210ded43186175bf646fc5f4260405161375a91815260200190565b60405180910390a361377387604001518260170b613d45565b506060015195945050505050565b60008360170b12611ee75760006137b3633b9aca003a04866080015163ffffffff16876060015163ffffffff16613e49565b90506010360260005a905060006137dc8663ffffffff1685858b60e0015162ffffff1686613e6f565b90506000670de0b6b3a76400006001600160c01b03891683026001600160a01b03881660009081526002602052604090205460c08c01519290910492506201000090046001600160601b039081169163ffffffff16633b9aca0002828401019081168211156138515750505050505050611ee7565b6001600160a01b038816600090815260026020526040902080546001600160601b03909216620100000262010000600160701b031990921691909117905550505050505050505050565b600063ffffffff8211156138b157506000919050565b5063ffffffff166000908152600c602052604090205460170b90565b600063ffffffff8211156138e357506000919050565b5063ffffffff9081166000908152600c6020526040902054600160e01b90041690565b600080600580548060200260200160405190810160405280929190818152602001828054801561395f57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613941575b50508351600b54604080516103e08101918290529697509195600160301b90910463ffffffff169450600093509150600690601f908285855b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116139985790505050505050905060005b83811015613a2b578181601f81106139f8576139f8614719565b6020020151613a079084614745565b613a179063ffffffff1687614780565b955080613a238161484e565b9150506139de565b50600b54613a4a90600160901b900463ffffffff16633b9aca00614769565b613a549086614769565b945060005b83811015613ac85760026000868381518110613a7757613a77614719565b6020908102919091018101516001600160a01b0316825281019190915260400160002054613ab4906201000090046001600160601b031687614780565b955080613ac08161484e565b915050613a59565b505050505090565b600081831015613ae1575081610e94565b50919050565b806000106111005760405162461bcd60e51b815260206004820152601260248201527166206d75737420626520706f73697469766560701b6044820152606401610ace565b6000808a8a8a8a8a8a8a8a8a604051602001613b5099989796959493929190614ad6565b60408051601f1981840301815291905280516020909101206001600160f01b0316600160f01b179150505b9998505050505050505050565b336001600160a01b03821603613be05760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610ace565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6012546001600160a01b039081169082168114610b2757601280546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f793cb73064f3c8cde7e187ae515511e6e56d1ee89bf08b82fa60fb70f8d489129101611597565b613cd46040518060800160405280600063ffffffff1681526020016060815260200160608152602001600060170b81525090565b6000806060600085806020019051810190613cef9190614b71565b92965090945092509050613d038683613ed3565b81516040805160208082019690965281519082018252918252805160808101825263ffffffff969096168652938501529183015260170b606082015292915050565b60408051808201909152600e546001600160a01b038116808352600160a01b90910463ffffffff166020830152613d7b57505050565b6000613d88600185614745565b63ffffffff8181166000818152600c6020908152604091829020549087015187519251602481019490945260179190910b60448401819052898516606485015260848401899052949550613e0a93169160a40160408051601f198184030181529190526020810180516001600160e01b031663beed9b5160e01b179052613f44565b61151d5760405162461bcd60e51b815260206004820152601060248201526f696e73756666696369656e742067617360801b6044820152606401610ace565b60008383811015613e5c57600285850304015b613e668184613ad0565b95945050505050565b600081861015613ec15760405162461bcd60e51b815260206004820181905260248201527f6c6566744761732063616e6e6f742065786365656420696e697469616c4761736044820152606401610ace565b50633b9aca0094039190910101020290565b600081516020613ee39190614769565b613eee9060a0614780565b613ef9906000614780565b9050808351146128e15760405162461bcd60e51b81526020600482015260166024820152750e4cae0dee4e840d8cadccee8d040dad2e6dac2e8c6d60531b6044820152606401610ace565b60005a6113888110613f785761138881039050846040820482031115613f78576000808451602086016000888af150600191505b509392505050565b50805460008255906000526020600020908101906111009190614096565b828054828255906000526020600020908101928215613ff3579160200282015b82811115613ff357825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613fbe565b50613fff929150614096565b5090565b600483019183908215613ff35791602002820160005b8382111561405d57835183826101000a81548163ffffffff021916908363ffffffff1602179055509260200192600401602081600301049283019260010302614019565b801561408d5782816101000a81549063ffffffff021916905560040160208160030104928301926001030261405d565b5050613fff9291505b5b80821115613fff5760008155600101614097565b6001600160a01b038116811461110057600080fd5b6000602082840312156140d257600080fd5b813561275c816140ab565b6000815180845260005b81811015614103576020818501810151868301820152016140e7565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000610e9160208301846140dd565b6000806040838503121561414957600080fd5b8235614154816140ab565b91506020830135614164816140ab565b809150509250929050565b63ffffffff8116811461110057600080fd5b600080600080600060a0868803121561419957600080fd5b85356141a48161416f565b945060208601356141b48161416f565b935060408601356141c48161416f565b925060608601356141d48161416f565b9150608086013562ffffff811681146141ec57600080fd5b809150509295509295909350565b600081518084526020808501945080840160005b838110156142335781516001600160a01b03168752958201959082019060010161420e565b509495945050505050565b602081526000610e9160208301846141fa565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561428f5761428f614251565b604052919050565b600082601f8301126142a857600080fd5b81356001600160401b038111156142c1576142c1614251565b6142d4601f8201601f1916602001614267565b8181528460208386010111156142e957600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561431957600080fd5b8235614324816140ab565b915060208301356001600160401b0381111561433f57600080fd5b61434b85828601614297565b9150509250929050565b60006020828403121561436757600080fd5b813569ffffffffffffffffffff8116811461275c57600080fd5b60008083601f84011261439357600080fd5b5081356001600160401b038111156143aa57600080fd5b6020830191508360208260051b85010111156143c557600080fd5b9250929050565b600080600080604085870312156143e257600080fd5b84356001600160401b03808211156143f957600080fd5b61440588838901614381565b9096509450602087013591508082111561441e57600080fd5b5061442b87828801614381565b95989497509550505050565b60008060008060008060008060e0898b03121561445357600080fd5b606089018a81111561446457600080fd5b899850356001600160401b038082111561447d57600080fd5b818b0191508b601f83011261449157600080fd5b8135818111156144a057600080fd5b8c60208285010111156144b257600080fd5b6020830199508098505060808b01359150808211156144d057600080fd5b6144dc8c838d01614381565b909750955060a08b01359150808211156144f557600080fd5b506145028b828c01614381565b999c989b50969995989497949560c00135949350505050565b60006020828403121561452d57600080fd5b5035919050565b6000806040838503121561454757600080fd5b8235614552816140ab565b946020939093013593505050565b60006001600160401b0382111561457957614579614251565b5060051b60200190565b600082601f83011261459457600080fd5b813560206145a96145a483614560565b614267565b82815260059290921b840181019181810190868411156145c857600080fd5b8286015b848110156145ec5780356145df816140ab565b83529183019183016145cc565b509695505050505050565b803560ff81168114611c2f57600080fd5b80356001600160401b0381168114611c2f57600080fd5b60008060008060008060c0878903121561463857600080fd5b86356001600160401b038082111561464f57600080fd5b61465b8a838b01614583565b9750602089013591508082111561467157600080fd5b61467d8a838b01614583565b965061468b60408a016145f7565b955060608901359150808211156146a157600080fd5b6146ad8a838b01614297565b94506146bb60808a01614608565b935060a08901359150808211156146d157600080fd5b506146de89828a01614297565b9150509295509295509295565b600080604083850312156146fe57600080fd5b8235614709816140ab565b915060208301356141648161416f565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b63ffffffff8281168282160390808211156147625761476261472f565b5092915050565b8082028115828204841417610e9457610e9461472f565b80820180821115610e9457610e9461472f565b6000602082840312156147a557600080fd5b5051919050565b6000602082840312156147be57600080fd5b8151801515811461275c57600080fd5b6020808252600990820152684e6f2061636365737360b81b604082015260600190565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b63ffffffff8181168382160190808211156147625761476261472f565b6000600182016148605761486061472f565b5060010190565b60ff8181168382160190811115610e9457610e9461472f565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b81810381811115610e9457610e9461472f565b602080825260129082015271696e73756666696369656e742066756e647360701b604082015260600190565b81810360008312801583831316838312821617156147625761476261472f565b60ff81811683821602908116908181146147625761476261472f565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526149518184018a6141fa565b9050828103608084015261496581896141fa565b905060ff871660a084015282810360c084015261498281876140dd565b90506001600160401b03851660e08401528281036101008401526149a681856140dd565b9c9b505050505050505050505050565b600181811c908216806149ca57607f821691505b602082108103613ae157634e487b7160e01b600052602260045260246000fd5b600082614a0757634e487b7160e01b600052601260045260246000fd5b500490565b600063ffffffff808316818103614a2557614a2561472f565b6001019392505050565b601789810b82526001600160a01b03891660208084019190915263ffffffff891660408401526101006060840181905288519084018190526000926101208501928a810192855b81811015614a94578451840b86529482019493820193600101614a76565b50505050508281036080840152614aab81886140dd565b915050614abd60a083018660170b9052565b8360c0830152613b7b60e083018464ffffffffff169052565b8981526001600160a01b03891660208201526001600160401b03888116604083015261012060608301819052600091614b118483018b6141fa565b91508382036080850152614b25828a6141fa565b915060ff881660a085015283820360c0850152614b4282886140dd565b90861660e085015283810361010085015290506149a681856140dd565b8051601781900b8114611c2f57600080fd5b60008060008060808587031215614b8757600080fd5b8451614b928161416f565b80945050602080860151935060408601516001600160401b03811115614bb757600080fd5b8601601f81018813614bc857600080fd5b8051614bd66145a482614560565b81815260059190911b8201830190838101908a831115614bf557600080fd5b928401925b82841015614c1a57614c0b84614b5f565b82529284019290840190614bfa565b8096505050505050614c2e60608601614b5f565b90509295919450925056fe416363657373436f6e74726f6c6c65644f43523241676772656761746f7220312e302e302d616c706861a26469706673582212201645cfb8ed2a0d111e7ffa313a8264260a72335f33fbad27406436ee9de87c3a64736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000779877a7b0d9e8603169ddbd7836e478b4624789000000000000000000000000000000000000000000000000000000000000000100000000000000000000ffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000a4c494e4b202f2055534400000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _link (address): 0x779877A7B0D9E8603169DdbD7836e478b4624789
Arg [1] : _minAnswer (int192): 1
Arg [2] : _maxAnswer (int192): 95780971304118053647396689196894323976171195136475135
Arg [3] : _billingAccessController (address): 0x0000000000000000000000000000000000000000
Arg [4] : _requesterAccessController (address): 0x0000000000000000000000000000000000000000
Arg [5] : _decimals (uint8): 8
Arg [6] : description (string): LINK / USD
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 000000000000000000000000779877a7b0d9e8603169ddbd7836e478b4624789
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [2] : 00000000000000000000ffffffffffffffffffffffffffffffffffffffffffff
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [6] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [7] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [8] : 4c494e4b202f2055534400000000000000000000000000000000000000000000
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.