Source Code
Overview
ETH Balance
0 ETH
Token Holdings
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 25 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Transmit | 9075025 | 102 days ago | IN | 0 ETH | 0.00000231 | ||||
Transfer Ownersh... | 8905362 | 108 days ago | IN | 0 ETH | 0.00000132 | ||||
Transfer Ownersh... | 8905333 | 108 days ago | IN | 0 ETH | 0.00000705 | ||||
Set Payees | 8880351 | 109 days ago | IN | 0 ETH | 0.00001003 | ||||
Set Config | 8854700 | 110 days ago | IN | 0 ETH | 0.00001114 | ||||
Transmit | 8803579 | 112 days ago | IN | 0 ETH | 0.00000293 | ||||
Transmit | 8803458 | 112 days ago | IN | 0 ETH | 0.00000278 | ||||
Transmit | 8802117 | 112 days ago | IN | 0 ETH | 0.0000034 | ||||
Transmit | 8795460 | 112 days ago | IN | 0 ETH | 0.00001914 | ||||
Transmit | 8790675 | 113 days ago | IN | 0 ETH | 0.00003156 | ||||
Transmit | 8555565 | 121 days ago | IN | 0 ETH | 0.00000167 | ||||
Transmit | 8555252 | 121 days ago | IN | 0 ETH | 0.00000168 | ||||
Transmit | 8533592 | 122 days ago | IN | 0 ETH | 0.00003594 | ||||
Transmit | 8533495 | 122 days ago | IN | 0 ETH | 0.00003963 | ||||
Transmit | 8533398 | 122 days ago | IN | 0 ETH | 0.00004198 | ||||
Transmit | 8533300 | 122 days ago | IN | 0 ETH | 0.00004115 | ||||
Transmit | 8533202 | 122 days ago | IN | 0 ETH | 0.00002374 | ||||
Transmit | 8533091 | 122 days ago | IN | 0 ETH | 0.000014 | ||||
Transmit | 8533056 | 122 days ago | IN | 0 ETH | 0.00000619 | ||||
Transmit | 8532993 | 122 days ago | IN | 0 ETH | 0.00001506 | ||||
Transmit | 8532896 | 122 days ago | IN | 0 ETH | 0.00001864 | ||||
Transmit | 8532799 | 122 days ago | IN | 0 ETH | 0.00002233 | ||||
Transmit | 8532701 | 122 days ago | IN | 0 ETH | 0.00002418 | ||||
Transmit | 8532605 | 122 days ago | IN | 0 ETH | 0.00002569 | ||||
Transmit | 8532507 | 122 days ago | IN | 0 ETH | 0.00003527 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
9075025 | 102 days ago | 0 ETH | ||||
9075025 | 102 days ago | 0 ETH | ||||
9075025 | 102 days ago | 0 ETH | ||||
9075025 | 102 days ago | 0 ETH | ||||
9075025 | 102 days ago | 0 ETH | ||||
9075025 | 102 days ago | 0 ETH | ||||
9075025 | 102 days ago | 0 ETH | ||||
8905414 | 108 days ago | 0 ETH | ||||
8880351 | 109 days ago | 0 ETH | ||||
8880351 | 109 days ago | 0 ETH | ||||
8880351 | 109 days ago | 0 ETH | ||||
8854700 | 110 days ago | 0 ETH | ||||
8854700 | 110 days ago | 0 ETH | ||||
8854700 | 110 days ago | 0 ETH | ||||
8854700 | 110 days ago | 0 ETH | ||||
8854700 | 110 days ago | 0 ETH | ||||
8803579 | 112 days ago | 0 ETH | ||||
8803579 | 112 days ago | 0 ETH | ||||
8803579 | 112 days ago | 0 ETH | ||||
8803579 | 112 days ago | 0 ETH | ||||
8803579 | 112 days ago | 0 ETH | ||||
8803579 | 112 days ago | 0 ETH | ||||
8803579 | 112 days ago | 0 ETH | ||||
8803458 | 112 days ago | 0 ETH | ||||
8803458 | 112 days ago | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
AutomationRegistry2_3
Compiler Version
v0.8.19+commit.7dd6d404
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; import {Address} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; import {AutomationRegistryBase2_3} from "./AutomationRegistryBase2_3.sol"; import {AutomationRegistryLogicA2_3} from "./AutomationRegistryLogicA2_3.sol"; import {AutomationRegistryLogicC2_3} from "./AutomationRegistryLogicC2_3.sol"; import {Chainable} from "../Chainable.sol"; import {OCR2Abstract} from "../../shared/ocr2/OCR2Abstract.sol"; import {IERC20Metadata as IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; /** * @notice Registry for adding work for Chainlink nodes to perform on client * contracts. Clients must support the AutomationCompatibleInterface interface. */ contract AutomationRegistry2_3 is AutomationRegistryBase2_3, OCR2Abstract, Chainable { using Address for address; using EnumerableSet for EnumerableSet.UintSet; using EnumerableSet for EnumerableSet.AddressSet; /** * @notice versions: * AutomationRegistry 2.3.0: supports native and ERC20 billing * changes flat fee to USD-denominated * adds support for custom billing overrides * AutomationRegistry 2.2.0: moves chain-specific integration code into a separate module * KeeperRegistry 2.1.0: introduces support for log triggers * removes the need for "wrapped perform data" * KeeperRegistry 2.0.2: pass revert bytes as performData when target contract reverts * fixes issue with arbitrum block number * does an early return in case of stale report instead of revert * KeeperRegistry 2.0.1: implements workaround for buggy migrate function in 1.X * KeeperRegistry 2.0.0: implement OCR interface * KeeperRegistry 1.3.0: split contract into Proxy and Logic * account for Arbitrum and Optimism L1 gas fee * allow users to configure upkeeps * KeeperRegistry 1.2.0: allow funding within performUpkeep * allow configurable registry maxPerformGas * add function to let admin change upkeep gas limit * add minUpkeepSpend requirement * upgrade to solidity v0.8 * KeeperRegistry 1.1.0: added flatFeeMicroLink * KeeperRegistry 1.0.0: initial release */ string public constant override typeAndVersion = "AutomationRegistry 2.3.0"; /** * @param logicA the address of the first logic contract * @dev we cast the contract to logicC in order to call logicC functions (via fallback) */ constructor( AutomationRegistryLogicA2_3 logicA ) AutomationRegistryBase2_3( AutomationRegistryLogicC2_3(address(logicA)).getLinkAddress(), AutomationRegistryLogicC2_3(address(logicA)).getLinkUSDFeedAddress(), AutomationRegistryLogicC2_3(address(logicA)).getNativeUSDFeedAddress(), AutomationRegistryLogicC2_3(address(logicA)).getFastGasFeedAddress(), AutomationRegistryLogicC2_3(address(logicA)).getAutomationForwarderLogic(), AutomationRegistryLogicC2_3(address(logicA)).getAllowedReadOnlyAddress(), AutomationRegistryLogicC2_3(address(logicA)).getPayoutMode(), AutomationRegistryLogicC2_3(address(logicA)).getWrappedNativeTokenAddress() ) Chainable(address(logicA)) {} /** * @notice holds the variables used in the transmit function, necessary to avoid stack too deep errors */ struct TransmitVars { uint16 numUpkeepsPassedChecks; uint96 totalReimbursement; uint96 totalPremium; uint256 totalCalldataWeight; } // ================================================================ // | HOT PATH ACTIONS | // ================================================================ /** * @inheritdoc OCR2Abstract */ function transmit( bytes32[3] calldata reportContext, bytes calldata rawReport, bytes32[] calldata rs, bytes32[] calldata ss, bytes32 rawVs ) external override { uint256 gasOverhead = gasleft(); // use this msg.data length check to ensure no extra data is included in the call // 4 is first 4 bytes of the keccak-256 hash of the function signature. ss.length == rs.length so use one of them // 4 + (32 * 3) + (rawReport.length + 32 + 32) + (32 * rs.length + 32 + 32) + (32 * ss.length + 32 + 32) + 32 uint256 requiredLength = 324 + rawReport.length + 64 * rs.length; if (msg.data.length != requiredLength) revert InvalidDataLength(); HotVars memory hotVars = s_hotVars; if (hotVars.paused) revert RegistryPaused(); if (!s_transmitters[msg.sender].active) revert OnlyActiveTransmitters(); // Verify signatures if (s_latestConfigDigest != reportContext[0]) revert ConfigDigestMismatch(); if (rs.length != hotVars.f + 1 || rs.length != ss.length) revert IncorrectNumberOfSignatures(); _verifyReportSignature(reportContext, rawReport, rs, ss, rawVs); Report memory report = _decodeReport(rawReport); uint40 epochAndRound = uint40(uint256(reportContext[1])); uint32 epoch = uint32(epochAndRound >> 8); _handleReport(hotVars, report, gasOverhead); if (epoch > hotVars.latestEpoch) { s_hotVars.latestEpoch = epoch; } } /** * @notice handles the report by performing the upkeeps and updating the state * @param hotVars the hot variables of the registry * @param report the report to be handled (already verified and decoded) * @param gasOverhead the running tally of gas overhead to be split across the upkeeps * @dev had to split this function from transmit() to avoid stack too deep errors * @dev all other internal / private functions are generally defined in the Base contract * we leave this here because it is essentially a continuation of the transmit() function, */ function _handleReport(HotVars memory hotVars, Report memory report, uint256 gasOverhead) private { UpkeepTransmitInfo[] memory upkeepTransmitInfo = new UpkeepTransmitInfo[](report.upkeepIds.length); TransmitVars memory transmitVars = TransmitVars({ numUpkeepsPassedChecks: 0, totalCalldataWeight: 0, totalReimbursement: 0, totalPremium: 0 }); uint256 blocknumber = hotVars.chainModule.blockNumber(); uint256 l1Fee = hotVars.chainModule.getCurrentL1Fee(msg.data.length); for (uint256 i = 0; i < report.upkeepIds.length; i++) { upkeepTransmitInfo[i].upkeep = s_upkeep[report.upkeepIds[i]]; upkeepTransmitInfo[i].triggerType = _getTriggerType(report.upkeepIds[i]); (upkeepTransmitInfo[i].earlyChecksPassed, upkeepTransmitInfo[i].dedupID) = _prePerformChecks( report.upkeepIds[i], blocknumber, report.triggers[i], upkeepTransmitInfo[i], hotVars ); if (upkeepTransmitInfo[i].earlyChecksPassed) { transmitVars.numUpkeepsPassedChecks += 1; } else { continue; } // Actually perform the target upkeep (upkeepTransmitInfo[i].performSuccess, upkeepTransmitInfo[i].gasUsed) = _performUpkeep( upkeepTransmitInfo[i].upkeep.forwarder, report.gasLimits[i], report.performDatas[i] ); // To split L1 fee across the upkeeps, assign a weight to this upkeep based on the length // of the perform data and calldata overhead upkeepTransmitInfo[i].calldataWeight = report.performDatas[i].length + TRANSMIT_CALLDATA_FIXED_BYTES_OVERHEAD + (TRANSMIT_CALLDATA_PER_SIGNER_BYTES_OVERHEAD * (hotVars.f + 1)); transmitVars.totalCalldataWeight += upkeepTransmitInfo[i].calldataWeight; // Deduct the gasUsed by upkeep from the overhead tally - upkeeps pay for their own gas individually gasOverhead -= upkeepTransmitInfo[i].gasUsed; // Store last perform block number / deduping key for upkeep _updateTriggerMarker(report.upkeepIds[i], blocknumber, upkeepTransmitInfo[i]); } // No upkeeps to be performed in this report if (transmitVars.numUpkeepsPassedChecks == 0) { return; } // This is the overall gas overhead that will be split across performed upkeeps // Take upper bound of 16 gas per callData bytes gasOverhead = (gasOverhead - gasleft()) + (16 * msg.data.length) + ACCOUNTING_FIXED_GAS_OVERHEAD; gasOverhead = gasOverhead / transmitVars.numUpkeepsPassedChecks + ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD; { BillingTokenPaymentParams memory billingTokenParams; uint256 nativeUSD = _getNativeUSD(hotVars); for (uint256 i = 0; i < report.upkeepIds.length; i++) { if (upkeepTransmitInfo[i].earlyChecksPassed) { if (i == 0 || upkeepTransmitInfo[i].upkeep.billingToken != upkeepTransmitInfo[i - 1].upkeep.billingToken) { billingTokenParams = _getBillingTokenPaymentParams(hotVars, upkeepTransmitInfo[i].upkeep.billingToken); } PaymentReceipt memory receipt = _handlePayment( hotVars, PaymentParams({ gasLimit: upkeepTransmitInfo[i].gasUsed, gasOverhead: gasOverhead, l1CostWei: (l1Fee * upkeepTransmitInfo[i].calldataWeight) / transmitVars.totalCalldataWeight, fastGasWei: report.fastGasWei, linkUSD: report.linkUSD, nativeUSD: nativeUSD, billingToken: upkeepTransmitInfo[i].upkeep.billingToken, billingTokenParams: billingTokenParams, isTransaction: true }), report.upkeepIds[i], upkeepTransmitInfo[i].upkeep ); transmitVars.totalPremium += receipt.premiumInJuels; transmitVars.totalReimbursement += receipt.gasReimbursementInJuels; emit UpkeepPerformed( report.upkeepIds[i], upkeepTransmitInfo[i].performSuccess, receipt.gasChargeInBillingToken + receipt.premiumInBillingToken, upkeepTransmitInfo[i].gasUsed, gasOverhead, report.triggers[i] ); } } } // record payments to NOPs, all in LINK s_transmitters[msg.sender].balance += transmitVars.totalReimbursement; s_hotVars.totalPremium += transmitVars.totalPremium; s_reserveAmounts[IERC20(address(i_link))] += transmitVars.totalReimbursement + transmitVars.totalPremium; } // ================================================================ // | OCR2ABSTRACT | // ================================================================ /** * @inheritdoc OCR2Abstract * @dev prefer the type-safe version of setConfig (below) whenever possible. The OnchainConfig could differ between registry versions * @dev this function takes up precious space on the root contract, but must be implemented to conform to the OCR2Abstract interface */ function setConfig( address[] memory signers, address[] memory transmitters, uint8 f, bytes memory onchainConfigBytes, uint64 offchainConfigVersion, bytes memory offchainConfig ) external override { (OnchainConfig memory config, IERC20[] memory billingTokens, BillingConfig[] memory billingConfigs) = abi.decode( onchainConfigBytes, (OnchainConfig, IERC20[], BillingConfig[]) ); setConfigTypeSafe( signers, transmitters, f, config, offchainConfigVersion, offchainConfig, billingTokens, billingConfigs ); } /** * @notice sets the configuration for the registry * @param signers the list of permitted signers * @param transmitters the list of permitted transmitters * @param f the maximum tolerance for faulty nodes * @param onchainConfig configuration values that are used on-chain * @param offchainConfigVersion the version of the offchainConfig * @param offchainConfig configuration values that are used off-chain * @param billingTokens the list of valid billing tokens * @param billingConfigs the configurations for each billing token */ function setConfigTypeSafe( address[] memory signers, address[] memory transmitters, uint8 f, OnchainConfig memory onchainConfig, uint64 offchainConfigVersion, bytes memory offchainConfig, IERC20[] memory billingTokens, BillingConfig[] memory billingConfigs ) public onlyOwner { if (signers.length > MAX_NUM_ORACLES) revert TooManyOracles(); if (f == 0) revert IncorrectNumberOfFaultyOracles(); if (signers.length != transmitters.length || signers.length <= 3 * f) revert IncorrectNumberOfSigners(); if (billingTokens.length != billingConfigs.length) revert ParameterLengthError(); // set billing config for tokens _setBillingConfig(billingTokens, billingConfigs); _updateTransmitters(signers, transmitters); s_hotVars = HotVars({ f: f, stalenessSeconds: onchainConfig.stalenessSeconds, gasCeilingMultiplier: onchainConfig.gasCeilingMultiplier, paused: s_hotVars.paused, reentrancyGuard: s_hotVars.reentrancyGuard, totalPremium: s_hotVars.totalPremium, latestEpoch: 0, // DON restarts epoch reorgProtectionEnabled: onchainConfig.reorgProtectionEnabled, chainModule: onchainConfig.chainModule }); uint32 previousConfigBlockNumber = s_storage.latestConfigBlockNumber; uint32 newLatestConfigBlockNumber = uint32(onchainConfig.chainModule.blockNumber()); uint32 newConfigCount = s_storage.configCount + 1; s_storage = Storage({ checkGasLimit: onchainConfig.checkGasLimit, maxPerformGas: onchainConfig.maxPerformGas, transcoder: onchainConfig.transcoder, maxCheckDataSize: onchainConfig.maxCheckDataSize, maxPerformDataSize: onchainConfig.maxPerformDataSize, maxRevertDataSize: onchainConfig.maxRevertDataSize, upkeepPrivilegeManager: onchainConfig.upkeepPrivilegeManager, financeAdmin: onchainConfig.financeAdmin, nonce: s_storage.nonce, configCount: newConfigCount, latestConfigBlockNumber: newLatestConfigBlockNumber }); s_fallbackGasPrice = onchainConfig.fallbackGasPrice; s_fallbackLinkPrice = onchainConfig.fallbackLinkPrice; s_fallbackNativePrice = onchainConfig.fallbackNativePrice; bytes memory onchainConfigBytes = abi.encode(onchainConfig); s_latestConfigDigest = _configDigestFromConfigData( block.chainid, address(this), s_storage.configCount, signers, transmitters, f, onchainConfigBytes, offchainConfigVersion, offchainConfig ); for (uint256 idx = s_registrars.length(); idx > 0; idx--) { s_registrars.remove(s_registrars.at(idx - 1)); } for (uint256 idx = 0; idx < onchainConfig.registrars.length; idx++) { s_registrars.add(onchainConfig.registrars[idx]); } emit ConfigSet( previousConfigBlockNumber, s_latestConfigDigest, s_storage.configCount, signers, transmitters, f, onchainConfigBytes, offchainConfigVersion, offchainConfig ); } /** * @inheritdoc OCR2Abstract * @dev this function takes up precious space on the root contract, but must be implemented to conform to the OCR2Abstract interface */ function latestConfigDetails() external view override returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest) { return (s_storage.configCount, s_storage.latestConfigBlockNumber, s_latestConfigDigest); } /** * @inheritdoc OCR2Abstract * @dev this function takes up precious space on the root contract, but must be implemented to conform to the OCR2Abstract interface */ function latestConfigDigestAndEpoch() external view override returns (bool scanLogs, bytes32 configDigest, uint32 epoch) { return (false, s_latestConfigDigest, s_hotVars.latestEpoch); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.16; import {IAutomationRegistryConsumer} from "./interfaces/IAutomationRegistryConsumer.sol"; uint256 constant PERFORM_GAS_CUSHION = 5_000; /** * @title AutomationForwarder is a relayer that sits between the registry and the customer's target contract * @dev The purpose of the forwarder is to give customers a consistent address to authorize against, * which stays consistent between migrations. The Forwarder also exposes the registry address, so that users who * want to programatically interact with the registry (ie top up funds) can do so. */ contract AutomationForwarder { /// @notice the user's target contract address address private immutable i_target; /// @notice the shared logic address address private immutable i_logic; IAutomationRegistryConsumer private s_registry; constructor(address target, address registry, address logic) { s_registry = IAutomationRegistryConsumer(registry); i_target = target; i_logic = logic; } /** * @notice forward is called by the registry and forwards the call to the target * @param gasAmount is the amount of gas to use in the call * @param data is the 4 bytes function selector + arbitrary function data * @return success indicating whether the target call succeeded or failed */ function forward(uint256 gasAmount, bytes memory data) external returns (bool success, uint256 gasUsed) { if (msg.sender != address(s_registry)) revert(); address target = i_target; gasUsed = gasleft(); assembly { let g := gas() // Compute g -= PERFORM_GAS_CUSHION and check for underflow if lt(g, PERFORM_GAS_CUSHION) { revert(0, 0) } g := sub(g, PERFORM_GAS_CUSHION) // if g - g//64 <= gasAmount, revert // (we subtract g//64 because of EIP-150) if iszero(gt(sub(g, div(g, 64)), gasAmount)) { revert(0, 0) } // solidity calls check that a contract actually exists at the destination, so we do the same if iszero(extcodesize(target)) { revert(0, 0) } // call with exact gas success := call(gasAmount, target, 0, add(data, 0x20), mload(data), 0, 0) } gasUsed = gasUsed - gasleft(); return (success, gasUsed); } function getTarget() external view returns (address) { return i_target; } fallback() external { // copy to memory for assembly access address logic = i_logic; // copied directly from OZ's Proxy contract assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas(), logic, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; /** * @title Chainable - the contract size limit nullifier * @notice Chainable is designed to link together a "chain" of contracts through fallback functions * and delegatecalls. All code is executed in the context of the head of the chain, the "master" contract. */ contract Chainable { /** * @dev addresses of the next contract in the chain **have to be immutable/constant** or the system won't work */ address private immutable i_FALLBACK_ADDRESS; /** * @param fallbackAddress the address of the next contract in the chain */ constructor(address fallbackAddress) { i_FALLBACK_ADDRESS = fallbackAddress; } /** * @notice returns the address of the next contract in the chain */ function fallbackTo() external view returns (address) { return i_FALLBACK_ADDRESS; } /** * @notice the fallback function routes the call to the next contract in the chain * @dev most of the implementation is copied directly from OZ's Proxy contract */ // solhint-disable-next-line no-complex-fallback fallback() external payable { // copy to memory for assembly access address next = i_FALLBACK_ADDRESS; // copied directly from OZ's Proxy contract assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // Call the next contract. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas(), next, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // solhint-disable-next-line interface-starts-with-i interface AutomationCompatibleInterface { /** * @notice method that is simulated by the keepers to see if any work actually * needs to be performed. This method does does not actually need to be * executable, and since it is only ever simulated it can consume lots of gas. * @dev To ensure that it is never called, you may want to add the * cannotExecute modifier from KeeperBase to your implementation of this * method. * @param checkData specified in the upkeep registration so it is always the * same for a registered upkeep. This can easily be broken down into specific * arguments using `abi.decode`, so multiple upkeeps can be registered on the * same contract and easily differentiated by the contract. * @return upkeepNeeded boolean to indicate whether the keeper should call * performUpkeep or not. * @return performData bytes that the keeper should call performUpkeep with, if * upkeep is needed. If you would like to encode data to decode later, try * `abi.encode`. */ function checkUpkeep(bytes calldata checkData) external returns (bool upkeepNeeded, bytes memory performData); /** * @notice method that is actually executed by the keepers, via the registry. * The data returned by the checkUpkeep simulation will be passed into * this method to actually be executed. * @dev The input to this method should not be trusted, and the caller of the * method should not even be restricted to any single registry. Anyone should * be able call it, and the input should be validated, there is no guarantee * that the data passed in is the performData returned from checkUpkeep. This * could happen due to malicious keepers, racing keepers, or simply a state * change while the performUpkeep transaction is waiting for confirmation. * Always validate the data passed in. * @param performData is the data which was passed back from the checkData * simulation. If it is encoded, it can easily be decoded into other types by * calling `abi.decode`. This data should not be trusted, and should be * validated against the contract's current state. */ function performUpkeep(bytes calldata performData) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; import {IAutomationRegistryConsumer} from "./IAutomationRegistryConsumer.sol"; interface IAutomationForwarder is ITypeAndVersion { function forward(uint256 gasAmount, bytes memory data) external returns (bool success, uint256 gasUsed); function updateRegistry(address newRegistry) external; function getRegistry() external view returns (IAutomationRegistryConsumer); function getTarget() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /** * @notice IAutomationRegistryConsumer defines the LTS user-facing interface that we intend to maintain for * across upgrades. As long as users use functions from within this interface, their upkeeps will retain * backwards compatability across migrations. * @dev Functions can be added to this interface, but not removed. */ interface IAutomationRegistryConsumer { function getBalance(uint256 id) external view returns (uint96 balance); function getMinBalance(uint256 id) external view returns (uint96 minBalance); function cancelUpkeep(uint256 id) external; function pauseUpkeep(uint256 id) external; function unpauseUpkeep(uint256 id) external; function addFunds(uint256 id, uint96 amount) external; function withdrawFunds(uint256 id, address to) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.4; interface IAutomationV21PlusCommon { // registry events event AdminPrivilegeConfigSet(address indexed admin, bytes privilegeConfig); event CancelledUpkeepReport(uint256 indexed id, bytes trigger); event ConfigSet( uint32 previousConfigBlockNumber, bytes32 configDigest, uint64 configCount, address[] signers, address[] transmitters, uint8 f, bytes onchainConfig, uint64 offchainConfigVersion, bytes offchainConfig ); event DedupKeyAdded(bytes32 indexed dedupKey); event InsufficientFundsUpkeepReport(uint256 indexed id, bytes trigger); event OwnershipTransferred(address indexed from, address indexed to); event OwnershipTransferRequested(address indexed from, address indexed to); event Paused(address account); event PayeeshipTransferred(address indexed transmitter, address indexed from, address indexed to); event PayeeshipTransferRequested(address indexed transmitter, address indexed from, address indexed to); event PayeesUpdated(address[] transmitters, address[] payees); event PaymentWithdrawn(address indexed transmitter, uint256 indexed amount, address indexed to, address payee); event ReorgedUpkeepReport(uint256 indexed id, bytes trigger); event StaleUpkeepReport(uint256 indexed id, bytes trigger); event Transmitted(bytes32 configDigest, uint32 epoch); event Unpaused(address account); // upkeep events event FundsAdded(uint256 indexed id, address indexed from, uint96 amount); event FundsWithdrawn(uint256 indexed id, uint256 amount, address to); event UpkeepAdminTransferred(uint256 indexed id, address indexed from, address indexed to); event UpkeepAdminTransferRequested(uint256 indexed id, address indexed from, address indexed to); event UpkeepCanceled(uint256 indexed id, uint64 indexed atBlockHeight); event UpkeepCheckDataSet(uint256 indexed id, bytes newCheckData); event UpkeepGasLimitSet(uint256 indexed id, uint96 gasLimit); event UpkeepMigrated(uint256 indexed id, uint256 remainingBalance, address destination); event UpkeepOffchainConfigSet(uint256 indexed id, bytes offchainConfig); event UpkeepPaused(uint256 indexed id); event UpkeepPerformed( uint256 indexed id, bool indexed success, uint96 totalPayment, uint256 gasUsed, uint256 gasOverhead, bytes trigger ); event UpkeepPrivilegeConfigSet(uint256 indexed id, bytes privilegeConfig); event UpkeepReceived(uint256 indexed id, uint256 startingBalance, address importedFrom); event UpkeepRegistered(uint256 indexed id, uint32 performGas, address admin); event UpkeepTriggerConfigSet(uint256 indexed id, bytes triggerConfig); event UpkeepUnpaused(uint256 indexed id); /** * @notice structure of trigger for log triggers */ struct LogTriggerConfig { address contractAddress; uint8 filterSelector; // denotes which topics apply to filter ex 000, 101, 111...only last 3 bits apply bytes32 topic0; bytes32 topic1; bytes32 topic2; bytes32 topic3; } /// @dev Report transmitted by OCR to transmit function struct Report { uint256 fastGasWei; uint256 linkNative; uint256[] upkeepIds; uint256[] gasLimits; bytes[] triggers; bytes[] performDatas; } /** * @notice all information about an upkeep * @dev only used in return values * @dev this will likely be deprecated in a future version of the registry * @member target the contract which needs to be serviced * @member performGas the gas limit of upkeep execution * @member checkData the checkData bytes for this upkeep * @member balance the balance of this upkeep * @member admin for this upkeep * @member maxValidBlocknumber until which block this upkeep is valid * @member lastPerformedBlockNumber the last block number when this upkeep was performed * @member amountSpent the amount this upkeep has spent * @member paused if this upkeep has been paused * @member offchainConfig the off-chain config of this upkeep */ struct UpkeepInfoLegacy { address target; uint32 performGas; bytes checkData; uint96 balance; address admin; uint64 maxValidBlocknumber; uint32 lastPerformedBlockNumber; uint96 amountSpent; bool paused; bytes offchainConfig; } /** * @notice the trigger structure conditional trigger type */ struct ConditionalTrigger { uint32 blockNum; bytes32 blockHash; } /** * @notice the trigger structure of log upkeeps * @dev NOTE that blockNum / blockHash describe the block used for the callback, * not necessarily the block number that the log was emitted in!!!! */ struct LogTrigger { bytes32 logBlockHash; bytes32 txHash; uint32 logIndex; uint32 blockNum; bytes32 blockHash; } /** * @notice state of the registry * @dev only used in params and return values * @dev this will likely be deprecated in a future version of the registry in favor of individual getters * @member nonce used for ID generation * @member ownerLinkBalance withdrawable balance of LINK by contract owner * @member expectedLinkBalance the expected balance of LINK of the registry * @member totalPremium the total premium collected on registry so far * @member numUpkeeps total number of upkeeps on the registry * @member configCount ordinal number of current config, out of all configs applied to this contract so far * @member latestConfigBlockNumber last block at which this config was set * @member latestConfigDigest domain-separation tag for current config * @member latestEpoch for which a report was transmitted * @member paused freeze on execution scoped to the entire registry */ // solhint-disable-next-line gas-struct-packing struct StateLegacy { uint32 nonce; uint96 ownerLinkBalance; uint256 expectedLinkBalance; uint96 totalPremium; uint256 numUpkeeps; uint32 configCount; uint32 latestConfigBlockNumber; bytes32 latestConfigDigest; uint32 latestEpoch; bool paused; } /** * @notice OnchainConfigLegacy of the registry * @dev only used in params and return values * @member paymentPremiumPPB payment premium rate oracles receive on top of * being reimbursed for gas, measured in parts per billion * @member flatFeeMicroLink flat fee paid to oracles for performing upkeeps, * priced in MicroLink; can be used in conjunction with or independently of * paymentPremiumPPB * @member checkGasLimit gas limit when checking for upkeep * @member stalenessSeconds number of seconds that is allowed for feed data to * be stale before switching to the fallback pricing * @member gasCeilingMultiplier multiplier to apply to the fast gas feed price * when calculating the payment ceiling for keepers * @member minUpkeepSpend minimum LINK that an upkeep must spend before cancelling * @member maxPerformGas max performGas allowed for an upkeep on this registry * @member maxCheckDataSize max length of checkData bytes * @member maxPerformDataSize max length of performData bytes * @member maxRevertDataSize max length of revertData bytes * @member fallbackGasPrice gas price used if the gas price feed is stale * @member fallbackLinkPrice LINK price used if the LINK price feed is stale * @member transcoder address of the transcoder contract * @member registrars addresses of the registrar contracts * @member upkeepPrivilegeManager address which can set privilege for upkeeps */ // solhint-disable-next-line gas-struct-packing struct OnchainConfigLegacy { uint32 paymentPremiumPPB; uint32 flatFeeMicroLink; // min 0.000001 LINK, max 4294 LINK uint32 checkGasLimit; uint24 stalenessSeconds; uint16 gasCeilingMultiplier; uint96 minUpkeepSpend; uint32 maxPerformGas; uint32 maxCheckDataSize; uint32 maxPerformDataSize; uint32 maxRevertDataSize; uint256 fallbackGasPrice; uint256 fallbackLinkPrice; address transcoder; address[] registrars; address upkeepPrivilegeManager; } function checkUpkeep( uint256 id, bytes memory triggerData ) external view returns ( bool upkeepNeeded, bytes memory performData, uint8 upkeepFailureReason, uint256 gasUsed, uint256 gasLimit, uint256 fastGasWei, uint256 linkNative ); function checkUpkeep( uint256 id ) external view returns ( bool upkeepNeeded, bytes memory performData, uint8 upkeepFailureReason, uint256 gasUsed, uint256 gasLimit, uint256 fastGasWei, uint256 linkNative ); function simulatePerformUpkeep( uint256 id, bytes memory performData ) external view returns (bool success, uint256 gasUsed); function executeCallback( uint256 id, bytes memory payload ) external returns (bool upkeepNeeded, bytes memory performData, uint8 upkeepFailureReason, uint256 gasUsed); function checkCallback( uint256 id, bytes[] memory values, bytes memory extraData ) external view returns (bool upkeepNeeded, bytes memory performData, uint8 upkeepFailureReason, uint256 gasUsed); function typeAndVersion() external view returns (string memory); function addFunds(uint256 id, uint96 amount) external; function cancelUpkeep(uint256 id) external; function getUpkeepPrivilegeConfig(uint256 upkeepId) external view returns (bytes memory); function hasDedupKey(bytes32 dedupKey) external view returns (bool); function getUpkeepTriggerConfig(uint256 upkeepId) external view returns (bytes memory); function getUpkeep(uint256 id) external view returns (UpkeepInfoLegacy memory upkeepInfo); function getMinBalance(uint256 id) external view returns (uint96); function getState() external view returns ( StateLegacy memory state, OnchainConfigLegacy memory config, address[] memory signers, address[] memory transmitters, uint8 f ); function setUpkeepGasLimit(uint256 id, uint32 gasLimit) external; function setUpkeepPrivilegeConfig(uint256 upkeepId, bytes memory newPrivilegeConfig) external; function pauseUpkeep(uint256 id) external; function unpauseUpkeep(uint256 id) external; function getActiveUpkeepIDs(uint256 startIndex, uint256 maxCount) external view returns (uint256[] memory); function pause() external; function setUpkeepCheckData(uint256 id, bytes memory newCheckData) external; function setUpkeepTriggerConfig(uint256 id, bytes memory triggerConfig) external; function owner() external view returns (address); function getTriggerType(uint256 upkeepId) external pure returns (uint8); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; interface IChainModule { /* @notice this function provides the block number of current chain. * @dev certain chains have its own function to retrieve block number, e.g. Arbitrum * @return blockNumber the block number of the current chain. */ function blockNumber() external view returns (uint256 blockNumber); /* @notice this function provides the block hash of a block number. * @dev this function can usually look back 256 blocks at most, unless otherwise specified * @param blockNumber the block number * @return blockHash the block hash of the input block number */ function blockHash(uint256 blockNumber) external view returns (bytes32 blockHash); /* @notice this function provides the L1 fee of current transaction. * @dev retrieve the L1 data fee for a L2 transaction. it should return 0 for L1 chains. it should * return 0 for L2 chains if they don't have L1 fee component. * @param dataSize the calldata size of the current transaction * @return l1Fee the L1 fee in wei incurred by calldata of this data size */ function getCurrentL1Fee(uint256 dataSize) external view returns (uint256 l1Fee); /* @notice this function provides the max possible L1 fee of current transaction. * @dev retrieve the max possible L1 data fee for a L2 transaction. it should return 0 for L1 chains. it should * return 0 for L2 chains if they don't have L1 fee component. * @param dataSize the calldata size of the current transaction * @return maxL1Fee the max possible L1 fee in wei incurred by calldata of this data size */ function getMaxL1Fee(uint256 dataSize) external view returns (uint256 maxL1Fee); /* @notice this function provides the overheads of calling this chain module. * @return chainModuleFixedOverhead the fixed overhead incurred by calling this chain module * @return chainModulePerByteOverhead the fixed overhead per byte incurred by calling this chain module with calldata */ function getGasOverhead() external view returns (uint256 chainModuleFixedOverhead, uint256 chainModulePerByteOverhead); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @member index the index of the log in the block. 0 for the first log * @member timestamp the timestamp of the block containing the log * @member txHash the hash of the transaction containing the log * @member blockNumber the number of the block containing the log * @member blockHash the hash of the block containing the log * @member source the address of the contract that emitted the log * @member topics the indexed topics of the log * @member data the data of the log */ struct Log { uint256 index; uint256 timestamp; bytes32 txHash; uint256 blockNumber; bytes32 blockHash; address source; bytes32[] topics; bytes data; } interface ILogAutomation { /** * @notice method that is simulated by the keepers to see if any work actually * needs to be performed. This method does does not actually need to be * executable, and since it is only ever simulated it can consume lots of gas. * @dev To ensure that it is never called, you may want to add the * cannotExecute modifier from KeeperBase to your implementation of this * method. * @param log the raw log data matching the filter that this contract has * registered as a trigger * @param checkData user-specified extra data to provide context to this upkeep * @return upkeepNeeded boolean to indicate whether the keeper should call * performUpkeep or not. * @return performData bytes that the keeper should call performUpkeep with, if * upkeep is needed. If you would like to encode data to decode later, try * `abi.encode`. */ function checkLog( Log calldata log, bytes memory checkData ) external returns (bool upkeepNeeded, bytes memory performData); /** * @notice method that is actually executed by the keepers, via the registry. * The data returned by the checkUpkeep simulation will be passed into * this method to actually be executed. * @dev The input to this method should not be trusted, and the caller of the * method should not even be restricted to any single registry. Anyone should * be able call it, and the input should be validated, there is no guarantee * that the data passed in is the performData returned from checkUpkeep. This * could happen due to malicious keepers, racing keepers, or simply a state * change while the performUpkeep transaction is waiting for confirmation. * Always validate the data passed in. * @param performData is the data which was passed back from the checkData * simulation. If it is encoded, it can easily be decoded into other types by * calling `abi.decode`. This data should not be trusted, and should be * validated against the contract's current state. */ function performUpkeep(bytes calldata performData) external; }
// SPDX-License-Identifier: MIT /** * @notice This is a deprecated interface. Please use AutomationCompatibleInterface directly. */ pragma solidity ^0.8.0; // solhint-disable-next-line no-unused-import import {AutomationCompatibleInterface as KeeperCompatibleInterface} from "./AutomationCompatibleInterface.sol";
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // solhint-disable-next-line interface-starts-with-i interface MigratableKeeperRegistryInterfaceV2 { /** * @notice Migrates upkeeps from one registry to another, including LINK and upkeep params. * Only callable by the upkeep admin. All upkeeps must have the same admin. Can only migrate active upkeeps. * @param upkeepIDs ids of upkeeps to migrate * @param destination the address of the registry to migrate to */ function migrateUpkeeps(uint256[] calldata upkeepIDs, address destination) external; /** * @notice Called by other registries when migrating upkeeps. Only callable by other registries. * @param encodedUpkeeps abi encoding of upkeeps to import - decoded by the transcoder */ function receiveUpkeeps(bytes calldata encodedUpkeeps) external; /** * @notice Specifies the version of upkeep data that this registry requires in order to import */ function upkeepVersion() external view returns (uint8 version); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // solhint-disable-next-line interface-starts-with-i interface StreamsLookupCompatibleInterface { error StreamsLookup(string feedParamKey, string[] feeds, string timeParamKey, uint256 time, bytes extraData); /** * @notice any contract which wants to utilize StreamsLookup feature needs to * implement this interface as well as the automation compatible interface. * @param values an array of bytes returned from data streams endpoint. * @param extraData context data from streams lookup process. * @return upkeepNeeded boolean to indicate whether the keeper should call performUpkeep or not. * @return performData bytes that the keeper should call performUpkeep with, if * upkeep is needed. If you would like to encode data to decode later, try `abi.encode`. */ function checkCallback( bytes[] memory values, bytes memory extraData ) external view returns (bool upkeepNeeded, bytes memory performData); /** * @notice this is a new, optional function in streams lookup. It is meant to surface streams lookup errors. * @param errCode an uint value that represents the streams lookup error code. * @param extraData context data from streams lookup process. * @return upkeepNeeded boolean to indicate whether the keeper should call performUpkeep or not. * @return performData bytes that the keeper should call performUpkeep with, if * upkeep is needed. If you would like to encode data to decode later, try `abi.encode`. */ function checkErrorHandler( uint256 errCode, bytes memory extraData ) external view returns (bool upkeepNeeded, bytes memory performData); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // solhint-disable-next-line interface-starts-with-i interface UpkeepTranscoderInterfaceV2 { function transcodeUpkeeps( uint8 fromVersion, uint8 toVersion, bytes calldata encodedUpkeeps ) external view returns (bytes memory); }
// abi-checksum: 0xacb9d0daec3e3bed110c8cf95bdbe7280a21ce61519d4cd496f802884bf05524 // SPDX-License-Identifier: MIT // !! THIS FILE WAS AUTOGENERATED BY abi-to-sol v0.6.6. SEE SOURCE BELOW. !! pragma solidity ^0.8.4; interface IAutomationRegistryMaster2_3 { error ArrayHasNoEntries(); error CannotCancel(); error CheckDataExceedsLimit(); error ConfigDigestMismatch(); error DuplicateEntry(); error DuplicateSigners(); error GasLimitCanOnlyIncrease(); error GasLimitOutsideRange(); error IncorrectNumberOfFaultyOracles(); error IncorrectNumberOfSignatures(); error IncorrectNumberOfSigners(); error IndexOutOfRange(); error InsufficientBalance(uint256 available, uint256 requested); error InsufficientLinkLiquidity(); error InvalidDataLength(); error InvalidFeed(); error InvalidPayee(); error InvalidRecipient(); error InvalidReport(); error InvalidSigner(); error InvalidToken(); error InvalidTransmitter(); error InvalidTrigger(); error InvalidTriggerType(); error MigrationNotPermitted(); error MustSettleOffchain(); error MustSettleOnchain(); error NotAContract(); error OnlyActiveSigners(); error OnlyActiveTransmitters(); error OnlyCallableByAdmin(); error OnlyCallableByLINKToken(); error OnlyCallableByOwnerOrAdmin(); error OnlyCallableByOwnerOrRegistrar(); error OnlyCallableByPayee(); error OnlyCallableByProposedAdmin(); error OnlyCallableByProposedPayee(); error OnlyCallableByUpkeepPrivilegeManager(); error OnlyFinanceAdmin(); error OnlyPausedUpkeep(); error OnlySimulatedBackend(); error OnlyUnpausedUpkeep(); error ParameterLengthError(); error ReentrantCall(); error RegistryPaused(); error RepeatedSigner(); error RepeatedTransmitter(); error TargetCheckReverted(bytes reason); error TooManyOracles(); error TranscoderNotSet(); error TransferFailed(); error UpkeepAlreadyExists(); error UpkeepCancelled(); error UpkeepNotCanceled(); error UpkeepNotNeeded(); error ValueNotChanged(); error ZeroAddressNotAllowed(); event AdminPrivilegeConfigSet(address indexed admin, bytes privilegeConfig); event BillingConfigOverridden(uint256 indexed id, AutomationRegistryBase2_3.BillingOverrides overrides); event BillingConfigOverrideRemoved(uint256 indexed id); event BillingConfigSet(address indexed token, AutomationRegistryBase2_3.BillingConfig config); event CancelledUpkeepReport(uint256 indexed id, bytes trigger); event ChainSpecificModuleUpdated(address newModule); event ConfigSet( uint32 previousConfigBlockNumber, bytes32 configDigest, uint64 configCount, address[] signers, address[] transmitters, uint8 f, bytes onchainConfig, uint64 offchainConfigVersion, bytes offchainConfig ); event DedupKeyAdded(bytes32 indexed dedupKey); event FeesWithdrawn(address indexed assetAddress, address indexed recipient, uint256 amount); event FundsAdded(uint256 indexed id, address indexed from, uint96 amount); event FundsWithdrawn(uint256 indexed id, uint256 amount, address to); event InsufficientFundsUpkeepReport(uint256 indexed id, bytes trigger); event NOPsSettledOffchain(address[] payees, uint256[] payments); event OwnershipTransferRequested(address indexed from, address indexed to); event OwnershipTransferred(address indexed from, address indexed to); event Paused(address account); event PayeesUpdated(address[] transmitters, address[] payees); event PayeeshipTransferRequested(address indexed transmitter, address indexed from, address indexed to); event PayeeshipTransferred(address indexed transmitter, address indexed from, address indexed to); event PaymentWithdrawn(address indexed transmitter, uint256 indexed amount, address indexed to, address payee); event ReorgedUpkeepReport(uint256 indexed id, bytes trigger); event StaleUpkeepReport(uint256 indexed id, bytes trigger); event Transmitted(bytes32 configDigest, uint32 epoch); event Unpaused(address account); event UpkeepAdminTransferRequested(uint256 indexed id, address indexed from, address indexed to); event UpkeepAdminTransferred(uint256 indexed id, address indexed from, address indexed to); event UpkeepCanceled(uint256 indexed id, uint64 indexed atBlockHeight); event UpkeepCharged(uint256 indexed id, AutomationRegistryBase2_3.PaymentReceipt receipt); event UpkeepCheckDataSet(uint256 indexed id, bytes newCheckData); event UpkeepGasLimitSet(uint256 indexed id, uint96 gasLimit); event UpkeepMigrated(uint256 indexed id, uint256 remainingBalance, address destination); event UpkeepOffchainConfigSet(uint256 indexed id, bytes offchainConfig); event UpkeepPaused(uint256 indexed id); event UpkeepPerformed( uint256 indexed id, bool indexed success, uint96 totalPayment, uint256 gasUsed, uint256 gasOverhead, bytes trigger ); event UpkeepPrivilegeConfigSet(uint256 indexed id, bytes privilegeConfig); event UpkeepReceived(uint256 indexed id, uint256 startingBalance, address importedFrom); event UpkeepRegistered(uint256 indexed id, uint32 performGas, address admin); event UpkeepTriggerConfigSet(uint256 indexed id, bytes triggerConfig); event UpkeepUnpaused(uint256 indexed id); fallback() external payable; function acceptOwnership() external; function fallbackTo() external view returns (address); function latestConfigDetails() external view returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest); function latestConfigDigestAndEpoch() external view returns (bool scanLogs, bytes32 configDigest, uint32 epoch); function owner() external view returns (address); function setConfig( address[] memory signers, address[] memory transmitters, uint8 f, bytes memory onchainConfigBytes, uint64 offchainConfigVersion, bytes memory offchainConfig ) external; function setConfigTypeSafe( address[] memory signers, address[] memory transmitters, uint8 f, AutomationRegistryBase2_3.OnchainConfig memory onchainConfig, uint64 offchainConfigVersion, bytes memory offchainConfig, address[] memory billingTokens, AutomationRegistryBase2_3.BillingConfig[] memory billingConfigs ) external; function transferOwnership(address to) external; function transmit( bytes32[3] memory reportContext, bytes memory rawReport, bytes32[] memory rs, bytes32[] memory ss, bytes32 rawVs ) external; function typeAndVersion() external view returns (string memory); function cancelUpkeep(uint256 id) external; function migrateUpkeeps(uint256[] memory ids, address destination) external; function onTokenTransfer(address sender, uint256 amount, bytes memory data) external; function receiveUpkeeps(bytes memory encodedUpkeeps) external; function registerUpkeep( address target, uint32 gasLimit, address admin, uint8 triggerType, address billingToken, bytes memory checkData, bytes memory triggerConfig, bytes memory offchainConfig ) external returns (uint256 id); function acceptUpkeepAdmin(uint256 id) external; function addFunds(uint256 id, uint96 amount) external payable; function checkCallback( uint256 id, bytes[] memory values, bytes memory extraData ) external view returns (bool upkeepNeeded, bytes memory performData, uint8 upkeepFailureReason, uint256 gasUsed); function checkUpkeep( uint256 id, bytes memory triggerData ) external view returns ( bool upkeepNeeded, bytes memory performData, uint8 upkeepFailureReason, uint256 gasUsed, uint256 gasLimit, uint256 fastGasWei, uint256 linkUSD ); function checkUpkeep( uint256 id ) external view returns ( bool upkeepNeeded, bytes memory performData, uint8 upkeepFailureReason, uint256 gasUsed, uint256 gasLimit, uint256 fastGasWei, uint256 linkUSD ); function executeCallback( uint256 id, bytes memory payload ) external returns (bool upkeepNeeded, bytes memory performData, uint8 upkeepFailureReason, uint256 gasUsed); function pauseUpkeep(uint256 id) external; function removeBillingOverrides(uint256 id) external; function setBillingOverrides(uint256 id, AutomationRegistryBase2_3.BillingOverrides memory billingOverrides) external; function setUpkeepCheckData(uint256 id, bytes memory newCheckData) external; function setUpkeepGasLimit(uint256 id, uint32 gasLimit) external; function setUpkeepOffchainConfig(uint256 id, bytes memory config) external; function setUpkeepTriggerConfig(uint256 id, bytes memory triggerConfig) external; function simulatePerformUpkeep( uint256 id, bytes memory performData ) external view returns (bool success, uint256 gasUsed); function transferUpkeepAdmin(uint256 id, address proposed) external; function unpauseUpkeep(uint256 id) external; function withdrawERC20Fees(address asset, address to, uint256 amount) external; function withdrawFunds(uint256 id, address to) external; function withdrawLink(address to, uint256 amount) external; function acceptPayeeship(address transmitter) external; function disableOffchainPayments() external; function getActiveUpkeepIDs(uint256 startIndex, uint256 maxCount) external view returns (uint256[] memory); function getAdminPrivilegeConfig(address admin) external view returns (bytes memory); function getAllowedReadOnlyAddress() external view returns (address); function getAutomationForwarderLogic() external view returns (address); function getAvailableERC20ForPayment(address billingToken) external view returns (uint256); function getBalance(uint256 id) external view returns (uint96 balance); function getBillingConfig( address billingToken ) external view returns (AutomationRegistryBase2_3.BillingConfig memory); function getBillingOverrides( uint256 upkeepID ) external view returns (AutomationRegistryBase2_3.BillingOverrides memory); function getBillingOverridesEnabled(uint256 upkeepID) external view returns (bool); function getBillingToken(uint256 upkeepID) external view returns (address); function getBillingTokenConfig(address token) external view returns (AutomationRegistryBase2_3.BillingConfig memory); function getBillingTokens() external view returns (address[] memory); function getCancellationDelay() external pure returns (uint256); function getChainModule() external view returns (address chainModule); function getConditionalGasOverhead() external pure returns (uint256); function getConfig() external view returns (AutomationRegistryBase2_3.OnchainConfig memory); function getFallbackNativePrice() external view returns (uint256); function getFastGasFeedAddress() external view returns (address); function getForwarder(uint256 upkeepID) external view returns (address); function getHotVars() external view returns (AutomationRegistryBase2_3.HotVars memory); function getLinkAddress() external view returns (address); function getLinkUSDFeedAddress() external view returns (address); function getLogGasOverhead() external pure returns (uint256); function getMaxPaymentForGas( uint256 id, uint8 triggerType, uint32 gasLimit, address billingToken ) external view returns (uint96 maxPayment); function getMinBalance(uint256 id) external view returns (uint96); function getMinBalanceForUpkeep(uint256 id) external view returns (uint96 minBalance); function getNativeUSDFeedAddress() external view returns (address); function getNumUpkeeps() external view returns (uint256); function getPayoutMode() external view returns (uint8); function getPeerRegistryMigrationPermission(address peer) external view returns (uint8); function getPerPerformByteGasOverhead() external pure returns (uint256); function getPerSignerGasOverhead() external pure returns (uint256); function getReorgProtectionEnabled() external view returns (bool reorgProtectionEnabled); function getReserveAmount(address billingToken) external view returns (uint256); function getSignerInfo(address query) external view returns (bool active, uint8 index); function getState() external view returns ( IAutomationV21PlusCommon.StateLegacy memory state, IAutomationV21PlusCommon.OnchainConfigLegacy memory config, address[] memory signers, address[] memory transmitters, uint8 f ); function getStorage() external view returns (AutomationRegistryBase2_3.Storage memory); function getTransmitCalldataFixedBytesOverhead() external pure returns (uint256); function getTransmitCalldataPerSignerBytesOverhead() external pure returns (uint256); function getTransmitterInfo( address query ) external view returns (bool active, uint8 index, uint96 balance, uint96 lastCollected, address payee); function getTransmittersWithPayees() external view returns (AutomationRegistryBase2_3.TransmitterPayeeInfo[] memory); function getTriggerType(uint256 upkeepId) external pure returns (uint8); function getUpkeep(uint256 id) external view returns (IAutomationV21PlusCommon.UpkeepInfoLegacy memory upkeepInfo); function getUpkeepPrivilegeConfig(uint256 upkeepId) external view returns (bytes memory); function getUpkeepTriggerConfig(uint256 upkeepId) external view returns (bytes memory); function getWrappedNativeTokenAddress() external view returns (address); function hasDedupKey(bytes32 dedupKey) external view returns (bool); function linkAvailableForPayment() external view returns (int256); function pause() external; function setAdminPrivilegeConfig(address admin, bytes memory newPrivilegeConfig) external; function setPayees(address[] memory payees) external; function setPeerRegistryMigrationPermission(address peer, uint8 permission) external; function setUpkeepPrivilegeConfig(uint256 upkeepId, bytes memory newPrivilegeConfig) external; function settleNOPsOffchain() external; function supportsBillingToken(address token) external view returns (bool); function transferPayeeship(address transmitter, address proposed) external; function unpause() external; function upkeepVersion() external pure returns (uint8); function withdrawPayment(address from, address to) external; } interface AutomationRegistryBase2_3 { struct BillingOverrides { uint32 gasFeePPB; uint24 flatFeeMilliCents; } struct BillingConfig { uint32 gasFeePPB; uint24 flatFeeMilliCents; address priceFeed; uint8 decimals; uint256 fallbackPrice; uint96 minSpend; } struct PaymentReceipt { uint96 gasChargeInBillingToken; uint96 premiumInBillingToken; uint96 gasReimbursementInJuels; uint96 premiumInJuels; address billingToken; uint96 linkUSD; uint96 nativeUSD; uint96 billingUSD; } struct OnchainConfig { uint32 checkGasLimit; uint32 maxPerformGas; uint32 maxCheckDataSize; address transcoder; bool reorgProtectionEnabled; uint24 stalenessSeconds; uint32 maxPerformDataSize; uint32 maxRevertDataSize; address upkeepPrivilegeManager; uint16 gasCeilingMultiplier; address financeAdmin; uint256 fallbackGasPrice; uint256 fallbackLinkPrice; uint256 fallbackNativePrice; address[] registrars; address chainModule; } struct HotVars { uint96 totalPremium; uint32 latestEpoch; uint24 stalenessSeconds; uint16 gasCeilingMultiplier; uint8 f; bool paused; bool reentrancyGuard; bool reorgProtectionEnabled; address chainModule; } struct Storage { address transcoder; uint32 checkGasLimit; uint32 maxPerformGas; uint32 nonce; address upkeepPrivilegeManager; uint32 configCount; uint32 latestConfigBlockNumber; uint32 maxCheckDataSize; address financeAdmin; uint32 maxPerformDataSize; uint32 maxRevertDataSize; } struct TransmitterPayeeInfo { address transmitterAddress; address payeeAddress; } } interface IAutomationV21PlusCommon { struct StateLegacy { uint32 nonce; uint96 ownerLinkBalance; uint256 expectedLinkBalance; uint96 totalPremium; uint256 numUpkeeps; uint32 configCount; uint32 latestConfigBlockNumber; bytes32 latestConfigDigest; uint32 latestEpoch; bool paused; } struct OnchainConfigLegacy { uint32 paymentPremiumPPB; uint32 flatFeeMicroLink; uint32 checkGasLimit; uint24 stalenessSeconds; uint16 gasCeilingMultiplier; uint96 minUpkeepSpend; uint32 maxPerformGas; uint32 maxCheckDataSize; uint32 maxPerformDataSize; uint32 maxRevertDataSize; uint256 fallbackGasPrice; uint256 fallbackLinkPrice; address transcoder; address[] registrars; address upkeepPrivilegeManager; } struct UpkeepInfoLegacy { address target; uint32 performGas; bytes checkData; uint96 balance; address admin; uint64 maxValidBlocknumber; uint32 lastPerformedBlockNumber; uint96 amountSpent; bool paused; bytes offchainConfig; } } // THIS FILE WAS AUTOGENERATED FROM THE FOLLOWING ABI JSON: /* [{"inputs":[{"internalType":"contract AutomationRegistryLogicA2_3","name":"logicA","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ArrayHasNoEntries","type":"error"},{"inputs":[],"name":"CannotCancel","type":"error"},{"inputs":[],"name":"CheckDataExceedsLimit","type":"error"},{"inputs":[],"name":"ConfigDigestMismatch","type":"error"},{"inputs":[],"name":"DuplicateEntry","type":"error"},{"inputs":[],"name":"DuplicateSigners","type":"error"},{"inputs":[],"name":"GasLimitCanOnlyIncrease","type":"error"},{"inputs":[],"name":"GasLimitOutsideRange","type":"error"},{"inputs":[],"name":"IncorrectNumberOfFaultyOracles","type":"error"},{"inputs":[],"name":"IncorrectNumberOfSignatures","type":"error"},{"inputs":[],"name":"IncorrectNumberOfSigners","type":"error"},{"inputs":[],"name":"IndexOutOfRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"available","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InsufficientLinkLiquidity","type":"error"},{"inputs":[],"name":"InvalidDataLength","type":"error"},{"inputs":[],"name":"InvalidFeed","type":"error"},{"inputs":[],"name":"InvalidPayee","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidReport","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"inputs":[],"name":"InvalidTransmitter","type":"error"},{"inputs":[],"name":"InvalidTrigger","type":"error"},{"inputs":[],"name":"InvalidTriggerType","type":"error"},{"inputs":[],"name":"MigrationNotPermitted","type":"error"},{"inputs":[],"name":"MustSettleOffchain","type":"error"},{"inputs":[],"name":"MustSettleOnchain","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"OnlyActiveSigners","type":"error"},{"inputs":[],"name":"OnlyActiveTransmitters","type":"error"},{"inputs":[],"name":"OnlyCallableByAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByLINKToken","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrRegistrar","type":"error"},{"inputs":[],"name":"OnlyCallableByPayee","type":"error"},{"inputs":[],"name":"OnlyCallableByProposedAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByProposedPayee","type":"error"},{"inputs":[],"name":"OnlyCallableByUpkeepPrivilegeManager","type":"error"},{"inputs":[],"name":"OnlyFinanceAdmin","type":"error"},{"inputs":[],"name":"OnlyPausedUpkeep","type":"error"},{"inputs":[],"name":"OnlySimulatedBackend","type":"error"},{"inputs":[],"name":"OnlyUnpausedUpkeep","type":"error"},{"inputs":[],"name":"ParameterLengthError","type":"error"},{"inputs":[],"name":"ReentrantCall","type":"error"},{"inputs":[],"name":"RegistryPaused","type":"error"},{"inputs":[],"name":"RepeatedSigner","type":"error"},{"inputs":[],"name":"RepeatedTransmitter","type":"error"},{"inputs":[{"internalType":"bytes","name":"reason","type":"bytes"}],"name":"TargetCheckReverted","type":"error"},{"inputs":[],"name":"TooManyOracles","type":"error"},{"inputs":[],"name":"TranscoderNotSet","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"UpkeepAlreadyExists","type":"error"},{"inputs":[],"name":"UpkeepCancelled","type":"error"},{"inputs":[],"name":"UpkeepNotCanceled","type":"error"},{"inputs":[],"name":"UpkeepNotNeeded","type":"error"},{"inputs":[],"name":"ValueNotChanged","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"bytes","name":"privilegeConfig","type":"bytes"}],"name":"AdminPrivilegeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"}],"indexed":false,"internalType":"struct AutomationRegistryBase2_3.BillingOverrides","name":"overrides","type":"tuple"}],"name":"BillingConfigOverridden","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"BillingConfigOverrideRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20Metadata","name":"token","type":"address"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"},{"internalType":"contract AggregatorV3Interface","name":"priceFeed","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"fallbackPrice","type":"uint256"},{"internalType":"uint96","name":"minSpend","type":"uint96"}],"indexed":false,"internalType":"struct AutomationRegistryBase2_3.BillingConfig","name":"config","type":"tuple"}],"name":"BillingConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"CancelledUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newModule","type":"address"}],"name":"ChainSpecificModuleUpdated","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":"bytes32","name":"dedupKey","type":"bytes32"}],"name":"DedupKeyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"assetAddress","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"}],"name":"FundsAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"FundsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"InsufficientFundsUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"payees","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"payments","type":"uint256[]"}],"name":"NOPsSettledOffchain","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":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"transmitters","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"payees","type":"address[]"}],"name":"PayeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"PayeeshipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"PayeeshipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"payee","type":"address"}],"name":"PaymentWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"ReorgedUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"StaleUpkeepReport","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":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"UpkeepAdminTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"UpkeepAdminTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint64","name":"atBlockHeight","type":"uint64"}],"name":"UpkeepCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint96","name":"gasChargeInBillingToken","type":"uint96"},{"internalType":"uint96","name":"premiumInBillingToken","type":"uint96"},{"internalType":"uint96","name":"gasReimbursementInJuels","type":"uint96"},{"internalType":"uint96","name":"premiumInJuels","type":"uint96"},{"internalType":"contract IERC20Metadata","name":"billingToken","type":"address"},{"internalType":"uint96","name":"linkUSD","type":"uint96"},{"internalType":"uint96","name":"nativeUSD","type":"uint96"},{"internalType":"uint96","name":"billingUSD","type":"uint96"}],"indexed":false,"internalType":"struct AutomationRegistryBase2_3.PaymentReceipt","name":"receipt","type":"tuple"}],"name":"UpkeepCharged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"newCheckData","type":"bytes"}],"name":"UpkeepCheckDataSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint96","name":"gasLimit","type":"uint96"}],"name":"UpkeepGasLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"remainingBalance","type":"uint256"},{"indexed":false,"internalType":"address","name":"destination","type":"address"}],"name":"UpkeepMigrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"UpkeepOffchainConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"UpkeepPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"uint96","name":"totalPayment","type":"uint96"},{"indexed":false,"internalType":"uint256","name":"gasUsed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasOverhead","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"UpkeepPerformed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"privilegeConfig","type":"bytes"}],"name":"UpkeepPrivilegeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startingBalance","type":"uint256"},{"indexed":false,"internalType":"address","name":"importedFrom","type":"address"}],"name":"UpkeepReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"performGas","type":"uint32"},{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"UpkeepRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"triggerConfig","type":"bytes"}],"name":"UpkeepTriggerConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"UpkeepUnpaused","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fallbackTo","outputs":[{"internalType":"address","name":"","type":"address"}],"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":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"internalType":"bytes","name":"onchainConfigBytes","type":"bytes"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"components":[{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"bool","name":"reorgProtectionEnabled","type":"bool"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"address","name":"financeAdmin","type":"address"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackNativePrice","type":"uint256"},{"internalType":"address[]","name":"registrars","type":"address[]"},{"internalType":"contract IChainModule","name":"chainModule","type":"address"}],"internalType":"struct AutomationRegistryBase2_3.OnchainConfig","name":"onchainConfig","type":"tuple"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"},{"internalType":"contract IERC20Metadata[]","name":"billingTokens","type":"address[]"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"},{"internalType":"contract AggregatorV3Interface","name":"priceFeed","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"fallbackPrice","type":"uint256"},{"internalType":"uint96","name":"minSpend","type":"uint96"}],"internalType":"struct AutomationRegistryBase2_3.BillingConfig[]","name":"billingConfigs","type":"tuple[]"}],"name":"setConfigTypeSafe","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[3]","name":"reportContext","type":"bytes32[3]"},{"internalType":"bytes","name":"rawReport","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":"view","type":"function"},{"inputs":[{"internalType":"contract AutomationRegistryLogicB2_3","name":"logicB","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"cancelUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"address","name":"destination","type":"address"}],"name":"migrateUpkeeps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onTokenTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedUpkeeps","type":"bytes"}],"name":"receiveUpkeeps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"enum AutomationRegistryBase2_3.Trigger","name":"triggerType","type":"uint8"},{"internalType":"contract IERC20Metadata","name":"billingToken","type":"address"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"bytes","name":"triggerConfig","type":"bytes"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"registerUpkeep","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract AutomationRegistryLogicC2_3","name":"logicC","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"acceptUpkeepAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint96","name":"amount","type":"uint96"}],"name":"addFunds","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes[]","name":"values","type":"bytes[]"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"checkCallback","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"triggerData","type":"bytes"}],"name":"checkUpkeep","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"fastGasWei","type":"uint256"},{"internalType":"uint256","name":"linkUSD","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"checkUpkeep","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"fastGasWei","type":"uint256"},{"internalType":"uint256","name":"linkUSD","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"executeCallback","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"pauseUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"removeBillingOverrides","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"}],"internalType":"struct AutomationRegistryBase2_3.BillingOverrides","name":"billingOverrides","type":"tuple"}],"name":"setBillingOverrides","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"newCheckData","type":"bytes"}],"name":"setUpkeepCheckData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint32","name":"gasLimit","type":"uint32"}],"name":"setUpkeepGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"config","type":"bytes"}],"name":"setUpkeepOffchainConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"triggerConfig","type":"bytes"}],"name":"setUpkeepTriggerConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"performData","type":"bytes"}],"name":"simulatePerformUpkeep","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"proposed","type":"address"}],"name":"transferUpkeepAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"unpauseUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Metadata","name":"asset","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawERC20Fees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawLink","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"link","type":"address"},{"internalType":"address","name":"linkUSDFeed","type":"address"},{"internalType":"address","name":"nativeUSDFeed","type":"address"},{"internalType":"address","name":"fastGasFeed","type":"address"},{"internalType":"address","name":"automationForwarderLogic","type":"address"},{"internalType":"address","name":"allowedReadOnlyAddress","type":"address"},{"internalType":"enum AutomationRegistryBase2_3.PayoutMode","name":"payoutMode","type":"uint8"},{"internalType":"address","name":"wrappedNativeTokenAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"}],"name":"acceptPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"disableOffchainPayments","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"maxCount","type":"uint256"}],"name":"getActiveUpkeepIDs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"getAdminPrivilegeConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllowedReadOnlyAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAutomationForwarderLogic","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Metadata","name":"billingToken","type":"address"}],"name":"getAvailableERC20ForPayment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getBalance","outputs":[{"internalType":"uint96","name":"balance","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Metadata","name":"billingToken","type":"address"}],"name":"getBillingConfig","outputs":[{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"},{"internalType":"contract AggregatorV3Interface","name":"priceFeed","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"fallbackPrice","type":"uint256"},{"internalType":"uint96","name":"minSpend","type":"uint96"}],"internalType":"struct AutomationRegistryBase2_3.BillingConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepID","type":"uint256"}],"name":"getBillingOverrides","outputs":[{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"}],"internalType":"struct AutomationRegistryBase2_3.BillingOverrides","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepID","type":"uint256"}],"name":"getBillingOverridesEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepID","type":"uint256"}],"name":"getBillingToken","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Metadata","name":"token","type":"address"}],"name":"getBillingTokenConfig","outputs":[{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"},{"internalType":"contract AggregatorV3Interface","name":"priceFeed","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"fallbackPrice","type":"uint256"},{"internalType":"uint96","name":"minSpend","type":"uint96"}],"internalType":"struct AutomationRegistryBase2_3.BillingConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBillingTokens","outputs":[{"internalType":"contract IERC20Metadata[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCancellationDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getChainModule","outputs":[{"internalType":"contract IChainModule","name":"chainModule","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getConditionalGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getConfig","outputs":[{"components":[{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"bool","name":"reorgProtectionEnabled","type":"bool"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"address","name":"financeAdmin","type":"address"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackNativePrice","type":"uint256"},{"internalType":"address[]","name":"registrars","type":"address[]"},{"internalType":"contract IChainModule","name":"chainModule","type":"address"}],"internalType":"struct AutomationRegistryBase2_3.OnchainConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFallbackNativePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFastGasFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepID","type":"uint256"}],"name":"getForwarder","outputs":[{"internalType":"contract IAutomationForwarder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getHotVars","outputs":[{"components":[{"internalType":"uint96","name":"totalPremium","type":"uint96"},{"internalType":"uint32","name":"latestEpoch","type":"uint32"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"uint8","name":"f","type":"uint8"},{"internalType":"bool","name":"paused","type":"bool"},{"internalType":"bool","name":"reentrancyGuard","type":"bool"},{"internalType":"bool","name":"reorgProtectionEnabled","type":"bool"},{"internalType":"contract IChainModule","name":"chainModule","type":"address"}],"internalType":"struct AutomationRegistryBase2_3.HotVars","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkUSDFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLogGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"enum AutomationRegistryBase2_3.Trigger","name":"triggerType","type":"uint8"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"contract IERC20Metadata","name":"billingToken","type":"address"}],"name":"getMaxPaymentForGas","outputs":[{"internalType":"uint96","name":"maxPayment","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getMinBalance","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getMinBalanceForUpkeep","outputs":[{"internalType":"uint96","name":"minBalance","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNativeUSDFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNumUpkeeps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPayoutMode","outputs":[{"internalType":"enum AutomationRegistryBase2_3.PayoutMode","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"}],"name":"getPeerRegistryMigrationPermission","outputs":[{"internalType":"enum AutomationRegistryBase2_3.MigrationPermission","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPerPerformByteGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getPerSignerGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getReorgProtectionEnabled","outputs":[{"internalType":"bool","name":"reorgProtectionEnabled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Metadata","name":"billingToken","type":"address"}],"name":"getReserveAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"query","type":"address"}],"name":"getSignerInfo","outputs":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint8","name":"index","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getState","outputs":[{"components":[{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"uint96","name":"ownerLinkBalance","type":"uint96"},{"internalType":"uint256","name":"expectedLinkBalance","type":"uint256"},{"internalType":"uint96","name":"totalPremium","type":"uint96"},{"internalType":"uint256","name":"numUpkeeps","type":"uint256"},{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"latestConfigBlockNumber","type":"uint32"},{"internalType":"bytes32","name":"latestConfigDigest","type":"bytes32"},{"internalType":"uint32","name":"latestEpoch","type":"uint32"},{"internalType":"bool","name":"paused","type":"bool"}],"internalType":"struct IAutomationV21PlusCommon.StateLegacy","name":"state","type":"tuple"},{"components":[{"internalType":"uint32","name":"paymentPremiumPPB","type":"uint32"},{"internalType":"uint32","name":"flatFeeMicroLink","type":"uint32"},{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"uint96","name":"minUpkeepSpend","type":"uint96"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"address[]","name":"registrars","type":"address[]"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"}],"internalType":"struct IAutomationV21PlusCommon.OnchainConfigLegacy","name":"config","type":"tuple"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStorage","outputs":[{"components":[{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"},{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"latestConfigBlockNumber","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"address","name":"financeAdmin","type":"address"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"}],"internalType":"struct AutomationRegistryBase2_3.Storage","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransmitCalldataFixedBytesOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTransmitCalldataPerSignerBytesOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"query","type":"address"}],"name":"getTransmitterInfo","outputs":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint8","name":"index","type":"uint8"},{"internalType":"uint96","name":"balance","type":"uint96"},{"internalType":"uint96","name":"lastCollected","type":"uint96"},{"internalType":"address","name":"payee","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransmittersWithPayees","outputs":[{"components":[{"internalType":"address","name":"transmitterAddress","type":"address"},{"internalType":"address","name":"payeeAddress","type":"address"}],"internalType":"struct AutomationRegistryBase2_3.TransmitterPayeeInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getTriggerType","outputs":[{"internalType":"enum AutomationRegistryBase2_3.Trigger","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getUpkeep","outputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"performGas","type":"uint32"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"uint96","name":"balance","type":"uint96"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"uint64","name":"maxValidBlocknumber","type":"uint64"},{"internalType":"uint32","name":"lastPerformedBlockNumber","type":"uint32"},{"internalType":"uint96","name":"amountSpent","type":"uint96"},{"internalType":"bool","name":"paused","type":"bool"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"internalType":"struct IAutomationV21PlusCommon.UpkeepInfoLegacy","name":"upkeepInfo","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getUpkeepPrivilegeConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getUpkeepTriggerConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWrappedNativeTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dedupKey","type":"bytes32"}],"name":"hasDedupKey","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"linkAvailableForPayment","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"bytes","name":"newPrivilegeConfig","type":"bytes"}],"name":"setAdminPrivilegeConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"payees","type":"address[]"}],"name":"setPayees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"},{"internalType":"enum AutomationRegistryBase2_3.MigrationPermission","name":"permission","type":"uint8"}],"name":"setPeerRegistryMigrationPermission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"},{"internalType":"bytes","name":"newPrivilegeConfig","type":"bytes"}],"name":"setUpkeepPrivilegeConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settleNOPsOffchain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Metadata","name":"token","type":"address"}],"name":"supportsBillingToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"},{"internalType":"address","name":"proposed","type":"address"}],"name":"transferPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"upkeepVersion","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawPayment","outputs":[],"stateMutability":"nonpayable","type":"function"}] */
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IERC20Metadata as IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; interface IWrappedNative is IERC20 { function deposit() external payable; function withdraw(uint256 wad) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; import {IAutomationRegistryMaster2_3} from "../interfaces/v2_3/IAutomationRegistryMaster2_3.sol"; import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol"; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; import {IERC677Receiver} from "../../shared/interfaces/IERC677Receiver.sol"; import {IERC20Metadata as IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {IWrappedNative} from "../interfaces/v2_3/IWrappedNative.sol"; import {SafeCast} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol"; import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; /** * @notice Contract to accept requests for upkeep registrations * @dev There are 2 registration workflows in this contract * Flow 1. auto approve OFF / manual registration - UI calls `register` function on this contract, this contract owner at a later time then manually * calls `approve` to register upkeep and emit events to inform UI and others interested. * Flow 2. auto approve ON / real time registration - UI calls `register` function as before, which calls the `registerUpkeep` function directly on * keeper registry and then emits approved event to finish the flow automatically without manual intervention. * The idea is to have same interface(functions,events) for UI or anyone using this contract irrespective of auto approve being enabled or not. * they can just listen to `RegistrationRequested` & `RegistrationApproved` events and know the status on registrations. */ contract AutomationRegistrar2_3 is TypeAndVersionInterface, ConfirmedOwner, IERC677Receiver { using SafeERC20 for IERC20; /** * DISABLED: No auto approvals, all new upkeeps should be approved manually. * ENABLED_SENDER_ALLOWLIST: Auto approvals for allowed senders subject to max allowed. Manual for rest. * ENABLED_ALL: Auto approvals for all new upkeeps subject to max allowed. */ enum AutoApproveType { DISABLED, ENABLED_SENDER_ALLOWLIST, ENABLED_ALL } /** * @notice versions: * - KeeperRegistrar 2.3.0: Update for compatability with registry 2.3.0 * Add native billing and ERC20 billing support * - KeeperRegistrar 2.1.0: Update for compatability with registry 2.1.0 * Add auto approval levels by type * - KeeperRegistrar 2.0.0: Remove source from register * Breaks our example of "Register an Upkeep using your own deployed contract" * - KeeperRegistrar 1.1.0: Add functionality for sender allowlist in auto approve * : Remove rate limit and add max allowed for auto approve * - KeeperRegistrar 1.0.0: initial release */ string public constant override typeAndVersion = "AutomationRegistrar 2.3.0"; /** * @notice TriggerRegistrationStorage stores the auto-approval levels for upkeeps by type * @member autoApproveType the auto approval setting (see enum) * @member autoApproveMaxAllowed the max number of upkeeps that can be auto approved of this type * @member approvedCount the count of upkeeps auto approved of this type */ struct TriggerRegistrationStorage { AutoApproveType autoApproveType; uint32 autoApproveMaxAllowed; uint32 approvedCount; } /** * @notice InitialTriggerConfig configures the auto-approval levels for upkeeps by trigger type * @dev this struct is only used in the constructor to set the initial values for various trigger configs * @member triggerType the upkeep type to configure * @member autoApproveType the auto approval setting (see enum) * @member autoApproveMaxAllowed the max number of upkeeps that can be auto approved of this type */ // solhint-disable-next-line gas-struct-packing struct InitialTriggerConfig { uint8 triggerType; AutoApproveType autoApproveType; uint32 autoApproveMaxAllowed; } struct PendingRequest { address admin; uint96 balance; IERC20 billingToken; } /** * @member upkeepContract address to perform upkeep on * @member amount quantity of billing token upkeep is funded with (specified in the billing token's decimals) * @member adminAddress address to cancel upkeep and withdraw remaining funds * @member gasLimit amount of gas to provide the target contract when performing upkeep * @member triggerType the type of trigger for the upkeep * @member billingToken the token to pay with * @member name string of the upkeep to be registered * @member encryptedEmail email address of upkeep contact * @member checkData data passed to the contract when checking for upkeep * @member triggerConfig the config for the trigger * @member offchainConfig offchainConfig for upkeep in bytes */ struct RegistrationParams { address upkeepContract; uint96 amount; // 1 word full address adminAddress; uint32 gasLimit; uint8 triggerType; // 7 bytes left in 2nd word IERC20 billingToken; // 12 bytes left in 3rd word string name; bytes encryptedEmail; bytes checkData; bytes triggerConfig; bytes offchainConfig; } LinkTokenInterface public immutable i_LINK; IWrappedNative public immutable i_WRAPPED_NATIVE_TOKEN; IAutomationRegistryMaster2_3 private s_registry; // Only applicable if trigger config is set to ENABLED_SENDER_ALLOWLIST mapping(address => bool) private s_autoApproveAllowedSenders; mapping(IERC20 => uint256) private s_minRegistrationAmounts; mapping(bytes32 => PendingRequest) private s_pendingRequests; mapping(uint8 => TriggerRegistrationStorage) private s_triggerRegistrations; event RegistrationRequested( bytes32 indexed hash, string name, bytes encryptedEmail, address indexed upkeepContract, uint32 gasLimit, address adminAddress, uint8 triggerType, bytes triggerConfig, bytes offchainConfig, bytes checkData, uint96 amount, IERC20 billingToken ); event RegistrationApproved(bytes32 indexed hash, string displayName, uint256 indexed upkeepId); event RegistrationRejected(bytes32 indexed hash); event AutoApproveAllowedSenderSet(address indexed senderAddress, bool allowed); event ConfigChanged(); event TriggerConfigSet(uint8 triggerType, AutoApproveType autoApproveType, uint32 autoApproveMaxAllowed); error HashMismatch(); error InsufficientPayment(); error InvalidAdminAddress(); error InvalidBillingToken(); error InvalidDataLength(); error TransferFailed(address to); error DuplicateEntry(); error OnlyAdminOrOwner(); error OnlyLink(); error RequestNotFound(); /** * @param LINKAddress Address of Link token * @param registry keeper registry address * @param triggerConfigs the initial config for individual triggers * @param billingTokens the tokens allowed for billing * @param minRegistrationFees the minimum amount for registering with each billing token * @param wrappedNativeToken wrapped native token */ constructor( address LINKAddress, IAutomationRegistryMaster2_3 registry, InitialTriggerConfig[] memory triggerConfigs, IERC20[] memory billingTokens, uint256[] memory minRegistrationFees, IWrappedNative wrappedNativeToken ) ConfirmedOwner(msg.sender) { i_LINK = LinkTokenInterface(LINKAddress); i_WRAPPED_NATIVE_TOKEN = wrappedNativeToken; setConfig(registry, billingTokens, minRegistrationFees); for (uint256 idx = 0; idx < triggerConfigs.length; idx++) { setTriggerConfig( triggerConfigs[idx].triggerType, triggerConfigs[idx].autoApproveType, triggerConfigs[idx].autoApproveMaxAllowed ); } } //EXTERNAL /** * @notice Allows external users to register upkeeps; assumes amount is approved for transfer by the contract * @param requestParams struct of all possible registration parameters */ function registerUpkeep(RegistrationParams memory requestParams) external payable returns (uint256) { if (requestParams.billingToken == IERC20(i_WRAPPED_NATIVE_TOKEN) && msg.value != 0) { requestParams.amount = SafeCast.toUint96(msg.value); // wrap and send native payment i_WRAPPED_NATIVE_TOKEN.deposit{value: msg.value}(); } else { // send ERC20 payment, including wrapped native token requestParams.billingToken.safeTransferFrom(msg.sender, address(this), requestParams.amount); } return _register(requestParams, msg.sender); } /** * @dev register upkeep on AutomationRegistry contract and emit RegistrationApproved event * @param requestParams struct of all possible registration parameters */ function approve(RegistrationParams calldata requestParams) external onlyOwner { bytes32 hash = keccak256(abi.encode(requestParams)); PendingRequest memory request = s_pendingRequests[hash]; if (request.admin == address(0)) { revert RequestNotFound(); } delete s_pendingRequests[hash]; _approve(requestParams, hash); } /** * @notice cancel will remove a registration request from the pending request queue and return the refunds to the request.admin * @param hash the request hash */ function cancel(bytes32 hash) external { PendingRequest memory request = s_pendingRequests[hash]; if (!(msg.sender == request.admin || msg.sender == owner())) { revert OnlyAdminOrOwner(); } if (request.admin == address(0)) { revert RequestNotFound(); } delete s_pendingRequests[hash]; request.billingToken.safeTransfer(request.admin, request.balance); emit RegistrationRejected(hash); } /** * @notice owner calls this function to set contract config * @param registry new keeper registry address * @param billingTokens the billing tokens that this registrar supports (registy must also support these) * @param minBalances minimum balances that users must supply to register with the corresponding billing token */ function setConfig( IAutomationRegistryMaster2_3 registry, IERC20[] memory billingTokens, uint256[] memory minBalances ) public onlyOwner { if (billingTokens.length != minBalances.length) revert InvalidDataLength(); s_registry = registry; for (uint256 i = 0; i < billingTokens.length; i++) { s_minRegistrationAmounts[billingTokens[i]] = minBalances[i]; } emit ConfigChanged(); } /** * @notice owner calls to set the config for this upkeep type * @param triggerType the upkeep type to configure * @param autoApproveType the auto approval setting (see enum) * @param autoApproveMaxAllowed the max number of upkeeps that can be auto approved of this type */ function setTriggerConfig( uint8 triggerType, AutoApproveType autoApproveType, uint32 autoApproveMaxAllowed ) public onlyOwner { s_triggerRegistrations[triggerType].autoApproveType = autoApproveType; s_triggerRegistrations[triggerType].autoApproveMaxAllowed = autoApproveMaxAllowed; emit TriggerConfigSet(triggerType, autoApproveType, autoApproveMaxAllowed); } /** * @notice owner calls this function to set allowlist status for senderAddress * @param senderAddress senderAddress to set the allowlist status for * @param allowed true if senderAddress needs to be added to allowlist, false if needs to be removed */ function setAutoApproveAllowedSender(address senderAddress, bool allowed) external onlyOwner { s_autoApproveAllowedSenders[senderAddress] = allowed; emit AutoApproveAllowedSenderSet(senderAddress, allowed); } /** * @notice read the allowlist status of senderAddress * @param senderAddress address to read the allowlist status for */ function getAutoApproveAllowedSender(address senderAddress) external view returns (bool) { return s_autoApproveAllowedSenders[senderAddress]; } /** * @notice gets the registry that this registrar is pointed to */ function getRegistry() external view returns (IAutomationRegistryMaster2_3) { return s_registry; } /** * @notice get the minimum registration fee for a particular billing token */ function getMinimumRegistrationAmount(IERC20 billingToken) external view returns (uint256) { return s_minRegistrationAmounts[billingToken]; } /** * @notice read the config for this upkeep type * @param triggerType upkeep type to read config for */ function getTriggerRegistrationDetails(uint8 triggerType) external view returns (TriggerRegistrationStorage memory) { return s_triggerRegistrations[triggerType]; } /** * @notice gets the admin address and the current balance of a registration request */ function getPendingRequest(bytes32 hash) external view returns (address, uint96) { PendingRequest memory request = s_pendingRequests[hash]; return (request.admin, request.balance); } /** * @notice Called when LINK is sent to the contract via `transferAndCall` * @param sender Address of the sender transfering LINK * @param amount Amount of LINK sent (specified in Juels) * @param data Payload of the transaction */ function onTokenTransfer(address sender, uint256 amount, bytes calldata data) external override { if (msg.sender != address(i_LINK)) revert OnlyLink(); RegistrationParams memory params = abi.decode(data, (RegistrationParams)); if (address(params.billingToken) != address(i_LINK)) revert OnlyLink(); params.amount = uint96(amount); // ignore whatever is sent in registration params, use actual value; casting safe because max supply LINK < 2^96 _register(params, sender); } // ================================================================ // | PRIVATE | // ================================================================ /** * @dev verify registration request and emit RegistrationRequested event * @dev we don't allow multiple duplicate registrations by adding to the original registration's balance * users can cancel and re-register if they want to update the registration */ function _register(RegistrationParams memory params, address sender) private returns (uint256) { if (params.amount < s_minRegistrationAmounts[params.billingToken]) { revert InsufficientPayment(); } if (params.adminAddress == address(0)) { revert InvalidAdminAddress(); } if (!s_registry.supportsBillingToken(address(params.billingToken))) { revert InvalidBillingToken(); } bytes32 hash = keccak256(abi.encode(params)); if (s_pendingRequests[hash].admin != address(0)) { revert DuplicateEntry(); } emit RegistrationRequested( hash, params.name, params.encryptedEmail, params.upkeepContract, params.gasLimit, params.adminAddress, params.triggerType, params.triggerConfig, params.offchainConfig, params.checkData, params.amount, params.billingToken ); uint256 upkeepId; if (_shouldAutoApprove(s_triggerRegistrations[params.triggerType], sender)) { s_triggerRegistrations[params.triggerType].approvedCount++; upkeepId = _approve(params, hash); } else { s_pendingRequests[hash] = PendingRequest({ admin: params.adminAddress, balance: params.amount, billingToken: params.billingToken }); } return upkeepId; } /** * @dev register upkeep on AutomationRegistry contract and emit RegistrationApproved event * @dev safeApprove is deprecated and removed from the latest (v5) OZ release, Use safeIncreaseAllowance when we upgrade OZ (we are on v4.8) * @dev we stick to the safeApprove because of the older version (v4.8) of safeIncreaseAllowance can't handle USDT correctly, but newer version can */ function _approve(RegistrationParams memory params, bytes32 hash) private returns (uint256) { IAutomationRegistryMaster2_3 registry = s_registry; uint256 upkeepId = registry.registerUpkeep( params.upkeepContract, params.gasLimit, params.adminAddress, params.triggerType, address(params.billingToken), // have to cast as address because master interface doesn't use contract types params.checkData, params.triggerConfig, params.offchainConfig ); if (address(params.billingToken) == address(i_LINK)) { bool success = i_LINK.transferAndCall(address(registry), params.amount, abi.encode(upkeepId)); if (!success) { revert TransferFailed(address(registry)); } } else { params.billingToken.safeApprove(address(registry), params.amount); registry.addFunds(upkeepId, params.amount); } emit RegistrationApproved(hash, params.name, upkeepId); return upkeepId; } /** * @dev verify sender allowlist if needed and check max limit */ function _shouldAutoApprove(TriggerRegistrationStorage memory config, address sender) private view returns (bool) { if (config.autoApproveType == AutoApproveType.DISABLED) { return false; } if (config.autoApproveType == AutoApproveType.ENABLED_SENDER_ALLOWLIST && (!s_autoApproveAllowedSenders[sender])) { return false; } if (config.approvedCount < config.autoApproveMaxAllowed) { return true; } return false; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; import {Address} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; import {StreamsLookupCompatibleInterface} from "../interfaces/StreamsLookupCompatibleInterface.sol"; import {ILogAutomation, Log} from "../interfaces/ILogAutomation.sol"; import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol"; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; import {AggregatorV3Interface} from "../../shared/interfaces/AggregatorV3Interface.sol"; import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; import {KeeperCompatibleInterface} from "../interfaces/KeeperCompatibleInterface.sol"; import {IChainModule} from "../interfaces/IChainModule.sol"; import {IERC20Metadata as IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {SafeCast} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol"; import {IWrappedNative} from "../interfaces/v2_3/IWrappedNative.sol"; /** * @notice Base Keeper Registry contract, contains shared logic between * AutomationRegistry and AutomationRegistryLogic * @dev all errors, events, and internal functions should live here */ // solhint-disable-next-line max-states-count abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { using Address for address; using EnumerableSet for EnumerableSet.UintSet; using EnumerableSet for EnumerableSet.AddressSet; address internal constant ZERO_ADDRESS = address(0); address internal constant IGNORE_ADDRESS = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF; bytes4 internal constant CHECK_SELECTOR = KeeperCompatibleInterface.checkUpkeep.selector; bytes4 internal constant PERFORM_SELECTOR = KeeperCompatibleInterface.performUpkeep.selector; bytes4 internal constant CHECK_CALLBACK_SELECTOR = StreamsLookupCompatibleInterface.checkCallback.selector; bytes4 internal constant CHECK_LOG_SELECTOR = ILogAutomation.checkLog.selector; uint256 internal constant PERFORM_GAS_MIN = 2_300; uint256 internal constant CANCELLATION_DELAY = 50; uint256 internal constant PERFORM_GAS_CUSHION = 5_000; uint256 internal constant PPB_BASE = 1_000_000_000; uint32 internal constant UINT32_MAX = type(uint32).max; // The first byte of the mask can be 0, because we only ever have 31 oracles uint256 internal constant ORACLE_MASK = 0x0001010101010101010101010101010101010101010101010101010101010101; uint8 internal constant UPKEEP_VERSION_BASE = 4; // Next block of constants are only used in maxPayment estimation during checkUpkeep simulation // These values are calibrated using hardhat tests which simulate various cases and verify that // the variables result in accurate estimation uint256 internal constant REGISTRY_CONDITIONAL_OVERHEAD = 98_200; // Fixed gas overhead for conditional upkeeps uint256 internal constant REGISTRY_LOG_OVERHEAD = 123_500; // Fixed gas overhead for log upkeeps uint256 internal constant REGISTRY_PER_SIGNER_GAS_OVERHEAD = 5_600; // Value scales with f uint256 internal constant REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD = 24; // Per perform data byte overhead // The overhead (in bytes) in addition to perform data for upkeep sent in calldata // This includes overhead for all struct encoding as well as report signatures // There is a fixed component and a per signer component. This is calculated exactly by doing abi encoding uint256 internal constant TRANSMIT_CALLDATA_FIXED_BYTES_OVERHEAD = 932; uint256 internal constant TRANSMIT_CALLDATA_PER_SIGNER_BYTES_OVERHEAD = 64; // Next block of constants are used in actual payment calculation. We calculate the exact gas used within the // tx itself, but since payment processing itself takes gas, and it needs the overhead as input, we use fixed constants // to account for gas used in payment processing. These values are calibrated using hardhat tests which simulates various cases and verifies that // the variables result in accurate estimation uint256 internal constant ACCOUNTING_FIXED_GAS_OVERHEAD = 51_200; // Fixed overhead per tx uint256 internal constant ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD = 14_200; // Overhead per upkeep performed in batch LinkTokenInterface internal immutable i_link; AggregatorV3Interface internal immutable i_linkUSDFeed; AggregatorV3Interface internal immutable i_nativeUSDFeed; AggregatorV3Interface internal immutable i_fastGasFeed; address internal immutable i_automationForwarderLogic; address internal immutable i_allowedReadOnlyAddress; IWrappedNative internal immutable i_wrappedNativeToken; /** * @dev - The storage is gas optimised for one and only one function - transmit. All the storage accessed in transmit * is stored compactly. Rest of the storage layout is not of much concern as transmit is the only hot path */ // Upkeep storage EnumerableSet.UintSet internal s_upkeepIDs; mapping(uint256 => Upkeep) internal s_upkeep; // accessed during transmit mapping(uint256 => address) internal s_upkeepAdmin; mapping(uint256 => address) internal s_proposedAdmin; mapping(uint256 => bytes) internal s_checkData; mapping(bytes32 => bool) internal s_dedupKeys; // Registry config and state EnumerableSet.AddressSet internal s_registrars; mapping(address => Transmitter) internal s_transmitters; mapping(address => Signer) internal s_signers; address[] internal s_signersList; // s_signersList contains the signing address of each oracle address[] internal s_transmittersList; // s_transmittersList contains the transmission address of each oracle EnumerableSet.AddressSet internal s_deactivatedTransmitters; mapping(address => address) internal s_transmitterPayees; // s_payees contains the mapping from transmitter to payee. mapping(address => address) internal s_proposedPayee; // proposed payee for a transmitter bytes32 internal s_latestConfigDigest; // Read on transmit path in case of signature verification HotVars internal s_hotVars; // Mixture of config and state, used in transmit Storage internal s_storage; // Mixture of config and state, not used in transmit uint256 internal s_fallbackGasPrice; uint256 internal s_fallbackLinkPrice; uint256 internal s_fallbackNativePrice; mapping(address => MigrationPermission) internal s_peerRegistryMigrationPermission; // Permissions for migration to and fro mapping(uint256 => bytes) internal s_upkeepTriggerConfig; // upkeep triggers mapping(uint256 => bytes) internal s_upkeepOffchainConfig; // general config set by users for each upkeep mapping(uint256 => bytes) internal s_upkeepPrivilegeConfig; // general config set by an administrative role for an upkeep mapping(address => bytes) internal s_adminPrivilegeConfig; // general config set by an administrative role for an admin // billing mapping(IERC20 billingToken => uint256 reserveAmount) internal s_reserveAmounts; // unspent user deposits + unwithdrawn NOP payments mapping(IERC20 billingToken => BillingConfig billingConfig) internal s_billingConfigs; // billing configurations for different tokens mapping(uint256 upkeepID => BillingOverrides billingOverrides) internal s_billingOverrides; // billing overrides for specific upkeeps IERC20[] internal s_billingTokens; // list of billing tokens PayoutMode internal s_payoutMode; error ArrayHasNoEntries(); error CannotCancel(); error CheckDataExceedsLimit(); error ConfigDigestMismatch(); error DuplicateEntry(); error DuplicateSigners(); error GasLimitCanOnlyIncrease(); error GasLimitOutsideRange(); error IncorrectNumberOfFaultyOracles(); error IncorrectNumberOfSignatures(); error IncorrectNumberOfSigners(); error IndexOutOfRange(); error InsufficientBalance(uint256 available, uint256 requested); error InsufficientLinkLiquidity(); error InvalidDataLength(); error InvalidFeed(); error InvalidTrigger(); error InvalidPayee(); error InvalidRecipient(); error InvalidReport(); error InvalidSigner(); error InvalidToken(); error InvalidTransmitter(); error InvalidTriggerType(); error MigrationNotPermitted(); error MustSettleOffchain(); error MustSettleOnchain(); error NotAContract(); error OnlyActiveSigners(); error OnlyActiveTransmitters(); error OnlyCallableByAdmin(); error OnlyCallableByLINKToken(); error OnlyCallableByOwnerOrAdmin(); error OnlyCallableByOwnerOrRegistrar(); error OnlyCallableByPayee(); error OnlyCallableByProposedAdmin(); error OnlyCallableByProposedPayee(); error OnlyCallableByUpkeepPrivilegeManager(); error OnlyFinanceAdmin(); error OnlyPausedUpkeep(); error OnlySimulatedBackend(); error OnlyUnpausedUpkeep(); error ParameterLengthError(); error ReentrantCall(); error RegistryPaused(); error RepeatedSigner(); error RepeatedTransmitter(); error TargetCheckReverted(bytes reason); error TooManyOracles(); error TranscoderNotSet(); error TransferFailed(); error UpkeepAlreadyExists(); error UpkeepCancelled(); error UpkeepNotCanceled(); error UpkeepNotNeeded(); error ValueNotChanged(); error ZeroAddressNotAllowed(); enum MigrationPermission { NONE, OUTGOING, INCOMING, BIDIRECTIONAL } enum Trigger { CONDITION, LOG } enum UpkeepFailureReason { NONE, UPKEEP_CANCELLED, UPKEEP_PAUSED, TARGET_CHECK_REVERTED, UPKEEP_NOT_NEEDED, PERFORM_DATA_EXCEEDS_LIMIT, INSUFFICIENT_BALANCE, CALLBACK_REVERTED, REVERT_DATA_EXCEEDS_LIMIT, REGISTRY_PAUSED } enum PayoutMode { ON_CHAIN, OFF_CHAIN } /** * @notice OnchainConfig of the registry * @dev used only in setConfig() * @member checkGasLimit gas limit when checking for upkeep * @member stalenessSeconds number of seconds that is allowed for feed data to * be stale before switching to the fallback pricing * @member gasCeilingMultiplier multiplier to apply to the fast gas feed price * when calculating the payment ceiling for keepers * @member maxPerformGas max performGas allowed for an upkeep on this registry * @member maxCheckDataSize max length of checkData bytes * @member maxPerformDataSize max length of performData bytes * @member maxRevertDataSize max length of revertData bytes * @member fallbackGasPrice gas price used if the gas price feed is stale * @member fallbackLinkPrice LINK price used if the LINK price feed is stale * @member transcoder address of the transcoder contract * @member registrars addresses of the registrar contracts * @member upkeepPrivilegeManager address which can set privilege for upkeeps * @member reorgProtectionEnabled if this registry enables re-org protection checks * @member chainModule the chain specific module */ struct OnchainConfig { uint32 checkGasLimit; uint32 maxPerformGas; uint32 maxCheckDataSize; address transcoder; // 1 word full bool reorgProtectionEnabled; uint24 stalenessSeconds; uint32 maxPerformDataSize; uint32 maxRevertDataSize; address upkeepPrivilegeManager; // 2 words full uint16 gasCeilingMultiplier; address financeAdmin; // 3 words uint256 fallbackGasPrice; uint256 fallbackLinkPrice; uint256 fallbackNativePrice; address[] registrars; IChainModule chainModule; } /** * @notice relevant state of an upkeep which is used in transmit function * @member paused if this upkeep has been paused * @member overridesEnabled if this upkeep has overrides enabled * @member performGas the gas limit of upkeep execution * @member maxValidBlocknumber until which block this upkeep is valid * @member forwarder the forwarder contract to use for this upkeep * @member amountSpent the amount this upkeep has spent, in the upkeep's billing token * @member balance the balance of this upkeep * @member lastPerformedBlockNumber the last block number when this upkeep was performed */ struct Upkeep { bool paused; bool overridesEnabled; uint32 performGas; uint32 maxValidBlocknumber; IAutomationForwarder forwarder; // 2 bytes left in 1st EVM word - read in transmit path uint128 amountSpent; uint96 balance; uint32 lastPerformedBlockNumber; // 0 bytes left in 2nd EVM word - written in transmit path IERC20 billingToken; // 12 bytes left in 3rd EVM word - read in transmit path } /// @dev Config + State storage struct which is on hot transmit path struct HotVars { uint96 totalPremium; // ─────────╮ total historical payment to oracles for premium uint32 latestEpoch; // │ latest epoch for which a report was transmitted uint24 stalenessSeconds; // │ Staleness tolerance for feeds uint16 gasCeilingMultiplier; // │ multiplier on top of fast gas feed for upper bound uint8 f; // │ maximum number of faulty oracles bool paused; // │ pause switch for all upkeeps in the registry bool reentrancyGuard; // | guard against reentrancy bool reorgProtectionEnabled; // ─╯ if this registry should enable the re-org protection mechanism IChainModule chainModule; // the interface of chain specific module } /// @dev Config + State storage struct which is not on hot transmit path struct Storage { address transcoder; // Address of transcoder contract used in migrations uint32 checkGasLimit; // Gas limit allowed in checkUpkeep uint32 maxPerformGas; // Max gas an upkeep can use on this registry uint32 nonce; // Nonce for each upkeep created // 1 EVM word full address upkeepPrivilegeManager; // address which can set privilege for upkeeps uint32 configCount; // incremented each time a new config is posted, The count is incorporated into the config digest to prevent replay attacks. uint32 latestConfigBlockNumber; // makes it easier for offchain systems to extract config from logs uint32 maxCheckDataSize; // max length of checkData bytes // 2 EVM word full address financeAdmin; // address which can withdraw funds from the contract uint32 maxPerformDataSize; // max length of performData bytes uint32 maxRevertDataSize; // max length of revertData bytes // 4 bytes left in 3rd EVM word } /// @dev Report transmitted by OCR to transmit function struct Report { uint256 fastGasWei; uint256 linkUSD; uint256[] upkeepIds; uint256[] gasLimits; bytes[] triggers; bytes[] performDatas; } /** * @dev This struct is used to maintain run time information about an upkeep in transmit function * @member upkeep the upkeep struct * @member earlyChecksPassed whether the upkeep passed early checks before perform * @member performSuccess whether the perform was successful * @member triggerType the type of trigger * @member gasUsed gasUsed by this upkeep in perform * @member calldataWeight weight assigned to this upkeep for its contribution to calldata. It is used to split L1 fee * @member dedupID unique ID used to dedup an upkeep/trigger combo */ struct UpkeepTransmitInfo { Upkeep upkeep; bool earlyChecksPassed; bool performSuccess; Trigger triggerType; uint256 gasUsed; uint256 calldataWeight; bytes32 dedupID; } /** * @notice holds information about a transmiter / node in the DON * @member active can this transmitter submit reports * @member index of oracle in s_signersList/s_transmittersList * @member balance a node's balance in LINK * @member lastCollected the total balance at which the node last withdrew * @dev uint96 is safe for balance / last collected because transmitters are only ever paid in LINK */ struct Transmitter { bool active; uint8 index; uint96 balance; uint96 lastCollected; } struct TransmitterPayeeInfo { address transmitterAddress; address payeeAddress; } struct Signer { bool active; // Index of oracle in s_signersList/s_transmittersList uint8 index; } /** * @notice the trigger structure conditional trigger type */ struct ConditionalTrigger { uint32 blockNum; bytes32 blockHash; } /** * @notice the trigger structure of log upkeeps * @dev NOTE that blockNum / blockHash describe the block used for the callback, * not necessarily the block number that the log was emitted in!!!! */ struct LogTrigger { bytes32 logBlockHash; bytes32 txHash; uint32 logIndex; uint32 blockNum; bytes32 blockHash; } /** * @notice the billing config of a token * @dev this is a storage struct */ // solhint-disable-next-line gas-struct-packing struct BillingConfig { uint32 gasFeePPB; uint24 flatFeeMilliCents; // min fee is $0.00001, max fee is $167 AggregatorV3Interface priceFeed; uint8 decimals; // 1st word, read in calculating BillingTokenPaymentParams uint256 fallbackPrice; // 2nd word only read if stale uint96 minSpend; // 3rd word only read during cancellation } /** * @notice override-able billing params of a billing token */ struct BillingOverrides { uint32 gasFeePPB; uint24 flatFeeMilliCents; } /** * @notice pricing params for a billing token * @dev this is a memory-only struct, so struct packing is less important */ struct BillingTokenPaymentParams { uint8 decimals; uint32 gasFeePPB; uint24 flatFeeMilliCents; uint256 priceUSD; } /** * @notice struct containing price & payment information used in calculating payment amount * @member gasLimit the amount of gas used * @member gasOverhead the amount of gas overhead * @member l1CostWei the amount to be charged for L1 fee in wei * @member fastGasWei the fast gas price * @member linkUSD the exchange ratio between LINK and USD * @member nativeUSD the exchange ratio between the chain's native token and USD * @member billingToken the billing token * @member billingTokenParams the payment params specific to a particular payment token * @member isTransaction is this an eth_call or a transaction */ struct PaymentParams { uint256 gasLimit; uint256 gasOverhead; uint256 l1CostWei; uint256 fastGasWei; uint256 linkUSD; uint256 nativeUSD; IERC20 billingToken; BillingTokenPaymentParams billingTokenParams; bool isTransaction; } /** * @notice struct containing receipt information about a payment or cost estimation * @member gasChargeInBillingToken the amount to charge a user for gas spent using the billing token's native decimals * @member premiumInBillingToken the premium charged to the user, shared between all nodes, using the billing token's native decimals * @member gasReimbursementInJuels the amount to reimburse a node for gas spent * @member premiumInJuels the premium paid to NOPs, shared between all nodes */ // solhint-disable-next-line gas-struct-packing struct PaymentReceipt { uint96 gasChargeInBillingToken; uint96 premiumInBillingToken; // one word ends uint96 gasReimbursementInJuels; uint96 premiumInJuels; // second word ends IERC20 billingToken; uint96 linkUSD; // third word ends uint96 nativeUSD; uint96 billingUSD; // fourth word ends } event AdminPrivilegeConfigSet(address indexed admin, bytes privilegeConfig); event BillingConfigOverridden(uint256 indexed id, BillingOverrides overrides); event BillingConfigOverrideRemoved(uint256 indexed id); event BillingConfigSet(IERC20 indexed token, BillingConfig config); event CancelledUpkeepReport(uint256 indexed id, bytes trigger); event ChainSpecificModuleUpdated(address newModule); event DedupKeyAdded(bytes32 indexed dedupKey); event FeesWithdrawn(address indexed assetAddress, address indexed recipient, uint256 amount); event FundsAdded(uint256 indexed id, address indexed from, uint96 amount); event FundsWithdrawn(uint256 indexed id, uint256 amount, address to); event InsufficientFundsUpkeepReport(uint256 indexed id, bytes trigger); event NOPsSettledOffchain(address[] payees, uint256[] payments); event Paused(address account); event PayeesUpdated(address[] transmitters, address[] payees); event PayeeshipTransferRequested(address indexed transmitter, address indexed from, address indexed to); event PayeeshipTransferred(address indexed transmitter, address indexed from, address indexed to); event PaymentWithdrawn(address indexed transmitter, uint256 indexed amount, address indexed to, address payee); event ReorgedUpkeepReport(uint256 indexed id, bytes trigger); event StaleUpkeepReport(uint256 indexed id, bytes trigger); event UpkeepAdminTransferred(uint256 indexed id, address indexed from, address indexed to); event UpkeepAdminTransferRequested(uint256 indexed id, address indexed from, address indexed to); event UpkeepCanceled(uint256 indexed id, uint64 indexed atBlockHeight); event UpkeepCheckDataSet(uint256 indexed id, bytes newCheckData); event UpkeepGasLimitSet(uint256 indexed id, uint96 gasLimit); event UpkeepMigrated(uint256 indexed id, uint256 remainingBalance, address destination); event UpkeepOffchainConfigSet(uint256 indexed id, bytes offchainConfig); event UpkeepPaused(uint256 indexed id); event UpkeepPerformed( uint256 indexed id, bool indexed success, uint96 totalPayment, uint256 gasUsed, uint256 gasOverhead, bytes trigger ); event UpkeepCharged(uint256 indexed id, PaymentReceipt receipt); event UpkeepPrivilegeConfigSet(uint256 indexed id, bytes privilegeConfig); event UpkeepReceived(uint256 indexed id, uint256 startingBalance, address importedFrom); event UpkeepRegistered(uint256 indexed id, uint32 performGas, address admin); event UpkeepTriggerConfigSet(uint256 indexed id, bytes triggerConfig); event UpkeepUnpaused(uint256 indexed id); event Unpaused(address account); /** * @param link address of the LINK Token * @param linkUSDFeed address of the LINK/USD price feed * @param nativeUSDFeed address of the Native/USD price feed * @param fastGasFeed address of the Fast Gas price feed * @param automationForwarderLogic the address of automation forwarder logic * @param allowedReadOnlyAddress the address of the allowed read only address * @param payoutMode the payout mode */ constructor( address link, address linkUSDFeed, address nativeUSDFeed, address fastGasFeed, address automationForwarderLogic, address allowedReadOnlyAddress, PayoutMode payoutMode, address wrappedNativeTokenAddress ) ConfirmedOwner(msg.sender) { i_link = LinkTokenInterface(link); i_linkUSDFeed = AggregatorV3Interface(linkUSDFeed); i_nativeUSDFeed = AggregatorV3Interface(nativeUSDFeed); i_fastGasFeed = AggregatorV3Interface(fastGasFeed); i_automationForwarderLogic = automationForwarderLogic; i_allowedReadOnlyAddress = allowedReadOnlyAddress; s_payoutMode = payoutMode; i_wrappedNativeToken = IWrappedNative(wrappedNativeTokenAddress); if (i_linkUSDFeed.decimals() != i_nativeUSDFeed.decimals()) { revert InvalidFeed(); } } // ================================================================ // | INTERNAL FUNCTIONS ONLY | // ================================================================ /** * @dev creates a new upkeep with the given fields * @param id the id of the upkeep * @param upkeep the upkeep to create * @param admin address to cancel upkeep and withdraw remaining funds * @param checkData data which is passed to user's checkUpkeep * @param triggerConfig the trigger config for this upkeep * @param offchainConfig the off-chain config of this upkeep */ function _createUpkeep( uint256 id, Upkeep memory upkeep, address admin, bytes memory checkData, bytes memory triggerConfig, bytes memory offchainConfig ) internal { if (s_hotVars.paused) revert RegistryPaused(); if (checkData.length > s_storage.maxCheckDataSize) revert CheckDataExceedsLimit(); if (upkeep.performGas < PERFORM_GAS_MIN || upkeep.performGas > s_storage.maxPerformGas) revert GasLimitOutsideRange(); if (address(s_upkeep[id].forwarder) != address(0)) revert UpkeepAlreadyExists(); if (address(s_billingConfigs[upkeep.billingToken].priceFeed) == address(0)) revert InvalidToken(); s_upkeep[id] = upkeep; s_upkeepAdmin[id] = admin; s_checkData[id] = checkData; s_reserveAmounts[upkeep.billingToken] = s_reserveAmounts[upkeep.billingToken] + upkeep.balance; s_upkeepTriggerConfig[id] = triggerConfig; s_upkeepOffchainConfig[id] = offchainConfig; s_upkeepIDs.add(id); } /** * @dev creates an ID for the upkeep based on the upkeep's type * @dev the format of the ID looks like this: * ****00000000000X**************** * 4 bytes of entropy * 11 bytes of zeros * 1 identifying byte for the trigger type * 16 bytes of entropy * @dev this maintains the same level of entropy as eth addresses, so IDs will still be unique * @dev we add the "identifying" part in the middle so that it is mostly hidden from users who usually only * see the first 4 and last 4 hex values ex 0x1234...ABCD */ function _createID(Trigger triggerType) internal view returns (uint256) { bytes1 empty; IChainModule chainModule = s_hotVars.chainModule; bytes memory idBytes = abi.encodePacked( keccak256(abi.encode(chainModule.blockHash((chainModule.blockNumber() - 1)), address(this), s_storage.nonce)) ); for (uint256 idx = 4; idx < 15; idx++) { idBytes[idx] = empty; } idBytes[15] = bytes1(uint8(triggerType)); return uint256(bytes32(idBytes)); } /** * @dev retrieves feed data for fast gas/native and link/native prices. if the feed * data is stale it uses the configured fallback price. Once a price is picked * for gas it takes the min of gas price in the transaction or the fast gas * price in order to reduce costs for the upkeep clients. */ function _getFeedData( HotVars memory hotVars ) internal view returns (uint256 gasWei, uint256 linkUSD, uint256 nativeUSD) { uint32 stalenessSeconds = hotVars.stalenessSeconds; bool staleFallback = stalenessSeconds > 0; uint256 timestamp; int256 feedValue; (, feedValue, , timestamp, ) = i_fastGasFeed.latestRoundData(); if ( feedValue <= 0 || block.timestamp < timestamp || (staleFallback && stalenessSeconds < block.timestamp - timestamp) ) { gasWei = s_fallbackGasPrice; } else { gasWei = uint256(feedValue); } (, feedValue, , timestamp, ) = i_linkUSDFeed.latestRoundData(); if ( feedValue <= 0 || block.timestamp < timestamp || (staleFallback && stalenessSeconds < block.timestamp - timestamp) ) { linkUSD = s_fallbackLinkPrice; } else { linkUSD = uint256(feedValue); } return (gasWei, linkUSD, _getNativeUSD(hotVars)); } /** * @dev this price has it's own getter for use in the transmit() hot path * in the future, all price data should be included in the report instead of * getting read during execution */ function _getNativeUSD(HotVars memory hotVars) internal view returns (uint256) { (, int256 feedValue, , uint256 timestamp, ) = i_nativeUSDFeed.latestRoundData(); if ( feedValue <= 0 || block.timestamp < timestamp || (hotVars.stalenessSeconds > 0 && hotVars.stalenessSeconds < block.timestamp - timestamp) ) { return s_fallbackNativePrice; } else { return uint256(feedValue); } } /** * @dev gets the price and billing params for a specific billing token */ function _getBillingTokenPaymentParams( HotVars memory hotVars, IERC20 billingToken ) internal view returns (BillingTokenPaymentParams memory paymentParams) { BillingConfig storage config = s_billingConfigs[billingToken]; paymentParams.flatFeeMilliCents = config.flatFeeMilliCents; paymentParams.gasFeePPB = config.gasFeePPB; paymentParams.decimals = config.decimals; (, int256 feedValue, , uint256 timestamp, ) = config.priceFeed.latestRoundData(); if ( feedValue <= 0 || block.timestamp < timestamp || (hotVars.stalenessSeconds > 0 && hotVars.stalenessSeconds < block.timestamp - timestamp) ) { paymentParams.priceUSD = config.fallbackPrice; } else { paymentParams.priceUSD = uint256(feedValue); } return paymentParams; } /** * @param hotVars the hot path variables * @param paymentParams the pricing data and gas usage data * @return receipt the receipt of payment with pricing breakdown * @dev use of PaymentParams struct is necessary to avoid stack too deep errors * @dev calculates LINK paid for gas spent plus a configure premium percentage * @dev 1 USD = 1e18 attoUSD * @dev 1 USD = 1e26 hexaicosaUSD (had to borrow this prefix from geometry because there is no metric prefix for 1e-26) * @dev 1 millicent = 1e-5 USD = 1e13 attoUSD */ function _calculatePaymentAmount( HotVars memory hotVars, PaymentParams memory paymentParams ) internal view returns (PaymentReceipt memory receipt) { uint256 decimals = paymentParams.billingTokenParams.decimals; uint256 gasWei = paymentParams.fastGasWei * hotVars.gasCeilingMultiplier; // in case it's actual execution use actual gas price, capped by fastGasWei * gasCeilingMultiplier if (paymentParams.isTransaction && tx.gasprice < gasWei) { gasWei = tx.gasprice; } // scaling factor is based on decimals of billing token, and applies to premium and gasCharge uint256 numeratorScalingFactor = decimals > 18 ? 10 ** (decimals - 18) : 1; uint256 denominatorScalingFactor = decimals < 18 ? 10 ** (18 - decimals) : 1; // gas calculation uint256 gasPaymentHexaicosaUSD = (gasWei * (paymentParams.gasLimit + paymentParams.gasOverhead) + paymentParams.l1CostWei) * paymentParams.nativeUSD; // gasPaymentHexaicosaUSD has an extra 8 zeros because of decimals on nativeUSD feed // gasChargeInBillingToken is scaled by the billing token's decimals. Round up to ensure a minimum billing token is charged for gas receipt.gasChargeInBillingToken = SafeCast.toUint96( ((gasPaymentHexaicosaUSD * numeratorScalingFactor) + (paymentParams.billingTokenParams.priceUSD * denominatorScalingFactor - 1)) / (paymentParams.billingTokenParams.priceUSD * denominatorScalingFactor) ); // 18 decimals: 26 decimals / 8 decimals receipt.gasReimbursementInJuels = SafeCast.toUint96(gasPaymentHexaicosaUSD / paymentParams.linkUSD); // premium calculation uint256 flatFeeHexaicosaUSD = uint256(paymentParams.billingTokenParams.flatFeeMilliCents) * 1e21; // 1e13 for milliCents to attoUSD and 1e8 for attoUSD to hexaicosaUSD uint256 premiumHexaicosaUSD = ((((gasWei * paymentParams.gasLimit) + paymentParams.l1CostWei) * paymentParams.billingTokenParams.gasFeePPB * paymentParams.nativeUSD) / 1e9) + flatFeeHexaicosaUSD; // premium is scaled by the billing token's decimals. Round up to ensure at least minimum charge receipt.premiumInBillingToken = SafeCast.toUint96( ((premiumHexaicosaUSD * numeratorScalingFactor) + (paymentParams.billingTokenParams.priceUSD * denominatorScalingFactor - 1)) / (paymentParams.billingTokenParams.priceUSD * denominatorScalingFactor) ); receipt.premiumInJuels = SafeCast.toUint96(premiumHexaicosaUSD / paymentParams.linkUSD); receipt.billingToken = paymentParams.billingToken; receipt.linkUSD = SafeCast.toUint96(paymentParams.linkUSD); receipt.nativeUSD = SafeCast.toUint96(paymentParams.nativeUSD); receipt.billingUSD = SafeCast.toUint96(paymentParams.billingTokenParams.priceUSD); return receipt; } /** * @dev calculates the max payment for an upkeep. Called during checkUpkeep simulation and assumes * maximum gas overhead, L1 fee */ function _getMaxPayment( uint256 upkeepId, HotVars memory hotVars, Trigger triggerType, uint32 performGas, uint256 fastGasWei, uint256 linkUSD, uint256 nativeUSD, IERC20 billingToken ) internal view returns (uint96) { uint256 maxL1Fee; uint256 maxGasOverhead; { if (triggerType == Trigger.CONDITION) { maxGasOverhead = REGISTRY_CONDITIONAL_OVERHEAD; } else if (triggerType == Trigger.LOG) { maxGasOverhead = REGISTRY_LOG_OVERHEAD; } else { revert InvalidTriggerType(); } uint256 maxCalldataSize = s_storage.maxPerformDataSize + TRANSMIT_CALLDATA_FIXED_BYTES_OVERHEAD + (TRANSMIT_CALLDATA_PER_SIGNER_BYTES_OVERHEAD * (hotVars.f + 1)); (uint256 chainModuleFixedOverhead, uint256 chainModulePerByteOverhead) = s_hotVars.chainModule.getGasOverhead(); maxGasOverhead += (REGISTRY_PER_SIGNER_GAS_OVERHEAD * (hotVars.f + 1)) + ((REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD + chainModulePerByteOverhead) * maxCalldataSize) + chainModuleFixedOverhead; maxL1Fee = hotVars.gasCeilingMultiplier * hotVars.chainModule.getMaxL1Fee(maxCalldataSize); } BillingTokenPaymentParams memory paymentParams = _getBillingTokenPaymentParams(hotVars, billingToken); if (s_upkeep[upkeepId].overridesEnabled) { BillingOverrides memory billingOverrides = s_billingOverrides[upkeepId]; // use the overridden configs paymentParams.gasFeePPB = billingOverrides.gasFeePPB; paymentParams.flatFeeMilliCents = billingOverrides.flatFeeMilliCents; } PaymentReceipt memory receipt = _calculatePaymentAmount( hotVars, PaymentParams({ gasLimit: performGas, gasOverhead: maxGasOverhead, l1CostWei: maxL1Fee, fastGasWei: fastGasWei, linkUSD: linkUSD, nativeUSD: nativeUSD, billingToken: billingToken, billingTokenParams: paymentParams, isTransaction: false }) ); return receipt.gasChargeInBillingToken + receipt.premiumInBillingToken; } /** * @dev move a transmitter's balance from total pool to withdrawable balance */ function _updateTransmitterBalanceFromPool( address transmitterAddress, uint96 totalPremium, uint96 payeeCount ) internal returns (uint96) { Transmitter memory transmitter = s_transmitters[transmitterAddress]; if (transmitter.active) { uint96 uncollected = totalPremium - transmitter.lastCollected; uint96 due = uncollected / payeeCount; transmitter.balance += due; transmitter.lastCollected += due * payeeCount; s_transmitters[transmitterAddress] = transmitter; } return transmitter.balance; } /** * @dev gets the trigger type from an upkeepID (trigger type is encoded in the middle of the ID) */ function _getTriggerType(uint256 upkeepId) internal pure returns (Trigger) { bytes32 rawID = bytes32(upkeepId); bytes1 empty = bytes1(0); for (uint256 idx = 4; idx < 15; idx++) { if (rawID[idx] != empty) { // old IDs that were created before this standard and migrated to this registry return Trigger.CONDITION; } } return Trigger(uint8(rawID[15])); } function _checkPayload( uint256 upkeepId, Trigger triggerType, bytes memory triggerData ) internal view returns (bytes memory) { if (triggerType == Trigger.CONDITION) { return abi.encodeWithSelector(CHECK_SELECTOR, s_checkData[upkeepId]); } else if (triggerType == Trigger.LOG) { Log memory log = abi.decode(triggerData, (Log)); return abi.encodeWithSelector(CHECK_LOG_SELECTOR, log, s_checkData[upkeepId]); } revert InvalidTriggerType(); } /** * @dev _decodeReport decodes a serialized report into a Report struct */ function _decodeReport(bytes calldata rawReport) internal pure returns (Report memory) { Report memory report = abi.decode(rawReport, (Report)); uint256 expectedLength = report.upkeepIds.length; if ( report.gasLimits.length != expectedLength || report.triggers.length != expectedLength || report.performDatas.length != expectedLength ) { revert InvalidReport(); } return report; } /** * @dev Does some early sanity checks before actually performing an upkeep * @return bool whether the upkeep should be performed * @return bytes32 dedupID for preventing duplicate performances of this trigger */ function _prePerformChecks( uint256 upkeepId, uint256 blocknumber, bytes memory rawTrigger, UpkeepTransmitInfo memory transmitInfo, HotVars memory hotVars ) internal returns (bool, bytes32) { bytes32 dedupID; if (transmitInfo.triggerType == Trigger.CONDITION) { if (!_validateConditionalTrigger(upkeepId, blocknumber, rawTrigger, transmitInfo, hotVars)) return (false, dedupID); } else if (transmitInfo.triggerType == Trigger.LOG) { bool valid; (valid, dedupID) = _validateLogTrigger(upkeepId, blocknumber, rawTrigger, hotVars); if (!valid) return (false, dedupID); } else { revert InvalidTriggerType(); } if (transmitInfo.upkeep.maxValidBlocknumber <= blocknumber) { // Can happen when an upkeep got cancelled after report was generated. // However we have a CANCELLATION_DELAY of 50 blocks so shouldn't happen in practice emit CancelledUpkeepReport(upkeepId, rawTrigger); return (false, dedupID); } return (true, dedupID); } /** * @dev Does some early sanity checks before actually performing an upkeep */ function _validateConditionalTrigger( uint256 upkeepId, uint256 blocknumber, bytes memory rawTrigger, UpkeepTransmitInfo memory transmitInfo, HotVars memory hotVars ) internal returns (bool) { ConditionalTrigger memory trigger = abi.decode(rawTrigger, (ConditionalTrigger)); if (trigger.blockNum < transmitInfo.upkeep.lastPerformedBlockNumber) { // Can happen when another report performed this upkeep after this report was generated emit StaleUpkeepReport(upkeepId, rawTrigger); return false; } if ( (hotVars.reorgProtectionEnabled && (trigger.blockHash != bytes32("") && hotVars.chainModule.blockHash(trigger.blockNum) != trigger.blockHash)) || trigger.blockNum >= blocknumber ) { // There are two cases of reorged report // 1. trigger block number is in future: this is an edge case during extreme deep reorgs of chain // which is always protected against // 2. blockHash at trigger block number was same as trigger time. This is an optional check which is // applied if DON sends non empty trigger.blockHash. Note: It only works for last 256 blocks on chain // when it is sent emit ReorgedUpkeepReport(upkeepId, rawTrigger); return false; } return true; } function _validateLogTrigger( uint256 upkeepId, uint256 blocknumber, bytes memory rawTrigger, HotVars memory hotVars ) internal returns (bool, bytes32) { LogTrigger memory trigger = abi.decode(rawTrigger, (LogTrigger)); bytes32 dedupID = keccak256(abi.encodePacked(upkeepId, trigger.logBlockHash, trigger.txHash, trigger.logIndex)); if ( (hotVars.reorgProtectionEnabled && (trigger.blockHash != bytes32("") && hotVars.chainModule.blockHash(trigger.blockNum) != trigger.blockHash)) || trigger.blockNum >= blocknumber ) { // Reorg protection is same as conditional trigger upkeeps emit ReorgedUpkeepReport(upkeepId, rawTrigger); return (false, dedupID); } if (s_dedupKeys[dedupID]) { emit StaleUpkeepReport(upkeepId, rawTrigger); return (false, dedupID); } return (true, dedupID); } /** * @dev Verify signatures attached to report */ function _verifyReportSignature( bytes32[3] calldata reportContext, bytes calldata report, bytes32[] calldata rs, bytes32[] calldata ss, bytes32 rawVs ) internal view { 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; address signerAddress; for (uint256 i = 0; i < rs.length; i++) { signerAddress = ecrecover(h, uint8(rawVs[i]) + 27, rs[i], ss[i]); signer = s_signers[signerAddress]; if (!signer.active) revert OnlyActiveSigners(); unchecked { signedCount += 1 << (8 * signer.index); } } if (signedCount & ORACLE_MASK != signedCount) revert DuplicateSigners(); } /** * @dev updates a storage marker for this upkeep to prevent duplicate and out of order performances * @dev for conditional triggers we set the latest block number, for log triggers we store a dedupID */ function _updateTriggerMarker( uint256 upkeepID, uint256 blocknumber, UpkeepTransmitInfo memory upkeepTransmitInfo ) internal { if (upkeepTransmitInfo.triggerType == Trigger.CONDITION) { s_upkeep[upkeepID].lastPerformedBlockNumber = uint32(blocknumber); } else if (upkeepTransmitInfo.triggerType == Trigger.LOG) { s_dedupKeys[upkeepTransmitInfo.dedupID] = true; emit DedupKeyAdded(upkeepTransmitInfo.dedupID); } } /** * @dev calls the Upkeep target with the performData param passed in by the * transmitter and the exact gas required by the Upkeep */ function _performUpkeep( IAutomationForwarder forwarder, uint256 performGas, bytes memory performData ) internal nonReentrant returns (bool success, uint256 gasUsed) { performData = abi.encodeWithSelector(PERFORM_SELECTOR, performData); return forwarder.forward(performGas, performData); } /** * @dev handles the payment processing after an upkeep has been performed. * Deducts an upkeep's balance and increases the amount spent. */ function _handlePayment( HotVars memory hotVars, PaymentParams memory paymentParams, uint256 upkeepId, Upkeep memory upkeep ) internal returns (PaymentReceipt memory) { if (upkeep.overridesEnabled) { BillingOverrides memory billingOverrides = s_billingOverrides[upkeepId]; // use the overridden configs paymentParams.billingTokenParams.gasFeePPB = billingOverrides.gasFeePPB; paymentParams.billingTokenParams.flatFeeMilliCents = billingOverrides.flatFeeMilliCents; } PaymentReceipt memory receipt = _calculatePaymentAmount(hotVars, paymentParams); // balance is in the token's native decimals uint96 balance = upkeep.balance; // payment is in the token's native decimals uint96 payment = receipt.gasChargeInBillingToken + receipt.premiumInBillingToken; // scaling factors to adjust decimals between billing token and LINK uint256 decimals = paymentParams.billingTokenParams.decimals; uint256 scalingFactor1 = decimals < 18 ? 10 ** (18 - decimals) : 1; uint256 scalingFactor2 = decimals > 18 ? 10 ** (decimals - 18) : 1; // this shouldn't happen, but in rare edge cases, we charge the full balance in case the user // can't cover the amount owed if (balance < receipt.gasChargeInBillingToken) { // if the user can't cover the gas fee, then direct all of the payment to the transmitter and distribute no premium to the DON payment = balance; receipt.gasReimbursementInJuels = SafeCast.toUint96( (balance * paymentParams.billingTokenParams.priceUSD * scalingFactor1) / (paymentParams.linkUSD * scalingFactor2) ); receipt.premiumInJuels = 0; receipt.premiumInBillingToken = 0; receipt.gasChargeInBillingToken = balance; } else if (balance < payment) { // if the user can cover the gas fee, but not the premium, then reduce the premium payment = balance; receipt.premiumInJuels = SafeCast.toUint96( ((balance * paymentParams.billingTokenParams.priceUSD * scalingFactor1) / (paymentParams.linkUSD * scalingFactor2)) - receipt.gasReimbursementInJuels ); // round up receipt.premiumInBillingToken = SafeCast.toUint96( ((receipt.premiumInJuels * paymentParams.linkUSD * scalingFactor2) + (paymentParams.billingTokenParams.priceUSD * scalingFactor1 - 1)) / (paymentParams.billingTokenParams.priceUSD * scalingFactor1) ); } s_upkeep[upkeepId].balance -= payment; s_upkeep[upkeepId].amountSpent += payment; s_reserveAmounts[paymentParams.billingToken] -= payment; emit UpkeepCharged(upkeepId, receipt); return receipt; } /** * @dev ensures the upkeep is not cancelled and the caller is the upkeep admin */ function _requireAdminAndNotCancelled(uint256 upkeepId) internal view { if (msg.sender != s_upkeepAdmin[upkeepId]) revert OnlyCallableByAdmin(); if (s_upkeep[upkeepId].maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled(); } /** * @dev replicates Open Zeppelin's ReentrancyGuard but optimized to fit our storage */ modifier nonReentrant() { if (s_hotVars.reentrancyGuard) revert ReentrantCall(); s_hotVars.reentrancyGuard = true; _; s_hotVars.reentrancyGuard = false; } /** * @notice only allows a pre-configured address to initiate offchain read */ function _preventExecution() internal view { // solhint-disable-next-line avoid-tx-origin if (tx.origin != i_allowedReadOnlyAddress) { revert OnlySimulatedBackend(); } } /** * @notice only allows finance admin to call the function */ function _onlyFinanceAdminAllowed() internal view { if (msg.sender != s_storage.financeAdmin) { revert OnlyFinanceAdmin(); } } /** * @notice only allows privilege manager to call the function */ function _onlyPrivilegeManagerAllowed() internal view { if (msg.sender != s_storage.upkeepPrivilegeManager) { revert OnlyCallableByUpkeepPrivilegeManager(); } } /** * @notice sets billing configuration for a token * @param billingTokens the addresses of tokens * @param billingConfigs the configs for tokens */ function _setBillingConfig(IERC20[] memory billingTokens, BillingConfig[] memory billingConfigs) internal { // Clear existing data for (uint256 i = 0; i < s_billingTokens.length; i++) { delete s_billingConfigs[s_billingTokens[i]]; } delete s_billingTokens; PayoutMode mode = s_payoutMode; for (uint256 i = 0; i < billingTokens.length; i++) { IERC20 token = billingTokens[i]; BillingConfig memory config = billingConfigs[i]; // most ERC20 tokens are 18 decimals, priceFeed must be 8 decimals if (config.decimals != token.decimals() || config.priceFeed.decimals() != 8) { revert InvalidToken(); } // if LINK is a billing option, payout mode must be ON_CHAIN if (address(token) == address(i_link) && mode == PayoutMode.OFF_CHAIN) { revert InvalidToken(); } if (address(token) == ZERO_ADDRESS || address(config.priceFeed) == ZERO_ADDRESS) { revert ZeroAddressNotAllowed(); } // if this is a new token, add it to tokens list. Otherwise revert if (address(s_billingConfigs[token].priceFeed) != ZERO_ADDRESS) { revert DuplicateEntry(); } s_billingTokens.push(token); // update the billing config for an existing token or add a new one s_billingConfigs[token] = config; emit BillingConfigSet(token, config); } } /** * @notice updates the signers and transmitters lists */ function _updateTransmitters(address[] memory signers, address[] memory transmitters) internal { uint96 transmittersListLength = uint96(s_transmittersList.length); uint96 totalPremium = s_hotVars.totalPremium; // move all pooled payments out of the pool to each transmitter's balance for (uint256 i = 0; i < s_transmittersList.length; i++) { _updateTransmitterBalanceFromPool(s_transmittersList[i], totalPremium, transmittersListLength); } // remove any old signer/transmitter addresses address transmitterAddress; PayoutMode mode = s_payoutMode; for (uint256 i = 0; i < s_transmittersList.length; i++) { transmitterAddress = s_transmittersList[i]; delete s_signers[s_signersList[i]]; // Do not delete the whole transmitter struct as it has balance information stored s_transmitters[transmitterAddress].active = false; if (mode == PayoutMode.OFF_CHAIN && s_transmitters[transmitterAddress].balance > 0) { s_deactivatedTransmitters.add(transmitterAddress); } } delete s_signersList; delete s_transmittersList; // add new signer/transmitter addresses Transmitter memory transmitter; for (uint256 i = 0; i < signers.length; i++) { if (s_signers[signers[i]].active) revert RepeatedSigner(); if (signers[i] == ZERO_ADDRESS) revert InvalidSigner(); s_signers[signers[i]] = Signer({active: true, index: uint8(i)}); transmitterAddress = transmitters[i]; if (transmitterAddress == ZERO_ADDRESS) revert InvalidTransmitter(); transmitter = s_transmitters[transmitterAddress]; if (transmitter.active) revert RepeatedTransmitter(); transmitter.active = true; transmitter.index = uint8(i); // new transmitters start afresh from current totalPremium // some spare change of premium from previous pool will be forfeited transmitter.lastCollected = s_hotVars.totalPremium; s_transmitters[transmitterAddress] = transmitter; if (mode == PayoutMode.OFF_CHAIN) { s_deactivatedTransmitters.remove(transmitterAddress); } } s_signersList = signers; s_transmittersList = transmitters; } /** * @notice returns the size of the LINK liquidity pool # @dev LINK max supply < 2^96, so casting to int256 is safe */ function _linkAvailableForPayment() internal view returns (int256) { return int256(i_link.balanceOf(address(this))) - int256(s_reserveAmounts[IERC20(address(i_link))]); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; import {Address} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; import {AutomationRegistryBase2_3} from "./AutomationRegistryBase2_3.sol"; import {AutomationRegistryLogicC2_3} from "./AutomationRegistryLogicC2_3.sol"; import {AutomationRegistryLogicB2_3} from "./AutomationRegistryLogicB2_3.sol"; import {Chainable} from "../Chainable.sol"; import {AutomationForwarder} from "../AutomationForwarder.sol"; import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol"; import {UpkeepTranscoderInterfaceV2} from "../interfaces/UpkeepTranscoderInterfaceV2.sol"; import {MigratableKeeperRegistryInterfaceV2} from "../interfaces/MigratableKeeperRegistryInterfaceV2.sol"; import {IERC20Metadata as IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; import {IERC677Receiver} from "../../shared/interfaces/IERC677Receiver.sol"; /** * @notice Logic contract, works in tandem with AutomationRegistry as a proxy */ contract AutomationRegistryLogicA2_3 is AutomationRegistryBase2_3, Chainable, IERC677Receiver { using Address for address; using EnumerableSet for EnumerableSet.UintSet; using EnumerableSet for EnumerableSet.AddressSet; using SafeERC20 for IERC20; /** * @param logicB the address of the second logic contract * @dev we cast the contract to logicC in order to call logicC functions (via fallback) */ constructor( AutomationRegistryLogicB2_3 logicB ) AutomationRegistryBase2_3( AutomationRegistryLogicC2_3(address(logicB)).getLinkAddress(), AutomationRegistryLogicC2_3(address(logicB)).getLinkUSDFeedAddress(), AutomationRegistryLogicC2_3(address(logicB)).getNativeUSDFeedAddress(), AutomationRegistryLogicC2_3(address(logicB)).getFastGasFeedAddress(), AutomationRegistryLogicC2_3(address(logicB)).getAutomationForwarderLogic(), AutomationRegistryLogicC2_3(address(logicB)).getAllowedReadOnlyAddress(), AutomationRegistryLogicC2_3(address(logicB)).getPayoutMode(), AutomationRegistryLogicC2_3(address(logicB)).getWrappedNativeTokenAddress() ) Chainable(address(logicB)) {} /** * @notice uses LINK's transferAndCall to LINK and add funding to an upkeep * @dev safe to cast uint256 to uint96 as total LINK supply is under UINT96MAX * @param sender the account which transferred the funds * @param amount number of LINK transfer */ function onTokenTransfer(address sender, uint256 amount, bytes calldata data) external override { if (msg.sender != address(i_link)) revert OnlyCallableByLINKToken(); if (data.length != 32) revert InvalidDataLength(); uint256 id = abi.decode(data, (uint256)); if (s_upkeep[id].maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled(); if (address(s_upkeep[id].billingToken) != address(i_link)) revert InvalidToken(); s_upkeep[id].balance = s_upkeep[id].balance + uint96(amount); s_reserveAmounts[IERC20(address(i_link))] = s_reserveAmounts[IERC20(address(i_link))] + amount; emit FundsAdded(id, sender, uint96(amount)); } // ================================================================ // | UPKEEP MANAGEMENT | // ================================================================ /** * @notice adds a new upkeep * @param target address to perform upkeep on * @param gasLimit amount of gas to provide the target contract when * performing upkeep * @param admin address to cancel upkeep and withdraw remaining funds * @param triggerType the trigger for the upkeep * @param billingToken the billing token for the upkeep * @param checkData data passed to the contract when checking for upkeep * @param triggerConfig the config for the trigger * @param offchainConfig arbitrary offchain config for the upkeep */ function registerUpkeep( address target, uint32 gasLimit, address admin, Trigger triggerType, IERC20 billingToken, bytes calldata checkData, bytes memory triggerConfig, bytes memory offchainConfig ) public returns (uint256 id) { if (msg.sender != owner() && !s_registrars.contains(msg.sender)) revert OnlyCallableByOwnerOrRegistrar(); if (!target.isContract()) revert NotAContract(); id = _createID(triggerType); IAutomationForwarder forwarder = IAutomationForwarder( address(new AutomationForwarder(target, address(this), i_automationForwarderLogic)) ); _createUpkeep( id, Upkeep({ overridesEnabled: false, performGas: gasLimit, balance: 0, maxValidBlocknumber: UINT32_MAX, lastPerformedBlockNumber: 0, amountSpent: 0, paused: false, forwarder: forwarder, billingToken: billingToken }), admin, checkData, triggerConfig, offchainConfig ); s_storage.nonce++; emit UpkeepRegistered(id, gasLimit, admin); emit UpkeepCheckDataSet(id, checkData); emit UpkeepTriggerConfigSet(id, triggerConfig); emit UpkeepOffchainConfigSet(id, offchainConfig); return (id); } /** * @notice cancels an upkeep * @param id the upkeepID to cancel * @dev if a user cancels an upkeep, their funds are locked for CANCELLATION_DELAY blocks to * allow any pending performUpkeep txs time to get confirmed */ function cancelUpkeep(uint256 id) external { Upkeep memory upkeep = s_upkeep[id]; bool isOwner = msg.sender == owner(); uint96 minSpend = s_billingConfigs[upkeep.billingToken].minSpend; uint256 height = s_hotVars.chainModule.blockNumber(); if (upkeep.maxValidBlocknumber == 0) revert CannotCancel(); if (upkeep.maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled(); if (!isOwner && msg.sender != s_upkeepAdmin[id]) revert OnlyCallableByOwnerOrAdmin(); if (!isOwner) { height = height + CANCELLATION_DELAY; } s_upkeep[id].maxValidBlocknumber = uint32(height); s_upkeepIDs.remove(id); // charge the cancellation fee if the minSpend is not met uint96 cancellationFee = 0; // cancellationFee is min(max(minSpend - amountSpent, 0), amountLeft) if (upkeep.amountSpent < minSpend) { cancellationFee = minSpend - uint96(upkeep.amountSpent); if (cancellationFee > upkeep.balance) { cancellationFee = upkeep.balance; } } s_upkeep[id].balance = upkeep.balance - cancellationFee; s_reserveAmounts[upkeep.billingToken] = s_reserveAmounts[upkeep.billingToken] - cancellationFee; emit UpkeepCanceled(id, uint64(height)); } /** * @notice migrates upkeeps from one registry to another. * @param ids the upkeepIDs to migrate * @param destination the destination registry address * @dev a transcoder must be set in order to enable migration * @dev migration permissions must be set on *both* sending and receiving registries * @dev only an upkeep admin can migrate their upkeeps * @dev this function is most gas-efficient if upkeepIDs are sorted by billing token * @dev s_billingOverrides and s_upkeepPrivilegeConfig are not migrated in this function */ function migrateUpkeeps(uint256[] calldata ids, address destination) external { if ( s_peerRegistryMigrationPermission[destination] != MigrationPermission.OUTGOING && s_peerRegistryMigrationPermission[destination] != MigrationPermission.BIDIRECTIONAL ) revert MigrationNotPermitted(); if (s_storage.transcoder == ZERO_ADDRESS) revert TranscoderNotSet(); if (ids.length == 0) revert ArrayHasNoEntries(); IERC20 billingToken; uint256 balanceToTransfer; uint256 id; Upkeep memory upkeep; address[] memory admins = new address[](ids.length); Upkeep[] memory upkeeps = new Upkeep[](ids.length); bytes[] memory checkDatas = new bytes[](ids.length); bytes[] memory triggerConfigs = new bytes[](ids.length); bytes[] memory offchainConfigs = new bytes[](ids.length); for (uint256 idx = 0; idx < ids.length; idx++) { id = ids[idx]; upkeep = s_upkeep[id]; if (idx == 0) { billingToken = upkeep.billingToken; balanceToTransfer = upkeep.balance; } // if we encounter a new billing token, send the sum from the last billing token to the destination registry if (upkeep.billingToken != billingToken) { s_reserveAmounts[billingToken] = s_reserveAmounts[billingToken] - balanceToTransfer; billingToken.safeTransfer(destination, balanceToTransfer); billingToken = upkeep.billingToken; balanceToTransfer = upkeep.balance; } else if (idx != 0) { balanceToTransfer += upkeep.balance; } _requireAdminAndNotCancelled(id); upkeep.forwarder.updateRegistry(destination); upkeeps[idx] = upkeep; admins[idx] = s_upkeepAdmin[id]; checkDatas[idx] = s_checkData[id]; triggerConfigs[idx] = s_upkeepTriggerConfig[id]; offchainConfigs[idx] = s_upkeepOffchainConfig[id]; delete s_upkeep[id]; delete s_checkData[id]; delete s_upkeepTriggerConfig[id]; delete s_upkeepOffchainConfig[id]; // nullify existing proposed admin change if an upkeep is being migrated delete s_proposedAdmin[id]; delete s_upkeepAdmin[id]; s_upkeepIDs.remove(id); emit UpkeepMigrated(id, upkeep.balance, destination); } // always transfer the rolling sum in the end s_reserveAmounts[billingToken] = s_reserveAmounts[billingToken] - balanceToTransfer; billingToken.safeTransfer(destination, balanceToTransfer); bytes memory encodedUpkeeps = abi.encode( ids, upkeeps, new address[](ids.length), admins, checkDatas, triggerConfigs, offchainConfigs ); MigratableKeeperRegistryInterfaceV2(destination).receiveUpkeeps( UpkeepTranscoderInterfaceV2(s_storage.transcoder).transcodeUpkeeps( UPKEEP_VERSION_BASE, MigratableKeeperRegistryInterfaceV2(destination).upkeepVersion(), encodedUpkeeps ) ); } /** * @notice received upkeeps migrated from another registry * @param encodedUpkeeps the raw upkeep data to import * @dev this function is never called directly, it is only called by another registry's migrate function * @dev s_billingOverrides and s_upkeepPrivilegeConfig are not handled in this function */ function receiveUpkeeps(bytes calldata encodedUpkeeps) external { if ( s_peerRegistryMigrationPermission[msg.sender] != MigrationPermission.INCOMING && s_peerRegistryMigrationPermission[msg.sender] != MigrationPermission.BIDIRECTIONAL ) revert MigrationNotPermitted(); ( uint256[] memory ids, Upkeep[] memory upkeeps, address[] memory targets, address[] memory upkeepAdmins, bytes[] memory checkDatas, bytes[] memory triggerConfigs, bytes[] memory offchainConfigs ) = abi.decode(encodedUpkeeps, (uint256[], Upkeep[], address[], address[], bytes[], bytes[], bytes[])); for (uint256 idx = 0; idx < ids.length; idx++) { if (address(upkeeps[idx].forwarder) == ZERO_ADDRESS) { upkeeps[idx].forwarder = IAutomationForwarder( address(new AutomationForwarder(targets[idx], address(this), i_automationForwarderLogic)) ); } _createUpkeep( ids[idx], upkeeps[idx], upkeepAdmins[idx], checkDatas[idx], triggerConfigs[idx], offchainConfigs[idx] ); emit UpkeepReceived(ids[idx], upkeeps[idx].balance, msg.sender); } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import {AutomationRegistryBase2_3} from "./AutomationRegistryBase2_3.sol"; import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; import {Address} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; import {AutomationRegistryLogicC2_3} from "./AutomationRegistryLogicC2_3.sol"; import {Chainable} from "../Chainable.sol"; import {IERC20Metadata as IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; import {SafeCast} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol"; contract AutomationRegistryLogicB2_3 is AutomationRegistryBase2_3, Chainable { using Address for address; using EnumerableSet for EnumerableSet.UintSet; using EnumerableSet for EnumerableSet.AddressSet; using SafeERC20 for IERC20; /** * @param logicC the address of the third logic contract */ constructor( AutomationRegistryLogicC2_3 logicC ) AutomationRegistryBase2_3( logicC.getLinkAddress(), logicC.getLinkUSDFeedAddress(), logicC.getNativeUSDFeedAddress(), logicC.getFastGasFeedAddress(), logicC.getAutomationForwarderLogic(), logicC.getAllowedReadOnlyAddress(), logicC.getPayoutMode(), logicC.getWrappedNativeTokenAddress() ) Chainable(address(logicC)) {} // ================================================================ // | PIPELINE FUNCTIONS | // ================================================================ /** * @notice called by the automation DON to check if work is needed * @param id the upkeep ID to check for work needed * @param triggerData extra contextual data about the trigger (not used in all code paths) * @dev this one of the core functions called in the hot path * @dev there is a 2nd checkUpkeep function (below) that is being maintained for backwards compatibility * @dev there is an incongruency on what gets returned during failure modes * ex sometimes we include price data, sometimes we omit it depending on the failure */ function checkUpkeep( uint256 id, bytes memory triggerData ) public returns ( bool upkeepNeeded, bytes memory performData, UpkeepFailureReason upkeepFailureReason, uint256 gasUsed, uint256 gasLimit, uint256 fastGasWei, uint256 linkUSD ) { _preventExecution(); Trigger triggerType = _getTriggerType(id); HotVars memory hotVars = s_hotVars; Upkeep memory upkeep = s_upkeep[id]; { uint256 nativeUSD; uint96 maxPayment; if (hotVars.paused) return (false, bytes(""), UpkeepFailureReason.REGISTRY_PAUSED, 0, upkeep.performGas, 0, 0); if (upkeep.maxValidBlocknumber != UINT32_MAX) return (false, bytes(""), UpkeepFailureReason.UPKEEP_CANCELLED, 0, upkeep.performGas, 0, 0); if (upkeep.paused) return (false, bytes(""), UpkeepFailureReason.UPKEEP_PAUSED, 0, upkeep.performGas, 0, 0); (fastGasWei, linkUSD, nativeUSD) = _getFeedData(hotVars); maxPayment = _getMaxPayment( id, hotVars, triggerType, upkeep.performGas, fastGasWei, linkUSD, nativeUSD, upkeep.billingToken ); if (upkeep.balance < maxPayment) { return (false, bytes(""), UpkeepFailureReason.INSUFFICIENT_BALANCE, 0, upkeep.performGas, 0, 0); } } bytes memory callData = _checkPayload(id, triggerType, triggerData); gasUsed = gasleft(); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory result) = upkeep.forwarder.getTarget().call{gas: s_storage.checkGasLimit}(callData); gasUsed = gasUsed - gasleft(); if (!success) { // User's target check reverted. We capture the revert data here and pass it within performData if (result.length > s_storage.maxRevertDataSize) { return ( false, bytes(""), UpkeepFailureReason.REVERT_DATA_EXCEEDS_LIMIT, gasUsed, upkeep.performGas, fastGasWei, linkUSD ); } return ( upkeepNeeded, result, UpkeepFailureReason.TARGET_CHECK_REVERTED, gasUsed, upkeep.performGas, fastGasWei, linkUSD ); } (upkeepNeeded, performData) = abi.decode(result, (bool, bytes)); if (!upkeepNeeded) return (false, bytes(""), UpkeepFailureReason.UPKEEP_NOT_NEEDED, gasUsed, upkeep.performGas, fastGasWei, linkUSD); if (performData.length > s_storage.maxPerformDataSize) return ( false, bytes(""), UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, gasUsed, upkeep.performGas, fastGasWei, linkUSD ); return (upkeepNeeded, performData, upkeepFailureReason, gasUsed, upkeep.performGas, fastGasWei, linkUSD); } /** * @notice see other checkUpkeep function for description * @dev this function may be deprecated in a future version of chainlink automation */ function checkUpkeep( uint256 id ) external returns ( bool upkeepNeeded, bytes memory performData, UpkeepFailureReason upkeepFailureReason, uint256 gasUsed, uint256 gasLimit, uint256 fastGasWei, uint256 linkUSD ) { return checkUpkeep(id, bytes("")); } /** * @dev checkCallback is used specifically for automation data streams lookups (see StreamsLookupCompatibleInterface.sol) * @param id the upkeepID to execute a callback for * @param values the values returned from the data streams lookup * @param extraData the user-provided extra context data */ function checkCallback( uint256 id, bytes[] memory values, bytes calldata extraData ) external returns (bool upkeepNeeded, bytes memory performData, UpkeepFailureReason upkeepFailureReason, uint256 gasUsed) { bytes memory payload = abi.encodeWithSelector(CHECK_CALLBACK_SELECTOR, values, extraData); return executeCallback(id, payload); } /** * @notice this is a generic callback executor that forwards a call to a user's contract with the configured * gas limit * @param id the upkeepID to execute a callback for * @param payload the data (including function selector) to call on the upkeep target contract */ function executeCallback( uint256 id, bytes memory payload ) public returns (bool upkeepNeeded, bytes memory performData, UpkeepFailureReason upkeepFailureReason, uint256 gasUsed) { _preventExecution(); Upkeep memory upkeep = s_upkeep[id]; gasUsed = gasleft(); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory result) = upkeep.forwarder.getTarget().call{gas: s_storage.checkGasLimit}(payload); gasUsed = gasUsed - gasleft(); if (!success) { return (false, bytes(""), UpkeepFailureReason.CALLBACK_REVERTED, gasUsed); } (upkeepNeeded, performData) = abi.decode(result, (bool, bytes)); if (!upkeepNeeded) { return (false, bytes(""), UpkeepFailureReason.UPKEEP_NOT_NEEDED, gasUsed); } if (performData.length > s_storage.maxPerformDataSize) { return (false, bytes(""), UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, gasUsed); } return (upkeepNeeded, performData, upkeepFailureReason, gasUsed); } /** * @notice simulates the upkeep with the perform data returned from checkUpkeep * @param id identifier of the upkeep to execute the data with. * @param performData calldata parameter to be passed to the target upkeep. * @return success whether the call reverted or not * @return gasUsed the amount of gas the target contract consumed */ function simulatePerformUpkeep( uint256 id, bytes calldata performData ) external returns (bool success, uint256 gasUsed) { _preventExecution(); if (s_hotVars.paused) revert RegistryPaused(); Upkeep memory upkeep = s_upkeep[id]; (success, gasUsed) = _performUpkeep(upkeep.forwarder, upkeep.performGas, performData); return (success, gasUsed); } // ================================================================ // | UPKEEP MANAGEMENT | // ================================================================ /** * @notice adds fund to an upkeep * @param id the upkeepID * @param amount the amount of funds to add, in the upkeep's billing token */ function addFunds(uint256 id, uint96 amount) external payable { Upkeep memory upkeep = s_upkeep[id]; if (upkeep.maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled(); if (msg.value != 0) { if (upkeep.billingToken != IERC20(i_wrappedNativeToken)) { revert InvalidToken(); } amount = SafeCast.toUint96(msg.value); } s_upkeep[id].balance = upkeep.balance + amount; s_reserveAmounts[upkeep.billingToken] = s_reserveAmounts[upkeep.billingToken] + amount; if (msg.value == 0) { // ERC20 payment upkeep.billingToken.safeTransferFrom(msg.sender, address(this), amount); } else { // native payment i_wrappedNativeToken.deposit{value: amount}(); } emit FundsAdded(id, msg.sender, amount); } /** * @notice overrides the billing config for an upkeep * @param id the upkeepID * @param billingOverrides the override-able billing config */ function setBillingOverrides(uint256 id, BillingOverrides calldata billingOverrides) external { _onlyPrivilegeManagerAllowed(); if (s_upkeep[id].maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled(); s_upkeep[id].overridesEnabled = true; s_billingOverrides[id] = billingOverrides; emit BillingConfigOverridden(id, billingOverrides); } /** * @notice remove the overridden billing config for an upkeep * @param id the upkeepID */ function removeBillingOverrides(uint256 id) external { _onlyPrivilegeManagerAllowed(); s_upkeep[id].overridesEnabled = false; delete s_billingOverrides[id]; emit BillingConfigOverrideRemoved(id); } /** * @notice transfers the address of an admin for an upkeep */ function transferUpkeepAdmin(uint256 id, address proposed) external { _requireAdminAndNotCancelled(id); if (proposed == msg.sender) revert ValueNotChanged(); if (s_proposedAdmin[id] != proposed) { s_proposedAdmin[id] = proposed; emit UpkeepAdminTransferRequested(id, msg.sender, proposed); } } /** * @notice accepts the transfer of an upkeep admin */ function acceptUpkeepAdmin(uint256 id) external { Upkeep memory upkeep = s_upkeep[id]; if (upkeep.maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled(); if (s_proposedAdmin[id] != msg.sender) revert OnlyCallableByProposedAdmin(); address past = s_upkeepAdmin[id]; s_upkeepAdmin[id] = msg.sender; s_proposedAdmin[id] = ZERO_ADDRESS; emit UpkeepAdminTransferred(id, past, msg.sender); } /** * @notice pauses an upkeep - an upkeep will be neither checked nor performed while paused */ function pauseUpkeep(uint256 id) external { _requireAdminAndNotCancelled(id); Upkeep memory upkeep = s_upkeep[id]; if (upkeep.paused) revert OnlyUnpausedUpkeep(); s_upkeep[id].paused = true; s_upkeepIDs.remove(id); emit UpkeepPaused(id); } /** * @notice unpauses an upkeep */ function unpauseUpkeep(uint256 id) external { _requireAdminAndNotCancelled(id); Upkeep memory upkeep = s_upkeep[id]; if (!upkeep.paused) revert OnlyPausedUpkeep(); s_upkeep[id].paused = false; s_upkeepIDs.add(id); emit UpkeepUnpaused(id); } /** * @notice updates the checkData for an upkeep */ function setUpkeepCheckData(uint256 id, bytes calldata newCheckData) external { _requireAdminAndNotCancelled(id); if (newCheckData.length > s_storage.maxCheckDataSize) revert CheckDataExceedsLimit(); s_checkData[id] = newCheckData; emit UpkeepCheckDataSet(id, newCheckData); } /** * @notice updates the gas limit for an upkeep */ function setUpkeepGasLimit(uint256 id, uint32 gasLimit) external { if (gasLimit < PERFORM_GAS_MIN || gasLimit > s_storage.maxPerformGas) revert GasLimitOutsideRange(); _requireAdminAndNotCancelled(id); s_upkeep[id].performGas = gasLimit; emit UpkeepGasLimitSet(id, gasLimit); } /** * @notice updates the offchain config for an upkeep */ function setUpkeepOffchainConfig(uint256 id, bytes calldata config) external { _requireAdminAndNotCancelled(id); s_upkeepOffchainConfig[id] = config; emit UpkeepOffchainConfigSet(id, config); } /** * @notice sets the upkeep trigger config * @param id the upkeepID to change the trigger for * @param triggerConfig the new trigger config */ function setUpkeepTriggerConfig(uint256 id, bytes calldata triggerConfig) external { _requireAdminAndNotCancelled(id); s_upkeepTriggerConfig[id] = triggerConfig; emit UpkeepTriggerConfigSet(id, triggerConfig); } /** * @notice withdraws an upkeep's funds from an upkeep * @dev note that an upkeep must be cancelled first!! */ function withdrawFunds(uint256 id, address to) external nonReentrant { if (to == ZERO_ADDRESS) revert InvalidRecipient(); Upkeep memory upkeep = s_upkeep[id]; if (s_upkeepAdmin[id] != msg.sender) revert OnlyCallableByAdmin(); if (upkeep.maxValidBlocknumber > s_hotVars.chainModule.blockNumber()) revert UpkeepNotCanceled(); uint96 amountToWithdraw = s_upkeep[id].balance; s_reserveAmounts[upkeep.billingToken] = s_reserveAmounts[upkeep.billingToken] - amountToWithdraw; s_upkeep[id].balance = 0; upkeep.billingToken.safeTransfer(to, amountToWithdraw); emit FundsWithdrawn(id, amountToWithdraw, to); } // ================================================================ // | FINANCE ACTIONS | // ================================================================ /** * @notice withdraws excess LINK from the liquidity pool * @param to the address to send the fees to * @param amount the amount to withdraw */ function withdrawLink(address to, uint256 amount) external { _onlyFinanceAdminAllowed(); if (to == ZERO_ADDRESS) revert InvalidRecipient(); int256 available = _linkAvailableForPayment(); if (available < 0) { revert InsufficientBalance(0, amount); } else if (amount > uint256(available)) { revert InsufficientBalance(uint256(available), amount); } bool transferStatus = i_link.transfer(to, amount); if (!transferStatus) { revert TransferFailed(); } emit FeesWithdrawn(address(i_link), to, amount); } /** * @notice withdraws non-LINK fees earned by the contract * @param asset the asset to withdraw * @param to the address to send the fees to * @param amount the amount to withdraw * @dev in ON_CHAIN mode, we prevent withdrawing non-LINK fees unless there is sufficient LINK liquidity * to cover all outstanding debts on the registry */ function withdrawERC20Fees(IERC20 asset, address to, uint256 amount) external { _onlyFinanceAdminAllowed(); if (to == ZERO_ADDRESS) revert InvalidRecipient(); if (address(asset) == address(i_link)) revert InvalidToken(); if (_linkAvailableForPayment() < 0 && s_payoutMode == PayoutMode.ON_CHAIN) revert InsufficientLinkLiquidity(); uint256 available = asset.balanceOf(address(this)) - s_reserveAmounts[asset]; if (amount > available) revert InsufficientBalance(available, amount); asset.safeTransfer(to, amount); emit FeesWithdrawn(address(asset), to, amount); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import {AutomationRegistryBase2_3} from "./AutomationRegistryBase2_3.sol"; import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; import {Address} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol"; import {IChainModule} from "../interfaces/IChainModule.sol"; import {IERC20Metadata as IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {IAutomationV21PlusCommon} from "../interfaces/IAutomationV21PlusCommon.sol"; contract AutomationRegistryLogicC2_3 is AutomationRegistryBase2_3 { using Address for address; using EnumerableSet for EnumerableSet.UintSet; using EnumerableSet for EnumerableSet.AddressSet; /** * @dev see AutomationRegistry master contract for constructor description */ constructor( address link, address linkUSDFeed, address nativeUSDFeed, address fastGasFeed, address automationForwarderLogic, address allowedReadOnlyAddress, PayoutMode payoutMode, address wrappedNativeTokenAddress ) AutomationRegistryBase2_3( link, linkUSDFeed, nativeUSDFeed, fastGasFeed, automationForwarderLogic, allowedReadOnlyAddress, payoutMode, wrappedNativeTokenAddress ) {} // ================================================================ // | NODE ACTIONS | // ================================================================ /** * @notice transfers the address of payee for a transmitter */ function transferPayeeship(address transmitter, address proposed) external { if (s_transmitterPayees[transmitter] != msg.sender) revert OnlyCallableByPayee(); if (proposed == msg.sender) revert ValueNotChanged(); if (s_proposedPayee[transmitter] != proposed) { s_proposedPayee[transmitter] = proposed; emit PayeeshipTransferRequested(transmitter, msg.sender, proposed); } } /** * @notice accepts the transfer of the payee */ function acceptPayeeship(address transmitter) external { if (s_proposedPayee[transmitter] != msg.sender) revert OnlyCallableByProposedPayee(); address past = s_transmitterPayees[transmitter]; s_transmitterPayees[transmitter] = msg.sender; s_proposedPayee[transmitter] = ZERO_ADDRESS; emit PayeeshipTransferred(transmitter, past, msg.sender); } /** * @notice this is for NOPs to withdraw LINK received as payment for work performed */ function withdrawPayment(address from, address to) external { if (to == ZERO_ADDRESS) revert InvalidRecipient(); if (s_payoutMode == PayoutMode.OFF_CHAIN) revert MustSettleOffchain(); if (s_transmitterPayees[from] != msg.sender) revert OnlyCallableByPayee(); uint96 balance = _updateTransmitterBalanceFromPool(from, s_hotVars.totalPremium, uint96(s_transmittersList.length)); s_transmitters[from].balance = 0; s_reserveAmounts[IERC20(address(i_link))] = s_reserveAmounts[IERC20(address(i_link))] - balance; bool transferStatus = i_link.transfer(to, balance); if (!transferStatus) { revert TransferFailed(); } emit PaymentWithdrawn(from, balance, to, msg.sender); } // ================================================================ // | OWNER / MANAGER ACTIONS | // ================================================================ /** * @notice sets the privilege config for an upkeep */ function setUpkeepPrivilegeConfig(uint256 upkeepId, bytes calldata newPrivilegeConfig) external { _onlyPrivilegeManagerAllowed(); s_upkeepPrivilegeConfig[upkeepId] = newPrivilegeConfig; emit UpkeepPrivilegeConfigSet(upkeepId, newPrivilegeConfig); } /** * @notice this is used by the owner to set the initial payees for newly added transmitters. The owner is not allowed to change payees for existing transmitters. * @dev the IGNORE_ADDRESS is a "helper" that makes it easier to construct a list of payees when you only care about setting the payee for a small number of transmitters. */ function setPayees(address[] calldata payees) external onlyOwner { if (s_transmittersList.length != payees.length) revert ParameterLengthError(); for (uint256 i = 0; i < s_transmittersList.length; i++) { address transmitter = s_transmittersList[i]; address oldPayee = s_transmitterPayees[transmitter]; address newPayee = payees[i]; if ( (newPayee == ZERO_ADDRESS) || (oldPayee != ZERO_ADDRESS && oldPayee != newPayee && newPayee != IGNORE_ADDRESS) ) { revert InvalidPayee(); } if (newPayee != IGNORE_ADDRESS) { s_transmitterPayees[transmitter] = newPayee; } } emit PayeesUpdated(s_transmittersList, payees); } /** * @notice sets the migration permission for a peer registry * @dev this must be done before upkeeps can be migrated to/from another registry */ function setPeerRegistryMigrationPermission(address peer, MigrationPermission permission) external onlyOwner { s_peerRegistryMigrationPermission[peer] = permission; } /** * @notice pauses the entire registry */ function pause() external onlyOwner { s_hotVars.paused = true; emit Paused(msg.sender); } /** * @notice unpauses the entire registry */ function unpause() external onlyOwner { s_hotVars.paused = false; emit Unpaused(msg.sender); } /** * @notice sets a generic bytes field used to indicate the privilege that this admin address had * @param admin the address to set privilege for * @param newPrivilegeConfig the privileges that this admin has */ function setAdminPrivilegeConfig(address admin, bytes calldata newPrivilegeConfig) external { _onlyPrivilegeManagerAllowed(); s_adminPrivilegeConfig[admin] = newPrivilegeConfig; emit AdminPrivilegeConfigSet(admin, newPrivilegeConfig); } /** * @notice settles NOPs' LINK payment offchain */ function settleNOPsOffchain() external { _onlyFinanceAdminAllowed(); if (s_payoutMode == PayoutMode.ON_CHAIN) revert MustSettleOnchain(); uint96 totalPremium = s_hotVars.totalPremium; uint256 activeTransmittersLength = s_transmittersList.length; uint256 deactivatedTransmittersLength = s_deactivatedTransmitters.length(); uint256 length = activeTransmittersLength + deactivatedTransmittersLength; uint256[] memory payments = new uint256[](length); address[] memory payees = new address[](length); for (uint256 i = 0; i < activeTransmittersLength; i++) { address transmitterAddr = s_transmittersList[i]; uint96 balance = _updateTransmitterBalanceFromPool( transmitterAddr, totalPremium, uint96(activeTransmittersLength) ); payments[i] = balance; payees[i] = s_transmitterPayees[transmitterAddr]; s_transmitters[transmitterAddr].balance = 0; } for (uint256 i = 0; i < deactivatedTransmittersLength; i++) { address deactivatedAddr = s_deactivatedTransmitters.at(i); Transmitter memory transmitter = s_transmitters[deactivatedAddr]; payees[i + activeTransmittersLength] = s_transmitterPayees[deactivatedAddr]; payments[i + activeTransmittersLength] = transmitter.balance; s_transmitters[deactivatedAddr].balance = 0; } // reserve amount of LINK is reset to 0 since no user deposits of LINK are expected in offchain mode s_reserveAmounts[IERC20(address(i_link))] = 0; for (uint256 idx = s_deactivatedTransmitters.length(); idx > 0; idx--) { s_deactivatedTransmitters.remove(s_deactivatedTransmitters.at(idx - 1)); } emit NOPsSettledOffchain(payees, payments); } /** * @notice disables offchain payment for NOPs */ function disableOffchainPayments() external onlyOwner { s_payoutMode = PayoutMode.ON_CHAIN; } // ================================================================ // | GETTERS | // ================================================================ function getConditionalGasOverhead() external pure returns (uint256) { return REGISTRY_CONDITIONAL_OVERHEAD; } function getLogGasOverhead() external pure returns (uint256) { return REGISTRY_LOG_OVERHEAD; } function getPerPerformByteGasOverhead() external pure returns (uint256) { return REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD; } function getPerSignerGasOverhead() external pure returns (uint256) { return REGISTRY_PER_SIGNER_GAS_OVERHEAD; } function getTransmitCalldataFixedBytesOverhead() external pure returns (uint256) { return TRANSMIT_CALLDATA_FIXED_BYTES_OVERHEAD; } function getTransmitCalldataPerSignerBytesOverhead() external pure returns (uint256) { return TRANSMIT_CALLDATA_PER_SIGNER_BYTES_OVERHEAD; } function getCancellationDelay() external pure returns (uint256) { return CANCELLATION_DELAY; } function getLinkAddress() external view returns (address) { return address(i_link); } function getLinkUSDFeedAddress() external view returns (address) { return address(i_linkUSDFeed); } function getNativeUSDFeedAddress() external view returns (address) { return address(i_nativeUSDFeed); } function getFastGasFeedAddress() external view returns (address) { return address(i_fastGasFeed); } function getAutomationForwarderLogic() external view returns (address) { return i_automationForwarderLogic; } function getAllowedReadOnlyAddress() external view returns (address) { return i_allowedReadOnlyAddress; } function getWrappedNativeTokenAddress() external view returns (address) { return address(i_wrappedNativeToken); } function getBillingToken(uint256 upkeepID) external view returns (IERC20) { return s_upkeep[upkeepID].billingToken; } function getBillingTokens() external view returns (IERC20[] memory) { return s_billingTokens; } function supportsBillingToken(IERC20 token) external view returns (bool) { return address(s_billingConfigs[token].priceFeed) != address(0); } function getBillingTokenConfig(IERC20 token) external view returns (BillingConfig memory) { return s_billingConfigs[token]; } function getBillingOverridesEnabled(uint256 upkeepID) external view returns (bool) { return s_upkeep[upkeepID].overridesEnabled; } function getPayoutMode() external view returns (PayoutMode) { return s_payoutMode; } function upkeepVersion() public pure returns (uint8) { return UPKEEP_VERSION_BASE; } /** * @notice gets the number of upkeeps on the registry */ function getNumUpkeeps() external view returns (uint256) { return s_upkeepIDs.length(); } /** * @notice read all of the details about an upkeep * @dev this function may be deprecated in a future version of automation in favor of individual * getters for each field */ function getUpkeep(uint256 id) external view returns (IAutomationV21PlusCommon.UpkeepInfoLegacy memory upkeepInfo) { Upkeep memory reg = s_upkeep[id]; address target = address(reg.forwarder) == address(0) ? address(0) : reg.forwarder.getTarget(); upkeepInfo = IAutomationV21PlusCommon.UpkeepInfoLegacy({ target: target, performGas: reg.performGas, checkData: s_checkData[id], balance: reg.balance, admin: s_upkeepAdmin[id], maxValidBlocknumber: reg.maxValidBlocknumber, lastPerformedBlockNumber: reg.lastPerformedBlockNumber, amountSpent: uint96(reg.amountSpent), // force casting to uint96 for backwards compatibility. Not an issue if it overflows. paused: reg.paused, offchainConfig: s_upkeepOffchainConfig[id] }); return upkeepInfo; } /** * @notice retrieve active upkeep IDs. Active upkeep is defined as an upkeep which is not paused and not canceled. * @param startIndex starting index in list * @param maxCount max count to retrieve (0 = unlimited) * @dev the order of IDs in the list is **not guaranteed**, therefore, if making successive calls, one * should consider keeping the blockheight constant to ensure a holistic picture of the contract state */ function getActiveUpkeepIDs(uint256 startIndex, uint256 maxCount) external view returns (uint256[] memory) { uint256 numUpkeeps = s_upkeepIDs.length(); if (startIndex >= numUpkeeps) revert IndexOutOfRange(); uint256 endIndex = startIndex + maxCount; endIndex = endIndex > numUpkeeps || maxCount == 0 ? numUpkeeps : endIndex; uint256[] memory ids = new uint256[](endIndex - startIndex); for (uint256 idx = 0; idx < ids.length; idx++) { ids[idx] = s_upkeepIDs.at(idx + startIndex); } return ids; } /** * @notice returns the upkeep's trigger type */ function getTriggerType(uint256 upkeepId) external pure returns (Trigger) { return _getTriggerType(upkeepId); } /** * @notice returns the trigger config for an upkeeep */ function getUpkeepTriggerConfig(uint256 upkeepId) public view returns (bytes memory) { return s_upkeepTriggerConfig[upkeepId]; } /** * @notice read the current info about any transmitter address */ function getTransmitterInfo( address query ) external view returns (bool active, uint8 index, uint96 balance, uint96 lastCollected, address payee) { Transmitter memory transmitter = s_transmitters[query]; uint96 pooledShare = 0; if (transmitter.active) { uint96 totalDifference = s_hotVars.totalPremium - transmitter.lastCollected; pooledShare = totalDifference / uint96(s_transmittersList.length); } return ( transmitter.active, transmitter.index, (transmitter.balance + pooledShare), transmitter.lastCollected, s_transmitterPayees[query] ); } /** * @notice read the current info about any signer address */ function getSignerInfo(address query) external view returns (bool active, uint8 index) { Signer memory signer = s_signers[query]; return (signer.active, signer.index); } /** * @notice read the current on-chain config of the registry * @dev this function will change between versions, it should never be used where * backwards compatibility matters! */ function getConfig() external view returns (OnchainConfig memory) { return OnchainConfig({ checkGasLimit: s_storage.checkGasLimit, stalenessSeconds: s_hotVars.stalenessSeconds, gasCeilingMultiplier: s_hotVars.gasCeilingMultiplier, maxPerformGas: s_storage.maxPerformGas, maxCheckDataSize: s_storage.maxCheckDataSize, maxPerformDataSize: s_storage.maxPerformDataSize, maxRevertDataSize: s_storage.maxRevertDataSize, fallbackGasPrice: s_fallbackGasPrice, fallbackLinkPrice: s_fallbackLinkPrice, fallbackNativePrice: s_fallbackNativePrice, transcoder: s_storage.transcoder, registrars: s_registrars.values(), upkeepPrivilegeManager: s_storage.upkeepPrivilegeManager, chainModule: s_hotVars.chainModule, reorgProtectionEnabled: s_hotVars.reorgProtectionEnabled, financeAdmin: s_storage.financeAdmin }); } /** * @notice read the current state of the registry * @dev this function is deprecated */ function getState() external view returns ( IAutomationV21PlusCommon.StateLegacy memory state, IAutomationV21PlusCommon.OnchainConfigLegacy memory config, address[] memory signers, address[] memory transmitters, uint8 f ) { state = IAutomationV21PlusCommon.StateLegacy({ nonce: s_storage.nonce, ownerLinkBalance: 0, // deprecated expectedLinkBalance: 0, // deprecated totalPremium: s_hotVars.totalPremium, numUpkeeps: s_upkeepIDs.length(), configCount: s_storage.configCount, latestConfigBlockNumber: s_storage.latestConfigBlockNumber, latestConfigDigest: s_latestConfigDigest, latestEpoch: s_hotVars.latestEpoch, paused: s_hotVars.paused }); config = IAutomationV21PlusCommon.OnchainConfigLegacy({ paymentPremiumPPB: 0, // deprecated flatFeeMicroLink: 0, // deprecated checkGasLimit: s_storage.checkGasLimit, stalenessSeconds: s_hotVars.stalenessSeconds, gasCeilingMultiplier: s_hotVars.gasCeilingMultiplier, minUpkeepSpend: 0, // deprecated maxPerformGas: s_storage.maxPerformGas, maxCheckDataSize: s_storage.maxCheckDataSize, maxPerformDataSize: s_storage.maxPerformDataSize, maxRevertDataSize: s_storage.maxRevertDataSize, fallbackGasPrice: s_fallbackGasPrice, fallbackLinkPrice: s_fallbackLinkPrice, transcoder: s_storage.transcoder, registrars: s_registrars.values(), upkeepPrivilegeManager: s_storage.upkeepPrivilegeManager }); return (state, config, s_signersList, s_transmittersList, s_hotVars.f); } /** * @notice read the Storage data * @dev this function signature will change with each version of automation * this should not be treated as a stable function */ function getStorage() external view returns (Storage memory) { return s_storage; } /** * @notice read the HotVars data * @dev this function signature will change with each version of automation * this should not be treated as a stable function */ function getHotVars() external view returns (HotVars memory) { return s_hotVars; } /** * @notice get the chain module */ function getChainModule() external view returns (IChainModule chainModule) { return s_hotVars.chainModule; } /** * @notice if this registry has reorg protection enabled */ function getReorgProtectionEnabled() external view returns (bool reorgProtectionEnabled) { return s_hotVars.reorgProtectionEnabled; } /** * @notice calculates the minimum balance required for an upkeep to remain eligible * @param id the upkeep id to calculate minimum balance for */ function getBalance(uint256 id) external view returns (uint96 balance) { return s_upkeep[id].balance; } /** * @notice calculates the minimum balance required for an upkeep to remain eligible * @param id the upkeep id to calculate minimum balance for */ function getMinBalance(uint256 id) external view returns (uint96) { return getMinBalanceForUpkeep(id); } /** * @notice calculates the minimum balance required for an upkeep to remain eligible * @param id the upkeep id to calculate minimum balance for * @dev this will be deprecated in a future version in favor of getMinBalance */ function getMinBalanceForUpkeep(uint256 id) public view returns (uint96 minBalance) { Upkeep memory upkeep = s_upkeep[id]; return getMaxPaymentForGas(id, _getTriggerType(id), upkeep.performGas, upkeep.billingToken); } /** * @notice calculates the maximum payment for a given gas limit * @param gasLimit the gas to calculate payment for */ function getMaxPaymentForGas( uint256 id, Trigger triggerType, uint32 gasLimit, IERC20 billingToken ) public view returns (uint96 maxPayment) { HotVars memory hotVars = s_hotVars; (uint256 fastGasWei, uint256 linkUSD, uint256 nativeUSD) = _getFeedData(hotVars); return _getMaxPayment(id, hotVars, triggerType, gasLimit, fastGasWei, linkUSD, nativeUSD, billingToken); } /** * @notice retrieves the migration permission for a peer registry */ function getPeerRegistryMigrationPermission(address peer) external view returns (MigrationPermission) { return s_peerRegistryMigrationPermission[peer]; } /** * @notice returns the upkeep privilege config */ function getUpkeepPrivilegeConfig(uint256 upkeepId) external view returns (bytes memory) { return s_upkeepPrivilegeConfig[upkeepId]; } /** * @notice returns the admin's privilege config */ function getAdminPrivilegeConfig(address admin) external view returns (bytes memory) { return s_adminPrivilegeConfig[admin]; } /** * @notice returns the upkeep's forwarder contract */ function getForwarder(uint256 upkeepID) external view returns (IAutomationForwarder) { return s_upkeep[upkeepID].forwarder; } /** * @notice returns if the dedupKey exists or not */ function hasDedupKey(bytes32 dedupKey) external view returns (bool) { return s_dedupKeys[dedupKey]; } /** * @notice returns the fallback native price */ function getFallbackNativePrice() external view returns (uint256) { return s_fallbackNativePrice; } /** * @notice returns the amount of a particular token that is reserved as * user deposits / NOP payments */ function getReserveAmount(IERC20 billingToken) external view returns (uint256) { return s_reserveAmounts[billingToken]; } /** * @notice returns the amount of a particular token that is withdraw-able by finance admin */ function getAvailableERC20ForPayment(IERC20 billingToken) external view returns (uint256) { return billingToken.balanceOf(address(this)) - s_reserveAmounts[IERC20(address(billingToken))]; } /** * @notice returns the size of the LINK liquidity pool */ function linkAvailableForPayment() public view returns (int256) { return _linkAvailableForPayment(); } /** * @notice returns the BillingOverrides config for a given upkeep */ function getBillingOverrides(uint256 upkeepID) external view returns (BillingOverrides memory) { return s_billingOverrides[upkeepID]; } /** * @notice returns the BillingConfig for a given billing token, this includes decimals and price feed etc */ function getBillingConfig(IERC20 billingToken) external view returns (BillingConfig memory) { return s_billingConfigs[billingToken]; } /** * @notice returns all active transmitters with their associated payees */ function getTransmittersWithPayees() external view returns (TransmitterPayeeInfo[] memory) { uint256 transmitterCount = s_transmittersList.length; TransmitterPayeeInfo[] memory transmitters = new TransmitterPayeeInfo[](transmitterCount); for (uint256 i = 0; i < transmitterCount; i++) { address transmitterAddress = s_transmittersList[i]; address payeeAddress = s_transmitterPayees[transmitterAddress]; transmitters[i] = TransmitterPayeeInfo(transmitterAddress, payeeAddress); } return transmitters; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import {AutomationRegistryBase2_3} from "./AutomationRegistryBase2_3.sol"; /** * @notice this file exposes structs that are otherwise internal to the automation registry * doing this allows those structs to be encoded and decoded with type safety in offchain code * and tests because generated wrappers are made available */ contract AutomationUtils2_3 { /** * @dev this uses the v2.3 Report, which uses linkUSD instead of linkNative (as in v2.2 and prior). This should be used only in typescript tests. */ function _report(AutomationRegistryBase2_3.Report memory) external {} // 0xe65d6546 }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import {UpkeepTranscoderInterfaceV2} from "../interfaces/UpkeepTranscoderInterfaceV2.sol"; import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol"; enum RegistryVersion { V12, V13, V20, V21, V23 } /** * @notice UpkeepTranscoder is a contract that allows converting upkeep data from previous registry versions to newer versions * @dev it currently only supports 2.3 -> 2.3 migrations */ contract UpkeepTranscoder5_0 is UpkeepTranscoderInterfaceV2, TypeAndVersionInterface { error InvalidTranscoding(); string public constant override typeAndVersion = "UpkeepTranscoder 5.0.0"; /** * @notice transcodeUpkeeps transforms upkeep data from the format expected by * one registry to the format expected by another. It future-proofs migrations * by allowing automation team to customize migration paths and set sensible defaults * when new fields are added * @param fromVersion version the upkeep is migrating from * @param toVersion version the upkeep is migrating to * @param encodedUpkeeps encoded upkeep data * @dev this transcoder should ONLY be use for V23->V23 migrations for now */ function transcodeUpkeeps( uint8 fromVersion, uint8 toVersion, bytes calldata encodedUpkeeps ) external view override returns (bytes memory) { if (toVersion == uint8(RegistryVersion.V23) && fromVersion == uint8(RegistryVersion.V23)) { return encodedUpkeeps; } revert InvalidTranscoding(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; abstract contract TypeAndVersionInterface { function typeAndVersion() external pure virtual returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {ConfirmedOwnerWithProposal} from "./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 {IOwnable} from "../interfaces/IOwnable.sol"; /// @title The ConfirmedOwner contract /// @notice A contract with helpers for basic contract ownership. contract ConfirmedOwnerWithProposal is IOwnable { 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) { // solhint-disable-next-line gas-custom-errors 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. function transferOwnership(address to) public override onlyOwner { _transferOwnership(to); } /// @notice Allows an ownership transfer to be completed by the recipient. function acceptOwnership() external override { // solhint-disable-next-line gas-custom-errors 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 { // solhint-disable-next-line gas-custom-errors require(to != msg.sender, "Cannot transfer to self"); s_pendingOwner = to; emit OwnershipTransferRequested(s_owner, to); } /// @notice validate access function _validateOwnership() internal view { // solhint-disable-next-line gas-custom-errors 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; // solhint-disable-next-line interface-starts-with-i 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.6; interface IERC677Receiver { function onTokenTransfer(address sender, uint256 amount, bytes calldata data) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IOwnable { function owner() external returns (address); function transferOwnership(address recipient) external; function acceptOwnership() external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface ITypeAndVersion { function typeAndVersion() external pure returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // solhint-disable-next-line interface-starts-with-i 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; import {ITypeAndVersion} from "../interfaces/ITypeAndVersion.sol"; abstract contract OCR2Abstract is ITypeAndVersion { uint256 internal constant MAX_NUM_ORACLES = 31; uint256 private constant PREFIX_MASK = type(uint256).max << (256 - 16); // 0xFFFF00..00 uint256 private constant PREFIX = 0x0001 << (256 - 16); // 0x000100..00 /// @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 ) ) ); return bytes32((PREFIX & PREFIX_MASK) | (h & ~PREFIX_MASK)); } /// @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 [0]: ConfigDigest, [1]: 27 byte padding, 4-byte epoch and 1-byte round, [2]: 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 MAX_NUM_ORACLES entries /// @param ss ith element is the S components of the ith signature on report. Must have at most MAX_NUM_ORACLES 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 // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.0; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafeCast { /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toUint248(uint256 value) internal pure returns (uint248) { require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits"); return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toUint240(uint256 value) internal pure returns (uint240) { require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits"); return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toUint232(uint256 value) internal pure returns (uint232) { require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits"); return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.2._ */ function toUint224(uint256 value) internal pure returns (uint224) { require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits"); return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toUint216(uint256 value) internal pure returns (uint216) { require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits"); return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toUint208(uint256 value) internal pure returns (uint208) { require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits"); return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toUint200(uint256 value) internal pure returns (uint200) { require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits"); return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toUint192(uint256 value) internal pure returns (uint192) { require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits"); return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toUint184(uint256 value) internal pure returns (uint184) { require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits"); return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toUint176(uint256 value) internal pure returns (uint176) { require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits"); return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toUint168(uint256 value) internal pure returns (uint168) { require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits"); return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toUint160(uint256 value) internal pure returns (uint160) { require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits"); return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toUint152(uint256 value) internal pure returns (uint152) { require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits"); return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toUint144(uint256 value) internal pure returns (uint144) { require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits"); return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toUint136(uint256 value) internal pure returns (uint136) { require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits"); return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v2.5._ */ function toUint128(uint256 value) internal pure returns (uint128) { require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toUint120(uint256 value) internal pure returns (uint120) { require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits"); return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toUint112(uint256 value) internal pure returns (uint112) { require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits"); return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toUint104(uint256 value) internal pure returns (uint104) { require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits"); return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.2._ */ function toUint96(uint256 value) internal pure returns (uint96) { require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits"); return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toUint88(uint256 value) internal pure returns (uint88) { require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits"); return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toUint80(uint256 value) internal pure returns (uint80) { require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits"); return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toUint72(uint256 value) internal pure returns (uint72) { require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits"); return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v2.5._ */ function toUint64(uint256 value) internal pure returns (uint64) { require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toUint56(uint256 value) internal pure returns (uint56) { require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits"); return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toUint48(uint256 value) internal pure returns (uint48) { require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits"); return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toUint40(uint256 value) internal pure returns (uint40) { require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits"); return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v2.5._ */ function toUint32(uint256 value) internal pure returns (uint32) { require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toUint24(uint256 value) internal pure returns (uint24) { require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits"); return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v2.5._ */ function toUint16(uint256 value) internal pure returns (uint16) { require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v2.5._ */ function toUint8(uint256 value) internal pure returns (uint8) { require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. * * _Available since v3.0._ */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); require(downcasted == value, "SafeCast: value doesn't fit in 248 bits"); } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); require(downcasted == value, "SafeCast: value doesn't fit in 240 bits"); } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); require(downcasted == value, "SafeCast: value doesn't fit in 232 bits"); } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.7._ */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); require(downcasted == value, "SafeCast: value doesn't fit in 224 bits"); } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); require(downcasted == value, "SafeCast: value doesn't fit in 216 bits"); } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); require(downcasted == value, "SafeCast: value doesn't fit in 208 bits"); } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); require(downcasted == value, "SafeCast: value doesn't fit in 200 bits"); } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); require(downcasted == value, "SafeCast: value doesn't fit in 192 bits"); } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); require(downcasted == value, "SafeCast: value doesn't fit in 184 bits"); } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); require(downcasted == value, "SafeCast: value doesn't fit in 176 bits"); } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); require(downcasted == value, "SafeCast: value doesn't fit in 168 bits"); } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); require(downcasted == value, "SafeCast: value doesn't fit in 160 bits"); } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); require(downcasted == value, "SafeCast: value doesn't fit in 152 bits"); } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); require(downcasted == value, "SafeCast: value doesn't fit in 144 bits"); } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); require(downcasted == value, "SafeCast: value doesn't fit in 136 bits"); } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); require(downcasted == value, "SafeCast: value doesn't fit in 128 bits"); } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); require(downcasted == value, "SafeCast: value doesn't fit in 120 bits"); } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); require(downcasted == value, "SafeCast: value doesn't fit in 112 bits"); } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); require(downcasted == value, "SafeCast: value doesn't fit in 104 bits"); } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.7._ */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); require(downcasted == value, "SafeCast: value doesn't fit in 96 bits"); } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); require(downcasted == value, "SafeCast: value doesn't fit in 88 bits"); } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); require(downcasted == value, "SafeCast: value doesn't fit in 80 bits"); } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); require(downcasted == value, "SafeCast: value doesn't fit in 72 bits"); } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v3.1._ */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); require(downcasted == value, "SafeCast: value doesn't fit in 64 bits"); } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); require(downcasted == value, "SafeCast: value doesn't fit in 56 bits"); } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); require(downcasted == value, "SafeCast: value doesn't fit in 48 bits"); } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); require(downcasted == value, "SafeCast: value doesn't fit in 40 bits"); } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v3.1._ */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); require(downcasted == value, "SafeCast: value doesn't fit in 32 bits"); } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); require(downcasted == value, "SafeCast: value doesn't fit in 24 bits"); } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v3.1._ */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); require(downcasted == value, "SafeCast: value doesn't fit in 16 bits"); } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v3.1._ */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); require(downcasted == value, "SafeCast: value doesn't fit in 8 bits"); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. * * _Available since v3.0._ */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256"); return int256(value); } }
{ "optimizer": { "enabled": true, "runs": 1000000 }, "metadata": { "bytecodeHash": "none" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract ABI
API[{"inputs":[{"internalType":"contract AutomationRegistryLogicA2_3","name":"logicA","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ArrayHasNoEntries","type":"error"},{"inputs":[],"name":"CannotCancel","type":"error"},{"inputs":[],"name":"CheckDataExceedsLimit","type":"error"},{"inputs":[],"name":"ConfigDigestMismatch","type":"error"},{"inputs":[],"name":"DuplicateEntry","type":"error"},{"inputs":[],"name":"DuplicateSigners","type":"error"},{"inputs":[],"name":"GasLimitCanOnlyIncrease","type":"error"},{"inputs":[],"name":"GasLimitOutsideRange","type":"error"},{"inputs":[],"name":"IncorrectNumberOfFaultyOracles","type":"error"},{"inputs":[],"name":"IncorrectNumberOfSignatures","type":"error"},{"inputs":[],"name":"IncorrectNumberOfSigners","type":"error"},{"inputs":[],"name":"IndexOutOfRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"available","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InsufficientLinkLiquidity","type":"error"},{"inputs":[],"name":"InvalidDataLength","type":"error"},{"inputs":[],"name":"InvalidFeed","type":"error"},{"inputs":[],"name":"InvalidPayee","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidReport","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"inputs":[],"name":"InvalidTransmitter","type":"error"},{"inputs":[],"name":"InvalidTrigger","type":"error"},{"inputs":[],"name":"InvalidTriggerType","type":"error"},{"inputs":[],"name":"MigrationNotPermitted","type":"error"},{"inputs":[],"name":"MustSettleOffchain","type":"error"},{"inputs":[],"name":"MustSettleOnchain","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"OnlyActiveSigners","type":"error"},{"inputs":[],"name":"OnlyActiveTransmitters","type":"error"},{"inputs":[],"name":"OnlyCallableByAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByLINKToken","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrRegistrar","type":"error"},{"inputs":[],"name":"OnlyCallableByPayee","type":"error"},{"inputs":[],"name":"OnlyCallableByProposedAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByProposedPayee","type":"error"},{"inputs":[],"name":"OnlyCallableByUpkeepPrivilegeManager","type":"error"},{"inputs":[],"name":"OnlyFinanceAdmin","type":"error"},{"inputs":[],"name":"OnlyPausedUpkeep","type":"error"},{"inputs":[],"name":"OnlySimulatedBackend","type":"error"},{"inputs":[],"name":"OnlyUnpausedUpkeep","type":"error"},{"inputs":[],"name":"ParameterLengthError","type":"error"},{"inputs":[],"name":"ReentrantCall","type":"error"},{"inputs":[],"name":"RegistryPaused","type":"error"},{"inputs":[],"name":"RepeatedSigner","type":"error"},{"inputs":[],"name":"RepeatedTransmitter","type":"error"},{"inputs":[{"internalType":"bytes","name":"reason","type":"bytes"}],"name":"TargetCheckReverted","type":"error"},{"inputs":[],"name":"TooManyOracles","type":"error"},{"inputs":[],"name":"TranscoderNotSet","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"UpkeepAlreadyExists","type":"error"},{"inputs":[],"name":"UpkeepCancelled","type":"error"},{"inputs":[],"name":"UpkeepNotCanceled","type":"error"},{"inputs":[],"name":"UpkeepNotNeeded","type":"error"},{"inputs":[],"name":"ValueNotChanged","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"bytes","name":"privilegeConfig","type":"bytes"}],"name":"AdminPrivilegeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"}],"indexed":false,"internalType":"struct AutomationRegistryBase2_3.BillingOverrides","name":"overrides","type":"tuple"}],"name":"BillingConfigOverridden","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"BillingConfigOverrideRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20Metadata","name":"token","type":"address"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"},{"internalType":"contract AggregatorV3Interface","name":"priceFeed","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"fallbackPrice","type":"uint256"},{"internalType":"uint96","name":"minSpend","type":"uint96"}],"indexed":false,"internalType":"struct AutomationRegistryBase2_3.BillingConfig","name":"config","type":"tuple"}],"name":"BillingConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"CancelledUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newModule","type":"address"}],"name":"ChainSpecificModuleUpdated","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":"bytes32","name":"dedupKey","type":"bytes32"}],"name":"DedupKeyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"assetAddress","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"}],"name":"FundsAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"FundsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"InsufficientFundsUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"payees","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"payments","type":"uint256[]"}],"name":"NOPsSettledOffchain","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":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"transmitters","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"payees","type":"address[]"}],"name":"PayeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"PayeeshipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"PayeeshipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"payee","type":"address"}],"name":"PaymentWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"ReorgedUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"StaleUpkeepReport","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":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"UpkeepAdminTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"UpkeepAdminTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint64","name":"atBlockHeight","type":"uint64"}],"name":"UpkeepCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint96","name":"gasChargeInBillingToken","type":"uint96"},{"internalType":"uint96","name":"premiumInBillingToken","type":"uint96"},{"internalType":"uint96","name":"gasReimbursementInJuels","type":"uint96"},{"internalType":"uint96","name":"premiumInJuels","type":"uint96"},{"internalType":"contract IERC20Metadata","name":"billingToken","type":"address"},{"internalType":"uint96","name":"linkUSD","type":"uint96"},{"internalType":"uint96","name":"nativeUSD","type":"uint96"},{"internalType":"uint96","name":"billingUSD","type":"uint96"}],"indexed":false,"internalType":"struct AutomationRegistryBase2_3.PaymentReceipt","name":"receipt","type":"tuple"}],"name":"UpkeepCharged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"newCheckData","type":"bytes"}],"name":"UpkeepCheckDataSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint96","name":"gasLimit","type":"uint96"}],"name":"UpkeepGasLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"remainingBalance","type":"uint256"},{"indexed":false,"internalType":"address","name":"destination","type":"address"}],"name":"UpkeepMigrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"UpkeepOffchainConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"UpkeepPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"uint96","name":"totalPayment","type":"uint96"},{"indexed":false,"internalType":"uint256","name":"gasUsed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasOverhead","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"UpkeepPerformed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"privilegeConfig","type":"bytes"}],"name":"UpkeepPrivilegeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startingBalance","type":"uint256"},{"indexed":false,"internalType":"address","name":"importedFrom","type":"address"}],"name":"UpkeepReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"performGas","type":"uint32"},{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"UpkeepRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"triggerConfig","type":"bytes"}],"name":"UpkeepTriggerConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"UpkeepUnpaused","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fallbackTo","outputs":[{"internalType":"address","name":"","type":"address"}],"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":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"internalType":"bytes","name":"onchainConfigBytes","type":"bytes"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"components":[{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"bool","name":"reorgProtectionEnabled","type":"bool"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"address","name":"financeAdmin","type":"address"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackNativePrice","type":"uint256"},{"internalType":"address[]","name":"registrars","type":"address[]"},{"internalType":"contract IChainModule","name":"chainModule","type":"address"}],"internalType":"struct AutomationRegistryBase2_3.OnchainConfig","name":"onchainConfig","type":"tuple"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"},{"internalType":"contract IERC20Metadata[]","name":"billingTokens","type":"address[]"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"},{"internalType":"contract AggregatorV3Interface","name":"priceFeed","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"fallbackPrice","type":"uint256"},{"internalType":"uint96","name":"minSpend","type":"uint96"}],"internalType":"struct AutomationRegistryBase2_3.BillingConfig[]","name":"billingConfigs","type":"tuple[]"}],"name":"setConfigTypeSafe","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[3]","name":"reportContext","type":"bytes32[3]"},{"internalType":"bytes","name":"rawReport","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":"view","type":"function"}]
Contract Creation Code
6101806040523480156200001257600080fd5b50604051620065423803806200654283398101604081905262000035916200062f565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b91906200062f565b826001600160a01b031663226cf83c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200010091906200062f565b836001600160a01b031663614486af6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016591906200062f565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca91906200062f565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f91906200062f565b866001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200026e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029491906200062f565b876001600160a01b031663c5b964e06040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002f9919062000656565b886001600160a01b031663ac4dc59a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000338573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035e91906200062f565b3380600081620003b55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620003e857620003e8816200056b565b5050506001600160a01b0380891660805287811660a05286811660c05285811660e052848116610100528316610120526025805483919060ff19166001838181111562000439576200043962000679565b0217905550806001600160a01b0316610140816001600160a01b03168152505060c0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200049a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004c091906200068f565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200052a91906200068f565b60ff16146200054c576040516301f86e1760e41b815260040160405180910390fd5b5050506001600160a01b039095166101605250620006b4945050505050565b336001600160a01b03821603620005c55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620003ac565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200062c57600080fd5b50565b6000602082840312156200064257600080fd5b81516200064f8162000616565b9392505050565b6000602082840312156200066957600080fd5b8151600281106200064f57600080fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215620006a257600080fd5b815160ff811681146200064f57600080fd5b60805160a05160c05160e05161010051610120516101405161016051615e2a620007186000396000818160b3015261018601526000505060005050600050506000505060006137bd015260005050600081816113710152612de60152615e2a6000f3fe6080604052600436106100b15760003560e01c80638da5cb5b11610069578063b1dc65a41161004e578063b1dc65a4146102cb578063e3d0e712146102eb578063f2fde38b1461030b576100b1565b80638da5cb5b1461025a578063afcb95d714610285576100b1565b8063349e8cca1161009a578063349e8cca1461017757806379ba5097146101cb57806381ff7048146101e0576100b1565b80630870d3a1146100f8578063181f5a7714610118575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e8080156100f1573d6000f35b3d6000fd5b005b34801561010457600080fd5b506100f6610113366004614b9e565b61032b565b34801561012457600080fd5b506101616040518060400160405280601881526020017f4175746f6d6174696f6e526567697374727920322e332e30000000000000000081525081565b60405161016e9190614d1a565b60405180910390f35b34801561018357600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161016e565b3480156101d757600080fd5b506100f6610c0f565b3480156101ec57600080fd5b5061023760175460135463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff94851681529390921660208401529082015260600161016e565b34801561026657600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166101a6565b34801561029157600080fd5b50601354601454604080516000815260208101939093526c0100000000000000000000000090910463ffffffff169082015260600161016e565b3480156102d757600080fd5b506100f66102e6366004614d79565b610d11565b3480156102f757600080fd5b506100f6610306366004614e5e565b611051565b34801561031757600080fd5b506100f6610326366004614f2b565b61108b565b61033361109f565b601f8851111561036f576040517f25d0209c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8560ff166000036103ac576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b865188511415806103cb57506103c3866003614f77565b60ff16885111155b15610402576040517f1d2d1c5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805182511461043d576040517fcf54c06a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104478282611122565b610451888861175a565b604051806101200160405280601460000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff168152602001600063ffffffff1681526020018660a0015162ffffff16815260200186610120015161ffff1681526020018760ff168152602001601460000160169054906101000a900460ff1615158152602001601460000160179054906101000a900460ff1615158152602001866080015115158152602001866101e0015173ffffffffffffffffffffffffffffffffffffffff16815250601460008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160106101000a81548162ffffff021916908362ffffff16021790555060608201518160000160136101000a81548161ffff021916908361ffff16021790555060808201518160000160156101000a81548160ff021916908360ff16021790555060a08201518160000160166101000a81548160ff02191690831515021790555060c08201518160000160176101000a81548160ff02191690831515021790555060e08201518160000160186101000a81548160ff0219169083151502179055506101008201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050506000601660010160189054906101000a900463ffffffff1690506000866101e0015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610701573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107259190614f93565b6017549091506000906107579074010000000000000000000000000000000000000000900463ffffffff166001614fac565b9050604051806101600160405280896060015173ffffffffffffffffffffffffffffffffffffffff168152602001896000015163ffffffff168152602001896020015163ffffffff1681526020016016600001601c9054906101000a900463ffffffff1663ffffffff16815260200189610100015173ffffffffffffffffffffffffffffffffffffffff1681526020018263ffffffff1681526020018363ffffffff168152602001896040015163ffffffff16815260200189610140015173ffffffffffffffffffffffffffffffffffffffff1681526020018960c0015163ffffffff1681526020018960e0015163ffffffff16815250601660008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a08201518160010160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101208201518160020160146101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160186101000a81548163ffffffff021916908363ffffffff160217905550905050876101600151601981905550876101800151601a81905550876101a00151601b81905550600088604051602001610a9a919061501a565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152919052601754909150610aff904690309074010000000000000000000000000000000000000000900463ffffffff168f8f8f878f8f611e19565b6013556000610b0e6009611ec3565b90505b8015610b4b57610b38610b30610b286001846151a0565b600990611ed3565b600990611ee6565b5080610b43816151b3565b915050610b11565b5060005b896101c0015151811015610ba257610b8f8a6101c001518281518110610b7757610b776151e8565b60200260200101516009611f0890919063ffffffff16565b5080610b9a81615217565b915050610b4f565b507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0584601354601660010160149054906101000a900463ffffffff168f8f8f878f8f604051610bf99998979695949392919061524f565b60405180910390a1505050505050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610c95576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005a90506000610d238660406152e5565b610d2f896101446152fc565b610d3991906152fc565b9050368114610d74576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051610120810182526014546bffffffffffffffffffffffff8116825263ffffffff6c01000000000000000000000000820416602083015262ffffff7001000000000000000000000000000000008204169282019290925261ffff730100000000000000000000000000000000000000830416606082015260ff75010000000000000000000000000000000000000000008304811660808301527601000000000000000000000000000000000000000000008304811615801560a08401527701000000000000000000000000000000000000000000000084048216151560c0840152780100000000000000000000000000000000000000000000000090930416151560e082015260155473ffffffffffffffffffffffffffffffffffffffff1661010082015290610ed3576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b602052604090205460ff16610f1c576040517f1099ed7500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6013548b3514610f58576040517fdfdcf8e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6080810151610f6890600161530f565b60ff1687141580610f795750868514155b15610fb0576040517f0244f71a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fc08b8b8b8b8b8b8b8b611f2a565b6000610fcc8b8b612193565b905060208c0135600881901c63ffffffff16610fe984848861224c565b836020015163ffffffff168163ffffffff16111561104157601480547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff8416021790555b5050505050505050505050505050565b60008060008580602001905181019061106a9190615495565b925092509250611080898989868989888861032b565b505050505050505050565b61109361109f565b61109c81612e5c565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314611120576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610c8c565b565b60005b6024548110156111e0576022600060248381548110611146576111466151e8565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181019190915560020180547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000169055806111d881615217565b915050611125565b506111ed602460006145f2565b60255460ff1660005b8351811015611754576000848281518110611213576112136151e8565b602002602001015190506000848381518110611231576112316151e8565b602002602001015190508173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611286573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112aa9190615640565b60ff16816060015160ff161415806113385750806040015173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561130c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113309190615640565b60ff16600814155b1561136f576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480156113db575060018460018111156113d9576113d961565d565b145b15611412576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216158061144d5750604081015173ffffffffffffffffffffffffffffffffffffffff16155b15611484576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff828116600090815260226020526040902054670100000000000000900416156114ee576040517f357d0cc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6024805460018181019092557f7cd332d19b93bcabe3cce7ca0c18a052f57e5fd03b4758a09f30f5ddc4b22ec401805473ffffffffffffffffffffffffffffffffffffffff8086167fffffffffffffffffffffffff0000000000000000000000000000000000000000909216821790925560008181526022602090815260409182902086518154928801518489015160608a015160ff167b01000000000000000000000000000000000000000000000000000000027fffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffff9190981667010000000000000002167fffffffff000000000000000000000000000000000000000000ffffffffffffff62ffffff909216640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000090951663ffffffff9093169290921793909317929092169190911793909317835560808501519383019390935560a0840151600290920180546bffffffffffffffffffffffff9093167fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009093169290921790915590517fca93cbe727c73163ec538f71be6c0a64877d7f1f6dd35d5ca7cbaef3a3e34ba390611737908490600060c08201905063ffffffff835116825262ffffff602084015116602083015273ffffffffffffffffffffffffffffffffffffffff604084015116604083015260ff6060840151166060830152608083015160808301526bffffffffffffffffffffffff60a08401511660a083015292915050565b60405180910390a25050808061174c90615217565b9150506111f6565b50505050565b600e546014546bffffffffffffffffffffffff1660005b600e548110156117cd576117ba600e8281548110611791576117916151e8565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff168385612f51565b50806117c581615217565b915050611771565b5060255460009060ff16815b600e5481101561193e57600e81815481106117f6576117f66151e8565b6000918252602082200154600d805473ffffffffffffffffffffffffffffffffffffffff9092169550600c929184908110611833576118336151e8565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff9081168452838201949094526040928301822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690559286168152600b909252902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905560018260018111156118d5576118d561565d565b14801561191a575073ffffffffffffffffffffffffffffffffffffffff83166000908152600b60205260409020546201000090046bffffffffffffffffffffffff1615155b1561192c5761192a600f84611f08565b505b8061193681615217565b9150506117d9565b5061194b600d60006145f2565b611957600e60006145f2565b6040805160808101825260008082526020820181905291810182905260608101829052905b8751811015611de757600c600089838151811061199b5761199b6151e8565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff1615611a06576040517f77cea0fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16888281518110611a3057611a306151e8565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611a85576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806001151581526020018260ff16815250600c60008a8481518110611ab657611ab66151e8565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528181019290925260400160002082518154939092015160ff16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909316929092171790558651879082908110611b5e57611b5e6151e8565b60200260200101519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603611bce576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff84166000908152600b60209081526040918290208251608081018452905460ff80821615801584526101008304909116938301939093526bffffffffffffffffffffffff6201000082048116948301949094526e01000000000000000000000000000090049092166060830152909250611c89576040517f6a7281ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180835260ff80831660208086019182526014546bffffffffffffffffffffffff9081166060880190815273ffffffffffffffffffffffffffffffffffffffff8a166000908152600b909352604092839020885181549551948a0151925184166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff939094166201000002929092167fffffffffffff000000000000000000000000000000000000000000000000ffff94909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090951694909417179190911692909217919091179055836001811115611dc357611dc361565d565b03611dd557611dd3600f85611ee6565b505b80611ddf81615217565b91505061197c565b508651611dfb90600d9060208a0190614610565b508551611e0f90600e906020890190614610565b5050505050505050565b6000808a8a8a8a8a8a8a8a8a604051602001611e3d9998979695949392919061568c565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179b9a5050505050505050505050565b6000611ecd825490565b92915050565b6000611edf8383613159565b9392505050565b6000611edf8373ffffffffffffffffffffffffffffffffffffffff8416613183565b6000611edf8373ffffffffffffffffffffffffffffffffffffffff841661327d565b60008787604051611f3c929190615721565b604051908190038120611f53918b90602001615731565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201208383019092526000808452908301819052909250906000805b8881101561212a57600185878360208110611fbf57611fbf6151e8565b611fcc91901a601b61530f565b8c8c85818110611fde57611fde6151e8565b905060200201358b8b86818110611ff757611ff76151e8565b9050602002013560405160008152602001604052604051612034949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015612056573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff81166000908152600c602090815290849020838501909452925460ff8082161515808552610100909204169383019390935290955093509050612104576040517f0f4c073700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015160080260ff166001901b84019350808061212290615217565b915050611fa2565b50827e01010101010101010101010101010101010101010101010101010101010101841614612185576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050565b6121cc6040518060c001604052806000815260200160008152602001606081526020016060815260200160608152602001606081525090565b60006121da83850185615822565b60408101515160608201515191925090811415806121fd57508082608001515114155b8061220d5750808260a001515114155b15612244576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b509392505050565b600082604001515167ffffffffffffffff81111561226c5761226c6146a7565b60405190808252806020026020018201604052801561233857816020015b6040805161020081018252600060e08201818152610100830182905261012083018290526101408301829052610160830182905261018083018290526101a083018290526101c083018290526101e0830182905282526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161228a5790505b50905060006040518060800160405280600061ffff16815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff16815260200160008152509050600085610100015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123fa9190614f93565b6101008701516040517f7810d12a00000000000000000000000000000000000000000000000000000000815236600482015291925060009173ffffffffffffffffffffffffffffffffffffffff90911690637810d12a90602401602060405180830381865afa158015612471573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124959190614f93565b905060005b8660400151518110156129255760046000886040015183815181106124c1576124c16151e8565b6020908102919091018101518252818101929092526040908101600020815161012081018352815460ff8082161515835261010080830490911615159583019590955263ffffffff620100008204811694830194909452660100000000000081048416606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490931660e08201526002909101549091169181019190915285518690839081106125e4576125e46151e8565b6020026020010151600001819052506126198760400151828151811061260c5761260c6151e8565b60200260200101516132cc565b85828151811061262b5761262b6151e8565b60200260200101516060019060018111156126485761264861565d565b9081600181111561265b5761265b61565d565b815250506126bf87604001518281518110612678576126786151e8565b60200260200101518489608001518481518110612697576126976151e8565b60200260200101518885815181106126b1576126b16151e8565b60200260200101518c613377565b8683815181106126d1576126d16151e8565b60200260200101516020018784815181106126ee576126ee6151e8565b602002602001015160c0018281525082151515158152505050848181518110612719576127196151e8565b602002602001015160200151156127495760018460000181815161273d919061590f565b61ffff1690525061274e565b612913565b6127b4858281518110612763576127636151e8565b6020026020010151600001516080015188606001518381518110612789576127896151e8565b60200260200101518960a0015184815181106127a7576127a76151e8565b6020026020010151613496565b8683815181106127c6576127c66151e8565b60200260200101516040018784815181106127e3576127e36151e8565b602002602001015160800182815250821515151581525050508760800151600161280d919061530f565b61281b9060ff1660406152e5565b6103a48860a001518381518110612834576128346151e8565b60200260200101515161284791906152fc565b61285191906152fc565b858281518110612863576128636151e8565b602002602001015160a0018181525050848181518110612885576128856151e8565b602002602001015160a00151846060018181516128a291906152fc565b90525084518590829081106128b9576128b96151e8565b602002602001015160800151866128d091906151a0565b9550612913876040015182815181106128eb576128eb6151e8565b602002602001015184878481518110612906576129066151e8565b60200260200101516136b1565b8061291d81615217565b91505061249a565b50825161ffff1660000361293c5750505050505050565b61c80061294a3660106152e5565b5a61295590886151a0565b61295f91906152fc565b61296991906152fc565b8351909550613778906129809061ffff1687615959565b61298a91906152fc565b60408051608081018252600080825260208201819052918101829052606081018290529196506129b9896137b6565b905060005b886040015151811015612cf5578681815181106129dd576129dd6151e8565b60200260200101516020015115612ce357801580612a75575086612a026001836151a0565b81518110612a1257612a126151e8565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff16878281518110612a4b57612a4b6151e8565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff1614155b15612aa957612aa68a888381518110612a9057612a906151e8565b60200260200101516000015161010001516138a0565b92505b6000612bc78b6040518061012001604052808b8681518110612acd57612acd6151e8565b60200260200101516080015181526020018c81526020018a606001518c8781518110612afb57612afb6151e8565b602002602001015160a001518a612b1291906152e5565b612b1c9190615959565b81526020018d6000015181526020018d6020015181526020018681526020018b8681518110612b4d57612b4d6151e8565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff168152602001878152602001600115158152508c604001518581518110612b9c57612b9c6151e8565b60200260200101518b8681518110612bb657612bb66151e8565b602002602001015160000151613a1c565b9050806060015187604001818151612bdf919061596d565b6bffffffffffffffffffffffff169052506040810151602088018051612c0690839061596d565b6bffffffffffffffffffffffff169052508751889083908110612c2b57612c2b6151e8565b60200260200101516040015115158a604001518381518110612c4f57612c4f6151e8565b60200260200101517fad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b83602001518460000151612c8c919061596d565b8b8681518110612c9e57612c9e6151e8565b6020026020010151608001518d8f608001518881518110612cc157612cc16151e8565b6020026020010151604051612cd99493929190615992565b60405180910390a3505b80612ced81615217565b9150506129be565b505050602083810151336000908152600b90925260409091208054600290612d329084906201000090046bffffffffffffffffffffffff1661596d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508260400151601460000160008282829054906101000a90046bffffffffffffffffffffffff16612d90919061596d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555082604001518360200151612dd2919061596d565b6bffffffffffffffffffffffff16602160007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254612e4e91906152fc565b909155505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603612edb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610c8c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e010000000000000000000000000000900490911660608201529061314d576000816060015185612fe991906159cf565b90506000612ff785836159f4565b9050808360400181815161300b919061596d565b6bffffffffffffffffffffffff169052506130268582615a1f565b83606001818151613037919061596d565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b60400151949350505050565b6000826000018281548110613170576131706151e8565b9060005260206000200154905092915050565b6000818152600183016020526040812054801561326c5760006131a76001836151a0565b85549091506000906131bb906001906151a0565b90508181146132205760008660000182815481106131db576131db6151e8565b90600052602060002001549050808760000184815481106131fe576131fe6151e8565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061323157613231615a4f565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611ecd565b6000915050611ecd565b5092915050565b60008181526001830160205260408120546132c457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611ecd565b506000611ecd565b6000818160045b600f811015613359577fff000000000000000000000000000000000000000000000000000000000000008216838260208110613311576133116151e8565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461334757506000949350505050565b8061335181615217565b9150506132d3565b5081600f1a600181111561336f5761336f61565d565b949350505050565b6000808080856060015160018111156133925761339261565d565b036133b8576133a48888888888613e8b565b6133b35760009250905061348c565b613430565b6001856060015160018111156133d0576133d061565d565b036133fe5760006133e389898988614015565b92509050806133f8575060009250905061348c565b50613430565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84516060015163ffffffff16871061348557877fc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636876040516134729190614d1a565b60405180910390a260009250905061348c565b6001925090505b9550959350505050565b601454600090819077010000000000000000000000000000000000000000000000900460ff16156134f3576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16770100000000000000000000000000000000000000000000001790556040517f4585e33b0000000000000000000000000000000000000000000000000000000090613568908590602401614d1a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d169061363b9087908790600401615a7e565b60408051808303816000875af1158015613659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061367d9190615a97565b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16905590969095509350505050565b6000816060015160018111156136c9576136c961565d565b0361372d57600083815260046020526040902060010180547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff851602179055505050565b6001816060015160018111156137455761374561565d565b036137b15760c08101805160009081526008602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055915191517fa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f29190a25b505050565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613826573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061384a9190615adf565b5093505092505060008213158061386057508042105b8061389057506000846040015162ffffff16118015613890575061388481426151a0565b846040015162ffffff16105b15613276575050601b5492915050565b60408051608081018252600080825260208083018281528385018381526060850184905273ffffffffffffffffffffffffffffffffffffffff878116855260229093528584208054640100000000810462ffffff1690925263ffffffff82169092527b01000000000000000000000000000000000000000000000000000000810460ff16855285517ffeaf968c00000000000000000000000000000000000000000000000000000000815295519495919484936701000000000000009092049091169163feaf968c9160048083019260a09291908290030181865afa15801561398d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b19190615adf565b509350509250506000821315806139c757508042105b806139f757506000866040015162ffffff161180156139f757506139eb81426151a0565b866040015162ffffff16105b15613a0b5760018301546060850152613a13565b606084018290525b50505092915050565b604080516101008101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201529082015115613ab25760008381526023602090815260409182902082518084018452905463ffffffff811680835262ffffff640100000000909204821692840192835260e089018051909401529051915191169101525b6000613abe8686614222565b60c0840151602082015182519293509091600091613adb9161596d565b60e08801515190915060ff16600060128210613af8576001613b0e565b613b038260126151a0565b613b0e90600a615c4f565b9050600060128311613b21576001613b37565b613b2c6012846151a0565b613b3790600a615c4f565b905085600001516bffffffffffffffffffffffff16856bffffffffffffffffffffffff161015613bdf57849350613bb3818b60800151613b7791906152e5565b838c60e0015160600151886bffffffffffffffffffffffff16613b9a91906152e5565b613ba491906152e5565b613bae9190615959565b614550565b6bffffffffffffffffffffffff9081166040880152600060608801819052602088015285168652613d05565b836bffffffffffffffffffffffff16856bffffffffffffffffffffffff161015613d0557849350613c6d86604001516bffffffffffffffffffffffff16828c60800151613c2c91906152e5565b848d60e0015160600151896bffffffffffffffffffffffff16613c4f91906152e5565b613c5991906152e5565b613c639190615959565b613bae91906151a0565b6bffffffffffffffffffffffff1660608088019190915260e08b01510151613cf190613c9a9084906152e5565b6001848d60e0015160600151613cb091906152e5565b613cba91906151a0565b838d608001518a606001516bffffffffffffffffffffffff16613cdd91906152e5565b613ce791906152e5565b613ba491906152fc565b6bffffffffffffffffffffffff1660208701525b60008981526004602052604090206001018054859190601090613d4b90849070010000000000000000000000000000000090046bffffffffffffffffffffffff166159cf565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008b81526004602052604081206001018054928816935091613da69084906fffffffffffffffffffffffffffffffff16615c5b565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550836bffffffffffffffffffffffff16602160008c60c0015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254613e3d91906151a0565b92505081905550887f801ba6ed51146ffe3e99d1dbd9dd0f4de6292e78a9a34c39c0183de17b3f40fc87604051613e749190615c84565b60405180910390a250939998505050505050505050565b60008084806020019051810190613ea29190615d44565b845160e00151815191925063ffffffff90811691161015613eff57867f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e886604051613eed9190614d1a565b60405180910390a2600091505061400c565b8260e001518015613fbf5750602081015115801590613fbf5750602081015161010084015182516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa158015613f98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fbc9190614f93565b14155b80613fd15750805163ffffffff168611155b1561400657867f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc30186604051613eed9190614d1a565b60019150505b95945050505050565b60008060008480602001905181019061402e9190615d9c565b905060008782600001518360200151846040015160405160200161409094939291909384526020840192909252604083015260e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606082015260640190565b6040516020818303038152906040528051906020012090508460e00151801561416b575060808201511580159061416b5750608082015161010086015160608401516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa158015614144573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141689190614f93565b14155b80614180575086826060015163ffffffff1610155b156141ca57877f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301876040516141b59190614d1a565b60405180910390a26000935091506142199050565b60008181526008602052604090205460ff161561421157877f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8876040516141b59190614d1a565b600193509150505b94509492505050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915260008260e001516000015160ff1690506000846060015161ffff16846060015161428d91906152e5565b905083610100015180156142a05750803a105b156142a857503a5b6000601283116142b95760016142cf565b6142c46012846151a0565b6142cf90600a615c4f565b90506000601284106142e25760016142f8565b6142ed8460126151a0565b6142f890600a615c4f565b905060008660a0015187604001518860200151896000015161431a91906152fc565b61432490876152e5565b61432e91906152fc565b61433891906152e5565b905061437b828860e001516060015161435191906152e5565b6001848a60e001516060015161436791906152e5565b61437191906151a0565b613ce786856152e5565b6bffffffffffffffffffffffff168652608087015161439e90613bae9083615959565b6bffffffffffffffffffffffff1660408088019190915260e088015101516000906143d79062ffffff16683635c9adc5dea000006152e5565b9050600081633b9aca008a60a001518b60e001516020015163ffffffff168c604001518d600001518b61440a91906152e5565b61441491906152fc565b61441e91906152e5565b61442891906152e5565b6144329190615959565b61443c91906152fc565b905061447f848a60e001516060015161445591906152e5565b6001868c60e001516060015161446b91906152e5565b61447591906151a0565b613ce788856152e5565b6bffffffffffffffffffffffff16602089015260808901516144a590613bae9083615959565b6bffffffffffffffffffffffff16606089015260c089015173ffffffffffffffffffffffffffffffffffffffff166080808a01919091528901516144e890614550565b6bffffffffffffffffffffffff1660a0808a019190915289015161450b90614550565b6bffffffffffffffffffffffff1660c089015260e08901516060015161453090614550565b6bffffffffffffffffffffffff1660e08901525050505050505092915050565b60006bffffffffffffffffffffffff8211156145ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610c8c565b5090565b508054600082559060005260206000209081019061109c9190614692565b82805482825590600052602060002090810192821561468a579160200282015b8281111561468a57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190614630565b506145ee9291505b5b808211156145ee5760008155600101614693565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610200810167ffffffffffffffff811182821017156146fa576146fa6146a7565b60405290565b60405160c0810167ffffffffffffffff811182821017156146fa576146fa6146a7565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561476a5761476a6146a7565b604052919050565b600067ffffffffffffffff82111561478c5761478c6146a7565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff8116811461109c57600080fd5b80356147c381614796565b919050565b600082601f8301126147d957600080fd5b813560206147ee6147e983614772565b614723565b82815260059290921b8401810191818101908684111561480d57600080fd5b8286015b8481101561483157803561482481614796565b8352918301918301614811565b509695505050505050565b60ff8116811461109c57600080fd5b80356147c38161483c565b63ffffffff8116811461109c57600080fd5b80356147c381614856565b801515811461109c57600080fd5b80356147c381614873565b62ffffff8116811461109c57600080fd5b80356147c38161488c565b61ffff8116811461109c57600080fd5b80356147c3816148a8565b600061020082840312156148d657600080fd5b6148de6146d6565b90506148e982614868565b81526148f760208301614868565b602082015261490860408301614868565b6040820152614919606083016147b8565b606082015261492a60808301614881565b608082015261493b60a0830161489d565b60a082015261494c60c08301614868565b60c082015261495d60e08301614868565b60e08201526101006149708184016147b8565b908201526101206149828382016148b8565b908201526101406149948382016147b8565b90820152610160828101359082015261018080830135908201526101a080830135908201526101c08083013567ffffffffffffffff8111156149d557600080fd5b6149e1858286016147c8565b8284015250506101e06149f58184016147b8565b9082015292915050565b803567ffffffffffffffff811681146147c357600080fd5b600082601f830112614a2857600080fd5b813567ffffffffffffffff811115614a4257614a426146a7565b614a7360207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614723565b818152846020838601011115614a8857600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff8116811461109c57600080fd5b600082601f830112614ad057600080fd5b81356020614ae06147e983614772565b82815260c09283028501820192828201919087851115614aff57600080fd5b8387015b85811015614b915781818a031215614b1b5760008081fd5b614b23614700565b8135614b2e81614856565b815281860135614b3d8161488c565b81870152604082810135614b5081614796565b90820152606082810135614b638161483c565b908201526080828101359082015260a080830135614b8081614aa5565b908201528452928401928101614b03565b5090979650505050505050565b600080600080600080600080610100898b031215614bbb57600080fd5b883567ffffffffffffffff80821115614bd357600080fd5b614bdf8c838d016147c8565b995060208b0135915080821115614bf557600080fd5b614c018c838d016147c8565b9850614c0f60408c0161484b565b975060608b0135915080821115614c2557600080fd5b614c318c838d016148c3565b9650614c3f60808c016149ff565b955060a08b0135915080821115614c5557600080fd5b614c618c838d01614a17565b945060c08b0135915080821115614c7757600080fd5b614c838c838d016147c8565b935060e08b0135915080821115614c9957600080fd5b50614ca68b828c01614abf565b9150509295985092959890939650565b6000815180845260005b81811015614cdc57602081850181015186830182015201614cc0565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000611edf6020830184614cb6565b60008083601f840112614d3f57600080fd5b50813567ffffffffffffffff811115614d5757600080fd5b6020830191508360208260051b8501011115614d7257600080fd5b9250929050565b60008060008060008060008060e0898b031215614d9557600080fd5b606089018a811115614da657600080fd5b8998503567ffffffffffffffff80821115614dc057600080fd5b818b0191508b601f830112614dd457600080fd5b813581811115614de357600080fd5b8c6020828501011115614df557600080fd5b6020830199508098505060808b0135915080821115614e1357600080fd5b614e1f8c838d01614d2d565b909750955060a08b0135915080821115614e3857600080fd5b50614e458b828c01614d2d565b999c989b50969995989497949560c00135949350505050565b60008060008060008060c08789031215614e7757600080fd5b863567ffffffffffffffff80821115614e8f57600080fd5b614e9b8a838b016147c8565b97506020890135915080821115614eb157600080fd5b614ebd8a838b016147c8565b9650614ecb60408a0161484b565b95506060890135915080821115614ee157600080fd5b614eed8a838b01614a17565b9450614efb60808a016149ff565b935060a0890135915080821115614f1157600080fd5b50614f1e89828a01614a17565b9150509295509295509295565b600060208284031215614f3d57600080fd5b8135611edf81614796565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60ff818116838216029081169081811461327657613276614f48565b600060208284031215614fa557600080fd5b5051919050565b63ffffffff81811683821601908082111561327657613276614f48565b600081518084526020808501945080840160005b8381101561500f57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614fdd565b509495945050505050565b6020815261503160208201835163ffffffff169052565b6000602083015161504a604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015173ffffffffffffffffffffffffffffffffffffffff8116608084015250608083015180151560a08401525060a083015162ffffff811660c08401525060c083015163ffffffff811660e08401525060e08301516101006150c98185018363ffffffff169052565b84015190506101206150f28482018373ffffffffffffffffffffffffffffffffffffffff169052565b84015190506101406151098482018361ffff169052565b84015190506101606151328482018373ffffffffffffffffffffffffffffffffffffffff169052565b840151610180848101919091528401516101a0808501919091528401516101c0808501919091528401516102006101e08086018290529192509061517a610220860184614fc9565b95015173ffffffffffffffffffffffffffffffffffffffff169301929092525090919050565b81810381811115611ecd57611ecd614f48565b6000816151c2576151c2614f48565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361524857615248614f48565b5060010190565b600061012063ffffffff808d1684528b6020850152808b1660408501525080606084015261527f8184018a614fc9565b905082810360808401526152938189614fc9565b905060ff871660a084015282810360c08401526152b08187614cb6565b905067ffffffffffffffff851660e08401528281036101008401526152d58185614cb6565b9c9b505050505050505050505050565b8082028115828204841417611ecd57611ecd614f48565b80820180821115611ecd57611ecd614f48565b60ff8181168382160190811115611ecd57611ecd614f48565b80516147c381614856565b80516147c381614796565b80516147c381614873565b80516147c38161488c565b80516147c3816148a8565b600082601f83011261537057600080fd5b815160206153806147e983614772565b82815260059290921b8401810191818101908684111561539f57600080fd5b8286015b848110156148315780516153b681614796565b83529183019183016153a3565b600082601f8301126153d457600080fd5b815160206153e46147e983614772565b82815260c0928302850182019282820191908785111561540357600080fd5b8387015b85811015614b915781818a03121561541f5760008081fd5b615427614700565b815161543281614856565b8152818601516154418161488c565b8187015260408281015161545481614796565b908201526060828101516154678161483c565b908201526080828101519082015260a08083015161548481614aa5565b908201528452928401928101615407565b6000806000606084860312156154aa57600080fd5b835167ffffffffffffffff808211156154c257600080fd5b9085019061020082880312156154d757600080fd5b6154df6146d6565b6154e883615328565b81526154f660208401615328565b602082015261550760408401615328565b604082015261551860608401615333565b60608201526155296080840161533e565b608082015261553a60a08401615349565b60a082015261554b60c08401615328565b60c082015261555c60e08401615328565b60e082015261010061556f818501615333565b90820152610120615581848201615354565b90820152610140615593848201615333565b90820152610160838101519082015261018080840151908201526101a080840151908201526101c080840151838111156155cc57600080fd5b6155d88a82870161535f565b8284015250506101e06155ec818501615333565b90820152602087015190955091508082111561560757600080fd5b6156138783880161535f565b9350604086015191508082111561562957600080fd5b50615636868287016153c3565b9150509250925092565b60006020828403121561565257600080fd5b8151611edf8161483c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526156d38285018b614fc9565b915083820360808501526156e7828a614fc9565b915060ff881660a085015283820360c08501526157048288614cb6565b90861660e085015283810361010085015290506152d58185614cb6565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b600082601f83011261575857600080fd5b813560206157686147e983614772565b82815260059290921b8401810191818101908684111561578757600080fd5b8286015b84811015614831578035835291830191830161578b565b600082601f8301126157b357600080fd5b813560206157c36147e983614772565b82815260059290921b840181019181810190868411156157e257600080fd5b8286015b8481101561483157803567ffffffffffffffff8111156158065760008081fd5b6158148986838b0101614a17565b8452509183019183016157e6565b60006020828403121561583457600080fd5b813567ffffffffffffffff8082111561584c57600080fd5b9083019060c0828603121561586057600080fd5b615868614700565b823581526020830135602082015260408301358281111561588857600080fd5b61589487828601615747565b6040830152506060830135828111156158ac57600080fd5b6158b887828601615747565b6060830152506080830135828111156158d057600080fd5b6158dc878286016157a2565b60808301525060a0830135828111156158f457600080fd5b615900878286016157a2565b60a08301525095945050505050565b61ffff81811683821601908082111561327657613276614f48565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826159685761596861592a565b500490565b6bffffffffffffffffffffffff81811683821601908082111561327657613276614f48565b6bffffffffffffffffffffffff851681528360208201528260408201526080606082015260006159c56080830184614cb6565b9695505050505050565b6bffffffffffffffffffffffff82811682821603908082111561327657613276614f48565b60006bffffffffffffffffffffffff80841680615a1357615a1361592a565b92169190910492915050565b6bffffffffffffffffffffffff818116838216028082169190828114615a4757615a47614f48565b505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b82815260406020820152600061336f6040830184614cb6565b60008060408385031215615aaa57600080fd5b8251615ab581614873565b6020939093015192949293505050565b805169ffffffffffffffffffff811681146147c357600080fd5b600080600080600060a08688031215615af757600080fd5b615b0086615ac5565b9450602086015193506040860151925060608601519150615b2360808701615ac5565b90509295509295909350565b600181815b80851115615b8857817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615b6e57615b6e614f48565b80851615615b7b57918102915b93841c9390800290615b34565b509250929050565b600082615b9f57506001611ecd565b81615bac57506000611ecd565b8160018114615bc25760028114615bcc57615be8565b6001915050611ecd565b60ff841115615bdd57615bdd614f48565b50506001821b611ecd565b5060208310610133831016604e8410600b8410161715615c0b575081810a611ecd565b615c158383615b2f565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615c4757615c47614f48565b029392505050565b6000611edf8383615b90565b6fffffffffffffffffffffffffffffffff81811683821601908082111561327657613276614f48565b6000610100820190506bffffffffffffffffffffffff8084511683528060208501511660208401528060408501511660408401528060608501511660608401525073ffffffffffffffffffffffffffffffffffffffff608084015116608083015260a0830151615d0460a08401826bffffffffffffffffffffffff169052565b5060c0830151615d2460c08401826bffffffffffffffffffffffff169052565b5060e083015161327660e08401826bffffffffffffffffffffffff169052565b600060408284031215615d5657600080fd5b6040516040810181811067ffffffffffffffff82111715615d7957615d796146a7565b6040528251615d8781614856565b81526020928301519281019290925250919050565b600060a08284031215615dae57600080fd5b60405160a0810181811067ffffffffffffffff82111715615dd157615dd16146a7565b806040525082518152602083015160208201526040830151615df281614856565b60408201526060830151615e0581614856565b6060820152608092830151928101929092525091905056fea164736f6c6343000813000a000000000000000000000000ae778b63fcb0c6b57c9a9e839c0706c7a0496489
Deployed Bytecode
0x6080604052600436106100b15760003560e01c80638da5cb5b11610069578063b1dc65a41161004e578063b1dc65a4146102cb578063e3d0e712146102eb578063f2fde38b1461030b576100b1565b80638da5cb5b1461025a578063afcb95d714610285576100b1565b8063349e8cca1161009a578063349e8cca1461017757806379ba5097146101cb57806381ff7048146101e0576100b1565b80630870d3a1146100f8578063181f5a7714610118575b7f000000000000000000000000ae778b63fcb0c6b57c9a9e839c0706c7a04964893660008037600080366000845af43d6000803e8080156100f1573d6000f35b3d6000fd5b005b34801561010457600080fd5b506100f6610113366004614b9e565b61032b565b34801561012457600080fd5b506101616040518060400160405280601881526020017f4175746f6d6174696f6e526567697374727920322e332e30000000000000000081525081565b60405161016e9190614d1a565b60405180910390f35b34801561018357600080fd5b507f000000000000000000000000ae778b63fcb0c6b57c9a9e839c0706c7a04964895b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161016e565b3480156101d757600080fd5b506100f6610c0f565b3480156101ec57600080fd5b5061023760175460135463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff94851681529390921660208401529082015260600161016e565b34801561026657600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166101a6565b34801561029157600080fd5b50601354601454604080516000815260208101939093526c0100000000000000000000000090910463ffffffff169082015260600161016e565b3480156102d757600080fd5b506100f66102e6366004614d79565b610d11565b3480156102f757600080fd5b506100f6610306366004614e5e565b611051565b34801561031757600080fd5b506100f6610326366004614f2b565b61108b565b61033361109f565b601f8851111561036f576040517f25d0209c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8560ff166000036103ac576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b865188511415806103cb57506103c3866003614f77565b60ff16885111155b15610402576040517f1d2d1c5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805182511461043d576040517fcf54c06a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104478282611122565b610451888861175a565b604051806101200160405280601460000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff168152602001600063ffffffff1681526020018660a0015162ffffff16815260200186610120015161ffff1681526020018760ff168152602001601460000160169054906101000a900460ff1615158152602001601460000160179054906101000a900460ff1615158152602001866080015115158152602001866101e0015173ffffffffffffffffffffffffffffffffffffffff16815250601460008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160106101000a81548162ffffff021916908362ffffff16021790555060608201518160000160136101000a81548161ffff021916908361ffff16021790555060808201518160000160156101000a81548160ff021916908360ff16021790555060a08201518160000160166101000a81548160ff02191690831515021790555060c08201518160000160176101000a81548160ff02191690831515021790555060e08201518160000160186101000a81548160ff0219169083151502179055506101008201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050506000601660010160189054906101000a900463ffffffff1690506000866101e0015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610701573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107259190614f93565b6017549091506000906107579074010000000000000000000000000000000000000000900463ffffffff166001614fac565b9050604051806101600160405280896060015173ffffffffffffffffffffffffffffffffffffffff168152602001896000015163ffffffff168152602001896020015163ffffffff1681526020016016600001601c9054906101000a900463ffffffff1663ffffffff16815260200189610100015173ffffffffffffffffffffffffffffffffffffffff1681526020018263ffffffff1681526020018363ffffffff168152602001896040015163ffffffff16815260200189610140015173ffffffffffffffffffffffffffffffffffffffff1681526020018960c0015163ffffffff1681526020018960e0015163ffffffff16815250601660008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a08201518160010160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101208201518160020160146101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160186101000a81548163ffffffff021916908363ffffffff160217905550905050876101600151601981905550876101800151601a81905550876101a00151601b81905550600088604051602001610a9a919061501a565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152919052601754909150610aff904690309074010000000000000000000000000000000000000000900463ffffffff168f8f8f878f8f611e19565b6013556000610b0e6009611ec3565b90505b8015610b4b57610b38610b30610b286001846151a0565b600990611ed3565b600990611ee6565b5080610b43816151b3565b915050610b11565b5060005b896101c0015151811015610ba257610b8f8a6101c001518281518110610b7757610b776151e8565b60200260200101516009611f0890919063ffffffff16565b5080610b9a81615217565b915050610b4f565b507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0584601354601660010160149054906101000a900463ffffffff168f8f8f878f8f604051610bf99998979695949392919061524f565b60405180910390a1505050505050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610c95576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005a90506000610d238660406152e5565b610d2f896101446152fc565b610d3991906152fc565b9050368114610d74576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051610120810182526014546bffffffffffffffffffffffff8116825263ffffffff6c01000000000000000000000000820416602083015262ffffff7001000000000000000000000000000000008204169282019290925261ffff730100000000000000000000000000000000000000830416606082015260ff75010000000000000000000000000000000000000000008304811660808301527601000000000000000000000000000000000000000000008304811615801560a08401527701000000000000000000000000000000000000000000000084048216151560c0840152780100000000000000000000000000000000000000000000000090930416151560e082015260155473ffffffffffffffffffffffffffffffffffffffff1661010082015290610ed3576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b602052604090205460ff16610f1c576040517f1099ed7500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6013548b3514610f58576040517fdfdcf8e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6080810151610f6890600161530f565b60ff1687141580610f795750868514155b15610fb0576040517f0244f71a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fc08b8b8b8b8b8b8b8b611f2a565b6000610fcc8b8b612193565b905060208c0135600881901c63ffffffff16610fe984848861224c565b836020015163ffffffff168163ffffffff16111561104157601480547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff8416021790555b5050505050505050505050505050565b60008060008580602001905181019061106a9190615495565b925092509250611080898989868989888861032b565b505050505050505050565b61109361109f565b61109c81612e5c565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314611120576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610c8c565b565b60005b6024548110156111e0576022600060248381548110611146576111466151e8565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181019190915560020180547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000169055806111d881615217565b915050611125565b506111ed602460006145f2565b60255460ff1660005b8351811015611754576000848281518110611213576112136151e8565b602002602001015190506000848381518110611231576112316151e8565b602002602001015190508173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611286573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112aa9190615640565b60ff16816060015160ff161415806113385750806040015173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561130c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113309190615640565b60ff16600814155b1561136f576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000005576815a38a3706f37bf815b261ccc7cca77e97573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480156113db575060018460018111156113d9576113d961565d565b145b15611412576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216158061144d5750604081015173ffffffffffffffffffffffffffffffffffffffff16155b15611484576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff828116600090815260226020526040902054670100000000000000900416156114ee576040517f357d0cc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6024805460018181019092557f7cd332d19b93bcabe3cce7ca0c18a052f57e5fd03b4758a09f30f5ddc4b22ec401805473ffffffffffffffffffffffffffffffffffffffff8086167fffffffffffffffffffffffff0000000000000000000000000000000000000000909216821790925560008181526022602090815260409182902086518154928801518489015160608a015160ff167b01000000000000000000000000000000000000000000000000000000027fffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffff9190981667010000000000000002167fffffffff000000000000000000000000000000000000000000ffffffffffffff62ffffff909216640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000090951663ffffffff9093169290921793909317929092169190911793909317835560808501519383019390935560a0840151600290920180546bffffffffffffffffffffffff9093167fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009093169290921790915590517fca93cbe727c73163ec538f71be6c0a64877d7f1f6dd35d5ca7cbaef3a3e34ba390611737908490600060c08201905063ffffffff835116825262ffffff602084015116602083015273ffffffffffffffffffffffffffffffffffffffff604084015116604083015260ff6060840151166060830152608083015160808301526bffffffffffffffffffffffff60a08401511660a083015292915050565b60405180910390a25050808061174c90615217565b9150506111f6565b50505050565b600e546014546bffffffffffffffffffffffff1660005b600e548110156117cd576117ba600e8281548110611791576117916151e8565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff168385612f51565b50806117c581615217565b915050611771565b5060255460009060ff16815b600e5481101561193e57600e81815481106117f6576117f66151e8565b6000918252602082200154600d805473ffffffffffffffffffffffffffffffffffffffff9092169550600c929184908110611833576118336151e8565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff9081168452838201949094526040928301822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690559286168152600b909252902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905560018260018111156118d5576118d561565d565b14801561191a575073ffffffffffffffffffffffffffffffffffffffff83166000908152600b60205260409020546201000090046bffffffffffffffffffffffff1615155b1561192c5761192a600f84611f08565b505b8061193681615217565b9150506117d9565b5061194b600d60006145f2565b611957600e60006145f2565b6040805160808101825260008082526020820181905291810182905260608101829052905b8751811015611de757600c600089838151811061199b5761199b6151e8565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff1615611a06576040517f77cea0fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16888281518110611a3057611a306151e8565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611a85576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806001151581526020018260ff16815250600c60008a8481518110611ab657611ab66151e8565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528181019290925260400160002082518154939092015160ff16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909316929092171790558651879082908110611b5e57611b5e6151e8565b60200260200101519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603611bce576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff84166000908152600b60209081526040918290208251608081018452905460ff80821615801584526101008304909116938301939093526bffffffffffffffffffffffff6201000082048116948301949094526e01000000000000000000000000000090049092166060830152909250611c89576040517f6a7281ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180835260ff80831660208086019182526014546bffffffffffffffffffffffff9081166060880190815273ffffffffffffffffffffffffffffffffffffffff8a166000908152600b909352604092839020885181549551948a0151925184166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff939094166201000002929092167fffffffffffff000000000000000000000000000000000000000000000000ffff94909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090951694909417179190911692909217919091179055836001811115611dc357611dc361565d565b03611dd557611dd3600f85611ee6565b505b80611ddf81615217565b91505061197c565b508651611dfb90600d9060208a0190614610565b508551611e0f90600e906020890190614610565b5050505050505050565b6000808a8a8a8a8a8a8a8a8a604051602001611e3d9998979695949392919061568c565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179b9a5050505050505050505050565b6000611ecd825490565b92915050565b6000611edf8383613159565b9392505050565b6000611edf8373ffffffffffffffffffffffffffffffffffffffff8416613183565b6000611edf8373ffffffffffffffffffffffffffffffffffffffff841661327d565b60008787604051611f3c929190615721565b604051908190038120611f53918b90602001615731565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201208383019092526000808452908301819052909250906000805b8881101561212a57600185878360208110611fbf57611fbf6151e8565b611fcc91901a601b61530f565b8c8c85818110611fde57611fde6151e8565b905060200201358b8b86818110611ff757611ff76151e8565b9050602002013560405160008152602001604052604051612034949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015612056573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff81166000908152600c602090815290849020838501909452925460ff8082161515808552610100909204169383019390935290955093509050612104576040517f0f4c073700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015160080260ff166001901b84019350808061212290615217565b915050611fa2565b50827e01010101010101010101010101010101010101010101010101010101010101841614612185576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050565b6121cc6040518060c001604052806000815260200160008152602001606081526020016060815260200160608152602001606081525090565b60006121da83850185615822565b60408101515160608201515191925090811415806121fd57508082608001515114155b8061220d5750808260a001515114155b15612244576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b509392505050565b600082604001515167ffffffffffffffff81111561226c5761226c6146a7565b60405190808252806020026020018201604052801561233857816020015b6040805161020081018252600060e08201818152610100830182905261012083018290526101408301829052610160830182905261018083018290526101a083018290526101c083018290526101e0830182905282526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161228a5790505b50905060006040518060800160405280600061ffff16815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff16815260200160008152509050600085610100015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123fa9190614f93565b6101008701516040517f7810d12a00000000000000000000000000000000000000000000000000000000815236600482015291925060009173ffffffffffffffffffffffffffffffffffffffff90911690637810d12a90602401602060405180830381865afa158015612471573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124959190614f93565b905060005b8660400151518110156129255760046000886040015183815181106124c1576124c16151e8565b6020908102919091018101518252818101929092526040908101600020815161012081018352815460ff8082161515835261010080830490911615159583019590955263ffffffff620100008204811694830194909452660100000000000081048416606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490931660e08201526002909101549091169181019190915285518690839081106125e4576125e46151e8565b6020026020010151600001819052506126198760400151828151811061260c5761260c6151e8565b60200260200101516132cc565b85828151811061262b5761262b6151e8565b60200260200101516060019060018111156126485761264861565d565b9081600181111561265b5761265b61565d565b815250506126bf87604001518281518110612678576126786151e8565b60200260200101518489608001518481518110612697576126976151e8565b60200260200101518885815181106126b1576126b16151e8565b60200260200101518c613377565b8683815181106126d1576126d16151e8565b60200260200101516020018784815181106126ee576126ee6151e8565b602002602001015160c0018281525082151515158152505050848181518110612719576127196151e8565b602002602001015160200151156127495760018460000181815161273d919061590f565b61ffff1690525061274e565b612913565b6127b4858281518110612763576127636151e8565b6020026020010151600001516080015188606001518381518110612789576127896151e8565b60200260200101518960a0015184815181106127a7576127a76151e8565b6020026020010151613496565b8683815181106127c6576127c66151e8565b60200260200101516040018784815181106127e3576127e36151e8565b602002602001015160800182815250821515151581525050508760800151600161280d919061530f565b61281b9060ff1660406152e5565b6103a48860a001518381518110612834576128346151e8565b60200260200101515161284791906152fc565b61285191906152fc565b858281518110612863576128636151e8565b602002602001015160a0018181525050848181518110612885576128856151e8565b602002602001015160a00151846060018181516128a291906152fc565b90525084518590829081106128b9576128b96151e8565b602002602001015160800151866128d091906151a0565b9550612913876040015182815181106128eb576128eb6151e8565b602002602001015184878481518110612906576129066151e8565b60200260200101516136b1565b8061291d81615217565b91505061249a565b50825161ffff1660000361293c5750505050505050565b61c80061294a3660106152e5565b5a61295590886151a0565b61295f91906152fc565b61296991906152fc565b8351909550613778906129809061ffff1687615959565b61298a91906152fc565b60408051608081018252600080825260208201819052918101829052606081018290529196506129b9896137b6565b905060005b886040015151811015612cf5578681815181106129dd576129dd6151e8565b60200260200101516020015115612ce357801580612a75575086612a026001836151a0565b81518110612a1257612a126151e8565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff16878281518110612a4b57612a4b6151e8565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff1614155b15612aa957612aa68a888381518110612a9057612a906151e8565b60200260200101516000015161010001516138a0565b92505b6000612bc78b6040518061012001604052808b8681518110612acd57612acd6151e8565b60200260200101516080015181526020018c81526020018a606001518c8781518110612afb57612afb6151e8565b602002602001015160a001518a612b1291906152e5565b612b1c9190615959565b81526020018d6000015181526020018d6020015181526020018681526020018b8681518110612b4d57612b4d6151e8565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff168152602001878152602001600115158152508c604001518581518110612b9c57612b9c6151e8565b60200260200101518b8681518110612bb657612bb66151e8565b602002602001015160000151613a1c565b9050806060015187604001818151612bdf919061596d565b6bffffffffffffffffffffffff169052506040810151602088018051612c0690839061596d565b6bffffffffffffffffffffffff169052508751889083908110612c2b57612c2b6151e8565b60200260200101516040015115158a604001518381518110612c4f57612c4f6151e8565b60200260200101517fad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b83602001518460000151612c8c919061596d565b8b8681518110612c9e57612c9e6151e8565b6020026020010151608001518d8f608001518881518110612cc157612cc16151e8565b6020026020010151604051612cd99493929190615992565b60405180910390a3505b80612ced81615217565b9150506129be565b505050602083810151336000908152600b90925260409091208054600290612d329084906201000090046bffffffffffffffffffffffff1661596d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508260400151601460000160008282829054906101000a90046bffffffffffffffffffffffff16612d90919061596d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555082604001518360200151612dd2919061596d565b6bffffffffffffffffffffffff16602160007f0000000000000000000000005576815a38a3706f37bf815b261ccc7cca77e97573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254612e4e91906152fc565b909155505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603612edb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610c8c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e010000000000000000000000000000900490911660608201529061314d576000816060015185612fe991906159cf565b90506000612ff785836159f4565b9050808360400181815161300b919061596d565b6bffffffffffffffffffffffff169052506130268582615a1f565b83606001818151613037919061596d565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b60400151949350505050565b6000826000018281548110613170576131706151e8565b9060005260206000200154905092915050565b6000818152600183016020526040812054801561326c5760006131a76001836151a0565b85549091506000906131bb906001906151a0565b90508181146132205760008660000182815481106131db576131db6151e8565b90600052602060002001549050808760000184815481106131fe576131fe6151e8565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061323157613231615a4f565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611ecd565b6000915050611ecd565b5092915050565b60008181526001830160205260408120546132c457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611ecd565b506000611ecd565b6000818160045b600f811015613359577fff000000000000000000000000000000000000000000000000000000000000008216838260208110613311576133116151e8565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461334757506000949350505050565b8061335181615217565b9150506132d3565b5081600f1a600181111561336f5761336f61565d565b949350505050565b6000808080856060015160018111156133925761339261565d565b036133b8576133a48888888888613e8b565b6133b35760009250905061348c565b613430565b6001856060015160018111156133d0576133d061565d565b036133fe5760006133e389898988614015565b92509050806133f8575060009250905061348c565b50613430565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84516060015163ffffffff16871061348557877fc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636876040516134729190614d1a565b60405180910390a260009250905061348c565b6001925090505b9550959350505050565b601454600090819077010000000000000000000000000000000000000000000000900460ff16156134f3576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16770100000000000000000000000000000000000000000000001790556040517f4585e33b0000000000000000000000000000000000000000000000000000000090613568908590602401614d1a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d169061363b9087908790600401615a7e565b60408051808303816000875af1158015613659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061367d9190615a97565b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16905590969095509350505050565b6000816060015160018111156136c9576136c961565d565b0361372d57600083815260046020526040902060010180547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff851602179055505050565b6001816060015160018111156137455761374561565d565b036137b15760c08101805160009081526008602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055915191517fa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f29190a25b505050565b60008060007f000000000000000000000000d94522a6fef7779f672f4c88eb672da9222f2eac73ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613826573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061384a9190615adf565b5093505092505060008213158061386057508042105b8061389057506000846040015162ffffff16118015613890575061388481426151a0565b846040015162ffffff16105b15613276575050601b5492915050565b60408051608081018252600080825260208083018281528385018381526060850184905273ffffffffffffffffffffffffffffffffffffffff878116855260229093528584208054640100000000810462ffffff1690925263ffffffff82169092527b01000000000000000000000000000000000000000000000000000000810460ff16855285517ffeaf968c00000000000000000000000000000000000000000000000000000000815295519495919484936701000000000000009092049091169163feaf968c9160048083019260a09291908290030181865afa15801561398d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b19190615adf565b509350509250506000821315806139c757508042105b806139f757506000866040015162ffffff161180156139f757506139eb81426151a0565b866040015162ffffff16105b15613a0b5760018301546060850152613a13565b606084018290525b50505092915050565b604080516101008101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201529082015115613ab25760008381526023602090815260409182902082518084018452905463ffffffff811680835262ffffff640100000000909204821692840192835260e089018051909401529051915191169101525b6000613abe8686614222565b60c0840151602082015182519293509091600091613adb9161596d565b60e08801515190915060ff16600060128210613af8576001613b0e565b613b038260126151a0565b613b0e90600a615c4f565b9050600060128311613b21576001613b37565b613b2c6012846151a0565b613b3790600a615c4f565b905085600001516bffffffffffffffffffffffff16856bffffffffffffffffffffffff161015613bdf57849350613bb3818b60800151613b7791906152e5565b838c60e0015160600151886bffffffffffffffffffffffff16613b9a91906152e5565b613ba491906152e5565b613bae9190615959565b614550565b6bffffffffffffffffffffffff9081166040880152600060608801819052602088015285168652613d05565b836bffffffffffffffffffffffff16856bffffffffffffffffffffffff161015613d0557849350613c6d86604001516bffffffffffffffffffffffff16828c60800151613c2c91906152e5565b848d60e0015160600151896bffffffffffffffffffffffff16613c4f91906152e5565b613c5991906152e5565b613c639190615959565b613bae91906151a0565b6bffffffffffffffffffffffff1660608088019190915260e08b01510151613cf190613c9a9084906152e5565b6001848d60e0015160600151613cb091906152e5565b613cba91906151a0565b838d608001518a606001516bffffffffffffffffffffffff16613cdd91906152e5565b613ce791906152e5565b613ba491906152fc565b6bffffffffffffffffffffffff1660208701525b60008981526004602052604090206001018054859190601090613d4b90849070010000000000000000000000000000000090046bffffffffffffffffffffffff166159cf565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008b81526004602052604081206001018054928816935091613da69084906fffffffffffffffffffffffffffffffff16615c5b565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550836bffffffffffffffffffffffff16602160008c60c0015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254613e3d91906151a0565b92505081905550887f801ba6ed51146ffe3e99d1dbd9dd0f4de6292e78a9a34c39c0183de17b3f40fc87604051613e749190615c84565b60405180910390a250939998505050505050505050565b60008084806020019051810190613ea29190615d44565b845160e00151815191925063ffffffff90811691161015613eff57867f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e886604051613eed9190614d1a565b60405180910390a2600091505061400c565b8260e001518015613fbf5750602081015115801590613fbf5750602081015161010084015182516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa158015613f98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fbc9190614f93565b14155b80613fd15750805163ffffffff168611155b1561400657867f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc30186604051613eed9190614d1a565b60019150505b95945050505050565b60008060008480602001905181019061402e9190615d9c565b905060008782600001518360200151846040015160405160200161409094939291909384526020840192909252604083015260e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606082015260640190565b6040516020818303038152906040528051906020012090508460e00151801561416b575060808201511580159061416b5750608082015161010086015160608401516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa158015614144573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141689190614f93565b14155b80614180575086826060015163ffffffff1610155b156141ca57877f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301876040516141b59190614d1a565b60405180910390a26000935091506142199050565b60008181526008602052604090205460ff161561421157877f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8876040516141b59190614d1a565b600193509150505b94509492505050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915260008260e001516000015160ff1690506000846060015161ffff16846060015161428d91906152e5565b905083610100015180156142a05750803a105b156142a857503a5b6000601283116142b95760016142cf565b6142c46012846151a0565b6142cf90600a615c4f565b90506000601284106142e25760016142f8565b6142ed8460126151a0565b6142f890600a615c4f565b905060008660a0015187604001518860200151896000015161431a91906152fc565b61432490876152e5565b61432e91906152fc565b61433891906152e5565b905061437b828860e001516060015161435191906152e5565b6001848a60e001516060015161436791906152e5565b61437191906151a0565b613ce786856152e5565b6bffffffffffffffffffffffff168652608087015161439e90613bae9083615959565b6bffffffffffffffffffffffff1660408088019190915260e088015101516000906143d79062ffffff16683635c9adc5dea000006152e5565b9050600081633b9aca008a60a001518b60e001516020015163ffffffff168c604001518d600001518b61440a91906152e5565b61441491906152fc565b61441e91906152e5565b61442891906152e5565b6144329190615959565b61443c91906152fc565b905061447f848a60e001516060015161445591906152e5565b6001868c60e001516060015161446b91906152e5565b61447591906151a0565b613ce788856152e5565b6bffffffffffffffffffffffff16602089015260808901516144a590613bae9083615959565b6bffffffffffffffffffffffff16606089015260c089015173ffffffffffffffffffffffffffffffffffffffff166080808a01919091528901516144e890614550565b6bffffffffffffffffffffffff1660a0808a019190915289015161450b90614550565b6bffffffffffffffffffffffff1660c089015260e08901516060015161453090614550565b6bffffffffffffffffffffffff1660e08901525050505050505092915050565b60006bffffffffffffffffffffffff8211156145ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610c8c565b5090565b508054600082559060005260206000209081019061109c9190614692565b82805482825590600052602060002090810192821561468a579160200282015b8281111561468a57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190614630565b506145ee9291505b5b808211156145ee5760008155600101614693565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610200810167ffffffffffffffff811182821017156146fa576146fa6146a7565b60405290565b60405160c0810167ffffffffffffffff811182821017156146fa576146fa6146a7565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561476a5761476a6146a7565b604052919050565b600067ffffffffffffffff82111561478c5761478c6146a7565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff8116811461109c57600080fd5b80356147c381614796565b919050565b600082601f8301126147d957600080fd5b813560206147ee6147e983614772565b614723565b82815260059290921b8401810191818101908684111561480d57600080fd5b8286015b8481101561483157803561482481614796565b8352918301918301614811565b509695505050505050565b60ff8116811461109c57600080fd5b80356147c38161483c565b63ffffffff8116811461109c57600080fd5b80356147c381614856565b801515811461109c57600080fd5b80356147c381614873565b62ffffff8116811461109c57600080fd5b80356147c38161488c565b61ffff8116811461109c57600080fd5b80356147c3816148a8565b600061020082840312156148d657600080fd5b6148de6146d6565b90506148e982614868565b81526148f760208301614868565b602082015261490860408301614868565b6040820152614919606083016147b8565b606082015261492a60808301614881565b608082015261493b60a0830161489d565b60a082015261494c60c08301614868565b60c082015261495d60e08301614868565b60e08201526101006149708184016147b8565b908201526101206149828382016148b8565b908201526101406149948382016147b8565b90820152610160828101359082015261018080830135908201526101a080830135908201526101c08083013567ffffffffffffffff8111156149d557600080fd5b6149e1858286016147c8565b8284015250506101e06149f58184016147b8565b9082015292915050565b803567ffffffffffffffff811681146147c357600080fd5b600082601f830112614a2857600080fd5b813567ffffffffffffffff811115614a4257614a426146a7565b614a7360207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614723565b818152846020838601011115614a8857600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff8116811461109c57600080fd5b600082601f830112614ad057600080fd5b81356020614ae06147e983614772565b82815260c09283028501820192828201919087851115614aff57600080fd5b8387015b85811015614b915781818a031215614b1b5760008081fd5b614b23614700565b8135614b2e81614856565b815281860135614b3d8161488c565b81870152604082810135614b5081614796565b90820152606082810135614b638161483c565b908201526080828101359082015260a080830135614b8081614aa5565b908201528452928401928101614b03565b5090979650505050505050565b600080600080600080600080610100898b031215614bbb57600080fd5b883567ffffffffffffffff80821115614bd357600080fd5b614bdf8c838d016147c8565b995060208b0135915080821115614bf557600080fd5b614c018c838d016147c8565b9850614c0f60408c0161484b565b975060608b0135915080821115614c2557600080fd5b614c318c838d016148c3565b9650614c3f60808c016149ff565b955060a08b0135915080821115614c5557600080fd5b614c618c838d01614a17565b945060c08b0135915080821115614c7757600080fd5b614c838c838d016147c8565b935060e08b0135915080821115614c9957600080fd5b50614ca68b828c01614abf565b9150509295985092959890939650565b6000815180845260005b81811015614cdc57602081850181015186830182015201614cc0565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000611edf6020830184614cb6565b60008083601f840112614d3f57600080fd5b50813567ffffffffffffffff811115614d5757600080fd5b6020830191508360208260051b8501011115614d7257600080fd5b9250929050565b60008060008060008060008060e0898b031215614d9557600080fd5b606089018a811115614da657600080fd5b8998503567ffffffffffffffff80821115614dc057600080fd5b818b0191508b601f830112614dd457600080fd5b813581811115614de357600080fd5b8c6020828501011115614df557600080fd5b6020830199508098505060808b0135915080821115614e1357600080fd5b614e1f8c838d01614d2d565b909750955060a08b0135915080821115614e3857600080fd5b50614e458b828c01614d2d565b999c989b50969995989497949560c00135949350505050565b60008060008060008060c08789031215614e7757600080fd5b863567ffffffffffffffff80821115614e8f57600080fd5b614e9b8a838b016147c8565b97506020890135915080821115614eb157600080fd5b614ebd8a838b016147c8565b9650614ecb60408a0161484b565b95506060890135915080821115614ee157600080fd5b614eed8a838b01614a17565b9450614efb60808a016149ff565b935060a0890135915080821115614f1157600080fd5b50614f1e89828a01614a17565b9150509295509295509295565b600060208284031215614f3d57600080fd5b8135611edf81614796565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60ff818116838216029081169081811461327657613276614f48565b600060208284031215614fa557600080fd5b5051919050565b63ffffffff81811683821601908082111561327657613276614f48565b600081518084526020808501945080840160005b8381101561500f57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614fdd565b509495945050505050565b6020815261503160208201835163ffffffff169052565b6000602083015161504a604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015173ffffffffffffffffffffffffffffffffffffffff8116608084015250608083015180151560a08401525060a083015162ffffff811660c08401525060c083015163ffffffff811660e08401525060e08301516101006150c98185018363ffffffff169052565b84015190506101206150f28482018373ffffffffffffffffffffffffffffffffffffffff169052565b84015190506101406151098482018361ffff169052565b84015190506101606151328482018373ffffffffffffffffffffffffffffffffffffffff169052565b840151610180848101919091528401516101a0808501919091528401516101c0808501919091528401516102006101e08086018290529192509061517a610220860184614fc9565b95015173ffffffffffffffffffffffffffffffffffffffff169301929092525090919050565b81810381811115611ecd57611ecd614f48565b6000816151c2576151c2614f48565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361524857615248614f48565b5060010190565b600061012063ffffffff808d1684528b6020850152808b1660408501525080606084015261527f8184018a614fc9565b905082810360808401526152938189614fc9565b905060ff871660a084015282810360c08401526152b08187614cb6565b905067ffffffffffffffff851660e08401528281036101008401526152d58185614cb6565b9c9b505050505050505050505050565b8082028115828204841417611ecd57611ecd614f48565b80820180821115611ecd57611ecd614f48565b60ff8181168382160190811115611ecd57611ecd614f48565b80516147c381614856565b80516147c381614796565b80516147c381614873565b80516147c38161488c565b80516147c3816148a8565b600082601f83011261537057600080fd5b815160206153806147e983614772565b82815260059290921b8401810191818101908684111561539f57600080fd5b8286015b848110156148315780516153b681614796565b83529183019183016153a3565b600082601f8301126153d457600080fd5b815160206153e46147e983614772565b82815260c0928302850182019282820191908785111561540357600080fd5b8387015b85811015614b915781818a03121561541f5760008081fd5b615427614700565b815161543281614856565b8152818601516154418161488c565b8187015260408281015161545481614796565b908201526060828101516154678161483c565b908201526080828101519082015260a08083015161548481614aa5565b908201528452928401928101615407565b6000806000606084860312156154aa57600080fd5b835167ffffffffffffffff808211156154c257600080fd5b9085019061020082880312156154d757600080fd5b6154df6146d6565b6154e883615328565b81526154f660208401615328565b602082015261550760408401615328565b604082015261551860608401615333565b60608201526155296080840161533e565b608082015261553a60a08401615349565b60a082015261554b60c08401615328565b60c082015261555c60e08401615328565b60e082015261010061556f818501615333565b90820152610120615581848201615354565b90820152610140615593848201615333565b90820152610160838101519082015261018080840151908201526101a080840151908201526101c080840151838111156155cc57600080fd5b6155d88a82870161535f565b8284015250506101e06155ec818501615333565b90820152602087015190955091508082111561560757600080fd5b6156138783880161535f565b9350604086015191508082111561562957600080fd5b50615636868287016153c3565b9150509250925092565b60006020828403121561565257600080fd5b8151611edf8161483c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526156d38285018b614fc9565b915083820360808501526156e7828a614fc9565b915060ff881660a085015283820360c08501526157048288614cb6565b90861660e085015283810361010085015290506152d58185614cb6565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b600082601f83011261575857600080fd5b813560206157686147e983614772565b82815260059290921b8401810191818101908684111561578757600080fd5b8286015b84811015614831578035835291830191830161578b565b600082601f8301126157b357600080fd5b813560206157c36147e983614772565b82815260059290921b840181019181810190868411156157e257600080fd5b8286015b8481101561483157803567ffffffffffffffff8111156158065760008081fd5b6158148986838b0101614a17565b8452509183019183016157e6565b60006020828403121561583457600080fd5b813567ffffffffffffffff8082111561584c57600080fd5b9083019060c0828603121561586057600080fd5b615868614700565b823581526020830135602082015260408301358281111561588857600080fd5b61589487828601615747565b6040830152506060830135828111156158ac57600080fd5b6158b887828601615747565b6060830152506080830135828111156158d057600080fd5b6158dc878286016157a2565b60808301525060a0830135828111156158f457600080fd5b615900878286016157a2565b60a08301525095945050505050565b61ffff81811683821601908082111561327657613276614f48565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826159685761596861592a565b500490565b6bffffffffffffffffffffffff81811683821601908082111561327657613276614f48565b6bffffffffffffffffffffffff851681528360208201528260408201526080606082015260006159c56080830184614cb6565b9695505050505050565b6bffffffffffffffffffffffff82811682821603908082111561327657613276614f48565b60006bffffffffffffffffffffffff80841680615a1357615a1361592a565b92169190910492915050565b6bffffffffffffffffffffffff818116838216028082169190828114615a4757615a47614f48565b505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b82815260406020820152600061336f6040830184614cb6565b60008060408385031215615aaa57600080fd5b8251615ab581614873565b6020939093015192949293505050565b805169ffffffffffffffffffff811681146147c357600080fd5b600080600080600060a08688031215615af757600080fd5b615b0086615ac5565b9450602086015193506040860151925060608601519150615b2360808701615ac5565b90509295509295909350565b600181815b80851115615b8857817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615b6e57615b6e614f48565b80851615615b7b57918102915b93841c9390800290615b34565b509250929050565b600082615b9f57506001611ecd565b81615bac57506000611ecd565b8160018114615bc25760028114615bcc57615be8565b6001915050611ecd565b60ff841115615bdd57615bdd614f48565b50506001821b611ecd565b5060208310610133831016604e8410600b8410161715615c0b575081810a611ecd565b615c158383615b2f565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615c4757615c47614f48565b029392505050565b6000611edf8383615b90565b6fffffffffffffffffffffffffffffffff81811683821601908082111561327657613276614f48565b6000610100820190506bffffffffffffffffffffffff8084511683528060208501511660208401528060408501511660408401528060608501511660608401525073ffffffffffffffffffffffffffffffffffffffff608084015116608083015260a0830151615d0460a08401826bffffffffffffffffffffffff169052565b5060c0830151615d2460c08401826bffffffffffffffffffffffff169052565b5060e083015161327660e08401826bffffffffffffffffffffffff169052565b600060408284031215615d5657600080fd5b6040516040810181811067ffffffffffffffff82111715615d7957615d796146a7565b6040528251615d8781614856565b81526020928301519281019290925250919050565b600060a08284031215615dae57600080fd5b60405160a0810181811067ffffffffffffffff82111715615dd157615dd16146a7565b806040525082518152602083015160208201526040830151615df281614856565b60408201526060830151615e0581614856565b6060820152608092830151928101929092525091905056fea164736f6c6343000813000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ae778b63fcb0c6b57c9a9e839c0706c7a0496489
-----Decoded View---------------
Arg [0] : logicA (address): 0xAE778B63FCB0C6b57c9a9e839C0706c7a0496489
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000ae778b63fcb0c6b57c9a9e839c0706c7a0496489
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ 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.