// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./ConfirmedOwnerWithProposal.sol";
/**
* @title The ConfirmedOwner contract
* @notice A contract with helpers for basic contract ownership.
*/
contract ConfirmedOwner is ConfirmedOwnerWithProposal {
constructor(address newOwner) ConfirmedOwnerWithProposal(newOwner, address(0)) {}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./interfaces/OwnableInterface.sol";
/**
* @title The ConfirmedOwner contract
* @notice A contract with helpers for basic contract ownership.
*/
contract ConfirmedOwnerWithProposal is OwnableInterface {
address private s_owner;
address private s_pendingOwner;
event OwnershipTransferRequested(address indexed from, address indexed to);
event OwnershipTransferred(address indexed from, address indexed to);
constructor(address newOwner, address pendingOwner) {
require(newOwner != address(0), "Cannot set owner to zero");
s_owner = newOwner;
if (pendingOwner != address(0)) {
_transferOwnership(pendingOwner);
}
}
/**
* @notice Allows an owner to begin transferring ownership to a new address,
* pending.
*/
function transferOwnership(address to) public override onlyOwner {
_transferOwnership(to);
}
/**
* @notice Allows an ownership transfer to be completed by the recipient.
*/
function acceptOwnership() external override {
require(msg.sender == s_pendingOwner, "Must be proposed owner");
address oldOwner = s_owner;
s_owner = msg.sender;
s_pendingOwner = address(0);
emit OwnershipTransferred(oldOwner, msg.sender);
}
/**
* @notice Get the current owner
*/
function owner() public view override returns (address) {
return s_owner;
}
/**
* @notice validate, transfer ownership, and emit relevant events
*/
function _transferOwnership(address to) private {
require(to != msg.sender, "Cannot transfer to self");
s_pendingOwner = to;
emit OwnershipTransferRequested(s_owner, to);
}
/**
* @notice validate access
*/
function _validateOwnership() internal view {
require(msg.sender == s_owner, "Only callable by owner");
}
/**
* @notice Reverts if called by anyone other than the contract owner.
*/
modifier onlyOwner() {
_validateOwnership();
_;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
interface ERC677ReceiverInterface {
function onTokenTransfer(
address sender,
uint256 amount,
bytes calldata data
) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;
import "./interfaces/LinkTokenInterface.sol";
import "./interfaces/KeeperRegistryInterface.sol";
import "./interfaces/TypeAndVersionInterface.sol";
import "./ConfirmedOwner.sol";
import "./interfaces/ERC677ReceiverInterface.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 KeeperRegistrar is TypeAndVersionInterface, ConfirmedOwner, ERC677ReceiverInterface {
/**
* 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
}
bytes4 private constant REGISTER_REQUEST_SELECTOR = this.register.selector;
mapping(bytes32 => PendingRequest) private s_pendingRequests;
LinkTokenInterface public immutable LINK;
/**
* @notice versions:
* - 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 = "KeeperRegistrar 1.1.0";
struct Config {
AutoApproveType autoApproveConfigType;
uint32 autoApproveMaxAllowed;
uint32 approvedCount;
KeeperRegistryBaseInterface keeperRegistry;
uint96 minLINKJuels;
}
struct PendingRequest {
address admin;
uint96 balance;
}
Config private s_config;
// Only applicable if s_config.configType is ENABLED_SENDER_ALLOWLIST
mapping(address => bool) private s_autoApproveAllowedSenders;
event RegistrationRequested(
bytes32 indexed hash,
string name,
bytes encryptedEmail,
address indexed upkeepContract,
uint32 gasLimit,
address adminAddress,
bytes checkData,
uint96 amount,
uint8 indexed source
);
event RegistrationApproved(bytes32 indexed hash, string displayName, uint256 indexed upkeepId);
event RegistrationRejected(bytes32 indexed hash);
event AutoApproveAllowedSenderSet(address indexed senderAddress, bool allowed);
event ConfigChanged(
AutoApproveType autoApproveConfigType,
uint32 autoApproveMaxAllowed,
address keeperRegistry,
uint96 minLINKJuels
);
error InvalidAdminAddress();
error RequestNotFound();
error HashMismatch();
error OnlyAdminOrOwner();
error InsufficientPayment();
error RegistrationRequestFailed();
error OnlyLink();
error AmountMismatch();
error SenderMismatch();
error FunctionNotPermitted();
error LinkTransferFailed(address to);
error InvalidDataLength();
/*
* @param LINKAddress Address of Link token
* @param autoApproveConfigType setting for auto-approve registrations
* @param autoApproveMaxAllowed max number of registrations that can be auto approved
* @param keeperRegistry keeper registry address
* @param minLINKJuels minimum LINK that new registrations should fund their upkeep with
*/
constructor(
address LINKAddress,
AutoApproveType autoApproveConfigType,
uint16 autoApproveMaxAllowed,
address keeperRegistry,
uint96 minLINKJuels
) ConfirmedOwner(msg.sender) {
LINK = LinkTokenInterface(LINKAddress);
setRegistrationConfig(autoApproveConfigType, autoApproveMaxAllowed, keeperRegistry, minLINKJuels);
}
//EXTERNAL
/**
* @notice register can only be called through transferAndCall on LINK contract
* @param name string of the upkeep to be registered
* @param encryptedEmail email address of upkeep contact
* @param upkeepContract address to perform upkeep on
* @param gasLimit amount of gas to provide the target contract when performing upkeep
* @param adminAddress address to cancel upkeep and withdraw remaining funds
* @param checkData data passed to the contract when checking for upkeep
* @param amount quantity of LINK upkeep is funded with (specified in Juels)
* @param source application sending this request
* @param sender address of the sender making the request
*/
function register(
string memory name,
bytes calldata encryptedEmail,
address upkeepContract,
uint32 gasLimit,
address adminAddress,
bytes calldata checkData,
uint96 amount,
uint8 source,
address sender
) external onlyLINK {
if (adminAddress == address(0)) {
revert InvalidAdminAddress();
}
bytes32 hash = keccak256(abi.encode(upkeepContract, gasLimit, adminAddress, checkData));
emit RegistrationRequested(
hash,
name,
encryptedEmail,
upkeepContract,
gasLimit,
adminAddress,
checkData,
amount,
source
);
Config memory config = s_config;
if (_shouldAutoApprove(config, sender)) {
s_config.approvedCount = config.approvedCount + 1;
_approve(name, upkeepContract, gasLimit, adminAddress, checkData, amount, hash);
} else {
uint96 newBalance = s_pendingRequests[hash].balance + amount;
s_pendingRequests[hash] = PendingRequest({admin: adminAddress, balance: newBalance});
}
}
/**
* @dev register upkeep on KeeperRegistry contract and emit RegistrationApproved event
*/
function approve(
string memory name,
address upkeepContract,
uint32 gasLimit,
address adminAddress,
bytes calldata checkData,
bytes32 hash
) external onlyOwner {
PendingRequest memory request = s_pendingRequests[hash];
if (request.admin == address(0)) {
revert RequestNotFound();
}
bytes32 expectedHash = keccak256(abi.encode(upkeepContract, gasLimit, adminAddress, checkData));
if (hash != expectedHash) {
revert HashMismatch();
}
delete s_pendingRequests[hash];
_approve(name, upkeepContract, gasLimit, adminAddress, checkData, request.balance, hash);
}
/**
* @notice cancel will remove a registration request and return the refunds to the msg.sender
* @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];
bool success = LINK.transfer(msg.sender, request.balance);
if (!success) {
revert LinkTransferFailed(msg.sender);
}
emit RegistrationRejected(hash);
}
/**
* @notice owner calls this function to set if registration requests should be sent directly to the Keeper Registry
* @param autoApproveConfigType setting for auto-approve registrations
* note: autoApproveAllowedSenders list persists across config changes irrespective of type
* @param autoApproveMaxAllowed max number of registrations that can be auto approved
* @param keeperRegistry new keeper registry address
* @param minLINKJuels minimum LINK that new registrations should fund their upkeep with
*/
function setRegistrationConfig(
AutoApproveType autoApproveConfigType,
uint16 autoApproveMaxAllowed,
address keeperRegistry,
uint96 minLINKJuels
) public onlyOwner {
uint32 approvedCount = s_config.approvedCount;
s_config = Config({
autoApproveConfigType: autoApproveConfigType,
autoApproveMaxAllowed: autoApproveMaxAllowed,
approvedCount: approvedCount,
minLINKJuels: minLINKJuels,
keeperRegistry: KeeperRegistryBaseInterface(keeperRegistry)
});
emit ConfigChanged(autoApproveConfigType, autoApproveMaxAllowed, keeperRegistry, minLINKJuels);
}
/**
* @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 read the current registration configuration
*/
function getRegistrationConfig()
external
view
returns (
AutoApproveType autoApproveConfigType,
uint32 autoApproveMaxAllowed,
uint32 approvedCount,
address keeperRegistry,
uint256 minLINKJuels
)
{
Config memory config = s_config;
return (
config.autoApproveConfigType,
config.autoApproveMaxAllowed,
config.approvedCount,
address(config.keeperRegistry),
config.minLINKJuels
);
}
/**
* @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 onlyLINK permittedFunctionsForLINK(data) isActualAmount(amount, data) isActualSender(sender, data) {
if (data.length < 292) revert InvalidDataLength();
if (amount < s_config.minLINKJuels) {
revert InsufficientPayment();
}
(bool success, ) = address(this).delegatecall(data);
// calls register
if (!success) {
revert RegistrationRequestFailed();
}
}
//PRIVATE
/**
* @dev register upkeep on KeeperRegistry contract and emit RegistrationApproved event
*/
function _approve(
string memory name,
address upkeepContract,
uint32 gasLimit,
address adminAddress,
bytes calldata checkData,
uint96 amount,
bytes32 hash
) private {
KeeperRegistryBaseInterface keeperRegistry = s_config.keeperRegistry;
// register upkeep
uint256 upkeepId = keeperRegistry.registerUpkeep(upkeepContract, gasLimit, adminAddress, checkData);
// fund upkeep
bool success = LINK.transferAndCall(address(keeperRegistry), amount, abi.encode(upkeepId));
if (!success) {
revert LinkTransferFailed(address(keeperRegistry));
}
emit RegistrationApproved(hash, name, upkeepId);
}
/**
* @dev verify sender allowlist if needed and check max limit
*/
function _shouldAutoApprove(Config memory config, address sender) private returns (bool) {
if (config.autoApproveConfigType == AutoApproveType.DISABLED) {
return false;
}
if (
config.autoApproveConfigType == AutoApproveType.ENABLED_SENDER_ALLOWLIST && (!s_autoApproveAllowedSenders[sender])
) {
return false;
}
if (config.approvedCount < config.autoApproveMaxAllowed) {
return true;
}
return false;
}
//MODIFIERS
/**
* @dev Reverts if not sent from the LINK token
*/
modifier onlyLINK() {
if (msg.sender != address(LINK)) {
revert OnlyLink();
}
_;
}
/**
* @dev Reverts if the given data does not begin with the `register` function selector
* @param _data The data payload of the request
*/
modifier permittedFunctionsForLINK(bytes memory _data) {
bytes4 funcSelector;
assembly {
// solhint-disable-next-line avoid-low-level-calls
funcSelector := mload(add(_data, 32)) // First 32 bytes contain length of data
}
if (funcSelector != REGISTER_REQUEST_SELECTOR) {
revert FunctionNotPermitted();
}
_;
}
/**
* @dev Reverts if the actual amount passed does not match the expected amount
* @param expected amount that should match the actual amount
* @param data bytes
*/
modifier isActualAmount(uint256 expected, bytes memory data) {
uint256 actual;
assembly {
actual := mload(add(data, 228))
}
if (expected != actual) {
revert AmountMismatch();
}
_;
}
/**
* @dev Reverts if the actual sender address does not match the expected sender address
* @param expected address that should match the actual sender address
* @param data bytes
*/
modifier isActualSender(address expected, bytes memory data) {
address actual;
assembly {
actual := mload(add(data, 292))
}
if (expected != actual) {
revert SenderMismatch();
}
_;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @notice config 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 blockCountPerTurn number of blocks each oracle has during their turn to
* perform upkeep before it will be the next keeper's turn to submit
* @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 executeGas allowed for an upkeep on this registry
* @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 registrar address of the registrar contract
*/
struct Config {
uint32 paymentPremiumPPB;
uint32 flatFeeMicroLink; // min 0.000001 LINK, max 4294 LINK
uint24 blockCountPerTurn;
uint32 checkGasLimit;
uint24 stalenessSeconds;
uint16 gasCeilingMultiplier;
uint96 minUpkeepSpend;
uint32 maxPerformGas;
uint256 fallbackGasPrice;
uint256 fallbackLinkPrice;
address transcoder;
address registrar;
}
/**
* @notice config of the registry
* @dev only used in params and return values
* @member nonce used for ID generation
* @ownerLinkBalance withdrawable balance of LINK by contract owner
* @numUpkeeps total number of upkeeps on the registry
*/
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
);
}
/**
* @dev The view methods are not actually marked as view in the implementation
* but we want them to be easily queried off-chain. Solidity will not compile
* if we actually inherit from this interface, so we document it here.
*/
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
);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface LinkTokenInterface {
function allowance(address owner, address spender) external view returns (uint256 remaining);
function approve(address spender, uint256 value) external returns (bool success);
function balanceOf(address owner) external view returns (uint256 balance);
function decimals() external view returns (uint8 decimalPlaces);
function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);
function increaseApproval(address spender, uint256 subtractedValue) external;
function name() external view returns (string memory tokenName);
function symbol() external view returns (string memory tokenSymbol);
function totalSupply() external view returns (uint256 totalTokensIssued);
function transfer(address to, uint256 value) external returns (bool success);
function transferAndCall(
address to,
uint256 value,
bytes calldata data
) external returns (bool success);
function transferFrom(
address from,
address to,
uint256 value
) external returns (bool success);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface OwnableInterface {
function owner() external returns (address);
function transferOwnership(address recipient) external;
function acceptOwnership() external;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
abstract contract TypeAndVersionInterface {
function typeAndVersion() external pure virtual returns (string memory);
}
{
"compilationTarget": {
"contracts/v0.8/KeeperRegistrar.sol": "KeeperRegistrar"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "none",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 1000000
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"LINKAddress","type":"address"},{"internalType":"enum KeeperRegistrar.AutoApproveType","name":"autoApproveConfigType","type":"uint8"},{"internalType":"uint16","name":"autoApproveMaxAllowed","type":"uint16"},{"internalType":"address","name":"keeperRegistry","type":"address"},{"internalType":"uint96","name":"minLINKJuels","type":"uint96"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AmountMismatch","type":"error"},{"inputs":[],"name":"FunctionNotPermitted","type":"error"},{"inputs":[],"name":"HashMismatch","type":"error"},{"inputs":[],"name":"InsufficientPayment","type":"error"},{"inputs":[],"name":"InvalidAdminAddress","type":"error"},{"inputs":[],"name":"InvalidDataLength","type":"error"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"LinkTransferFailed","type":"error"},{"inputs":[],"name":"OnlyAdminOrOwner","type":"error"},{"inputs":[],"name":"OnlyLink","type":"error"},{"inputs":[],"name":"RegistrationRequestFailed","type":"error"},{"inputs":[],"name":"RequestNotFound","type":"error"},{"inputs":[],"name":"SenderMismatch","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":[{"indexed":false,"internalType":"enum KeeperRegistrar.AutoApproveType","name":"autoApproveConfigType","type":"uint8"},{"indexed":false,"internalType":"uint32","name":"autoApproveMaxAllowed","type":"uint32"},{"indexed":false,"internalType":"address","name":"keeperRegistry","type":"address"},{"indexed":false,"internalType":"uint96","name":"minLINKJuels","type":"uint96"}],"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":"bytes","name":"checkData","type":"bytes"},{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"},{"indexed":true,"internalType":"uint8","name":"source","type":"uint8"}],"name":"RegistrationRequested","type":"event"},{"inputs":[],"name":"LINK","outputs":[{"internalType":"contract LinkTokenInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"address","name":"upkeepContract","type":"address"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"address","name":"adminAddress","type":"address"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"bytes32","name":"hash","type":"bytes32"}],"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":"bytes32","name":"hash","type":"bytes32"}],"name":"getPendingRequest","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRegistrationConfig","outputs":[{"internalType":"enum KeeperRegistrar.AutoApproveType","name":"autoApproveConfigType","type":"uint8"},{"internalType":"uint32","name":"autoApproveMaxAllowed","type":"uint32"},{"internalType":"uint32","name":"approvedCount","type":"uint32"},{"internalType":"address","name":"keeperRegistry","type":"address"},{"internalType":"uint256","name":"minLINKJuels","type":"uint256"}],"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":[{"internalType":"string","name":"name","type":"string"},{"internalType":"bytes","name":"encryptedEmail","type":"bytes"},{"internalType":"address","name":"upkeepContract","type":"address"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"address","name":"adminAddress","type":"address"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"uint96","name":"amount","type":"uint96"},{"internalType":"uint8","name":"source","type":"uint8"},{"internalType":"address","name":"sender","type":"address"}],"name":"register","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"setAutoApproveAllowedSender","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum KeeperRegistrar.AutoApproveType","name":"autoApproveConfigType","type":"uint8"},{"internalType":"uint16","name":"autoApproveMaxAllowed","type":"uint16"},{"internalType":"address","name":"keeperRegistry","type":"address"},{"internalType":"uint96","name":"minLINKJuels","type":"uint96"}],"name":"setRegistrationConfig","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"}]