文件 1 的 39:Address.sol
pragma solidity ^0.8.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 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 的 39: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 的 39:ArbGasInfo.sol
pragma solidity >=0.4.21 <0.9.0;
interface ArbGasInfo {
function getPricesInWeiWithAggregator(address aggregator) external view returns (uint, uint, uint, uint, uint, uint);
function getPricesInWei() external view returns (uint, uint, uint, uint, uint, uint);
function getPricesInArbGasWithAggregator(address aggregator) external view returns (uint, uint, uint);
function getPricesInArbGas() external view returns (uint, uint, uint);
function getGasAccountingParams() external view returns (uint, uint, uint);
function getL1GasPriceEstimate() external view returns(uint);
function setL1GasPriceEstimate(uint priceInWei) external;
function getCurrentTxL1GasFees() external view returns(uint);
}
文件 4 的 39:ArbSys.sol
pragma solidity >=0.4.21 <0.9.0;
interface ArbSys {
function arbBlockNumber() external view returns (uint256);
function arbBlockHash(uint256 arbBlockNum) external view returns (bytes32);
function arbChainID() external view returns (uint256);
function arbOSVersion() external view returns (uint256);
function getStorageGasAvailable() external view returns (uint256);
function isTopLevelCall() external view returns (bool);
function mapL1SenderContractAddressToL2Alias(address sender, address unused)
external
pure
returns (address);
function wasMyCallersAddressAliased() external view returns (bool);
function myCallersAddressWithoutAliasing() external view returns (address);
function withdrawEth(address destination) external payable returns (uint256);
function sendTxToL1(address destination, bytes calldata data)
external
payable
returns (uint256);
function sendMerkleTreeState()
external
view
returns (
uint256 size,
bytes32 root,
bytes32[] memory partials
);
event L2ToL1Tx(
address caller,
address indexed destination,
uint256 indexed hash,
uint256 indexed position,
uint256 arbBlockNum,
uint256 ethBlockNum,
uint256 timestamp,
uint256 callvalue,
bytes data
);
event L2ToL1Transaction(
address caller,
address indexed destination,
uint256 indexed uniqueId,
uint256 indexed batchNumber,
uint256 indexInBatch,
uint256 arbBlockNum,
uint256 ethBlockNum,
uint256 timestamp,
uint256 callvalue,
bytes data
);
event SendMerkleUpdate(
uint256 indexed reserved,
bytes32 indexed hash,
uint256 indexed position
);
}
文件 5 的 39:AutomationBase.sol
pragma solidity ^0.8.0;
contract AutomationBase {
error OnlySimulatedBackend();
function preventExecution() internal view {
if (tx.origin != address(0)) {
revert OnlySimulatedBackend();
}
}
modifier cannotExecute() {
preventExecution();
_;
}
}
文件 6 的 39:AutomationCompatibleInterface.sol
pragma solidity ^0.8.0;
interface AutomationCompatibleInterface {
function checkUpkeep(bytes calldata checkData) external returns (bool upkeepNeeded, bytes memory performData);
function performUpkeep(bytes calldata performData) external;
}
文件 7 的 39:AutomationRegistryInterface1_2.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 AutomationRegistryBaseInterface {
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 AutomationRegistryInterface is AutomationRegistryBaseInterface {
function checkUpkeep(uint256 upkeepId, address from)
external
view
returns (
bytes memory performData,
uint256 maxLinkPayment,
uint256 gasLimit,
int256 gasWei,
int256 linkEth
);
}
interface AutomationRegistryExecutableInterface is AutomationRegistryBaseInterface {
function checkUpkeep(uint256 upkeepId, address from)
external
returns (
bytes memory performData,
uint256 maxLinkPayment,
uint256 gasLimit,
uint256 adjustedGasWei,
uint256 linkEth
);
}
文件 8 的 39:AutomationRegistryInterface1_3.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;
}
struct Upkeep {
uint96 balance;
address lastKeeper;
uint96 amountSpent;
address admin;
uint32 executeGas;
uint32 maxValidBlocknumber;
address target;
bool paused;
}
interface AutomationRegistryBaseInterface {
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 pauseUpkeep(uint256 id) external;
function unpauseUpkeep(uint256 id) external;
function transferUpkeepAdmin(uint256 id, address proposed) external;
function acceptUpkeepAdmin(uint256 id) external;
function updateCheckData(uint256 id, bytes calldata newCheckData) 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,
bool paused
);
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 AutomationRegistryInterface is AutomationRegistryBaseInterface {
function checkUpkeep(uint256 upkeepId, address from)
external
view
returns (
bytes memory performData,
uint256 maxLinkPayment,
uint256 gasLimit,
int256 gasWei,
int256 linkEth
);
}
interface AutomationRegistryExecutableInterface is AutomationRegistryBaseInterface {
function checkUpkeep(uint256 upkeepId, address from)
external
returns (
bytes memory performData,
uint256 maxLinkPayment,
uint256 gasLimit,
uint256 adjustedGasWei,
uint256 linkEth
);
}
文件 9 的 39:AutomationRegistryInterface2_0.sol
pragma solidity ^0.8.0;
struct OnchainConfig {
uint32 paymentPremiumPPB;
uint32 flatFeeMicroLink;
uint32 checkGasLimit;
uint24 stalenessSeconds;
uint16 gasCeilingMultiplier;
uint96 minUpkeepSpend;
uint32 maxPerformGas;
uint32 maxCheckDataSize;
uint32 maxPerformDataSize;
uint256 fallbackGasPrice;
uint256 fallbackLinkPrice;
address transcoder;
address registrar;
}
struct State {
uint32 nonce;
uint96 ownerLinkBalance;
uint256 expectedLinkBalance;
uint96 totalPremium;
uint256 numUpkeeps;
uint32 configCount;
uint32 latestConfigBlockNumber;
bytes32 latestConfigDigest;
uint32 latestEpoch;
bool paused;
}
struct UpkeepInfo {
address target;
uint32 executeGas;
bytes checkData;
uint96 balance;
address admin;
uint64 maxValidBlocknumber;
uint32 lastPerformBlockNumber;
uint96 amountSpent;
bool paused;
bytes offchainConfig;
}
enum UpkeepFailureReason {
NONE,
UPKEEP_CANCELLED,
UPKEEP_PAUSED,
TARGET_CHECK_REVERTED,
UPKEEP_NOT_NEEDED,
PERFORM_DATA_EXCEEDS_LIMIT,
INSUFFICIENT_BALANCE
}
interface AutomationRegistryBaseInterface {
function registerUpkeep(
address target,
uint32 gasLimit,
address admin,
bytes calldata checkData,
bytes calldata offchainConfig
) external returns (uint256 id);
function cancelUpkeep(uint256 id) external;
function pauseUpkeep(uint256 id) external;
function unpauseUpkeep(uint256 id) external;
function transferUpkeepAdmin(uint256 id, address proposed) external;
function acceptUpkeepAdmin(uint256 id) external;
function updateCheckData(uint256 id, bytes calldata newCheckData) external;
function addFunds(uint256 id, uint96 amount) external;
function setUpkeepGasLimit(uint256 id, uint32 gasLimit) external;
function setUpkeepOffchainConfig(uint256 id, bytes calldata config) external;
function getUpkeep(uint256 id) external view returns (UpkeepInfo memory upkeepInfo);
function getActiveUpkeepIDs(uint256 startIndex, uint256 maxCount) external view returns (uint256[] memory);
function getTransmitterInfo(address query)
external
view
returns (
bool active,
uint8 index,
uint96 balance,
uint96 lastCollected,
address payee
);
function getState()
external
view
returns (
State memory state,
OnchainConfig memory config,
address[] memory signers,
address[] memory transmitters,
uint8 f
);
}
interface AutomationRegistryInterface is AutomationRegistryBaseInterface {
function checkUpkeep(uint256 upkeepId)
external
view
returns (
bool upkeepNeeded,
bytes memory performData,
UpkeepFailureReason upkeepFailureReason,
uint256 gasUsed,
uint256 fastGasWei,
uint256 linkNative
);
}
interface AutomationRegistryExecutableInterface is AutomationRegistryBaseInterface {
function checkUpkeep(uint256 upkeepId)
external
returns (
bool upkeepNeeded,
bytes memory performData,
UpkeepFailureReason upkeepFailureReason,
uint256 gasUsed,
uint256 fastGasWei,
uint256 linkNative
);
}
文件 10 的 39:ConfirmedOwner.sol
pragma solidity ^0.8.0;
import "./ConfirmedOwnerWithProposal.sol";
contract ConfirmedOwner is ConfirmedOwnerWithProposal {
constructor(address newOwner) ConfirmedOwnerWithProposal(newOwner, address(0)) {}
}
文件 11 的 39: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();
_;
}
}
文件 12 的 39: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;
}
}
文件 13 的 39:ERC677ReceiverInterface.sol
pragma solidity ^0.8.6;
interface ERC677ReceiverInterface {
function onTokenTransfer(
address sender,
uint256 amount,
bytes calldata data
) external;
}
文件 14 的 39: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) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
assembly {
result := store
}
return result;
}
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;
}
}
文件 15 的 39:ExecutionPrevention.sol
pragma solidity ^0.8.0;
abstract contract ExecutionPrevention {
error OnlySimulatedBackend();
function preventExecution() internal view {
if (tx.origin != address(0)) {
revert OnlySimulatedBackend();
}
}
modifier cannotExecute() {
preventExecution();
_;
}
}
文件 16 的 39:KeeperBase.sol
pragma solidity ^0.8.0;
import {AutomationBase as KeeperBase} from "./AutomationBase.sol";
文件 17 的 39:KeeperCompatibleInterface.sol
pragma solidity ^0.8.0;
import {AutomationCompatibleInterface as KeeperCompatibleInterface} from "./AutomationCompatibleInterface.sol";
文件 18 的 39:KeeperRegistry1_2.sol
pragma solidity 0.8.6;
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/automation/KeeperCompatibleInterface.sol";
import "../../interfaces/automation/1_2/KeeperRegistryInterface1_2.sol";
import "../../interfaces/automation/MigratableKeeperRegistryInterface.sol";
import "../../interfaces/automation/UpkeepTranscoderInterface.sol";
import "../../interfaces/ERC677ReceiverInterface.sol";
struct Upkeep {
uint96 balance;
address lastKeeper;
uint32 executeGas;
uint64 maxValidBlocknumber;
address target;
uint96 amountSpent;
address admin;
}
contract KeeperRegistry1_2 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 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 override {
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 override 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();
_;
}
}
文件 19 的 39:KeeperRegistry2_0.sol
pragma solidity 0.8.6;
import "../../vendor/openzeppelin-solidity/v4.7.3/contracts/proxy/Proxy.sol";
import "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol";
import "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol";
import "./KeeperRegistryBase2_0.sol";
import {AutomationRegistryExecutableInterface, UpkeepInfo} from "../../interfaces/automation/2_0/AutomationRegistryInterface2_0.sol";
import "../../interfaces/automation/MigratableKeeperRegistryInterface.sol";
import "../../interfaces/automation/MigratableKeeperRegistryInterfaceV2.sol";
import "../../interfaces/ERC677ReceiverInterface.sol";
import "../../OCR2Abstract.sol";
contract KeeperRegistry2_0 is
KeeperRegistryBase2_0,
Proxy,
OCR2Abstract,
AutomationRegistryExecutableInterface,
MigratableKeeperRegistryInterface,
MigratableKeeperRegistryInterfaceV2,
ERC677ReceiverInterface
{
using Address for address;
using EnumerableSet for EnumerableSet.UintSet;
address private immutable i_keeperRegistryLogic;
string public constant override typeAndVersion = "KeeperRegistry 2.0.2";
UpkeepFormat public constant override upkeepTranscoderVersion = UPKEEP_TRANSCODER_VERSION_BASE;
uint8 public constant override upkeepVersion = UPKEEP_VERSION_BASE;
constructor(KeeperRegistryBase2_0 keeperRegistryLogic)
KeeperRegistryBase2_0(
keeperRegistryLogic.getMode(),
keeperRegistryLogic.getLinkAddress(),
keeperRegistryLogic.getLinkNativeFeedAddress(),
keeperRegistryLogic.getFastGasFeedAddress()
)
{
i_keeperRegistryLogic = address(keeperRegistryLogic);
}
struct UpkeepTransmitInfo {
Upkeep upkeep;
bool earlyChecksPassed;
uint96 maxLinkPayment;
bool performSuccess;
uint256 gasUsed;
uint256 gasOverhead;
}
function transmit(
bytes32[3] calldata reportContext,
bytes calldata rawReport,
bytes32[] calldata rs,
bytes32[] calldata ss,
bytes32 rawVs
) external override {
uint256 gasOverhead = gasleft();
HotVars memory hotVars = s_hotVars;
if (hotVars.paused) revert RegistryPaused();
if (!s_transmitters[msg.sender].active) revert OnlyActiveTransmitters();
Report memory report = _decodeReport(rawReport);
UpkeepTransmitInfo[] memory upkeepTransmitInfo = new UpkeepTransmitInfo[](report.upkeepIds.length);
uint16 numUpkeepsPassedChecks;
for (uint256 i = 0; i < report.upkeepIds.length; i++) {
upkeepTransmitInfo[i].upkeep = s_upkeep[report.upkeepIds[i]];
upkeepTransmitInfo[i].maxLinkPayment = _getMaxLinkPayment(
hotVars,
upkeepTransmitInfo[i].upkeep.executeGas,
uint32(report.wrappedPerformDatas[i].performData.length),
report.fastGasWei,
report.linkNative,
true
);
upkeepTransmitInfo[i].earlyChecksPassed = _prePerformChecks(
report.upkeepIds[i],
report.wrappedPerformDatas[i],
upkeepTransmitInfo[i].upkeep,
upkeepTransmitInfo[i].maxLinkPayment
);
if (upkeepTransmitInfo[i].earlyChecksPassed) {
numUpkeepsPassedChecks += 1;
}
}
if (numUpkeepsPassedChecks == 0) {
return;
}
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);
for (uint256 i = 0; i < report.upkeepIds.length; i++) {
if (upkeepTransmitInfo[i].earlyChecksPassed) {
if (s_upkeep[report.upkeepIds[i]].lastPerformBlockNumber == uint32(_blockNum())) {
revert InvalidReport();
}
(upkeepTransmitInfo[i].performSuccess, upkeepTransmitInfo[i].gasUsed) = _performUpkeep(
upkeepTransmitInfo[i].upkeep,
report.wrappedPerformDatas[i].performData
);
gasOverhead -= upkeepTransmitInfo[i].gasUsed;
s_upkeep[report.upkeepIds[i]].lastPerformBlockNumber = uint32(_blockNum());
}
}
gasOverhead =
(gasOverhead - gasleft() + 16 * rawReport.length) +
ACCOUNTING_FIXED_GAS_OVERHEAD +
(ACCOUNTING_PER_SIGNER_GAS_OVERHEAD * (hotVars.f + 1));
gasOverhead = gasOverhead / numUpkeepsPassedChecks + ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD;
uint96 totalReimbursement;
uint96 totalPremium;
{
uint96 reimbursement;
uint96 premium;
for (uint256 i = 0; i < report.upkeepIds.length; i++) {
if (upkeepTransmitInfo[i].earlyChecksPassed) {
upkeepTransmitInfo[i].gasOverhead = _getCappedGasOverhead(
gasOverhead,
uint32(report.wrappedPerformDatas[i].performData.length),
hotVars.f
);
(reimbursement, premium) = _postPerformPayment(
hotVars,
report.upkeepIds[i],
upkeepTransmitInfo[i],
report.fastGasWei,
report.linkNative,
numUpkeepsPassedChecks
);
totalPremium += premium;
totalReimbursement += reimbursement;
emit UpkeepPerformed(
report.upkeepIds[i],
upkeepTransmitInfo[i].performSuccess,
report.wrappedPerformDatas[i].checkBlockNumber,
upkeepTransmitInfo[i].gasUsed,
upkeepTransmitInfo[i].gasOverhead,
reimbursement + premium
);
}
}
}
s_transmitters[msg.sender].balance += totalReimbursement;
s_hotVars.totalPremium += totalPremium;
uint40 epochAndRound = uint40(uint256(reportContext[1]));
uint32 epoch = uint32(epochAndRound >> 8);
if (epoch > hotVars.latestEpoch) {
s_hotVars.latestEpoch = epoch;
}
}
function simulatePerformUpkeep(uint256 id, bytes calldata performData)
external
cannotExecute
returns (bool success, uint256 gasUsed)
{
if (s_hotVars.paused) revert RegistryPaused();
Upkeep memory upkeep = s_upkeep[id];
return _performUpkeep(upkeep, performData);
}
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();
s_upkeep[id].balance = s_upkeep[id].balance + uint96(amount);
s_expectedLinkBalance = s_expectedLinkBalance + amount;
emit FundsAdded(id, sender, uint96(amount));
}
function setConfig(
address[] memory signers,
address[] memory transmitters,
uint8 f,
bytes memory onchainConfig,
uint64 offchainConfigVersion,
bytes memory offchainConfig
) external override onlyOwner {
if (signers.length > maxNumOracles) revert TooManyOracles();
if (f == 0) revert IncorrectNumberOfFaultyOracles();
if (signers.length != transmitters.length || signers.length <= 3 * f) revert IncorrectNumberOfSigners();
uint96 totalPremium = s_hotVars.totalPremium;
uint96 oldLength = uint96(s_transmittersList.length);
for (uint256 i = 0; i < oldLength; i++) {
_updateTransmitterBalanceFromPool(s_transmittersList[i], totalPremium, oldLength);
}
address signerAddress;
address transmitterAddress;
for (uint256 i = 0; i < oldLength; i++) {
signerAddress = s_signersList[i];
transmitterAddress = s_transmittersList[i];
delete s_signers[signerAddress];
s_transmitters[transmitterAddress].active = false;
}
delete s_signersList;
delete s_transmittersList;
{
Transmitter memory transmitter;
address temp;
for (uint256 i = 0; i < signers.length; i++) {
if (s_signers[signers[i]].active) revert RepeatedSigner();
s_signers[signers[i]] = Signer({active: true, index: uint8(i)});
temp = transmitters[i];
transmitter = s_transmitters[temp];
if (transmitter.active) revert RepeatedTransmitter();
transmitter.active = true;
transmitter.index = uint8(i);
transmitter.lastCollected = totalPremium;
s_transmitters[temp] = transmitter;
}
}
s_signersList = signers;
s_transmittersList = transmitters;
OnchainConfig memory onchainConfigStruct = abi.decode(onchainConfig, (OnchainConfig));
if (onchainConfigStruct.maxPerformGas < s_storage.maxPerformGas) revert GasLimitCanOnlyIncrease();
if (onchainConfigStruct.maxCheckDataSize < s_storage.maxCheckDataSize) revert MaxCheckDataSizeCanOnlyIncrease();
if (onchainConfigStruct.maxPerformDataSize < s_storage.maxPerformDataSize)
revert MaxPerformDataSizeCanOnlyIncrease();
s_hotVars = HotVars({
f: f,
paymentPremiumPPB: onchainConfigStruct.paymentPremiumPPB,
flatFeeMicroLink: onchainConfigStruct.flatFeeMicroLink,
stalenessSeconds: onchainConfigStruct.stalenessSeconds,
gasCeilingMultiplier: onchainConfigStruct.gasCeilingMultiplier,
paused: false,
reentrancyGuard: false,
totalPremium: totalPremium,
latestEpoch: 0
});
s_storage = Storage({
checkGasLimit: onchainConfigStruct.checkGasLimit,
minUpkeepSpend: onchainConfigStruct.minUpkeepSpend,
maxPerformGas: onchainConfigStruct.maxPerformGas,
transcoder: onchainConfigStruct.transcoder,
registrar: onchainConfigStruct.registrar,
maxCheckDataSize: onchainConfigStruct.maxCheckDataSize,
maxPerformDataSize: onchainConfigStruct.maxPerformDataSize,
nonce: s_storage.nonce,
configCount: s_storage.configCount,
latestConfigBlockNumber: s_storage.latestConfigBlockNumber,
ownerLinkBalance: s_storage.ownerLinkBalance
});
s_fallbackGasPrice = onchainConfigStruct.fallbackGasPrice;
s_fallbackLinkPrice = onchainConfigStruct.fallbackLinkPrice;
uint32 previousConfigBlockNumber = s_storage.latestConfigBlockNumber;
s_storage.latestConfigBlockNumber = uint32(_blockNum());
s_storage.configCount += 1;
s_latestConfigDigest = _configDigestFromConfigData(
block.chainid,
address(this),
s_storage.configCount,
signers,
transmitters,
f,
onchainConfig,
offchainConfigVersion,
offchainConfig
);
emit ConfigSet(
previousConfigBlockNumber,
s_latestConfigDigest,
s_storage.configCount,
signers,
transmitters,
f,
onchainConfig,
offchainConfigVersion,
offchainConfig
);
}
function getUpkeep(uint256 id) external view override returns (UpkeepInfo memory upkeepInfo) {
Upkeep memory reg = s_upkeep[id];
upkeepInfo = UpkeepInfo({
target: reg.target,
executeGas: reg.executeGas,
checkData: s_checkData[id],
balance: reg.balance,
admin: s_upkeepAdmin[id],
maxValidBlocknumber: reg.maxValidBlocknumber,
lastPerformBlockNumber: reg.lastPerformBlockNumber,
amountSpent: reg.amountSpent,
paused: reg.paused,
offchainConfig: s_upkeepOffchainConfig[id]
});
return upkeepInfo;
}
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 getTransmitterInfo(address query)
external
view
override
returns (
bool active,
uint8 index,
uint96 balance,
uint96 lastCollected,
address payee
)
{
Transmitter memory transmitter = s_transmitters[query];
uint96 totalDifference = s_hotVars.totalPremium - transmitter.lastCollected;
uint96 pooledShare = totalDifference / uint96(s_transmittersList.length);
return (
transmitter.active,
transmitter.index,
(transmitter.balance + pooledShare),
transmitter.lastCollected,
s_transmitterPayees[query]
);
}
function getSignerInfo(address query) external view returns (bool active, uint8 index) {
Signer memory signer = s_signers[query];
return (signer.active, signer.index);
}
function getState()
external
view
override
returns (
State memory state,
OnchainConfig memory config,
address[] memory signers,
address[] memory transmitters,
uint8 f
)
{
state = State({
nonce: s_storage.nonce,
ownerLinkBalance: s_storage.ownerLinkBalance,
expectedLinkBalance: s_expectedLinkBalance,
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 = OnchainConfig({
paymentPremiumPPB: s_hotVars.paymentPremiumPPB,
flatFeeMicroLink: s_hotVars.flatFeeMicroLink,
checkGasLimit: s_storage.checkGasLimit,
stalenessSeconds: s_hotVars.stalenessSeconds,
gasCeilingMultiplier: s_hotVars.gasCeilingMultiplier,
minUpkeepSpend: s_storage.minUpkeepSpend,
maxPerformGas: s_storage.maxPerformGas,
maxCheckDataSize: s_storage.maxCheckDataSize,
maxPerformDataSize: s_storage.maxPerformDataSize,
fallbackGasPrice: s_fallbackGasPrice,
fallbackLinkPrice: s_fallbackLinkPrice,
transcoder: s_storage.transcoder,
registrar: s_storage.registrar
});
return (state, config, s_signersList, s_transmittersList, s_hotVars.f);
}
function getMinBalanceForUpkeep(uint256 id) external view returns (uint96 minBalance) {
return getMaxPaymentForGas(s_upkeep[id].executeGas);
}
function getMaxPaymentForGas(uint32 gasLimit) public view returns (uint96 maxPayment) {
HotVars memory hotVars = s_hotVars;
(uint256 fastGasWei, uint256 linkNative) = _getFeedData(hotVars);
return _getMaxLinkPayment(hotVars, gasLimit, s_storage.maxPerformDataSize, fastGasWei, linkNative, false);
}
function getPeerRegistryMigrationPermission(address peer) external view returns (MigrationPermission) {
return s_peerRegistryMigrationPermission[peer];
}
function getKeeperRegistryLogicAddress() external view returns (address) {
return i_keeperRegistryLogic;
}
function latestConfigDetails()
external
view
override
returns (
uint32 configCount,
uint32 blockNumber,
bytes32 configDigest
)
{
return (s_storage.configCount, s_storage.latestConfigBlockNumber, s_latestConfigDigest);
}
function latestConfigDigestAndEpoch()
external
view
override
returns (
bool scanLogs,
bytes32 configDigest,
uint32 epoch
)
{
return (false, s_latestConfigDigest, s_hotVars.latestEpoch);
}
function _implementation() internal view override returns (address) {
return i_keeperRegistryLogic;
}
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 _decodeReport(bytes memory rawReport) internal pure returns (Report memory) {
(
uint256 fastGasWei,
uint256 linkNative,
uint256[] memory upkeepIds,
PerformDataWrapper[] memory wrappedPerformDatas
) = abi.decode(rawReport, (uint256, uint256, uint256[], PerformDataWrapper[]));
if (upkeepIds.length != wrappedPerformDatas.length) revert InvalidReport();
return
Report({
fastGasWei: fastGasWei,
linkNative: linkNative,
upkeepIds: upkeepIds,
wrappedPerformDatas: wrappedPerformDatas
});
}
function _prePerformChecks(
uint256 upkeepId,
PerformDataWrapper memory wrappedPerformData,
Upkeep memory upkeep,
uint96 maxLinkPayment
) internal returns (bool) {
if (wrappedPerformData.checkBlockNumber < upkeep.lastPerformBlockNumber) {
emit StaleUpkeepReport(upkeepId);
return false;
}
if (_blockHash(wrappedPerformData.checkBlockNumber) != wrappedPerformData.checkBlockhash) {
emit ReorgedUpkeepReport(upkeepId);
return false;
}
if (upkeep.maxValidBlocknumber <= _blockNum()) {
emit CancelledUpkeepReport(upkeepId);
return false;
}
if (upkeep.balance < maxLinkPayment) {
emit InsufficientFundsUpkeepReport(upkeepId);
return false;
}
return true;
}
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));
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();
}
function _performUpkeep(Upkeep memory upkeep, bytes memory performData)
private
nonReentrant
returns (bool success, uint256 gasUsed)
{
gasUsed = gasleft();
bytes memory callData = abi.encodeWithSelector(PERFORM_SELECTOR, performData);
success = _callWithExactGas(upkeep.executeGas, upkeep.target, callData);
gasUsed = gasUsed - gasleft();
return (success, gasUsed);
}
function _postPerformPayment(
HotVars memory hotVars,
uint256 upkeepId,
UpkeepTransmitInfo memory upkeepTransmitInfo,
uint256 fastGasWei,
uint256 linkNative,
uint16 numBatchedUpkeeps
) internal returns (uint96 gasReimbursement, uint96 premium) {
(gasReimbursement, premium) = _calculatePaymentAmount(
hotVars,
upkeepTransmitInfo.gasUsed,
upkeepTransmitInfo.gasOverhead,
fastGasWei,
linkNative,
numBatchedUpkeeps,
true
);
uint96 payment = gasReimbursement + premium;
s_upkeep[upkeepId].balance -= payment;
s_upkeep[upkeepId].amountSpent += payment;
return (gasReimbursement, premium);
}
function _getCappedGasOverhead(
uint256 calculatedGasOverhead,
uint32 performDataLength,
uint8 f
) private pure returns (uint256 cappedGasOverhead) {
cappedGasOverhead = _getMaxGasOverhead(performDataLength, f);
if (calculatedGasOverhead < cappedGasOverhead) {
return calculatedGasOverhead;
}
return cappedGasOverhead;
}
function registerUpkeep(
address target,
uint32 gasLimit,
address admin,
bytes calldata checkData,
bytes calldata offchainConfig
) external override returns (uint256 id) {
_fallback();
}
function checkUpkeep(uint256 id)
external
override
cannotExecute
returns (
bool upkeepNeeded,
bytes memory performData,
UpkeepFailureReason upkeepFailureReason,
uint256 gasUsed,
uint256 fastGasWei,
uint256 linkNative
)
{
_fallback();
}
function cancelUpkeep(uint256 id) external override {
_fallback();
}
function pauseUpkeep(uint256 id) external override {
_fallback();
}
function unpauseUpkeep(uint256 id) external override {
_fallback();
}
function updateCheckData(uint256 id, bytes calldata newCheckData) external override {
_fallback();
}
function addFunds(uint256 id, uint96 amount) external override {
_fallback();
}
function withdrawFunds(uint256 id, address to) external {
_fallback();
}
function setUpkeepGasLimit(uint256 id, uint32 gasLimit) external override {
_fallback();
}
function setUpkeepOffchainConfig(uint256 id, bytes calldata config) external override {
_fallback();
}
function withdrawPayment(address from, address to) external {
_fallback();
}
function transferPayeeship(address transmitter, address proposed) external {
_fallback();
}
function acceptPayeeship(address transmitter) external {
_fallback();
}
function transferUpkeepAdmin(uint256 id, address proposed) external override {
_fallback();
}
function acceptUpkeepAdmin(uint256 id) external override {
_fallback();
}
function migrateUpkeeps(uint256[] calldata ids, address destination)
external
override(MigratableKeeperRegistryInterface, MigratableKeeperRegistryInterfaceV2)
{
_fallback();
}
function receiveUpkeeps(bytes calldata encodedUpkeeps)
external
override(MigratableKeeperRegistryInterface, MigratableKeeperRegistryInterfaceV2)
{
_fallback();
}
function recoverFunds() external {
_fallback();
}
function withdrawOwnerFunds() external {
_fallback();
}
function setPayees(address[] calldata payees) external {
_fallback();
}
function pause() external {
_fallback();
}
function unpause() external {
_fallback();
}
function setPeerRegistryMigrationPermission(address peer, MigrationPermission permission) external {
_fallback();
}
}
文件 20 的 39:KeeperRegistryBase1_3.sol
pragma solidity 0.8.6;
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbGasInfo.sol";
import "../../vendor/@eth-optimism/contracts/0.8.6/contracts/L2/predeploys/OVM_GasPriceOracle.sol";
import "../ExecutionPrevention.sol";
import {Config, State, Upkeep} from "../../interfaces/automation/1_3/AutomationRegistryInterface1_3.sol";
import "../../ConfirmedOwner.sol";
import "../../interfaces/AggregatorV3Interface.sol";
import "../../interfaces/LinkTokenInterface.sol";
import "../../interfaces/automation/KeeperCompatibleInterface.sol";
import "../../interfaces/automation/UpkeepTranscoderInterface.sol";
abstract contract KeeperRegistryBase1_3 is ConfirmedOwner, ExecutionPrevention, ReentrancyGuard, Pausable {
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;
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;
uint96 internal constant LINK_TOTAL_SUPPLY = 1e27;
UpkeepFormat internal constant UPKEEP_TRANSCODER_VERSION_BASE = UpkeepFormat.V2;
bytes internal constant L1_FEE_DATA_PADDING =
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
bytes internal constant MAX_INPUT_DATA =
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
address[] internal s_keeperList;
EnumerableSet.UintSet internal s_upkeepIDs;
mapping(uint256 => Upkeep) internal s_upkeep;
mapping(address => KeeperInfo) internal s_keeperInfo;
mapping(address => address) internal s_proposedPayee;
mapping(uint256 => address) internal s_proposedAdmin;
mapping(uint256 => bytes) internal s_checkData;
mapping(address => MigrationPermission) internal s_peerRegistryMigrationPermission;
Storage internal s_storage;
uint256 internal s_fallbackGasPrice;
uint256 internal s_fallbackLinkPrice;
uint96 internal s_ownerLinkBalance;
uint256 internal s_expectedLinkBalance;
address internal s_transcoder;
address internal s_registrar;
LinkTokenInterface public immutable LINK;
AggregatorV3Interface public immutable LINK_ETH_FEED;
AggregatorV3Interface public immutable FAST_GAS_FEED;
OVM_GasPriceOracle public immutable OPTIMISM_ORACLE = OVM_GasPriceOracle(0x420000000000000000000000000000000000000F);
ArbGasInfo public immutable ARB_NITRO_ORACLE = ArbGasInfo(0x000000000000000000000000000000000000006C);
PaymentModel public immutable PAYMENT_MODEL;
uint256 public immutable REGISTRY_GAS_OVERHEAD;
error ArrayHasNoEntries();
error CannotCancel();
error DuplicateEntry();
error EmptyAddress();
error GasLimitCanOnlyIncrease();
error GasLimitOutsideRange();
error IndexOutOfRange();
error InsufficientFunds();
error InvalidDataLength();
error InvalidPayee();
error InvalidRecipient();
error KeepersMustTakeTurns();
error MigrationNotPermitted();
error NotAContract();
error OnlyActiveKeepers();
error OnlyCallableByAdmin();
error OnlyCallableByLINKToken();
error OnlyCallableByOwnerOrAdmin();
error OnlyCallableByOwnerOrRegistrar();
error OnlyCallableByPayee();
error OnlyCallableByProposedAdmin();
error OnlyCallableByProposedPayee();
error OnlyPausedUpkeep();
error OnlyUnpausedUpkeep();
error ParameterLengthError();
error PaymentGreaterThanAllLINK();
error TargetCheckReverted(bytes reason);
error TranscoderNotSet();
error UpkeepCancelled();
error UpkeepNotCanceled();
error UpkeepNotNeeded();
error ValueNotChanged();
enum MigrationPermission {
NONE,
OUTGOING,
INCOMING,
BIDIRECTIONAL
}
enum PaymentModel {
DEFAULT,
ARBITRUM,
OPTIMISM
}
struct Storage {
uint32 paymentPremiumPPB;
uint32 flatFeeMicroLink;
uint24 blockCountPerTurn;
uint32 checkGasLimit;
uint24 stalenessSeconds;
uint16 gasCeilingMultiplier;
uint96 minUpkeepSpend;
uint32 maxPerformGas;
uint32 nonce;
}
struct KeeperInfo {
address payee;
uint96 balance;
bool active;
}
struct PerformParams {
address from;
uint256 id;
bytes performData;
uint256 maxLinkPayment;
uint256 gasLimit;
uint256 fastGasWei;
uint256 linkEth;
}
event ConfigSet(Config config);
event FundsAdded(uint256 indexed id, address indexed from, uint96 amount);
event FundsWithdrawn(uint256 indexed id, uint256 amount, address to);
event KeepersUpdated(address[] keepers, address[] payees);
event OwnerFundsWithdrawn(uint96 amount);
event PayeeshipTransferRequested(address indexed keeper, address indexed from, address indexed to);
event PayeeshipTransferred(address indexed keeper, address indexed from, address indexed to);
event PaymentWithdrawn(address indexed keeper, uint256 indexed amount, address indexed to, address payee);
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 UpkeepCheckDataUpdated(uint256 indexed id, bytes newCheckData);
event UpkeepGasLimitSet(uint256 indexed id, uint96 gasLimit);
event UpkeepMigrated(uint256 indexed id, uint256 remainingBalance, address destination);
event UpkeepPaused(uint256 indexed id);
event UpkeepPerformed(
uint256 indexed id,
bool indexed success,
address indexed from,
uint96 payment,
bytes performData
);
event UpkeepReceived(uint256 indexed id, uint256 startingBalance, address importedFrom);
event UpkeepUnpaused(uint256 indexed id);
event UpkeepRegistered(uint256 indexed id, uint32 executeGas, address admin);
constructor(
PaymentModel paymentModel,
uint256 registryGasOverhead,
address link,
address linkEthFeed,
address fastGasFeed
) ConfirmedOwner(msg.sender) {
PAYMENT_MODEL = paymentModel;
REGISTRY_GAS_OVERHEAD = registryGasOverhead;
if (ZERO_ADDRESS == link || ZERO_ADDRESS == linkEthFeed || ZERO_ADDRESS == fastGasFeed) {
revert EmptyAddress();
}
LINK = LinkTokenInterface(link);
LINK_ETH_FEED = AggregatorV3Interface(linkEthFeed);
FAST_GAS_FEED = AggregatorV3Interface(fastGasFeed);
}
function _getFeedData() internal 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 fastGasWei,
uint256 linkEth,
bool isExecution
) internal view returns (uint96 payment) {
Storage memory store = s_storage;
uint256 gasWei = fastGasWei * store.gasCeilingMultiplier;
if (isExecution && tx.gasprice < gasWei) {
gasWei = tx.gasprice;
}
uint256 weiForGas = gasWei * (gasLimit + REGISTRY_GAS_OVERHEAD);
uint256 premium = PPB_BASE + store.paymentPremiumPPB;
uint256 l1CostWei = 0;
if (PAYMENT_MODEL == PaymentModel.OPTIMISM) {
bytes memory txCallData = new bytes(0);
if (isExecution) {
txCallData = bytes.concat(msg.data, L1_FEE_DATA_PADDING);
} else {
txCallData = MAX_INPUT_DATA;
}
l1CostWei = OPTIMISM_ORACLE.getL1Fee(txCallData);
} else if (PAYMENT_MODEL == PaymentModel.ARBITRUM) {
l1CostWei = ARB_NITRO_ORACLE.getCurrentTxL1GasFees();
}
if (!isExecution) {
l1CostWei = store.gasCeilingMultiplier * l1CostWei;
}
uint256 total = ((weiForGas + l1CostWei) * 1e9 * premium) / linkEth + uint256(store.flatFeeMicroLink) * 1e12;
if (total > LINK_TOTAL_SUPPLY) revert PaymentGreaterThanAllLINK();
return uint96(total);
}
function _prePerformUpkeep(
Upkeep memory upkeep,
address from,
uint256 maxLinkPayment
) internal view {
if (upkeep.paused) revert OnlyUnpausedUpkeep();
if (!s_keeperInfo[from].active) revert OnlyActiveKeepers();
if (upkeep.balance < maxLinkPayment) revert InsufficientFunds();
if (upkeep.lastKeeper == from) revert KeepersMustTakeTurns();
}
function requireAdminAndNotCancelled(Upkeep memory upkeep) internal view {
if (msg.sender != upkeep.admin) revert OnlyCallableByAdmin();
if (upkeep.maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled();
}
function _generatePerformParams(
address from,
uint256 id,
bytes memory performData,
bool isExecution
) internal view returns (PerformParams memory) {
uint256 gasLimit = s_upkeep[id].executeGas;
(uint256 fastGasWei, uint256 linkEth) = _getFeedData();
uint96 maxLinkPayment = _calculatePaymentAmount(gasLimit, fastGasWei, linkEth, isExecution);
return
PerformParams({
from: from,
id: id,
performData: performData,
maxLinkPayment: maxLinkPayment,
gasLimit: gasLimit,
fastGasWei: fastGasWei,
linkEth: linkEth
});
}
}
文件 21 的 39:KeeperRegistryBase2_0.sol
pragma solidity 0.8.6;
import "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol";
import "../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbGasInfo.sol";
import "../../vendor/@eth-optimism/contracts/0.8.6/contracts/L2/predeploys/OVM_GasPriceOracle.sol";
import {ArbSys} from "../../dev/vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol";
import "../ExecutionPrevention.sol";
import {OnchainConfig, State, UpkeepFailureReason} from "../../interfaces/automation/2_0/AutomationRegistryInterface2_0.sol";
import "../../ConfirmedOwner.sol";
import "../../interfaces/AggregatorV3Interface.sol";
import "../../interfaces/LinkTokenInterface.sol";
import "../../interfaces/automation/KeeperCompatibleInterface.sol";
import "../../interfaces/automation/UpkeepTranscoderInterface.sol";
struct Upkeep {
uint32 executeGas;
uint32 maxValidBlocknumber;
bool paused;
address target;
uint96 amountSpent;
uint96 balance;
uint32 lastPerformBlockNumber;
}
abstract contract KeeperRegistryBase2_0 is ConfirmedOwner, ExecutionPrevention {
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;
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;
uint96 internal constant LINK_TOTAL_SUPPLY = 1e27;
uint256 internal constant ORACLE_MASK = 0x0001010101010101010101010101010101010101010101010101010101010101;
UpkeepFormat internal constant UPKEEP_TRANSCODER_VERSION_BASE = UpkeepFormat.V1;
uint8 internal constant UPKEEP_VERSION_BASE = uint8(UpkeepFormat.V3);
bytes internal constant L1_FEE_DATA_PADDING =
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
uint256 internal constant REGISTRY_GAS_OVERHEAD = 70_000;
uint256 internal constant REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD = 20;
uint256 internal constant REGISTRY_PER_SIGNER_GAS_OVERHEAD = 7_500;
uint256 internal constant ACCOUNTING_FIXED_GAS_OVERHEAD = 26_900;
uint256 internal constant ACCOUNTING_PER_SIGNER_GAS_OVERHEAD = 1_100;
uint256 internal constant ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD = 5_800;
OVM_GasPriceOracle internal constant OPTIMISM_ORACLE = OVM_GasPriceOracle(0x420000000000000000000000000000000000000F);
ArbGasInfo internal constant ARB_NITRO_ORACLE = ArbGasInfo(0x000000000000000000000000000000000000006C);
ArbSys internal constant ARB_SYS = ArbSys(0x0000000000000000000000000000000000000064);
LinkTokenInterface internal immutable i_link;
AggregatorV3Interface internal immutable i_linkNativeFeed;
AggregatorV3Interface internal immutable i_fastGasFeed;
Mode internal immutable i_mode;
EnumerableSet.UintSet internal s_upkeepIDs;
mapping(uint256 => Upkeep) internal s_upkeep;
mapping(uint256 => address) internal s_upkeepAdmin;
mapping(uint256 => address) internal s_proposedAdmin;
mapping(uint256 => bytes) internal s_checkData;
mapping(address => Transmitter) internal s_transmitters;
mapping(address => Signer) internal s_signers;
address[] internal s_signersList;
address[] internal s_transmittersList;
mapping(address => address) internal s_transmitterPayees;
mapping(address => address) internal s_proposedPayee;
bytes32 internal s_latestConfigDigest;
HotVars internal s_hotVars;
Storage internal s_storage;
uint256 internal s_fallbackGasPrice;
uint256 internal s_fallbackLinkPrice;
uint256 internal s_expectedLinkBalance;
mapping(address => MigrationPermission) internal s_peerRegistryMigrationPermission;
mapping(uint256 => bytes) internal s_upkeepOffchainConfig;
error ArrayHasNoEntries();
error CannotCancel();
error DuplicateEntry();
error GasLimitCanOnlyIncrease();
error GasLimitOutsideRange();
error IndexOutOfRange();
error InsufficientFunds();
error InvalidDataLength();
error InvalidPayee();
error InvalidRecipient();
error MigrationNotPermitted();
error NotAContract();
error OnlyActiveTransmitters();
error OnlyCallableByAdmin();
error OnlyCallableByLINKToken();
error OnlyCallableByOwnerOrAdmin();
error OnlyCallableByOwnerOrRegistrar();
error OnlyCallableByPayee();
error OnlyCallableByProposedAdmin();
error OnlyCallableByProposedPayee();
error OnlyPausedUpkeep();
error OnlyUnpausedUpkeep();
error ParameterLengthError();
error PaymentGreaterThanAllLINK();
error TargetCheckReverted(bytes reason);
error TranscoderNotSet();
error UpkeepCancelled();
error UpkeepNotCanceled();
error UpkeepNotNeeded();
error ValueNotChanged();
error ConfigDigestMismatch();
error IncorrectNumberOfSignatures();
error OnlyActiveSigners();
error DuplicateSigners();
error TooManyOracles();
error IncorrectNumberOfSigners();
error IncorrectNumberOfFaultyOracles();
error RepeatedSigner();
error RepeatedTransmitter();
error OnchainConfigNonEmpty();
error CheckDataExceedsLimit();
error MaxCheckDataSizeCanOnlyIncrease();
error MaxPerformDataSizeCanOnlyIncrease();
error InvalidReport();
error RegistryPaused();
error ReentrantCall();
error UpkeepAlreadyExists();
enum MigrationPermission {
NONE,
OUTGOING,
INCOMING,
BIDIRECTIONAL
}
enum Mode {
DEFAULT,
ARBITRUM,
OPTIMISM
}
struct HotVars {
uint8 f;
uint32 paymentPremiumPPB;
uint32 flatFeeMicroLink;
uint24 stalenessSeconds;
uint16 gasCeilingMultiplier;
bool paused;
bool reentrancyGuard;
uint96 totalPremium;
uint32 latestEpoch;
}
struct Storage {
uint96 minUpkeepSpend;
address transcoder;
uint96 ownerLinkBalance;
address registrar;
uint32 checkGasLimit;
uint32 maxPerformGas;
uint32 nonce;
uint32 configCount;
uint32 latestConfigBlockNumber;
uint32 maxCheckDataSize;
uint32 maxPerformDataSize;
}
struct Transmitter {
bool active;
uint8 index;
uint96 balance;
uint96 lastCollected;
}
struct Signer {
bool active;
uint8 index;
}
struct PerformDataWrapper {
uint32 checkBlockNumber;
bytes32 checkBlockhash;
bytes performData;
}
struct Report {
uint256 fastGasWei;
uint256 linkNative;
uint256[] upkeepIds;
PerformDataWrapper[] wrappedPerformDatas;
}
event FundsAdded(uint256 indexed id, address indexed from, uint96 amount);
event FundsWithdrawn(uint256 indexed id, uint256 amount, address to);
event OwnerFundsWithdrawn(uint96 amount);
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 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 UpkeepCheckDataUpdated(uint256 indexed id, bytes newCheckData);
event UpkeepGasLimitSet(uint256 indexed id, uint96 gasLimit);
event UpkeepOffchainConfigSet(uint256 indexed id, bytes offchainConfig);
event UpkeepMigrated(uint256 indexed id, uint256 remainingBalance, address destination);
event UpkeepPaused(uint256 indexed id);
event UpkeepPerformed(
uint256 indexed id,
bool indexed success,
uint32 checkBlockNumber,
uint256 gasUsed,
uint256 gasOverhead,
uint96 totalPayment
);
event UpkeepReceived(uint256 indexed id, uint256 startingBalance, address importedFrom);
event UpkeepUnpaused(uint256 indexed id);
event UpkeepRegistered(uint256 indexed id, uint32 executeGas, address admin);
event StaleUpkeepReport(uint256 indexed id);
event ReorgedUpkeepReport(uint256 indexed id);
event InsufficientFundsUpkeepReport(uint256 indexed id);
event CancelledUpkeepReport(uint256 indexed id);
event Paused(address account);
event Unpaused(address account);
constructor(Mode mode, address link, address linkNativeFeed, address fastGasFeed) ConfirmedOwner(msg.sender) {
i_mode = mode;
i_link = LinkTokenInterface(link);
i_linkNativeFeed = AggregatorV3Interface(linkNativeFeed);
i_fastGasFeed = AggregatorV3Interface(fastGasFeed);
}
function getMode() external view returns (Mode) {
return i_mode;
}
function getLinkAddress() external view returns (address) {
return address(i_link);
}
function getLinkNativeFeedAddress() external view returns (address) {
return address(i_linkNativeFeed);
}
function getFastGasFeedAddress() external view returns (address) {
return address(i_fastGasFeed);
}
function _getFeedData(HotVars memory hotVars) internal view returns (uint256 gasWei, uint256 linkNative) {
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_linkNativeFeed.latestRoundData();
if (
feedValue <= 0 || block.timestamp < timestamp || (staleFallback && stalenessSeconds < block.timestamp - timestamp)
) {
linkNative = s_fallbackLinkPrice;
} else {
linkNative = uint256(feedValue);
}
return (gasWei, linkNative);
}
function _calculatePaymentAmount(
HotVars memory hotVars,
uint256 gasLimit,
uint256 gasOverhead,
uint256 fastGasWei,
uint256 linkNative,
uint16 numBatchedUpkeeps,
bool isExecution
) internal view returns (uint96, uint96) {
uint256 gasWei = fastGasWei * hotVars.gasCeilingMultiplier;
if (isExecution && tx.gasprice < gasWei) {
gasWei = tx.gasprice;
}
uint256 l1CostWei = 0;
if (i_mode == Mode.OPTIMISM) {
bytes memory txCallData = new bytes(0);
if (isExecution) {
txCallData = bytes.concat(msg.data, L1_FEE_DATA_PADDING);
} else {
txCallData = new bytes(4 * s_storage.maxPerformDataSize);
}
l1CostWei = OPTIMISM_ORACLE.getL1Fee(txCallData);
} else if (i_mode == Mode.ARBITRUM) {
l1CostWei = ARB_NITRO_ORACLE.getCurrentTxL1GasFees();
}
if (!isExecution) {
l1CostWei = hotVars.gasCeilingMultiplier * l1CostWei;
}
l1CostWei = l1CostWei / numBatchedUpkeeps;
uint256 gasPayment = ((gasWei * (gasLimit + gasOverhead) + l1CostWei) * 1e18) / linkNative;
uint256 premium = (((gasWei * gasLimit) + l1CostWei) * 1e9 * hotVars.paymentPremiumPPB) /
linkNative +
uint256(hotVars.flatFeeMicroLink) *
1e12;
if (gasPayment + premium > LINK_TOTAL_SUPPLY) revert PaymentGreaterThanAllLINK();
return (uint96(gasPayment), uint96(premium));
}
function _getMaxLinkPayment(
HotVars memory hotVars,
uint32 executeGas,
uint32 performDataLength,
uint256 fastGasWei,
uint256 linkNative,
bool isExecution
) internal view returns (uint96) {
uint256 gasOverhead = _getMaxGasOverhead(performDataLength, hotVars.f);
(uint96 reimbursement, uint96 premium) = _calculatePaymentAmount(
hotVars,
executeGas,
gasOverhead,
fastGasWei,
linkNative,
1,
isExecution
);
return reimbursement + premium;
}
function _getMaxGasOverhead(uint32 performDataLength, uint8 f) internal pure returns (uint256) {
return
REGISTRY_GAS_OVERHEAD +
(REGISTRY_PER_SIGNER_GAS_OVERHEAD * (f + 1)) +
(REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD * performDataLength);
}
function _updateTransmitterBalanceFromPool(
address transmitterAddress,
uint96 totalPremium,
uint96 payeeCount
) internal returns (uint96) {
Transmitter memory transmitter = s_transmitters[transmitterAddress];
uint96 uncollected = totalPremium - transmitter.lastCollected;
uint96 due = uncollected / payeeCount;
transmitter.balance += due;
transmitter.lastCollected = totalPremium;
s_storage.ownerLinkBalance += (uncollected - due * payeeCount);
s_transmitters[transmitterAddress] = transmitter;
return transmitter.balance;
}
function _blockNum() internal view returns (uint256) {
if (i_mode == Mode.ARBITRUM) {
return ARB_SYS.arbBlockNumber();
} else {
return block.number;
}
}
function _blockHash(uint256 n) internal view returns (bytes32) {
if (i_mode == Mode.ARBITRUM) {
uint256 blockNum = ARB_SYS.arbBlockNumber();
if (n >= blockNum || blockNum - n > 256) {
return "";
}
return ARB_SYS.arbBlockHash(n);
} else {
return blockhash(n);
}
}
modifier nonReentrant() {
if (s_hotVars.reentrancyGuard) revert ReentrantCall();
s_hotVars.reentrancyGuard = true;
_;
s_hotVars.reentrancyGuard = false;
}
}
文件 22 的 39:KeeperRegistryInterface1_2.sol
pragma solidity ^0.8.0;
import {Config, State} from "./AutomationRegistryInterface1_2.sol";
import {AutomationRegistryBaseInterface as KeeperRegistryBaseInterface} from "./AutomationRegistryInterface1_2.sol";
import {AutomationRegistryInterface as KeeperRegistryInterface} from "./AutomationRegistryInterface1_2.sol";
import {AutomationRegistryExecutableInterface as KeeperRegistryExecutableInterface} from "./AutomationRegistryInterface1_2.sol";
文件 23 的 39:KeeperRegistryLogic2_0.sol
pragma solidity 0.8.6;
import "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol";
import "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol";
import "./KeeperRegistryBase2_0.sol";
import "../../interfaces/automation/MigratableKeeperRegistryInterfaceV2.sol";
import "../../interfaces/automation/UpkeepTranscoderInterfaceV2.sol";
contract KeeperRegistryLogic2_0 is KeeperRegistryBase2_0 {
using Address for address;
using EnumerableSet for EnumerableSet.UintSet;
constructor(
Mode mode,
address link,
address linkNativeFeed,
address fastGasFeed
) KeeperRegistryBase2_0(mode, link, linkNativeFeed, fastGasFeed) {}
function checkUpkeep(uint256 id)
external
cannotExecute
returns (
bool upkeepNeeded,
bytes memory performData,
UpkeepFailureReason upkeepFailureReason,
uint256 gasUsed,
uint256 fastGasWei,
uint256 linkNative
)
{
HotVars memory hotVars = s_hotVars;
Upkeep memory upkeep = s_upkeep[id];
if (upkeep.maxValidBlocknumber != UINT32_MAX)
return (false, bytes(""), UpkeepFailureReason.UPKEEP_CANCELLED, gasUsed, 0, 0);
if (upkeep.paused) return (false, bytes(""), UpkeepFailureReason.UPKEEP_PAUSED, gasUsed, 0, 0);
(fastGasWei, linkNative) = _getFeedData(hotVars);
uint96 maxLinkPayment = _getMaxLinkPayment(
hotVars,
upkeep.executeGas,
s_storage.maxPerformDataSize,
fastGasWei,
linkNative,
false
);
if (upkeep.balance < maxLinkPayment)
return (false, bytes(""), UpkeepFailureReason.INSUFFICIENT_BALANCE, gasUsed, fastGasWei, linkNative);
gasUsed = gasleft();
bytes memory callData = abi.encodeWithSelector(CHECK_SELECTOR, s_checkData[id]);
(bool success, bytes memory result) = upkeep.target.call{gas: s_storage.checkGasLimit}(callData);
gasUsed = gasUsed - gasleft();
if (!success) {
upkeepFailureReason = UpkeepFailureReason.TARGET_CHECK_REVERTED;
} else {
(upkeepNeeded, result) = abi.decode(result, (bool, bytes));
if (!upkeepNeeded)
return (false, bytes(""), UpkeepFailureReason.UPKEEP_NOT_NEEDED, gasUsed, fastGasWei, linkNative);
if (result.length > s_storage.maxPerformDataSize)
return (false, bytes(""), UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, gasUsed, fastGasWei, linkNative);
}
performData = abi.encode(
PerformDataWrapper({
checkBlockNumber: uint32(_blockNum() - 1),
checkBlockhash: _blockHash(_blockNum() - 1),
performData: result
})
);
return (success, performData, upkeepFailureReason, gasUsed, fastGasWei, linkNative);
}
function withdrawOwnerFunds() external onlyOwner {
uint96 amount = s_storage.ownerLinkBalance;
s_expectedLinkBalance = s_expectedLinkBalance - amount;
s_storage.ownerLinkBalance = 0;
emit OwnerFundsWithdrawn(amount);
i_link.transfer(msg.sender, amount);
}
function recoverFunds() external onlyOwner {
uint256 total = i_link.balanceOf(address(this));
i_link.transfer(msg.sender, total - s_expectedLinkBalance);
}
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);
}
function pause() external onlyOwner {
s_hotVars.paused = true;
emit Paused(msg.sender);
}
function unpause() external onlyOwner {
s_hotVars.paused = false;
emit Unpaused(msg.sender);
}
function setPeerRegistryMigrationPermission(address peer, MigrationPermission permission) external onlyOwner {
s_peerRegistryMigrationPermission[peer] = permission;
}
function registerUpkeep(
address target,
uint32 gasLimit,
address admin,
bytes calldata checkData,
bytes calldata offchainConfig
) external returns (uint256 id) {
if (msg.sender != owner() && msg.sender != s_storage.registrar) revert OnlyCallableByOwnerOrRegistrar();
id = uint256(keccak256(abi.encode(_blockHash(_blockNum() - 1), address(this), s_storage.nonce)));
_createUpkeep(id, target, gasLimit, admin, 0, checkData, false);
s_storage.nonce++;
s_upkeepOffchainConfig[id] = offchainConfig;
emit UpkeepRegistered(id, gasLimit, admin);
return id;
}
function cancelUpkeep(uint256 id) external {
Upkeep memory upkeep = s_upkeep[id];
bool canceled = upkeep.maxValidBlocknumber != UINT32_MAX;
bool isOwner = msg.sender == owner();
if (canceled && !(isOwner && upkeep.maxValidBlocknumber > _blockNum())) revert CannotCancel();
if (!isOwner && msg.sender != s_upkeepAdmin[id]) revert OnlyCallableByOwnerOrAdmin();
uint256 height = _blockNum();
if (!isOwner) {
height = height + CANCELLATION_DELAY;
}
s_upkeep[id].maxValidBlocknumber = uint32(height);
s_upkeepIDs.remove(id);
uint96 minUpkeepSpend = s_storage.minUpkeepSpend;
uint96 cancellationFee = 0;
if (upkeep.amountSpent < minUpkeepSpend) {
cancellationFee = minUpkeepSpend - upkeep.amountSpent;
if (cancellationFee > upkeep.balance) {
cancellationFee = upkeep.balance;
}
}
s_upkeep[id].balance = upkeep.balance - cancellationFee;
s_storage.ownerLinkBalance = s_storage.ownerLinkBalance + cancellationFee;
emit UpkeepCanceled(id, uint64(height));
}
function addFunds(uint256 id, uint96 amount) external {
Upkeep memory upkeep = s_upkeep[id];
if (upkeep.maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled();
s_upkeep[id].balance = upkeep.balance + amount;
s_expectedLinkBalance = s_expectedLinkBalance + amount;
i_link.transferFrom(msg.sender, address(this), amount);
emit FundsAdded(id, msg.sender, amount);
}
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 > _blockNum()) revert UpkeepNotCanceled();
uint96 amountToWithdraw = s_upkeep[id].balance;
s_expectedLinkBalance = s_expectedLinkBalance - amountToWithdraw;
s_upkeep[id].balance = 0;
i_link.transfer(to, amountToWithdraw);
emit FundsWithdrawn(id, amountToWithdraw, to);
}
function setUpkeepGasLimit(uint256 id, uint32 gasLimit) external {
if (gasLimit < PERFORM_GAS_MIN || gasLimit > s_storage.maxPerformGas) revert GasLimitOutsideRange();
_requireAdminAndNotCancelled(id);
s_upkeep[id].executeGas = gasLimit;
emit UpkeepGasLimitSet(id, gasLimit);
}
function setUpkeepOffchainConfig(uint256 id, bytes calldata config) external {
_requireAdminAndNotCancelled(id);
s_upkeepOffchainConfig[id] = config;
emit UpkeepOffchainConfigSet(id, config);
}
function withdrawPayment(address from, address to) external {
if (to == ZERO_ADDRESS) revert InvalidRecipient();
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_expectedLinkBalance = s_expectedLinkBalance - balance;
i_link.transfer(to, balance);
emit PaymentWithdrawn(from, balance, to, msg.sender);
}
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);
}
}
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);
}
function transferUpkeepAdmin(uint256 id, address proposed) external {
_requireAdminAndNotCancelled(id);
if (proposed == msg.sender) revert ValueNotChanged();
if (proposed == ZERO_ADDRESS) revert InvalidRecipient();
if (s_proposedAdmin[id] != proposed) {
s_proposedAdmin[id] = proposed;
emit UpkeepAdminTransferRequested(id, msg.sender, proposed);
}
}
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);
}
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);
}
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);
}
function updateCheckData(uint256 id, bytes calldata newCheckData) external {
_requireAdminAndNotCancelled(id);
if (newCheckData.length > s_storage.maxCheckDataSize) revert CheckDataExceedsLimit();
s_checkData[id] = newCheckData;
emit UpkeepCheckDataUpdated(id, newCheckData);
}
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();
uint256 id;
Upkeep memory upkeep;
uint256 totalBalanceRemaining;
bytes[] memory checkDatas = new bytes[](ids.length);
address[] memory admins = new address[](ids.length);
Upkeep[] memory upkeeps = new Upkeep[](ids.length);
for (uint256 idx = 0; idx < ids.length; idx++) {
id = ids[idx];
upkeep = s_upkeep[id];
_requireAdminAndNotCancelled(id);
upkeeps[idx] = upkeep;
checkDatas[idx] = s_checkData[id];
admins[idx] = s_upkeepAdmin[id];
totalBalanceRemaining = totalBalanceRemaining + upkeep.balance;
delete s_upkeep[id];
delete s_checkData[id];
delete s_proposedAdmin[id];
s_upkeepIDs.remove(id);
emit UpkeepMigrated(id, upkeep.balance, destination);
}
s_expectedLinkBalance = s_expectedLinkBalance - totalBalanceRemaining;
bytes memory encodedUpkeeps = abi.encode(ids, upkeeps, checkDatas, admins);
MigratableKeeperRegistryInterfaceV2(destination).receiveUpkeeps(
UpkeepTranscoderInterfaceV2(s_storage.transcoder).transcodeUpkeeps(
UPKEEP_VERSION_BASE,
MigratableKeeperRegistryInterfaceV2(destination).upkeepVersion(),
encodedUpkeeps
)
);
i_link.transfer(destination, totalBalanceRemaining);
}
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, bytes[] memory checkDatas, address[] memory upkeepAdmins) = abi
.decode(encodedUpkeeps, (uint256[], Upkeep[], bytes[], address[]));
for (uint256 idx = 0; idx < ids.length; idx++) {
_createUpkeep(
ids[idx],
upkeeps[idx].target,
upkeeps[idx].executeGas,
upkeepAdmins[idx],
upkeeps[idx].balance,
checkDatas[idx],
upkeeps[idx].paused
);
emit UpkeepReceived(ids[idx], upkeeps[idx].balance, msg.sender);
}
}
function _createUpkeep(
uint256 id,
address target,
uint32 gasLimit,
address admin,
uint96 balance,
bytes memory checkData,
bool paused
) internal {
if (s_hotVars.paused) revert RegistryPaused();
if (!target.isContract()) revert NotAContract();
if (checkData.length > s_storage.maxCheckDataSize) revert CheckDataExceedsLimit();
if (gasLimit < PERFORM_GAS_MIN || gasLimit > s_storage.maxPerformGas) revert GasLimitOutsideRange();
if (s_upkeep[id].target != address(0)) revert UpkeepAlreadyExists();
s_upkeep[id] = Upkeep({
target: target,
executeGas: gasLimit,
balance: balance,
maxValidBlocknumber: UINT32_MAX,
lastPerformBlockNumber: 0,
amountSpent: 0,
paused: paused
});
s_upkeepAdmin[id] = admin;
s_expectedLinkBalance = s_expectedLinkBalance + balance;
s_checkData[id] = checkData;
s_upkeepIDs.add(id);
}
function _requireAdminAndNotCancelled(uint256 upkeepId) internal view {
if (msg.sender != s_upkeepAdmin[upkeepId]) revert OnlyCallableByAdmin();
if (s_upkeep[upkeepId].maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled();
}
}
文件 24 的 39: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);
}
文件 25 的 39:MigratableKeeperRegistryInterface.sol
pragma solidity ^0.8.0;
import "../../automation/UpkeepFormat.sol";
interface MigratableKeeperRegistryInterface {
function migrateUpkeeps(uint256[] calldata upkeepIDs, address destination) external;
function receiveUpkeeps(bytes calldata encodedUpkeeps) external;
function upkeepTranscoderVersion() external returns (UpkeepFormat version);
}
文件 26 的 39:MigratableKeeperRegistryInterfaceV2.sol
pragma solidity ^0.8.0;
import "../../automation/UpkeepFormat.sol";
interface MigratableKeeperRegistryInterfaceV2 {
function migrateUpkeeps(uint256[] calldata upkeepIDs, address destination) external;
function receiveUpkeeps(bytes calldata encodedUpkeeps) external;
function upkeepVersion() external returns (uint8 version);
}
文件 27 的 39:MockArbSys.sol
pragma solidity 0.8.6;
contract MockArbSys {
function arbBlockNumber() public view returns (uint256) {
return block.number;
}
function arbBlockHash(uint256 arbBlockNum) external view returns (bytes32) {
return blockhash(arbBlockNum);
}
}
文件 28 的 39:OCR2Abstract.sol
pragma solidity ^0.8.0;
import "./interfaces/TypeAndVersionInterface.sol";
abstract contract OCR2Abstract is TypeAndVersionInterface {
uint256 internal constant maxNumOracles = 31;
uint256 private constant prefixMask = type(uint256).max << (256 - 16);
uint256 private constant prefix = 0x0001 << (256 - 16);
event ConfigSet(
uint32 previousConfigBlockNumber,
bytes32 configDigest,
uint64 configCount,
address[] signers,
address[] transmitters,
uint8 f,
bytes onchainConfig,
uint64 offchainConfigVersion,
bytes offchainConfig
);
function setConfig(
address[] memory signers,
address[] memory transmitters,
uint8 f,
bytes memory onchainConfig,
uint64 offchainConfigVersion,
bytes memory offchainConfig
) external virtual;
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 & prefixMask) | (h & ~prefixMask));
}
event Transmitted(bytes32 configDigest, uint32 epoch);
function latestConfigDigestAndEpoch()
external
view
virtual
returns (
bool scanLogs,
bytes32 configDigest,
uint32 epoch
);
function transmit(
bytes32[3] calldata reportContext,
bytes calldata report,
bytes32[] calldata rs,
bytes32[] calldata ss,
bytes32 rawVs
) external virtual;
}
文件 29 的 39:OVM_GasPriceOracle.sol
pragma solidity 0.8.6;
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
contract OVM_GasPriceOracle is Ownable {
uint256 public gasPrice;
uint256 public l1BaseFee;
uint256 public overhead;
uint256 public scalar;
uint256 public decimals;
constructor(address _owner) Ownable() {
transferOwnership(_owner);
}
event GasPriceUpdated(uint256);
event L1BaseFeeUpdated(uint256);
event OverheadUpdated(uint256);
event ScalarUpdated(uint256);
event DecimalsUpdated(uint256);
function setGasPrice(uint256 _gasPrice) public onlyOwner {
gasPrice = _gasPrice;
emit GasPriceUpdated(_gasPrice);
}
function setL1BaseFee(uint256 _baseFee) public onlyOwner {
l1BaseFee = _baseFee;
emit L1BaseFeeUpdated(_baseFee);
}
function setOverhead(uint256 _overhead) public onlyOwner {
overhead = _overhead;
emit OverheadUpdated(_overhead);
}
function setScalar(uint256 _scalar) public onlyOwner {
scalar = _scalar;
emit ScalarUpdated(_scalar);
}
function setDecimals(uint256 _decimals) public onlyOwner {
decimals = _decimals;
emit DecimalsUpdated(_decimals);
}
function getL1Fee(bytes memory _data) public view returns (uint256) {
uint256 l1GasUsed = getL1GasUsed(_data);
uint256 l1Fee = l1GasUsed * l1BaseFee;
uint256 divisor = 10**decimals;
uint256 unscaled = l1Fee * scalar;
uint256 scaled = unscaled / divisor;
return scaled;
}
function getL1GasUsed(bytes memory _data) public view returns (uint256) {
uint256 total = 0;
for (uint256 i = 0; i < _data.length; i++) {
if (_data[i] == 0) {
total += 4;
} else {
total += 16;
}
}
uint256 unsigned = total + overhead;
return unsigned + (68 * 16);
}
}
文件 30 的 39:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_setOwner(_msgSender());
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
_setOwner(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_setOwner(newOwner);
}
function _setOwner(address newOwner) private {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 31 的 39:OwnableInterface.sol
pragma solidity ^0.8.0;
interface OwnableInterface {
function owner() external returns (address);
function transferOwnership(address recipient) external;
function acceptOwnership() external;
}
文件 32 的 39: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());
}
}
文件 33 的 39:Proxy.sol
pragma solidity ^0.8.0;
abstract contract Proxy {
function _delegate(address implementation) internal virtual {
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
function _implementation() internal view virtual returns (address);
function _fallback() internal virtual {
_beforeFallback();
_delegate(_implementation());
}
fallback() external payable virtual {
_fallback();
}
receive() external payable virtual {
_fallback();
}
function _beforeFallback() internal virtual {}
}
文件 34 的 39: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;
}
}
文件 35 的 39:TypeAndVersionInterface.sol
pragma solidity ^0.8.0;
abstract contract TypeAndVersionInterface {
function typeAndVersion() external pure virtual returns (string memory);
}
文件 36 的 39:UpkeepFormat.sol
pragma solidity ^0.8.0;
enum UpkeepFormat {
V1,
V2,
V3
}
文件 37 的 39:UpkeepTranscoder3_0.sol
pragma solidity 0.8.6;
import "../../interfaces/automation/UpkeepTranscoderInterface.sol";
import "../../interfaces/TypeAndVersionInterface.sol";
import {Upkeep as UpkeepV1} from "../../automation/1_2/KeeperRegistry1_2.sol";
import {Upkeep as UpkeepV2} from "../../automation/1_3/KeeperRegistryBase1_3.sol";
import {Upkeep as UpkeepV3} from "../../automation/2_0/KeeperRegistryBase2_0.sol";
import "../../automation/UpkeepFormat.sol";
contract UpkeepTranscoder3_0 is UpkeepTranscoderInterface, TypeAndVersionInterface {
error InvalidTranscoding();
string public constant override typeAndVersion = "UpkeepTranscoder 3.0.0";
uint32 internal constant UINT32_MAX = type(uint32).max;
function transcodeUpkeeps(
UpkeepFormat fromVersion,
UpkeepFormat,
bytes calldata encodedUpkeeps
) external view override returns (bytes memory) {
if (fromVersion == UpkeepFormat.V1) {
(uint256[] memory ids, UpkeepV1[] memory upkeepsV1, bytes[] memory checkDatas) = abi.decode(
encodedUpkeeps,
(uint256[], UpkeepV1[], bytes[])
);
if (ids.length != upkeepsV1.length || ids.length != checkDatas.length) {
revert InvalidTranscoding();
}
address[] memory admins = new address[](ids.length);
UpkeepV3[] memory newUpkeeps = new UpkeepV3[](ids.length);
UpkeepV1 memory upkeepV1;
for (uint256 idx = 0; idx < ids.length; idx++) {
upkeepV1 = upkeepsV1[idx];
newUpkeeps[idx] = UpkeepV3({
executeGas: upkeepV1.executeGas,
maxValidBlocknumber: UINT32_MAX,
paused: false,
target: upkeepV1.target,
amountSpent: upkeepV1.amountSpent,
balance: upkeepV1.balance,
lastPerformBlockNumber: 0
});
admins[idx] = upkeepV1.admin;
}
return abi.encode(ids, newUpkeeps, checkDatas, admins);
}
if (fromVersion == UpkeepFormat.V2) {
(uint256[] memory ids, UpkeepV2[] memory upkeepsV2, bytes[] memory checkDatas) = abi.decode(
encodedUpkeeps,
(uint256[], UpkeepV2[], bytes[])
);
if (ids.length != upkeepsV2.length || ids.length != checkDatas.length) {
revert InvalidTranscoding();
}
address[] memory admins = new address[](ids.length);
UpkeepV3[] memory newUpkeeps = new UpkeepV3[](ids.length);
UpkeepV2 memory upkeepV2;
for (uint256 idx = 0; idx < ids.length; idx++) {
upkeepV2 = upkeepsV2[idx];
newUpkeeps[idx] = UpkeepV3({
executeGas: upkeepV2.executeGas,
maxValidBlocknumber: upkeepV2.maxValidBlocknumber,
paused: upkeepV2.paused,
target: upkeepV2.target,
amountSpent: upkeepV2.amountSpent,
balance: upkeepV2.balance,
lastPerformBlockNumber: 0
});
admins[idx] = upkeepV2.admin;
}
return abi.encode(ids, newUpkeeps, checkDatas, admins);
}
revert InvalidTranscoding();
}
}
文件 38 的 39:UpkeepTranscoderInterface.sol
import "../../automation/UpkeepFormat.sol";
pragma solidity ^0.8.0;
interface UpkeepTranscoderInterface {
function transcodeUpkeeps(
UpkeepFormat fromVersion,
UpkeepFormat toVersion,
bytes calldata encodedUpkeeps
) external view returns (bytes memory);
}
文件 39 的 39:UpkeepTranscoderInterfaceV2.sol
pragma solidity ^0.8.0;
interface UpkeepTranscoderInterfaceV2 {
function transcodeUpkeeps(
uint8 fromVersion,
uint8 toVersion,
bytes calldata encodedUpkeeps
) external view returns (bytes memory);
}
{
"compilationTarget": {
"src/v0.8/automation/2_0/KeeperRegistry2_0.sol": "KeeperRegistry2_0"
},
"evmVersion": "berlin",
"libraries": {},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 1000000
},
"remappings": []
}
[{"inputs":[{"internalType":"contract KeeperRegistryBase2_0","name":"keeperRegistryLogic","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":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"InvalidDataLength","type":"error"},{"inputs":[],"name":"InvalidPayee","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidReport","type":"error"},{"inputs":[],"name":"MaxCheckDataSizeCanOnlyIncrease","type":"error"},{"inputs":[],"name":"MaxPerformDataSizeCanOnlyIncrease","type":"error"},{"inputs":[],"name":"MigrationNotPermitted","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"OnchainConfigNonEmpty","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":"OnlyPausedUpkeep","type":"error"},{"inputs":[],"name":"OnlySimulatedBackend","type":"error"},{"inputs":[],"name":"OnlyUnpausedUpkeep","type":"error"},{"inputs":[],"name":"ParameterLengthError","type":"error"},{"inputs":[],"name":"PaymentGreaterThanAllLINK","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":"UpkeepAlreadyExists","type":"error"},{"inputs":[],"name":"UpkeepCancelled","type":"error"},{"inputs":[],"name":"UpkeepNotCanceled","type":"error"},{"inputs":[],"name":"UpkeepNotNeeded","type":"error"},{"inputs":[],"name":"ValueNotChanged","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"CancelledUpkeepReport","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":"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"}],"name":"InsufficientFundsUpkeepReport","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":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"}],"name":"ReorgedUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"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"},{"indexed":false,"internalType":"bytes","name":"newCheckData","type":"bytes"}],"name":"UpkeepCheckDataUpdated","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":"uint32","name":"checkBlockNumber","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"gasUsed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasOverhead","type":"uint256"},{"indexed":false,"internalType":"uint96","name":"totalPayment","type":"uint96"}],"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"},{"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":[{"internalType":"address","name":"transmitter","type":"address"}],"name":"acceptPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"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":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"cancelUpkeep","outputs":[],"stateMutability":"nonpayable","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 UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"},{"internalType":"uint256","name":"fastGasWei","type":"uint256"},{"internalType":"uint256","name":"linkNative","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":[],"name":"getFastGasFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getKeeperRegistryLogicAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkNativeFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"gasLimit","type":"uint32"}],"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":[],"name":"getMode","outputs":[{"internalType":"enum KeeperRegistryBase2_0.Mode","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"}],"name":"getPeerRegistryMigrationPermission","outputs":[{"internalType":"enum KeeperRegistryBase2_0.MigrationPermission","name":"","type":"uint8"}],"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 State","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":"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 OnchainConfig","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":[{"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":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getUpkeep","outputs":[{"components":[{"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":"admin","type":"address"},{"internalType":"uint64","name":"maxValidBlocknumber","type":"uint64"},{"internalType":"uint32","name":"lastPerformBlockNumber","type":"uint32"},{"internalType":"uint96","name":"amountSpent","type":"uint96"},{"internalType":"bool","name":"paused","type":"bool"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"internalType":"struct UpkeepInfo","name":"upkeepInfo","type":"tuple"}],"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":[{"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":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"pauseUpkeep","outputs":[],"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"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"registerUpkeep","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"internalType":"bytes","name":"onchainConfig","type":"bytes"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"payees","type":"address[]"}],"name":"setPayees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"},{"internalType":"enum KeeperRegistryBase2_0.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":"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":"performData","type":"bytes"}],"name":"simulatePerformUpkeep","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"},{"internalType":"address","name":"proposed","type":"address"}],"name":"transferPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"proposed","type":"address"}],"name":"transferUpkeepAdmin","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":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"unpauseUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"newCheckData","type":"bytes"}],"name":"updateCheckData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"upkeepTranscoderVersion","outputs":[{"internalType":"enum UpkeepFormat","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"upkeepVersion","outputs":[{"internalType":"uint8","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"},{"stateMutability":"payable","type":"receive"}]