编译器
0.8.13+commit.abaa5c0e
文件 1 的 19:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
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");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
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");
}
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");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 19:AggregatorV3Interface.sol
pragma solidity ^0.8.0;
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(uint80 _roundId)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}
文件 3 的 19:ConfirmedOwner.sol
pragma solidity ^0.8.0;
import "./ConfirmedOwnerWithProposal.sol";
contract ConfirmedOwner is ConfirmedOwnerWithProposal {
constructor(address newOwner) ConfirmedOwnerWithProposal(newOwner, address(0)) {}
}
文件 4 的 19:ConfirmedOwnerWithProposal.sol
pragma solidity ^0.8.0;
import "./interfaces/OwnableInterface.sol";
contract ConfirmedOwnerWithProposal is OwnableInterface {
address private s_owner;
address private s_pendingOwner;
event OwnershipTransferRequested(address indexed from, address indexed to);
event OwnershipTransferred(address indexed from, address indexed to);
constructor(address newOwner, address pendingOwner) {
require(newOwner != address(0), "Cannot set owner to zero");
s_owner = newOwner;
if (pendingOwner != address(0)) {
_transferOwnership(pendingOwner);
}
}
function transferOwnership(address to) public override onlyOwner {
_transferOwnership(to);
}
function acceptOwnership() external override {
require(msg.sender == s_pendingOwner, "Must be proposed owner");
address oldOwner = s_owner;
s_owner = msg.sender;
s_pendingOwner = address(0);
emit OwnershipTransferred(oldOwner, msg.sender);
}
function owner() public view override returns (address) {
return s_owner;
}
function _transferOwnership(address to) private {
require(to != msg.sender, "Cannot transfer to self");
s_pendingOwner = to;
emit OwnershipTransferRequested(s_owner, to);
}
function _validateOwnership() internal view {
require(msg.sender == s_owner, "Only callable by owner");
}
modifier onlyOwner() {
_validateOwnership();
_;
}
}
文件 5 的 19:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 6 的 19:ERC677ReceiverInterface.sol
pragma solidity ^0.8.6;
interface ERC677ReceiverInterface {
function onTokenTransfer(
address sender,
uint256 amount,
bytes calldata data
) external;
}
文件 7 的 19:EnumerableSet.sol
pragma solidity ^0.8.0;
library EnumerableSet {
struct Set {
bytes32[] _values;
mapping(bytes32 => uint256) _indexes;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastvalue = set._values[lastIndex];
set._values[toDeleteIndex] = lastvalue;
set._indexes[lastvalue] = valueIndex;
}
set._values.pop();
delete set._indexes[value];
return true;
} else {
return false;
}
}
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
struct Bytes32Set {
Set _inner;
}
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
return _values(set._inner);
}
struct AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
struct UintSet {
Set _inner;
}
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}
文件 8 的 19:KeeperBase.sol
pragma solidity ^0.8.0;
contract KeeperBase {
error OnlySimulatedBackend();
function preventExecution() internal view {
if (tx.origin != address(0)) {
revert OnlySimulatedBackend();
}
}
modifier cannotExecute() {
preventExecution();
_;
}
}
文件 9 的 19:KeeperCompatibleInterface.sol
pragma solidity ^0.8.0;
interface KeeperCompatibleInterface {
function checkUpkeep(bytes calldata checkData) external returns (bool upkeepNeeded, bytes memory performData);
function performUpkeep(bytes calldata performData) external;
}
文件 10 的 19:KeeperRegistry.sol
pragma solidity 0.8.13;
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./KeeperBase.sol";
import "./ConfirmedOwner.sol";
import "./interfaces/TypeAndVersionInterface.sol";
import "./interfaces/AggregatorV3Interface.sol";
import "./interfaces/LinkTokenInterface.sol";
import "./interfaces/KeeperCompatibleInterface.sol";
import "./interfaces/KeeperRegistryInterface.sol";
import "./interfaces/MigratableKeeperRegistryInterface.sol";
import "./interfaces/UpkeepTranscoderInterface.sol";
import "./interfaces/ERC677ReceiverInterface.sol";
contract KeeperRegistry is
TypeAndVersionInterface,
ConfirmedOwner,
KeeperBase,
ReentrancyGuard,
Pausable,
KeeperRegistryExecutableInterface,
MigratableKeeperRegistryInterface,
ERC677ReceiverInterface
{
using Address for address;
using EnumerableSet for EnumerableSet.UintSet;
address private constant ZERO_ADDRESS = address(0);
address private constant IGNORE_ADDRESS = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF;
bytes4 private constant CHECK_SELECTOR = KeeperCompatibleInterface.checkUpkeep.selector;
bytes4 private constant PERFORM_SELECTOR = KeeperCompatibleInterface.performUpkeep.selector;
uint256 private constant PERFORM_GAS_MIN = 2_300;
uint256 private constant CANCELATION_DELAY = 50;
uint256 private constant PERFORM_GAS_CUSHION = 5_000;
uint256 private constant REGISTRY_GAS_OVERHEAD = 80_000;
uint256 private constant PPB_BASE = 1_000_000_000;
uint64 private constant UINT64_MAX = 2**64 - 1;
uint96 private constant LINK_TOTAL_SUPPLY = 1e27;
address[] private s_keeperList;
EnumerableSet.UintSet private s_upkeepIDs;
mapping(uint256 => Upkeep) private s_upkeep;
mapping(address => KeeperInfo) private s_keeperInfo;
mapping(address => address) private s_proposedPayee;
mapping(uint256 => bytes) private s_checkData;
mapping(address => MigrationPermission) private s_peerRegistryMigrationPermission;
Storage private s_storage;
uint256 private s_fallbackGasPrice;
uint256 private s_fallbackLinkPrice;
uint96 private s_ownerLinkBalance;
uint256 private s_expectedLinkBalance;
address private s_transcoder;
address private s_registrar;
LinkTokenInterface public immutable LINK;
AggregatorV3Interface public immutable LINK_ETH_FEED;
AggregatorV3Interface public immutable FAST_GAS_FEED;
string public constant override typeAndVersion = "KeeperRegistry 1.2.0";
error CannotCancel();
error UpkeepNotActive();
error MigrationNotPermitted();
error UpkeepNotCanceled();
error UpkeepNotNeeded();
error NotAContract();
error PaymentGreaterThanAllLINK();
error OnlyActiveKeepers();
error InsufficientFunds();
error KeepersMustTakeTurns();
error ParameterLengthError();
error OnlyCallableByOwnerOrAdmin();
error OnlyCallableByLINKToken();
error InvalidPayee();
error DuplicateEntry();
error ValueNotChanged();
error IndexOutOfRange();
error TranscoderNotSet();
error ArrayHasNoEntries();
error GasLimitOutsideRange();
error OnlyCallableByPayee();
error OnlyCallableByProposedPayee();
error GasLimitCanOnlyIncrease();
error OnlyCallableByAdmin();
error OnlyCallableByOwnerOrRegistrar();
error InvalidRecipient();
error InvalidDataLength();
error TargetCheckReverted(bytes reason);
enum MigrationPermission {
NONE,
OUTGOING,
INCOMING,
BIDIRECTIONAL
}
struct Storage {
uint32 paymentPremiumPPB;
uint32 flatFeeMicroLink;
uint24 blockCountPerTurn;
uint32 checkGasLimit;
uint24 stalenessSeconds;
uint16 gasCeilingMultiplier;
uint96 minUpkeepSpend;
uint32 maxPerformGas;
uint32 nonce;
}
struct Upkeep {
uint96 balance;
address lastKeeper;
uint32 executeGas;
uint64 maxValidBlocknumber;
address target;
uint96 amountSpent;
address admin;
}
struct KeeperInfo {
address payee;
uint96 balance;
bool active;
}
struct PerformParams {
address from;
uint256 id;
bytes performData;
uint256 maxLinkPayment;
uint256 gasLimit;
uint256 adjustedGasWei;
uint256 linkEth;
}
event UpkeepRegistered(uint256 indexed id, uint32 executeGas, address admin);
event UpkeepPerformed(
uint256 indexed id,
bool indexed success,
address indexed from,
uint96 payment,
bytes performData
);
event UpkeepCanceled(uint256 indexed id, uint64 indexed atBlockHeight);
event FundsAdded(uint256 indexed id, address indexed from, uint96 amount);
event FundsWithdrawn(uint256 indexed id, uint256 amount, address to);
event OwnerFundsWithdrawn(uint96 amount);
event UpkeepMigrated(uint256 indexed id, uint256 remainingBalance, address destination);
event UpkeepReceived(uint256 indexed id, uint256 startingBalance, address importedFrom);
event ConfigSet(Config config);
event KeepersUpdated(address[] keepers, address[] payees);
event PaymentWithdrawn(address indexed keeper, uint256 indexed amount, address indexed to, address payee);
event PayeeshipTransferRequested(address indexed keeper, address indexed from, address indexed to);
event PayeeshipTransferred(address indexed keeper, address indexed from, address indexed to);
event UpkeepGasLimitSet(uint256 indexed id, uint96 gasLimit);
constructor(
address link,
address linkEthFeed,
address fastGasFeed,
Config memory config
) ConfirmedOwner(msg.sender) {
LINK = LinkTokenInterface(link);
LINK_ETH_FEED = AggregatorV3Interface(linkEthFeed);
FAST_GAS_FEED = AggregatorV3Interface(fastGasFeed);
setConfig(config);
}
function registerUpkeep(
address target,
uint32 gasLimit,
address admin,
bytes calldata checkData
) external override onlyOwnerOrRegistrar returns (uint256 id) {
id = uint256(keccak256(abi.encodePacked(blockhash(block.number - 1), address(this), s_storage.nonce)));
_createUpkeep(id, target, gasLimit, admin, 0, checkData);
s_storage.nonce++;
emit UpkeepRegistered(id, gasLimit, admin);
return id;
}
function checkUpkeep(uint256 id, address from)
external
override
cannotExecute
returns (
bytes memory performData,
uint256 maxLinkPayment,
uint256 gasLimit,
uint256 adjustedGasWei,
uint256 linkEth
)
{
Upkeep memory upkeep = s_upkeep[id];
bytes memory callData = abi.encodeWithSelector(CHECK_SELECTOR, s_checkData[id]);
(bool success, bytes memory result) = upkeep.target.call{gas: s_storage.checkGasLimit}(callData);
if (!success) revert TargetCheckReverted(result);
(success, performData) = abi.decode(result, (bool, bytes));
if (!success) revert UpkeepNotNeeded();
PerformParams memory params = _generatePerformParams(from, id, performData, false);
_prePerformUpkeep(upkeep, params.from, params.maxLinkPayment);
return (performData, params.maxLinkPayment, params.gasLimit, params.adjustedGasWei, params.linkEth);
}
function performUpkeep(uint256 id, bytes calldata performData)
external
override
whenNotPaused
returns (bool success)
{
return _performUpkeepWithParams(_generatePerformParams(msg.sender, id, performData, true));
}
function cancelUpkeep(uint256 id) external override {
uint64 maxValid = s_upkeep[id].maxValidBlocknumber;
bool canceled = maxValid != UINT64_MAX;
bool isOwner = msg.sender == owner();
if (canceled && !(isOwner && maxValid > block.number)) revert CannotCancel();
if (!isOwner && msg.sender != s_upkeep[id].admin) revert OnlyCallableByOwnerOrAdmin();
uint256 height = block.number;
if (!isOwner) {
height = height + CANCELATION_DELAY;
}
s_upkeep[id].maxValidBlocknumber = uint64(height);
s_upkeepIDs.remove(id);
emit UpkeepCanceled(id, uint64(height));
}
function addFunds(uint256 id, uint96 amount) external override onlyActiveUpkeep(id) {
s_upkeep[id].balance = s_upkeep[id].balance + amount;
s_expectedLinkBalance = s_expectedLinkBalance + amount;
LINK.transferFrom(msg.sender, address(this), amount);
emit FundsAdded(id, msg.sender, amount);
}
function onTokenTransfer(
address sender,
uint256 amount,
bytes calldata data
) external {
if (msg.sender != address(LINK)) revert OnlyCallableByLINKToken();
if (data.length != 32) revert InvalidDataLength();
uint256 id = abi.decode(data, (uint256));
if (s_upkeep[id].maxValidBlocknumber != UINT64_MAX) revert UpkeepNotActive();
s_upkeep[id].balance = s_upkeep[id].balance + uint96(amount);
s_expectedLinkBalance = s_expectedLinkBalance + amount;
emit FundsAdded(id, sender, uint96(amount));
}
function withdrawFunds(uint256 id, address to) external validRecipient(to) onlyUpkeepAdmin(id) {
if (s_upkeep[id].maxValidBlocknumber > block.number) revert UpkeepNotCanceled();
uint96 minUpkeepSpend = s_storage.minUpkeepSpend;
uint96 amountLeft = s_upkeep[id].balance;
uint96 amountSpent = s_upkeep[id].amountSpent;
uint96 cancellationFee = 0;
if (amountSpent < minUpkeepSpend) {
cancellationFee = minUpkeepSpend - amountSpent;
if (cancellationFee > amountLeft) {
cancellationFee = amountLeft;
}
}
uint96 amountToWithdraw = amountLeft - cancellationFee;
s_upkeep[id].balance = 0;
s_ownerLinkBalance = s_ownerLinkBalance + cancellationFee;
s_expectedLinkBalance = s_expectedLinkBalance - amountToWithdraw;
emit FundsWithdrawn(id, amountToWithdraw, to);
LINK.transfer(to, amountToWithdraw);
}
function withdrawOwnerFunds() external onlyOwner {
uint96 amount = s_ownerLinkBalance;
s_expectedLinkBalance = s_expectedLinkBalance - amount;
s_ownerLinkBalance = 0;
emit OwnerFundsWithdrawn(amount);
LINK.transfer(msg.sender, amount);
}
function setUpkeepGasLimit(uint256 id, uint32 gasLimit) external override onlyActiveUpkeep(id) onlyUpkeepAdmin(id) {
if (gasLimit < PERFORM_GAS_MIN || gasLimit > s_storage.maxPerformGas) revert GasLimitOutsideRange();
s_upkeep[id].executeGas = gasLimit;
emit UpkeepGasLimitSet(id, gasLimit);
}
function recoverFunds() external onlyOwner {
uint256 total = LINK.balanceOf(address(this));
LINK.transfer(msg.sender, total - s_expectedLinkBalance);
}
function withdrawPayment(address from, address to) external validRecipient(to) {
KeeperInfo memory keeper = s_keeperInfo[from];
if (keeper.payee != msg.sender) revert OnlyCallableByPayee();
s_keeperInfo[from].balance = 0;
s_expectedLinkBalance = s_expectedLinkBalance - keeper.balance;
emit PaymentWithdrawn(from, keeper.balance, to, msg.sender);
LINK.transfer(to, keeper.balance);
}
function transferPayeeship(address keeper, address proposed) external {
if (s_keeperInfo[keeper].payee != msg.sender) revert OnlyCallableByPayee();
if (proposed == msg.sender) revert ValueNotChanged();
if (s_proposedPayee[keeper] != proposed) {
s_proposedPayee[keeper] = proposed;
emit PayeeshipTransferRequested(keeper, msg.sender, proposed);
}
}
function acceptPayeeship(address keeper) external {
if (s_proposedPayee[keeper] != msg.sender) revert OnlyCallableByProposedPayee();
address past = s_keeperInfo[keeper].payee;
s_keeperInfo[keeper].payee = msg.sender;
s_proposedPayee[keeper] = ZERO_ADDRESS;
emit PayeeshipTransferred(keeper, past, msg.sender);
}
function pause() external onlyOwner {
_pause();
}
function unpause() external onlyOwner {
_unpause();
}
function setConfig(Config memory config) public onlyOwner {
if (config.maxPerformGas < s_storage.maxPerformGas) revert GasLimitCanOnlyIncrease();
s_storage = Storage({
paymentPremiumPPB: config.paymentPremiumPPB,
flatFeeMicroLink: config.flatFeeMicroLink,
blockCountPerTurn: config.blockCountPerTurn,
checkGasLimit: config.checkGasLimit,
stalenessSeconds: config.stalenessSeconds,
gasCeilingMultiplier: config.gasCeilingMultiplier,
minUpkeepSpend: config.minUpkeepSpend,
maxPerformGas: config.maxPerformGas,
nonce: s_storage.nonce
});
s_fallbackGasPrice = config.fallbackGasPrice;
s_fallbackLinkPrice = config.fallbackLinkPrice;
s_transcoder = config.transcoder;
s_registrar = config.registrar;
emit ConfigSet(config);
}
function setKeepers(address[] calldata keepers, address[] calldata payees) external onlyOwner {
if (keepers.length != payees.length || keepers.length < 2) revert ParameterLengthError();
for (uint256 i = 0; i < s_keeperList.length; i++) {
address keeper = s_keeperList[i];
s_keeperInfo[keeper].active = false;
}
for (uint256 i = 0; i < keepers.length; i++) {
address keeper = keepers[i];
KeeperInfo storage s_keeper = s_keeperInfo[keeper];
address oldPayee = s_keeper.payee;
address newPayee = payees[i];
if (
(newPayee == ZERO_ADDRESS) || (oldPayee != ZERO_ADDRESS && oldPayee != newPayee && newPayee != IGNORE_ADDRESS)
) revert InvalidPayee();
if (s_keeper.active) revert DuplicateEntry();
s_keeper.active = true;
if (newPayee != IGNORE_ADDRESS) {
s_keeper.payee = newPayee;
}
}
s_keeperList = keepers;
emit KeepersUpdated(keepers, payees);
}
function getUpkeep(uint256 id)
external
view
override
returns (
address target,
uint32 executeGas,
bytes memory checkData,
uint96 balance,
address lastKeeper,
address admin,
uint64 maxValidBlocknumber,
uint96 amountSpent
)
{
Upkeep memory reg = s_upkeep[id];
return (
reg.target,
reg.executeGas,
s_checkData[id],
reg.balance,
reg.lastKeeper,
reg.admin,
reg.maxValidBlocknumber,
reg.amountSpent
);
}
function getActiveUpkeepIDs(uint256 startIndex, uint256 maxCount) external view override returns (uint256[] memory) {
uint256 maxIdx = s_upkeepIDs.length();
if (startIndex >= maxIdx) revert IndexOutOfRange();
if (maxCount == 0) {
maxCount = maxIdx - startIndex;
}
uint256[] memory ids = new uint256[](maxCount);
for (uint256 idx = 0; idx < maxCount; idx++) {
ids[idx] = s_upkeepIDs.at(startIndex + idx);
}
return ids;
}
function getKeeperInfo(address query)
external
view
override
returns (
address payee,
bool active,
uint96 balance
)
{
KeeperInfo memory keeper = s_keeperInfo[query];
return (keeper.payee, keeper.active, keeper.balance);
}
function getState()
external
view
override
returns (
State memory state,
Config memory config,
address[] memory keepers
)
{
Storage memory store = s_storage;
state.nonce = store.nonce;
state.ownerLinkBalance = s_ownerLinkBalance;
state.expectedLinkBalance = s_expectedLinkBalance;
state.numUpkeeps = s_upkeepIDs.length();
config.paymentPremiumPPB = store.paymentPremiumPPB;
config.flatFeeMicroLink = store.flatFeeMicroLink;
config.blockCountPerTurn = store.blockCountPerTurn;
config.checkGasLimit = store.checkGasLimit;
config.stalenessSeconds = store.stalenessSeconds;
config.gasCeilingMultiplier = store.gasCeilingMultiplier;
config.minUpkeepSpend = store.minUpkeepSpend;
config.maxPerformGas = store.maxPerformGas;
config.fallbackGasPrice = s_fallbackGasPrice;
config.fallbackLinkPrice = s_fallbackLinkPrice;
config.transcoder = s_transcoder;
config.registrar = s_registrar;
return (state, config, s_keeperList);
}
function getMinBalanceForUpkeep(uint256 id) external view returns (uint96 minBalance) {
return getMaxPaymentForGas(s_upkeep[id].executeGas);
}
function getMaxPaymentForGas(uint256 gasLimit) public view returns (uint96 maxPayment) {
(uint256 gasWei, uint256 linkEth) = _getFeedData();
uint256 adjustedGasWei = _adjustGasPrice(gasWei, false);
return _calculatePaymentAmount(gasLimit, adjustedGasWei, linkEth);
}
function getPeerRegistryMigrationPermission(address peer) external view returns (MigrationPermission) {
return s_peerRegistryMigrationPermission[peer];
}
function setPeerRegistryMigrationPermission(address peer, MigrationPermission permission) external onlyOwner {
s_peerRegistryMigrationPermission[peer] = permission;
}
function migrateUpkeeps(uint256[] calldata ids, address destination) external override {
if (
s_peerRegistryMigrationPermission[destination] != MigrationPermission.OUTGOING &&
s_peerRegistryMigrationPermission[destination] != MigrationPermission.BIDIRECTIONAL
) revert MigrationNotPermitted();
if (s_transcoder == ZERO_ADDRESS) revert TranscoderNotSet();
if (ids.length == 0) revert ArrayHasNoEntries();
uint256 id;
Upkeep memory upkeep;
uint256 totalBalanceRemaining;
bytes[] memory checkDatas = new bytes[](ids.length);
Upkeep[] memory upkeeps = new Upkeep[](ids.length);
for (uint256 idx = 0; idx < ids.length; idx++) {
id = ids[idx];
upkeep = s_upkeep[id];
if (upkeep.admin != msg.sender) revert OnlyCallableByAdmin();
if (upkeep.maxValidBlocknumber != UINT64_MAX) revert UpkeepNotActive();
upkeeps[idx] = upkeep;
checkDatas[idx] = s_checkData[id];
totalBalanceRemaining = totalBalanceRemaining + upkeep.balance;
delete s_upkeep[id];
delete s_checkData[id];
s_upkeepIDs.remove(id);
emit UpkeepMigrated(id, upkeep.balance, destination);
}
s_expectedLinkBalance = s_expectedLinkBalance - totalBalanceRemaining;
bytes memory encodedUpkeeps = abi.encode(ids, upkeeps, checkDatas);
MigratableKeeperRegistryInterface(destination).receiveUpkeeps(
UpkeepTranscoderInterface(s_transcoder).transcodeUpkeeps(
UpkeepFormat.V1,
MigratableKeeperRegistryInterface(destination).upkeepTranscoderVersion(),
encodedUpkeeps
)
);
LINK.transfer(destination, totalBalanceRemaining);
}
UpkeepFormat public constant upkeepTranscoderVersion = UpkeepFormat.V1;
function receiveUpkeeps(bytes calldata encodedUpkeeps) external override {
if (
s_peerRegistryMigrationPermission[msg.sender] != MigrationPermission.INCOMING &&
s_peerRegistryMigrationPermission[msg.sender] != MigrationPermission.BIDIRECTIONAL
) revert MigrationNotPermitted();
(uint256[] memory ids, Upkeep[] memory upkeeps, bytes[] memory checkDatas) = abi.decode(
encodedUpkeeps,
(uint256[], Upkeep[], bytes[])
);
for (uint256 idx = 0; idx < ids.length; idx++) {
_createUpkeep(
ids[idx],
upkeeps[idx].target,
upkeeps[idx].executeGas,
upkeeps[idx].admin,
upkeeps[idx].balance,
checkDatas[idx]
);
emit UpkeepReceived(ids[idx], upkeeps[idx].balance, msg.sender);
}
}
function _createUpkeep(
uint256 id,
address target,
uint32 gasLimit,
address admin,
uint96 balance,
bytes memory checkData
) internal whenNotPaused {
if (!target.isContract()) revert NotAContract();
if (gasLimit < PERFORM_GAS_MIN || gasLimit > s_storage.maxPerformGas) revert GasLimitOutsideRange();
s_upkeep[id] = Upkeep({
target: target,
executeGas: gasLimit,
balance: balance,
admin: admin,
maxValidBlocknumber: UINT64_MAX,
lastKeeper: ZERO_ADDRESS,
amountSpent: 0
});
s_expectedLinkBalance = s_expectedLinkBalance + balance;
s_checkData[id] = checkData;
s_upkeepIDs.add(id);
}
function _getFeedData() private view returns (uint256 gasWei, uint256 linkEth) {
uint32 stalenessSeconds = s_storage.stalenessSeconds;
bool staleFallback = stalenessSeconds > 0;
uint256 timestamp;
int256 feedValue;
(, feedValue, , timestamp, ) = FAST_GAS_FEED.latestRoundData();
if ((staleFallback && stalenessSeconds < block.timestamp - timestamp) || feedValue <= 0) {
gasWei = s_fallbackGasPrice;
} else {
gasWei = uint256(feedValue);
}
(, feedValue, , timestamp, ) = LINK_ETH_FEED.latestRoundData();
if ((staleFallback && stalenessSeconds < block.timestamp - timestamp) || feedValue <= 0) {
linkEth = s_fallbackLinkPrice;
} else {
linkEth = uint256(feedValue);
}
return (gasWei, linkEth);
}
function _calculatePaymentAmount(
uint256 gasLimit,
uint256 gasWei,
uint256 linkEth
) private view returns (uint96 payment) {
uint256 weiForGas = gasWei * (gasLimit + REGISTRY_GAS_OVERHEAD);
uint256 premium = PPB_BASE + s_storage.paymentPremiumPPB;
uint256 total = ((weiForGas * (1e9) * (premium)) / (linkEth)) + (uint256(s_storage.flatFeeMicroLink) * (1e12));
if (total > LINK_TOTAL_SUPPLY) revert PaymentGreaterThanAllLINK();
return uint96(total);
}
function _callWithExactGas(
uint256 gasAmount,
address target,
bytes memory data
) private returns (bool success) {
assembly {
let g := gas()
if lt(g, PERFORM_GAS_CUSHION) {
revert(0, 0)
}
g := sub(g, PERFORM_GAS_CUSHION)
if iszero(gt(sub(g, div(g, 64)), gasAmount)) {
revert(0, 0)
}
if iszero(extcodesize(target)) {
revert(0, 0)
}
success := call(gasAmount, target, 0, add(data, 0x20), mload(data), 0, 0)
}
return success;
}
function _performUpkeepWithParams(PerformParams memory params)
private
nonReentrant
validUpkeep(params.id)
returns (bool success)
{
Upkeep memory upkeep = s_upkeep[params.id];
_prePerformUpkeep(upkeep, params.from, params.maxLinkPayment);
uint256 gasUsed = gasleft();
bytes memory callData = abi.encodeWithSelector(PERFORM_SELECTOR, params.performData);
success = _callWithExactGas(params.gasLimit, upkeep.target, callData);
gasUsed = gasUsed - gasleft();
uint96 payment = _calculatePaymentAmount(gasUsed, params.adjustedGasWei, params.linkEth);
s_upkeep[params.id].balance = s_upkeep[params.id].balance - payment;
s_upkeep[params.id].amountSpent = s_upkeep[params.id].amountSpent + payment;
s_upkeep[params.id].lastKeeper = params.from;
s_keeperInfo[params.from].balance = s_keeperInfo[params.from].balance + payment;
emit UpkeepPerformed(params.id, success, params.from, payment, params.performData);
return success;
}
function _prePerformUpkeep(
Upkeep memory upkeep,
address from,
uint256 maxLinkPayment
) private view {
if (!s_keeperInfo[from].active) revert OnlyActiveKeepers();
if (upkeep.balance < maxLinkPayment) revert InsufficientFunds();
if (upkeep.lastKeeper == from) revert KeepersMustTakeTurns();
}
function _adjustGasPrice(uint256 gasWei, bool useTxGasPrice) private view returns (uint256 adjustedPrice) {
adjustedPrice = gasWei * s_storage.gasCeilingMultiplier;
if (useTxGasPrice && tx.gasprice < adjustedPrice) {
adjustedPrice = tx.gasprice;
}
}
function _generatePerformParams(
address from,
uint256 id,
bytes memory performData,
bool useTxGasPrice
) private view returns (PerformParams memory) {
uint256 gasLimit = s_upkeep[id].executeGas;
(uint256 gasWei, uint256 linkEth) = _getFeedData();
uint256 adjustedGasWei = _adjustGasPrice(gasWei, useTxGasPrice);
uint96 maxLinkPayment = _calculatePaymentAmount(gasLimit, adjustedGasWei, linkEth);
return
PerformParams({
from: from,
id: id,
performData: performData,
maxLinkPayment: maxLinkPayment,
gasLimit: gasLimit,
adjustedGasWei: adjustedGasWei,
linkEth: linkEth
});
}
modifier validUpkeep(uint256 id) {
if (s_upkeep[id].maxValidBlocknumber <= block.number) revert UpkeepNotActive();
_;
}
modifier onlyUpkeepAdmin(uint256 id) {
if (msg.sender != s_upkeep[id].admin) revert OnlyCallableByAdmin();
_;
}
modifier onlyActiveUpkeep(uint256 id) {
if (s_upkeep[id].maxValidBlocknumber != UINT64_MAX) revert UpkeepNotActive();
_;
}
modifier validRecipient(address to) {
if (to == ZERO_ADDRESS) revert InvalidRecipient();
_;
}
modifier onlyOwnerOrRegistrar() {
if (msg.sender != owner() && msg.sender != s_registrar) revert OnlyCallableByOwnerOrRegistrar();
_;
}
}
文件 11 的 19:KeeperRegistryInterface.sol
pragma solidity ^0.8.0;
struct Config {
uint32 paymentPremiumPPB;
uint32 flatFeeMicroLink;
uint24 blockCountPerTurn;
uint32 checkGasLimit;
uint24 stalenessSeconds;
uint16 gasCeilingMultiplier;
uint96 minUpkeepSpend;
uint32 maxPerformGas;
uint256 fallbackGasPrice;
uint256 fallbackLinkPrice;
address transcoder;
address registrar;
}
struct State {
uint32 nonce;
uint96 ownerLinkBalance;
uint256 expectedLinkBalance;
uint256 numUpkeeps;
}
interface KeeperRegistryBaseInterface {
function registerUpkeep(
address target,
uint32 gasLimit,
address admin,
bytes calldata checkData
) external returns (uint256 id);
function performUpkeep(uint256 id, bytes calldata performData) external returns (bool success);
function cancelUpkeep(uint256 id) external;
function addFunds(uint256 id, uint96 amount) external;
function setUpkeepGasLimit(uint256 id, uint32 gasLimit) external;
function getUpkeep(uint256 id)
external
view
returns (
address target,
uint32 executeGas,
bytes memory checkData,
uint96 balance,
address lastKeeper,
address admin,
uint64 maxValidBlocknumber,
uint96 amountSpent
);
function getActiveUpkeepIDs(uint256 startIndex, uint256 maxCount) external view returns (uint256[] memory);
function getKeeperInfo(address query)
external
view
returns (
address payee,
bool active,
uint96 balance
);
function getState()
external
view
returns (
State memory,
Config memory,
address[] memory
);
}
interface KeeperRegistryInterface is KeeperRegistryBaseInterface {
function checkUpkeep(uint256 upkeepId, address from)
external
view
returns (
bytes memory performData,
uint256 maxLinkPayment,
uint256 gasLimit,
int256 gasWei,
int256 linkEth
);
}
interface KeeperRegistryExecutableInterface is KeeperRegistryBaseInterface {
function checkUpkeep(uint256 upkeepId, address from)
external
returns (
bytes memory performData,
uint256 maxLinkPayment,
uint256 gasLimit,
uint256 adjustedGasWei,
uint256 linkEth
);
}
文件 12 的 19:LinkTokenInterface.sol
pragma solidity ^0.8.0;
interface LinkTokenInterface {
function allowance(address owner, address spender) external view returns (uint256 remaining);
function approve(address spender, uint256 value) external returns (bool success);
function balanceOf(address owner) external view returns (uint256 balance);
function decimals() external view returns (uint8 decimalPlaces);
function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);
function increaseApproval(address spender, uint256 subtractedValue) external;
function name() external view returns (string memory tokenName);
function symbol() external view returns (string memory tokenSymbol);
function totalSupply() external view returns (uint256 totalTokensIssued);
function transfer(address to, uint256 value) external returns (bool success);
function transferAndCall(
address to,
uint256 value,
bytes calldata data
) external returns (bool success);
function transferFrom(
address from,
address to,
uint256 value
) external returns (bool success);
}
文件 13 的 19:MigratableKeeperRegistryInterface.sol
pragma solidity ^0.8.0;
import "../UpkeepFormat.sol";
interface MigratableKeeperRegistryInterface {
function migrateUpkeeps(uint256[] calldata upkeepIDs, address destination) external;
function receiveUpkeeps(bytes calldata encodedUpkeeps) external;
function upkeepTranscoderVersion() external returns (UpkeepFormat version);
}
文件 14 的 19:OwnableInterface.sol
pragma solidity ^0.8.0;
interface OwnableInterface {
function owner() external returns (address);
function transferOwnership(address recipient) external;
function acceptOwnership() external;
}
文件 15 的 19:Pausable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Pausable is Context {
event Paused(address account);
event Unpaused(address account);
bool private _paused;
constructor() {
_paused = false;
}
function paused() public view virtual returns (bool) {
return _paused;
}
modifier whenNotPaused() {
require(!paused(), "Pausable: paused");
_;
}
modifier whenPaused() {
require(paused(), "Pausable: not paused");
_;
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
文件 16 的 19:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 17 的 19:TypeAndVersionInterface.sol
pragma solidity ^0.8.0;
abstract contract TypeAndVersionInterface {
function typeAndVersion() external pure virtual returns (string memory);
}
文件 18 的 19:UpkeepFormat.sol
pragma solidity ^0.8.0;
enum UpkeepFormat {
V1
}
文件 19 的 19:UpkeepTranscoderInterface.sol
import "../UpkeepFormat.sol";
pragma solidity ^0.8.0;
interface UpkeepTranscoderInterface {
function transcodeUpkeeps(
UpkeepFormat fromVersion,
UpkeepFormat toVersion,
bytes calldata encodedUpkeeps
) external view returns (bytes memory);
}
{
"compilationTarget": {
"contracts/v0.8/KeeperRegistry.sol": "KeeperRegistry"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "none",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 1000000
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"link","type":"address"},{"internalType":"address","name":"linkEthFeed","type":"address"},{"internalType":"address","name":"fastGasFeed","type":"address"},{"components":[{"internalType":"uint32","name":"paymentPremiumPPB","type":"uint32"},{"internalType":"uint32","name":"flatFeeMicroLink","type":"uint32"},{"internalType":"uint24","name":"blockCountPerTurn","type":"uint24"},{"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":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"address","name":"registrar","type":"address"}],"internalType":"struct Config","name":"config","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ArrayHasNoEntries","type":"error"},{"inputs":[],"name":"CannotCancel","type":"error"},{"inputs":[],"name":"DuplicateEntry","type":"error"},{"inputs":[],"name":"GasLimitCanOnlyIncrease","type":"error"},{"inputs":[],"name":"GasLimitOutsideRange","type":"error"},{"inputs":[],"name":"IndexOutOfRange","type":"error"},{"inputs":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"InvalidDataLength","type":"error"},{"inputs":[],"name":"InvalidPayee","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"KeepersMustTakeTurns","type":"error"},{"inputs":[],"name":"MigrationNotPermitted","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"OnlyActiveKeepers","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":"OnlyCallableByProposedPayee","type":"error"},{"inputs":[],"name":"OnlySimulatedBackend","type":"error"},{"inputs":[],"name":"ParameterLengthError","type":"error"},{"inputs":[],"name":"PaymentGreaterThanAllLINK","type":"error"},{"inputs":[{"internalType":"bytes","name":"reason","type":"bytes"}],"name":"TargetCheckReverted","type":"error"},{"inputs":[],"name":"TranscoderNotSet","type":"error"},{"inputs":[],"name":"UpkeepNotActive","type":"error"},{"inputs":[],"name":"UpkeepNotCanceled","type":"error"},{"inputs":[],"name":"UpkeepNotNeeded","type":"error"},{"inputs":[],"name":"ValueNotChanged","type":"error"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint32","name":"paymentPremiumPPB","type":"uint32"},{"internalType":"uint32","name":"flatFeeMicroLink","type":"uint32"},{"internalType":"uint24","name":"blockCountPerTurn","type":"uint24"},{"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":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"address","name":"registrar","type":"address"}],"indexed":false,"internalType":"struct Config","name":"config","type":"tuple"}],"name":"ConfigSet","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":false,"internalType":"address[]","name":"keepers","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"payees","type":"address[]"}],"name":"KeepersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"}],"name":"OwnerFundsWithdrawn","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":true,"internalType":"address","name":"keeper","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":"keeper","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":"keeper","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":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":"uint64","name":"atBlockHeight","type":"uint64"}],"name":"UpkeepCanceled","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":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint96","name":"payment","type":"uint96"},{"indexed":false,"internalType":"bytes","name":"performData","type":"bytes"}],"name":"UpkeepPerformed","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":"executeGas","type":"uint32"},{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"UpkeepRegistered","type":"event"},{"inputs":[],"name":"FAST_GAS_FEED","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LINK","outputs":[{"internalType":"contract LinkTokenInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LINK_ETH_FEED","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"keeper","type":"address"}],"name":"acceptPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint96","name":"amount","type":"uint96"}],"name":"addFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"cancelUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"from","type":"address"}],"name":"checkUpkeep","outputs":[{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"uint256","name":"maxLinkPayment","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"adjustedGasWei","type":"uint256"},{"internalType":"uint256","name":"linkEth","type":"uint256"}],"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":"query","type":"address"}],"name":"getKeeperInfo","outputs":[{"internalType":"address","name":"payee","type":"address"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint96","name":"balance","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"gasLimit","type":"uint256"}],"name":"getMaxPaymentForGas","outputs":[{"internalType":"uint96","name":"maxPayment","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":[{"internalType":"address","name":"peer","type":"address"}],"name":"getPeerRegistryMigrationPermission","outputs":[{"internalType":"enum KeeperRegistry.MigrationPermission","name":"","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":"uint256","name":"numUpkeeps","type":"uint256"}],"internalType":"struct State","name":"state","type":"tuple"},{"components":[{"internalType":"uint32","name":"paymentPremiumPPB","type":"uint32"},{"internalType":"uint32","name":"flatFeeMicroLink","type":"uint32"},{"internalType":"uint24","name":"blockCountPerTurn","type":"uint24"},{"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":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"address","name":"registrar","type":"address"}],"internalType":"struct Config","name":"config","type":"tuple"},{"internalType":"address[]","name":"keepers","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getUpkeep","outputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"executeGas","type":"uint32"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"uint96","name":"balance","type":"uint96"},{"internalType":"address","name":"lastKeeper","type":"address"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"uint64","name":"maxValidBlocknumber","type":"uint64"},{"internalType":"uint96","name":"amountSpent","type":"uint96"}],"stateMutability":"view","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":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"performData","type":"bytes"}],"name":"performUpkeep","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedUpkeeps","type":"bytes"}],"name":"receiveUpkeeps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"recoverFunds","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":"bytes","name":"checkData","type":"bytes"}],"name":"registerUpkeep","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"paymentPremiumPPB","type":"uint32"},{"internalType":"uint32","name":"flatFeeMicroLink","type":"uint32"},{"internalType":"uint24","name":"blockCountPerTurn","type":"uint24"},{"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":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"address","name":"registrar","type":"address"}],"internalType":"struct Config","name":"config","type":"tuple"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"keepers","type":"address[]"},{"internalType":"address[]","name":"payees","type":"address[]"}],"name":"setKeepers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"},{"internalType":"enum KeeperRegistry.MigrationPermission","name":"permission","type":"uint8"}],"name":"setPeerRegistryMigrationPermission","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":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"keeper","type":"address"},{"internalType":"address","name":"proposed","type":"address"}],"name":"transferPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"upkeepTranscoderVersion","outputs":[{"internalType":"enum UpkeepFormat","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawOwnerFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawPayment","outputs":[],"stateMutability":"nonpayable","type":"function"}]