Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Latest 13 from a total of 13 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Transfer Ownersh... | 8905362 | 108 days ago | IN | 0 ETH | 0.00000227 | ||||
Set Trigger Conf... | 8904844 | 108 days ago | IN | 0 ETH | 0.00000391 | ||||
Set Trigger Conf... | 8904843 | 108 days ago | IN | 0 ETH | 0.00000391 | ||||
Set Config | 8904843 | 108 days ago | IN | 0 ETH | 0.00000437 | ||||
Set Auto Approve... | 8879838 | 109 days ago | IN | 0 ETH | 0.00002691 | ||||
Register Upkeep | 8124835 | 137 days ago | IN | 0.1 ETH | 0.00003959 | ||||
Register Upkeep | 8124503 | 137 days ago | IN | 0.1 ETH | 0.00005054 | ||||
Register Upkeep | 8118952 | 138 days ago | IN | 0 ETH | 0.0001629 | ||||
Register Upkeep | 8117999 | 138 days ago | IN | 0 ETH | 0.00154439 | ||||
Set Auto Approve... | 8102075 | 138 days ago | IN | 0 ETH | 0.00000734 | ||||
Set Trigger Conf... | 8102066 | 138 days ago | IN | 0 ETH | 0.00000743 | ||||
Set Trigger Conf... | 8102066 | 138 days ago | IN | 0 ETH | 0.00000743 | ||||
Set Config | 8102065 | 138 days ago | IN | 0 ETH | 0.00001148 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
8905414 | 108 days ago | 0 ETH | ||||
8449236 | 125 days ago | 0 ETH | ||||
8449236 | 125 days ago | 0 ETH | ||||
8449236 | 125 days ago | 0 ETH | ||||
8449236 | 125 days ago | 0 ETH | ||||
8449181 | 125 days ago | 0 ETH | ||||
8449181 | 125 days ago | 0 ETH | ||||
8449181 | 125 days ago | 0 ETH | ||||
8449181 | 125 days ago | 0 ETH | ||||
8124835 | 137 days ago | 0 ETH | ||||
8124835 | 137 days ago | 0 ETH | ||||
8124835 | 137 days ago | 0 ETH | ||||
8124835 | 137 days ago | 0 ETH | ||||
8124835 | 137 days ago | 0 ETH | ||||
8124835 | 137 days ago | 0.1 ETH | ||||
8124503 | 137 days ago | 0 ETH | ||||
8124503 | 137 days ago | 0 ETH | ||||
8124503 | 137 days ago | 0 ETH | ||||
8124503 | 137 days ago | 0 ETH | ||||
8124503 | 137 days ago | 0 ETH | ||||
8124503 | 137 days ago | 0.1 ETH | ||||
8118952 | 138 days ago | 0 ETH | ||||
8118952 | 138 days ago | 0 ETH | ||||
8118952 | 138 days ago | 0 ETH | ||||
8118952 | 138 days ago | 0 ETH |
Loading...
Loading
Contract Name:
AutomationRegistrar2_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 {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.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 {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.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":"address","name":"LINKAddress","type":"address"},{"internalType":"contract IAutomationRegistryMaster2_3","name":"registry","type":"address"},{"components":[{"internalType":"uint8","name":"triggerType","type":"uint8"},{"internalType":"enum AutomationRegistrar2_3.AutoApproveType","name":"autoApproveType","type":"uint8"},{"internalType":"uint32","name":"autoApproveMaxAllowed","type":"uint32"}],"internalType":"struct AutomationRegistrar2_3.InitialTriggerConfig[]","name":"triggerConfigs","type":"tuple[]"},{"internalType":"contract IERC20Metadata[]","name":"billingTokens","type":"address[]"},{"internalType":"uint256[]","name":"minRegistrationFees","type":"uint256[]"},{"internalType":"contract IWrappedNative","name":"wrappedNativeToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DuplicateEntry","type":"error"},{"inputs":[],"name":"HashMismatch","type":"error"},{"inputs":[],"name":"InsufficientPayment","type":"error"},{"inputs":[],"name":"InvalidAdminAddress","type":"error"},{"inputs":[],"name":"InvalidBillingToken","type":"error"},{"inputs":[],"name":"InvalidDataLength","type":"error"},{"inputs":[],"name":"OnlyAdminOrOwner","type":"error"},{"inputs":[],"name":"OnlyLink","type":"error"},{"inputs":[],"name":"RequestNotFound","type":"error"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"TransferFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"senderAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"AutoApproveAllowedSenderSet","type":"event"},{"anonymous":false,"inputs":[],"name":"ConfigChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"hash","type":"bytes32"},{"indexed":false,"internalType":"string","name":"displayName","type":"string"},{"indexed":true,"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"RegistrationApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"RegistrationRejected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"hash","type":"bytes32"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"bytes","name":"encryptedEmail","type":"bytes"},{"indexed":true,"internalType":"address","name":"upkeepContract","type":"address"},{"indexed":false,"internalType":"uint32","name":"gasLimit","type":"uint32"},{"indexed":false,"internalType":"address","name":"adminAddress","type":"address"},{"indexed":false,"internalType":"uint8","name":"triggerType","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"triggerConfig","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"offchainConfig","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"checkData","type":"bytes"},{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"},{"indexed":false,"internalType":"contract IERC20Metadata","name":"billingToken","type":"address"}],"name":"RegistrationRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"triggerType","type":"uint8"},{"indexed":false,"internalType":"enum AutomationRegistrar2_3.AutoApproveType","name":"autoApproveType","type":"uint8"},{"indexed":false,"internalType":"uint32","name":"autoApproveMaxAllowed","type":"uint32"}],"name":"TriggerConfigSet","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"upkeepContract","type":"address"},{"internalType":"uint96","name":"amount","type":"uint96"},{"internalType":"address","name":"adminAddress","type":"address"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"uint8","name":"triggerType","type":"uint8"},{"internalType":"contract IERC20Metadata","name":"billingToken","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"bytes","name":"encryptedEmail","type":"bytes"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"bytes","name":"triggerConfig","type":"bytes"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"internalType":"struct AutomationRegistrar2_3.RegistrationParams","name":"requestParams","type":"tuple"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"senderAddress","type":"address"}],"name":"getAutoApproveAllowedSender","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Metadata","name":"billingToken","type":"address"}],"name":"getMinimumRegistrationAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"getPendingRequest","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRegistry","outputs":[{"internalType":"contract IAutomationRegistryMaster2_3","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"triggerType","type":"uint8"}],"name":"getTriggerRegistrationDetails","outputs":[{"components":[{"internalType":"enum AutomationRegistrar2_3.AutoApproveType","name":"autoApproveType","type":"uint8"},{"internalType":"uint32","name":"autoApproveMaxAllowed","type":"uint32"},{"internalType":"uint32","name":"approvedCount","type":"uint32"}],"internalType":"struct AutomationRegistrar2_3.TriggerRegistrationStorage","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"i_LINK","outputs":[{"internalType":"contract LinkTokenInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"i_WRAPPED_NATIVE_TOKEN","outputs":[{"internalType":"contract IWrappedNative","name":"","type":"address"}],"stateMutability":"view","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":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"upkeepContract","type":"address"},{"internalType":"uint96","name":"amount","type":"uint96"},{"internalType":"address","name":"adminAddress","type":"address"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"uint8","name":"triggerType","type":"uint8"},{"internalType":"contract IERC20Metadata","name":"billingToken","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"bytes","name":"encryptedEmail","type":"bytes"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"bytes","name":"triggerConfig","type":"bytes"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"internalType":"struct AutomationRegistrar2_3.RegistrationParams","name":"requestParams","type":"tuple"}],"name":"registerUpkeep","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"setAutoApproveAllowedSender","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IAutomationRegistryMaster2_3","name":"registry","type":"address"},{"internalType":"contract IERC20Metadata[]","name":"billingTokens","type":"address[]"},{"internalType":"uint256[]","name":"minBalances","type":"uint256[]"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"triggerType","type":"uint8"},{"internalType":"enum AutomationRegistrar2_3.AutoApproveType","name":"autoApproveType","type":"uint8"},{"internalType":"uint32","name":"autoApproveMaxAllowed","type":"uint32"}],"name":"setTriggerConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60c06040523480156200001157600080fd5b5060405162003571380380620035718339810160408190526200003491620005db565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be8162000183565b5050506001600160a01b03808716608052811660a052620000e18584846200022e565b60005b84518110156200017657620001618582815181106200010757620001076200076d565b6020026020010151600001518683815181106200012857620001286200076d565b6020026020010151602001518784815181106200014957620001496200076d565b6020026020010151604001516200032a60201b60201c565b806200016d8162000783565b915050620000e4565b5050505050505062000804565b336001600160a01b03821603620001dd5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b62000238620003d8565b80518251146200025b57604051630dfe930960e41b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b03851617905560005b8251811015620002fb578181815181106200029857620002986200076d565b602002602001015160046000858481518110620002b957620002b96200076d565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020819055508080620002f29062000783565b91505062000279565b506040517fb9b6902016bd1219d5fa6161243b61e7e9f7f959526dd94ef8fa3e403bf881c390600090a1505050565b62000334620003d8565b60ff83166000908152600660205260409020805483919060ff19166001836002811115620003665762000366620007ab565b021790555060ff831660009081526006602052604090819020805464ffffffff00191661010063ffffffff851602179055517f830a6d06a4e2caac67eba04323de22bdb04f032dd8b3d6a0c52b503d9a7036a390620003cb90859085908590620007c1565b60405180910390a1505050565b6000546001600160a01b03163314620004345760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b6001600160a01b03811681146200044c57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b03811182821017156200048a576200048a6200044f565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620004bb57620004bb6200044f565b604052919050565b60006001600160401b03821115620004df57620004df6200044f565b5060051b60200190565b600082601f830112620004fb57600080fd5b81516020620005146200050e83620004c3565b62000490565b82815260059290921b840181019181810190868411156200053457600080fd5b8286015b848110156200055c5780516200054e8162000436565b835291830191830162000538565b509695505050505050565b600082601f8301126200057957600080fd5b815160206200058c6200050e83620004c3565b82815260059290921b84018101918181019086841115620005ac57600080fd5b8286015b848110156200055c5780518352918301918301620005b0565b8051620005d68162000436565b919050565b60008060008060008060c08789031215620005f557600080fd5b8651620006028162000436565b80965050602080880151620006178162000436565b60408901519096506001600160401b03808211156200063557600080fd5b818a0191508a601f8301126200064a57600080fd5b81516200065b6200050e82620004c3565b81815260609091028301840190848101908d8311156200067a57600080fd5b938501935b8285101562000701576060858f0312156200069a5760008081fd5b620006a462000465565b855160ff81168114620006b75760008081fd5b81528587015160038110620006cc5760008081fd5b81880152604086015163ffffffff81168114620006e95760008081fd5b6040820152825260609490940193908501906200067f565b60608d015190995094505050808311156200071b57600080fd5b620007298b848c01620004e9565b955060808a01519250808311156200074057600080fd5b50506200075089828a0162000567565b9250506200076160a08801620005c9565b90509295509295509295565b634e487b7160e01b600052603260045260246000fd5b600060018201620007a457634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052602160045260246000fd5b60ff841681526060810160038410620007ea57634e487b7160e01b600052602160045260246000fd5b83602083015263ffffffff83166040830152949350505050565b60805160a051612d1d620008546000396000818161029b015281816105a601526106390152600081816104b301528181610b4c01528181610bb50152818161166101526116ba0152612d1d6000f3fe6080604052600436106101295760003560e01c80637e776f7f116100a5578063a4c0ed3611610074578063befdae4611610059578063befdae46146104a1578063c4d252f5146104d5578063f2fde38b146104f557600080fd5b8063a4c0ed3614610461578063b5ff5b411461048157600080fd5b80637e776f7f146102d257806388b12d55146103285780638da5cb5b146103f3578063a2b1ff941461041e57600080fd5b8063367b9b4f116100fc57806366ab87f9116100e157806366ab87f9146102695780636bf7d75f1461028957806379ba5097146102bd57600080fd5b8063367b9b4f146101fd5780635ab1bd531461021d57600080fd5b8063181f5a771461012e578063212d08841461018d5780632ce3a14a146101ba5780633188a2ce146101db575b600080fd5b34801561013a57600080fd5b506101776040518060400160405280601981526020017f4175746f6d6174696f6e52656769737472617220322e332e300000000000000081525081565b6040516101849190611f57565b60405180910390f35b34801561019957600080fd5b506101ad6101a8366004611f87565b610515565b604051610184919061200c565b6101cd6101c8366004612323565b6105a2565b604051908152602001610184565b3480156101e757600080fd5b506101fb6101f6366004612358565b610710565b005b34801561020957600080fd5b506101fb6102183660046123a2565b610859565b34801561022957600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610184565b34801561027557600080fd5b506101fb61028436600461246a565b6108eb565b34801561029557600080fd5b506102447f000000000000000000000000000000000000000000000000000000000000000081565b3480156102c957600080fd5b506101fb610a32565b3480156102de57600080fd5b506103186102ed366004612540565b73ffffffffffffffffffffffffffffffffffffffff1660009081526003602052604090205460ff1690565b6040519015158152602001610184565b34801561033457600080fd5b506103ba61034336600461255d565b6000908152600560209081526040918290208251606081018452815473ffffffffffffffffffffffffffffffffffffffff808216808452740100000000000000000000000000000000000000009092046bffffffffffffffffffffffff169483018590526001909301549092169301929092529091565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526bffffffffffffffffffffffff909116602083015201610184565b3480156103ff57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610244565b34801561042a57600080fd5b506101cd610439366004612540565b73ffffffffffffffffffffffffffffffffffffffff1660009081526004602052604090205490565b34801561046d57600080fd5b506101fb61047c366004612576565b610b34565b34801561048d57600080fd5b506101fb61049c3660046125ff565b610c62565b3480156104ad57600080fd5b506102447f000000000000000000000000000000000000000000000000000000000000000081565b3480156104e157600080fd5b506101fb6104f036600461255d565b610d41565b34801561050157600080fd5b506101fb610510366004612540565b610f08565b60408051606080820183526000808352602080840182905283850182905260ff86811683526006909152908490208451928301909452835492939192839116600281111561056557610565611fa2565b600281111561057657610576611fa2565b8152905463ffffffff610100820481166020840152650100000000009091041660409091015292915050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168260a0015173ffffffffffffffffffffffffffffffffffffffff1614801561060257503415155b156106bd5761061034610f1c565b82602001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff16815250507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561069f57600080fd5b505af11580156106b3573d6000803e3d6000fd5b5050505050610700565b610700333084602001516bffffffffffffffffffffffff168560a0015173ffffffffffffffffffffffffffffffffffffffff16610fbe909392919063ffffffff16565b61070a823361109a565b92915050565b610718611507565b60008160405160200161072b91906126fc565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181528282528051602091820120600081815260058352839020606085018452805473ffffffffffffffffffffffffffffffffffffffff808216808852740100000000000000000000000000000000000000009092046bffffffffffffffffffffffff169487019490945260019091015490921692840192909252909250610807576040517f4b13b31e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040812090815560010180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905561085361084d846128b8565b8361158a565b50505050565b610861611507565b73ffffffffffffffffffffffffffffffffffffffff821660008181526003602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f20c6237dac83526a849285a9f79d08a483291bdd3a056a0ef9ae94ecee1ad356910160405180910390a25050565b6108f3611507565b805182511461092e576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff851617905560005b8251811015610a035781818151811061098c5761098c6128c4565b6020026020010151600460008584815181106109aa576109aa6128c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555080806109fb90612922565b915050610971565b506040517fb9b6902016bd1219d5fa6161243b61e7e9f7f959526dd94ef8fa3e403bf881c390600090a1505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610ab8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610ba3576040517f018d10be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610bb182840184612323565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168160a0015173ffffffffffffffffffffffffffffffffffffffff1614610c3c576040517f018d10be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6bffffffffffffffffffffffff84166020820152610c5a818661109a565b505050505050565b610c6a611507565b60ff8316600090815260066020526040902080548391907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001836002811115610cb757610cb7611fa2565b021790555060ff83166000908152600660205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff1661010063ffffffff851602179055517f830a6d06a4e2caac67eba04323de22bdb04f032dd8b3d6a0c52b503d9a7036a390610d349085908590859061295a565b60405180910390a1505050565b6000818152600560209081526040918290208251606081018452815473ffffffffffffffffffffffffffffffffffffffff808216808452740100000000000000000000000000000000000000009092046bffffffffffffffffffffffff16948301949094526001909201549092169282019290925290331480610ddb575060005473ffffffffffffffffffffffffffffffffffffffff1633145b610e11576040517f61685c2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805173ffffffffffffffffffffffffffffffffffffffff16610e5f576040517f4b13b31e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560209081526040808320928355600190920180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905582519083015191830151610ed99273ffffffffffffffffffffffffffffffffffffffff90911691906bffffffffffffffffffffffff166118f5565b60405182907f3663fb28ebc87645eb972c9dad8521bf665c623f287e79f1c56f1eb374b82a2290600090a25050565b610f10611507565b610f1981611950565b50565b60006bffffffffffffffffffffffff821115610fba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610aaf565b5090565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526108539085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611a45565b60a082015173ffffffffffffffffffffffffffffffffffffffff166000908152600460209081526040822054908401516bffffffffffffffffffffffff161015611110576040517fcd1c886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604083015173ffffffffffffffffffffffffffffffffffffffff16611161576040517f05bb467c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460a08401516040517fa538b2eb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015291169063a538b2eb90602401602060405180830381865afa1580156111d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f99190612985565b61122f576040517f1183afea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360405160200161124291906129a2565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291815281516020928301206000818152600590935291205490915073ffffffffffffffffffffffffffffffffffffffff16156112d5576040517f357d0cc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b836000015173ffffffffffffffffffffffffffffffffffffffff16817fd178af9fe30387562e61bb997b245b7f49c26aad1e50c39d7b438ffa6c41b3068660c001518760e00151886060015189604001518a608001518b61012001518c61014001518d61010001518e602001518f60a0015160405161135d9a99989796959493929190612b0e565b60405180910390a3608084015160ff908116600090815260066020526040808220815160608101909252805492936113e09383911660028111156113a3576113a3611fa2565b60028111156113b4576113b4611fa2565b8152905463ffffffff610100820481166020840152650100000000009091041660409091015285611b51565b1561144857608085015160ff166000908152600660205260409020805465010000000000900463ffffffff1690600561141883612bed565b91906101000a81548163ffffffff021916908363ffffffff16021790555050611441858361158a565b90506114ff565b604080516060810182528682015173ffffffffffffffffffffffffffffffffffffffff90811682526020808901516bffffffffffffffffffffffff90811682850190815260a08b01518416858701908152600089815260059094529590922093519151167401000000000000000000000000000000000000000002908216178255915160019091018054919092167fffffffffffffffffffffffff0000000000000000000000000000000000000000919091161790555b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611588576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610aaf565b565b60025482516060840151604080860151608087015160a08801516101008901516101208a01516101408b015195517fc62cf68400000000000000000000000000000000000000000000000000000000815260009973ffffffffffffffffffffffffffffffffffffffff16988a988a9863c62cf6849861161a98939792969095939492939092909190600401612c10565b6020604051808303816000875af1158015611639573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165d9190612c8f565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168560a0015173ffffffffffffffffffffffffffffffffffffffff16036117d45760007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634000aea08488602001518560405160200161170d91815260200190565b6040516020818303038152906040526040518463ffffffff1660e01b815260040161173a93929190612ca8565b6020604051808303816000875af1158015611759573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177d9190612985565b9050806117ce576040517f39f1c8d900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610aaf565b506118b0565b6118158286602001516bffffffffffffffffffffffff168760a0015173ffffffffffffffffffffffffffffffffffffffff16611bf69092919063ffffffff16565b60208501516040517f948108f7000000000000000000000000000000000000000000000000000000008152600481018390526bffffffffffffffffffffffff909116602482015273ffffffffffffffffffffffffffffffffffffffff83169063948108f790604401600060405180830381600087803b15801561189757600080fd5b505af11580156118ab573d6000803e3d6000fd5b505050505b80847fb9a292fb7e3edd920cd2d2829a3615a640c43fd7de0a0820aa0668feb4c37d4b8760c001516040516118e59190611f57565b60405180910390a3949350505050565b60405173ffffffffffffffffffffffffffffffffffffffff831660248201526044810182905261194b9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611018565b505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036119cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610aaf565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000611aa7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16611d789092919063ffffffff16565b80519091501561194b5780806020019051810190611ac59190612985565b61194b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610aaf565b60008083516002811115611b6757611b67611fa2565b03611b745750600061070a565b600183516002811115611b8957611b89611fa2565b148015611bbc575073ffffffffffffffffffffffffffffffffffffffff821660009081526003602052604090205460ff16155b15611bc95750600061070a565b826020015163ffffffff16836040015163ffffffff161015611bed5750600161070a565b50600092915050565b801580611c9657506040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015284169063dd62ed3e90604401602060405180830381865afa158015611c70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c949190612c8f565b155b611d22576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401610aaf565b60405173ffffffffffffffffffffffffffffffffffffffff831660248201526044810182905261194b9084907f095ea7b30000000000000000000000000000000000000000000000000000000090606401611018565b60606114ff8484600085856000808673ffffffffffffffffffffffffffffffffffffffff168587604051611dac9190612cf4565b60006040518083038185875af1925050503d8060008114611de9576040519150601f19603f3d011682016040523d82523d6000602084013e611dee565b606091505b5091509150611dff87838387611e0a565b979650505050505050565b60608315611ea0578251600003611e995773ffffffffffffffffffffffffffffffffffffffff85163b611e99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610aaf565b50816114ff565b6114ff8383815115611eb55781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610aaf9190611f57565b60005b83811015611f04578181015183820152602001611eec565b50506000910152565b60008151808452611f25816020860160208601611ee9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611f6a6020830184611f0d565b9392505050565b803560ff81168114611f8257600080fd5b919050565b600060208284031215611f9957600080fd5b611f6a82611f71565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60038110612008577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b600060608201905061201f828451611fd1565b602083015163ffffffff8082166020850152806040860151166040850152505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610160810167ffffffffffffffff8111828210171561209857612098612045565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156120e5576120e5612045565b604052919050565b73ffffffffffffffffffffffffffffffffffffffff81168114610f1957600080fd5b8035611f82816120ed565b80356bffffffffffffffffffffffff81168114611f8257600080fd5b803563ffffffff81168114611f8257600080fd5b600082601f83011261215b57600080fd5b813567ffffffffffffffff81111561217557612175612045565b6121a660207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161209e565b8181528460208386010111156121bb57600080fd5b816020850160208301376000918101602001919091529392505050565b600061016082840312156121eb57600080fd5b6121f3612074565b90506121fe8261210f565b815261220c6020830161211a565b602082015261221d6040830161210f565b604082015261222e60608301612136565b606082015261223f60808301611f71565b608082015261225060a0830161210f565b60a082015260c082013567ffffffffffffffff8082111561227057600080fd5b61227c8583860161214a565b60c084015260e084013591508082111561229557600080fd5b6122a18583860161214a565b60e0840152610100915081840135818111156122bc57600080fd5b6122c88682870161214a565b8385015250610120915081840135818111156122e357600080fd5b6122ef8682870161214a565b83850152506101409150818401358181111561230a57600080fd5b6123168682870161214a565b8385015250505092915050565b60006020828403121561233557600080fd5b813567ffffffffffffffff81111561234c57600080fd5b6114ff848285016121d8565b60006020828403121561236a57600080fd5b813567ffffffffffffffff81111561238157600080fd5b82016101608185031215611f6a57600080fd5b8015158114610f1957600080fd5b600080604083850312156123b557600080fd5b82356123c0816120ed565b915060208301356123d081612394565b809150509250929050565b600067ffffffffffffffff8211156123f5576123f5612045565b5060051b60200190565b600082601f83011261241057600080fd5b81356020612425612420836123db565b61209e565b82815260059290921b8401810191818101908684111561244457600080fd5b8286015b8481101561245f5780358352918301918301612448565b509695505050505050565b60008060006060848603121561247f57600080fd5b833561248a816120ed565b925060208481013567ffffffffffffffff808211156124a857600080fd5b818701915087601f8301126124bc57600080fd5b81356124ca612420826123db565b81815260059190911b8301840190848101908a8311156124e957600080fd5b938501935b82851015612510578435612501816120ed565b825293850193908501906124ee565b96505050604087013592508083111561252857600080fd5b5050612536868287016123ff565b9150509250925092565b60006020828403121561255257600080fd5b8135611f6a816120ed565b60006020828403121561256f57600080fd5b5035919050565b6000806000806060858703121561258c57600080fd5b8435612597816120ed565b935060208501359250604085013567ffffffffffffffff808211156125bb57600080fd5b818701915087601f8301126125cf57600080fd5b8135818111156125de57600080fd5b8860208285010111156125f057600080fd5b95989497505060200194505050565b60008060006060848603121561261457600080fd5b61261d84611f71565b925060208401356003811061263157600080fd5b915061263f60408501612136565b90509250925092565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261267d57600080fd5b830160208101925035905067ffffffffffffffff81111561269d57600080fd5b8036038213156126ac57600080fd5b9250929050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b6020815261272a602082016127108461210f565b73ffffffffffffffffffffffffffffffffffffffff169052565b60006127386020840161211a565b6bffffffffffffffffffffffff81166040840152506127596040840161210f565b73ffffffffffffffffffffffffffffffffffffffff811660608401525061278260608401612136565b63ffffffff811660808401525061279b60808401611f71565b60ff811660a0840152506127b160a0840161210f565b73ffffffffffffffffffffffffffffffffffffffff811660c0840152506127db60c0840184612648565b6101608060e08601526127f3610180860183856126b3565b925061280260e0870187612648565b92507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061010081888703018189015261283c8686856126b3565b955061284a818a018a612648565b95509250506101208188870301818901526128668686856126b3565b9550612874818a018a612648565b95509250506101408188870301818901526128908686856126b3565b955061289e818a018a612648565b955092505080878603018388015250611dff8484836126b3565b600061070a36836121d8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612953576129536128f3565b5060010190565b60ff84168152606081016129716020830185611fd1565b63ffffffff83166040830152949350505050565b60006020828403121561299757600080fd5b8151611f6a81612394565b602081526129c960208201835173ffffffffffffffffffffffffffffffffffffffff169052565b600060208301516129ea60408401826bffffffffffffffffffffffff169052565b50604083015173ffffffffffffffffffffffffffffffffffffffff8116606084015250606083015163ffffffff8116608084015250608083015160ff811660a08401525060a083015173ffffffffffffffffffffffffffffffffffffffff811660c08401525060c08301516101608060e0850152612a6c610180850183611f0d565b915060e08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610100818786030181880152612aaa8584611f0d565b945080880151925050610120818786030181880152612ac98584611f0d565b945080880151925050610140818786030181880152612ae88584611f0d565b908801518782039092018488015293509050612b048382611f0d565b9695505050505050565b6000610140808352612b228184018e611f0d565b90508281036020840152612b36818d611f0d565b905063ffffffff8b16604084015273ffffffffffffffffffffffffffffffffffffffff8a16606084015260ff8916608084015282810360a0840152612b7b8189611f0d565b905082810360c0840152612b8f8188611f0d565b905082810360e0840152612ba38187611f0d565b9150506bffffffffffffffffffffffff8416610100830152612bde61012083018473ffffffffffffffffffffffffffffffffffffffff169052565b9b9a5050505050505050505050565b600063ffffffff808316818103612c0657612c066128f3565b6001019392505050565b600061010073ffffffffffffffffffffffffffffffffffffffff808c16845263ffffffff8b166020850152808a16604085015260ff891660608501528088166080850152508060a0840152612c6781840187611f0d565b905082810360c0840152612c7b8186611f0d565b905082810360e0840152612bde8185611f0d565b600060208284031215612ca157600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff841681526bffffffffffffffffffffffff83166020820152606060408201526000612ceb6060830184611f0d565b95945050505050565b60008251612d06818460208701611ee9565b919091019291505056fea164736f6c6343000813000a0000000000000000000000005576815a38a3706f37bf815b261ccc7cca77e9750000000000000000000000000f7e163446aab41db5375abdee2c3ecc56d9aa3200000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001000000000000000000000000001ce28d5c81b229c77c5651feb49c4c489f8c52c4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106101295760003560e01c80637e776f7f116100a5578063a4c0ed3611610074578063befdae4611610059578063befdae46146104a1578063c4d252f5146104d5578063f2fde38b146104f557600080fd5b8063a4c0ed3614610461578063b5ff5b411461048157600080fd5b80637e776f7f146102d257806388b12d55146103285780638da5cb5b146103f3578063a2b1ff941461041e57600080fd5b8063367b9b4f116100fc57806366ab87f9116100e157806366ab87f9146102695780636bf7d75f1461028957806379ba5097146102bd57600080fd5b8063367b9b4f146101fd5780635ab1bd531461021d57600080fd5b8063181f5a771461012e578063212d08841461018d5780632ce3a14a146101ba5780633188a2ce146101db575b600080fd5b34801561013a57600080fd5b506101776040518060400160405280601981526020017f4175746f6d6174696f6e52656769737472617220322e332e300000000000000081525081565b6040516101849190611f57565b60405180910390f35b34801561019957600080fd5b506101ad6101a8366004611f87565b610515565b604051610184919061200c565b6101cd6101c8366004612323565b6105a2565b604051908152602001610184565b3480156101e757600080fd5b506101fb6101f6366004612358565b610710565b005b34801561020957600080fd5b506101fb6102183660046123a2565b610859565b34801561022957600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610184565b34801561027557600080fd5b506101fb61028436600461246a565b6108eb565b34801561029557600080fd5b506102447f0000000000000000000000001ce28d5c81b229c77c5651feb49c4c489f8c52c481565b3480156102c957600080fd5b506101fb610a32565b3480156102de57600080fd5b506103186102ed366004612540565b73ffffffffffffffffffffffffffffffffffffffff1660009081526003602052604090205460ff1690565b6040519015158152602001610184565b34801561033457600080fd5b506103ba61034336600461255d565b6000908152600560209081526040918290208251606081018452815473ffffffffffffffffffffffffffffffffffffffff808216808452740100000000000000000000000000000000000000009092046bffffffffffffffffffffffff169483018590526001909301549092169301929092529091565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526bffffffffffffffffffffffff909116602083015201610184565b3480156103ff57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610244565b34801561042a57600080fd5b506101cd610439366004612540565b73ffffffffffffffffffffffffffffffffffffffff1660009081526004602052604090205490565b34801561046d57600080fd5b506101fb61047c366004612576565b610b34565b34801561048d57600080fd5b506101fb61049c3660046125ff565b610c62565b3480156104ad57600080fd5b506102447f0000000000000000000000005576815a38a3706f37bf815b261ccc7cca77e97581565b3480156104e157600080fd5b506101fb6104f036600461255d565b610d41565b34801561050157600080fd5b506101fb610510366004612540565b610f08565b60408051606080820183526000808352602080840182905283850182905260ff86811683526006909152908490208451928301909452835492939192839116600281111561056557610565611fa2565b600281111561057657610576611fa2565b8152905463ffffffff610100820481166020840152650100000000009091041660409091015292915050565b60007f0000000000000000000000001ce28d5c81b229c77c5651feb49c4c489f8c52c473ffffffffffffffffffffffffffffffffffffffff168260a0015173ffffffffffffffffffffffffffffffffffffffff1614801561060257503415155b156106bd5761061034610f1c565b82602001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff16815250507f0000000000000000000000001ce28d5c81b229c77c5651feb49c4c489f8c52c473ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561069f57600080fd5b505af11580156106b3573d6000803e3d6000fd5b5050505050610700565b610700333084602001516bffffffffffffffffffffffff168560a0015173ffffffffffffffffffffffffffffffffffffffff16610fbe909392919063ffffffff16565b61070a823361109a565b92915050565b610718611507565b60008160405160200161072b91906126fc565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181528282528051602091820120600081815260058352839020606085018452805473ffffffffffffffffffffffffffffffffffffffff808216808852740100000000000000000000000000000000000000009092046bffffffffffffffffffffffff169487019490945260019091015490921692840192909252909250610807576040517f4b13b31e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040812090815560010180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905561085361084d846128b8565b8361158a565b50505050565b610861611507565b73ffffffffffffffffffffffffffffffffffffffff821660008181526003602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f20c6237dac83526a849285a9f79d08a483291bdd3a056a0ef9ae94ecee1ad356910160405180910390a25050565b6108f3611507565b805182511461092e576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff851617905560005b8251811015610a035781818151811061098c5761098c6128c4565b6020026020010151600460008584815181106109aa576109aa6128c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555080806109fb90612922565b915050610971565b506040517fb9b6902016bd1219d5fa6161243b61e7e9f7f959526dd94ef8fa3e403bf881c390600090a1505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610ab8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000005576815a38a3706f37bf815b261ccc7cca77e9751614610ba3576040517f018d10be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610bb182840184612323565b90507f0000000000000000000000005576815a38a3706f37bf815b261ccc7cca77e97573ffffffffffffffffffffffffffffffffffffffff168160a0015173ffffffffffffffffffffffffffffffffffffffff1614610c3c576040517f018d10be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6bffffffffffffffffffffffff84166020820152610c5a818661109a565b505050505050565b610c6a611507565b60ff8316600090815260066020526040902080548391907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001836002811115610cb757610cb7611fa2565b021790555060ff83166000908152600660205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff1661010063ffffffff851602179055517f830a6d06a4e2caac67eba04323de22bdb04f032dd8b3d6a0c52b503d9a7036a390610d349085908590859061295a565b60405180910390a1505050565b6000818152600560209081526040918290208251606081018452815473ffffffffffffffffffffffffffffffffffffffff808216808452740100000000000000000000000000000000000000009092046bffffffffffffffffffffffff16948301949094526001909201549092169282019290925290331480610ddb575060005473ffffffffffffffffffffffffffffffffffffffff1633145b610e11576040517f61685c2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805173ffffffffffffffffffffffffffffffffffffffff16610e5f576040517f4b13b31e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560209081526040808320928355600190920180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905582519083015191830151610ed99273ffffffffffffffffffffffffffffffffffffffff90911691906bffffffffffffffffffffffff166118f5565b60405182907f3663fb28ebc87645eb972c9dad8521bf665c623f287e79f1c56f1eb374b82a2290600090a25050565b610f10611507565b610f1981611950565b50565b60006bffffffffffffffffffffffff821115610fba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610aaf565b5090565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526108539085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611a45565b60a082015173ffffffffffffffffffffffffffffffffffffffff166000908152600460209081526040822054908401516bffffffffffffffffffffffff161015611110576040517fcd1c886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604083015173ffffffffffffffffffffffffffffffffffffffff16611161576040517f05bb467c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460a08401516040517fa538b2eb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015291169063a538b2eb90602401602060405180830381865afa1580156111d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f99190612985565b61122f576040517f1183afea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360405160200161124291906129a2565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291815281516020928301206000818152600590935291205490915073ffffffffffffffffffffffffffffffffffffffff16156112d5576040517f357d0cc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b836000015173ffffffffffffffffffffffffffffffffffffffff16817fd178af9fe30387562e61bb997b245b7f49c26aad1e50c39d7b438ffa6c41b3068660c001518760e00151886060015189604001518a608001518b61012001518c61014001518d61010001518e602001518f60a0015160405161135d9a99989796959493929190612b0e565b60405180910390a3608084015160ff908116600090815260066020526040808220815160608101909252805492936113e09383911660028111156113a3576113a3611fa2565b60028111156113b4576113b4611fa2565b8152905463ffffffff610100820481166020840152650100000000009091041660409091015285611b51565b1561144857608085015160ff166000908152600660205260409020805465010000000000900463ffffffff1690600561141883612bed565b91906101000a81548163ffffffff021916908363ffffffff16021790555050611441858361158a565b90506114ff565b604080516060810182528682015173ffffffffffffffffffffffffffffffffffffffff90811682526020808901516bffffffffffffffffffffffff90811682850190815260a08b01518416858701908152600089815260059094529590922093519151167401000000000000000000000000000000000000000002908216178255915160019091018054919092167fffffffffffffffffffffffff0000000000000000000000000000000000000000919091161790555b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611588576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610aaf565b565b60025482516060840151604080860151608087015160a08801516101008901516101208a01516101408b015195517fc62cf68400000000000000000000000000000000000000000000000000000000815260009973ffffffffffffffffffffffffffffffffffffffff16988a988a9863c62cf6849861161a98939792969095939492939092909190600401612c10565b6020604051808303816000875af1158015611639573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165d9190612c8f565b90507f0000000000000000000000005576815a38a3706f37bf815b261ccc7cca77e97573ffffffffffffffffffffffffffffffffffffffff168560a0015173ffffffffffffffffffffffffffffffffffffffff16036117d45760007f0000000000000000000000005576815a38a3706f37bf815b261ccc7cca77e97573ffffffffffffffffffffffffffffffffffffffff16634000aea08488602001518560405160200161170d91815260200190565b6040516020818303038152906040526040518463ffffffff1660e01b815260040161173a93929190612ca8565b6020604051808303816000875af1158015611759573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177d9190612985565b9050806117ce576040517f39f1c8d900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610aaf565b506118b0565b6118158286602001516bffffffffffffffffffffffff168760a0015173ffffffffffffffffffffffffffffffffffffffff16611bf69092919063ffffffff16565b60208501516040517f948108f7000000000000000000000000000000000000000000000000000000008152600481018390526bffffffffffffffffffffffff909116602482015273ffffffffffffffffffffffffffffffffffffffff83169063948108f790604401600060405180830381600087803b15801561189757600080fd5b505af11580156118ab573d6000803e3d6000fd5b505050505b80847fb9a292fb7e3edd920cd2d2829a3615a640c43fd7de0a0820aa0668feb4c37d4b8760c001516040516118e59190611f57565b60405180910390a3949350505050565b60405173ffffffffffffffffffffffffffffffffffffffff831660248201526044810182905261194b9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611018565b505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036119cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610aaf565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000611aa7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16611d789092919063ffffffff16565b80519091501561194b5780806020019051810190611ac59190612985565b61194b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610aaf565b60008083516002811115611b6757611b67611fa2565b03611b745750600061070a565b600183516002811115611b8957611b89611fa2565b148015611bbc575073ffffffffffffffffffffffffffffffffffffffff821660009081526003602052604090205460ff16155b15611bc95750600061070a565b826020015163ffffffff16836040015163ffffffff161015611bed5750600161070a565b50600092915050565b801580611c9657506040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015284169063dd62ed3e90604401602060405180830381865afa158015611c70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c949190612c8f565b155b611d22576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401610aaf565b60405173ffffffffffffffffffffffffffffffffffffffff831660248201526044810182905261194b9084907f095ea7b30000000000000000000000000000000000000000000000000000000090606401611018565b60606114ff8484600085856000808673ffffffffffffffffffffffffffffffffffffffff168587604051611dac9190612cf4565b60006040518083038185875af1925050503d8060008114611de9576040519150601f19603f3d011682016040523d82523d6000602084013e611dee565b606091505b5091509150611dff87838387611e0a565b979650505050505050565b60608315611ea0578251600003611e995773ffffffffffffffffffffffffffffffffffffffff85163b611e99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610aaf565b50816114ff565b6114ff8383815115611eb55781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610aaf9190611f57565b60005b83811015611f04578181015183820152602001611eec565b50506000910152565b60008151808452611f25816020860160208601611ee9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611f6a6020830184611f0d565b9392505050565b803560ff81168114611f8257600080fd5b919050565b600060208284031215611f9957600080fd5b611f6a82611f71565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60038110612008577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b600060608201905061201f828451611fd1565b602083015163ffffffff8082166020850152806040860151166040850152505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610160810167ffffffffffffffff8111828210171561209857612098612045565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156120e5576120e5612045565b604052919050565b73ffffffffffffffffffffffffffffffffffffffff81168114610f1957600080fd5b8035611f82816120ed565b80356bffffffffffffffffffffffff81168114611f8257600080fd5b803563ffffffff81168114611f8257600080fd5b600082601f83011261215b57600080fd5b813567ffffffffffffffff81111561217557612175612045565b6121a660207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161209e565b8181528460208386010111156121bb57600080fd5b816020850160208301376000918101602001919091529392505050565b600061016082840312156121eb57600080fd5b6121f3612074565b90506121fe8261210f565b815261220c6020830161211a565b602082015261221d6040830161210f565b604082015261222e60608301612136565b606082015261223f60808301611f71565b608082015261225060a0830161210f565b60a082015260c082013567ffffffffffffffff8082111561227057600080fd5b61227c8583860161214a565b60c084015260e084013591508082111561229557600080fd5b6122a18583860161214a565b60e0840152610100915081840135818111156122bc57600080fd5b6122c88682870161214a565b8385015250610120915081840135818111156122e357600080fd5b6122ef8682870161214a565b83850152506101409150818401358181111561230a57600080fd5b6123168682870161214a565b8385015250505092915050565b60006020828403121561233557600080fd5b813567ffffffffffffffff81111561234c57600080fd5b6114ff848285016121d8565b60006020828403121561236a57600080fd5b813567ffffffffffffffff81111561238157600080fd5b82016101608185031215611f6a57600080fd5b8015158114610f1957600080fd5b600080604083850312156123b557600080fd5b82356123c0816120ed565b915060208301356123d081612394565b809150509250929050565b600067ffffffffffffffff8211156123f5576123f5612045565b5060051b60200190565b600082601f83011261241057600080fd5b81356020612425612420836123db565b61209e565b82815260059290921b8401810191818101908684111561244457600080fd5b8286015b8481101561245f5780358352918301918301612448565b509695505050505050565b60008060006060848603121561247f57600080fd5b833561248a816120ed565b925060208481013567ffffffffffffffff808211156124a857600080fd5b818701915087601f8301126124bc57600080fd5b81356124ca612420826123db565b81815260059190911b8301840190848101908a8311156124e957600080fd5b938501935b82851015612510578435612501816120ed565b825293850193908501906124ee565b96505050604087013592508083111561252857600080fd5b5050612536868287016123ff565b9150509250925092565b60006020828403121561255257600080fd5b8135611f6a816120ed565b60006020828403121561256f57600080fd5b5035919050565b6000806000806060858703121561258c57600080fd5b8435612597816120ed565b935060208501359250604085013567ffffffffffffffff808211156125bb57600080fd5b818701915087601f8301126125cf57600080fd5b8135818111156125de57600080fd5b8860208285010111156125f057600080fd5b95989497505060200194505050565b60008060006060848603121561261457600080fd5b61261d84611f71565b925060208401356003811061263157600080fd5b915061263f60408501612136565b90509250925092565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261267d57600080fd5b830160208101925035905067ffffffffffffffff81111561269d57600080fd5b8036038213156126ac57600080fd5b9250929050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b6020815261272a602082016127108461210f565b73ffffffffffffffffffffffffffffffffffffffff169052565b60006127386020840161211a565b6bffffffffffffffffffffffff81166040840152506127596040840161210f565b73ffffffffffffffffffffffffffffffffffffffff811660608401525061278260608401612136565b63ffffffff811660808401525061279b60808401611f71565b60ff811660a0840152506127b160a0840161210f565b73ffffffffffffffffffffffffffffffffffffffff811660c0840152506127db60c0840184612648565b6101608060e08601526127f3610180860183856126b3565b925061280260e0870187612648565b92507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061010081888703018189015261283c8686856126b3565b955061284a818a018a612648565b95509250506101208188870301818901526128668686856126b3565b9550612874818a018a612648565b95509250506101408188870301818901526128908686856126b3565b955061289e818a018a612648565b955092505080878603018388015250611dff8484836126b3565b600061070a36836121d8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612953576129536128f3565b5060010190565b60ff84168152606081016129716020830185611fd1565b63ffffffff83166040830152949350505050565b60006020828403121561299757600080fd5b8151611f6a81612394565b602081526129c960208201835173ffffffffffffffffffffffffffffffffffffffff169052565b600060208301516129ea60408401826bffffffffffffffffffffffff169052565b50604083015173ffffffffffffffffffffffffffffffffffffffff8116606084015250606083015163ffffffff8116608084015250608083015160ff811660a08401525060a083015173ffffffffffffffffffffffffffffffffffffffff811660c08401525060c08301516101608060e0850152612a6c610180850183611f0d565b915060e08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610100818786030181880152612aaa8584611f0d565b945080880151925050610120818786030181880152612ac98584611f0d565b945080880151925050610140818786030181880152612ae88584611f0d565b908801518782039092018488015293509050612b048382611f0d565b9695505050505050565b6000610140808352612b228184018e611f0d565b90508281036020840152612b36818d611f0d565b905063ffffffff8b16604084015273ffffffffffffffffffffffffffffffffffffffff8a16606084015260ff8916608084015282810360a0840152612b7b8189611f0d565b905082810360c0840152612b8f8188611f0d565b905082810360e0840152612ba38187611f0d565b9150506bffffffffffffffffffffffff8416610100830152612bde61012083018473ffffffffffffffffffffffffffffffffffffffff169052565b9b9a5050505050505050505050565b600063ffffffff808316818103612c0657612c066128f3565b6001019392505050565b600061010073ffffffffffffffffffffffffffffffffffffffff808c16845263ffffffff8b166020850152808a16604085015260ff891660608501528088166080850152508060a0840152612c6781840187611f0d565b905082810360c0840152612c7b8186611f0d565b905082810360e0840152612bde8185611f0d565b600060208284031215612ca157600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff841681526bffffffffffffffffffffffff83166020820152606060408201526000612ceb6060830184611f0d565b95945050505050565b60008251612d06818460208701611ee9565b919091019291505056fea164736f6c6343000813000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000005576815a38a3706f37bf815b261ccc7cca77e9750000000000000000000000000f7e163446aab41db5375abdee2c3ecc56d9aa3200000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001000000000000000000000000001ce28d5c81b229c77c5651feb49c4c489f8c52c4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : LINKAddress (address): 0x5576815a38A3706f37bf815b261cCc7cCA77e975
Arg [1] : registry (address): 0x0F7E163446AAb41DB5375AbdeE2c3eCC56D9aA32
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 0000000000000000000000005576815a38a3706f37bf815b261ccc7cca77e975
Arg [1] : 0000000000000000000000000f7e163446aab41db5375abdee2c3ecc56d9aa32
Arg [2] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [3] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [5] : 0000000000000000000000001ce28d5c81b229c77c5651feb49c4c489f8c52c4
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000000
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.