编译器
0.8.16+commit.07a7930e
文件 1 的 76:AccessControllerInterface.sol
pragma solidity ^0.8.0;
interface AccessControllerInterface {
function hasAccess(address user, bytes calldata data) external view returns (bool);
}
文件 2 的 76:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "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");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 3 的 76: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);
}
文件 4 的 76: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);
}
文件 5 的 76: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
);
}
文件 6 的 76: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();
_;
}
}
文件 7 的 76: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;
}
文件 8 的 76:AutomationConsumerBenchmark.sol
pragma solidity 0.8.16;
contract AutomationConsumerBenchmark {
event PerformingUpkeep(uint256 id, address from, uint256 initialCall, uint256 nextEligible, uint256 blockNumber);
mapping(uint256 => uint256) public initialCall;
mapping(uint256 => uint256) public nextEligible;
mapping(bytes32 => bool) public dummyMap;
mapping(uint256 => uint256) public count;
uint256 deployedAt;
constructor() {
deployedAt = block.number;
}
function checkUpkeep(bytes calldata checkData) external view returns (bool, bytes memory) {
(
uint256 id,
uint256 interval,
uint256 range,
uint256 checkBurnAmount,
uint256 performBurnAmount,
uint256 firstEligibleBuffer
) = abi.decode(checkData, (uint256, uint256, uint256, uint256, uint256, uint256));
uint256 startGas = gasleft();
bytes32 dummyIndex = blockhash(block.number - 1);
bool dummy;
if (checkBurnAmount > 0 && eligible(id, range, firstEligibleBuffer)) {
while (startGas - gasleft() < checkBurnAmount) {
dummy = dummy && dummyMap[dummyIndex];
dummyIndex = keccak256(abi.encode(dummyIndex, address(this)));
}
}
return (eligible(id, range, firstEligibleBuffer), checkData);
}
function performUpkeep(bytes calldata performData) external {
(
uint256 id,
uint256 interval,
uint256 range,
uint256 checkBurnAmount,
uint256 performBurnAmount,
uint256 firstEligibleBuffer
) = abi.decode(performData, (uint256, uint256, uint256, uint256, uint256, uint256));
require(eligible(id, range, firstEligibleBuffer));
uint256 startGas = gasleft();
if (initialCall[id] == 0) {
initialCall[id] = block.number;
}
nextEligible[id] = block.number + interval;
count[id]++;
emit PerformingUpkeep(id, tx.origin, initialCall[id], nextEligible[id], block.number);
bytes32 dummyIndex = blockhash(block.number - 1);
bool dummy;
while (startGas - gasleft() < performBurnAmount) {
dummy = dummy && dummyMap[dummyIndex];
dummyIndex = keccak256(abi.encode(dummyIndex, address(this)));
}
}
function getCountPerforms(uint256 id) public view returns (uint256) {
return count[id];
}
function eligible(uint256 id, uint256 range, uint256 firstEligibleBuffer) internal view returns (bool) {
return
initialCall[id] == 0
? block.number >= firstEligibleBuffer + deployedAt
: (block.number - initialCall[id] < range && block.number > nextEligible[id]);
}
function checkEligible(uint256 id, uint256 range, uint256 firstEligibleBuffer) public view returns (bool) {
return eligible(id, range, firstEligibleBuffer);
}
function reset() external {
deployedAt = block.number;
}
}
文件 9 的 76:AutomationForwarder.sol
pragma solidity 0.8.16;
import {IAutomationRegistryConsumer} from "../interfaces/IAutomationRegistryConsumer.sol";
uint256 constant PERFORM_GAS_CUSHION = 5_000;
contract AutomationForwarder {
address private immutable i_target;
address private immutable i_logic;
IAutomationRegistryConsumer private s_registry;
constructor(address target, address registry, address logic) {
s_registry = IAutomationRegistryConsumer(registry);
i_target = target;
i_logic = logic;
}
function forward(uint256 gasAmount, bytes memory data) external returns (bool success, uint256 gasUsed) {
if (msg.sender != address(s_registry)) revert();
address target = i_target;
gasUsed = gasleft();
assembly {
let g := gas()
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)
}
gasUsed = gasUsed - gasleft();
return (success, gasUsed);
}
function getTarget() external view returns (address) {
return i_target;
}
fallback() external {
address logic = i_logic;
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), logic, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
}
文件 10 的 76:AutomationForwarderLogic.sol
pragma solidity 0.8.16;
import {IAutomationRegistryConsumer} from "../interfaces/IAutomationRegistryConsumer.sol";
import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
contract AutomationForwarderLogic is ITypeAndVersion {
IAutomationRegistryConsumer private s_registry;
string public constant typeAndVersion = "AutomationForwarder 1.0.0";
function updateRegistry(address newRegistry) external {
if (msg.sender != address(s_registry)) revert();
s_registry = IAutomationRegistryConsumer(newRegistry);
}
function getRegistry() external view returns (IAutomationRegistryConsumer) {
return s_registry;
}
}
文件 11 的 76:AutomationRegistrar2_1.sol
pragma solidity 0.8.16;
import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol";
import {IKeeperRegistryMaster} from "../interfaces/v2_1/IKeeperRegistryMaster.sol";
import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol";
import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol";
import {IERC677Receiver} from "../../shared/interfaces/IERC677Receiver.sol";
contract AutomationRegistrar2_1 is TypeAndVersionInterface, ConfirmedOwner, IERC677Receiver {
enum AutoApproveType {
DISABLED,
ENABLED_SENDER_ALLOWLIST,
ENABLED_ALL
}
bytes4 private constant REGISTER_REQUEST_SELECTOR = this.register.selector;
mapping(bytes32 => PendingRequest) private s_pendingRequests;
mapping(uint8 => TriggerRegistrationStorage) private s_triggerRegistrations;
LinkTokenInterface public immutable LINK;
string public constant override typeAndVersion = "AutomationRegistrar 2.1.0";
struct TriggerRegistrationStorage {
AutoApproveType autoApproveType;
uint32 autoApproveMaxAllowed;
uint32 approvedCount;
}
struct InitialTriggerConfig {
uint8 triggerType;
AutoApproveType autoApproveType;
uint32 autoApproveMaxAllowed;
}
struct RegistrarConfig {
IKeeperRegistryMaster keeperRegistry;
uint96 minLINKJuels;
}
struct PendingRequest {
address admin;
uint96 balance;
}
struct RegistrationParams {
string name;
bytes encryptedEmail;
address upkeepContract;
uint32 gasLimit;
address adminAddress;
uint8 triggerType;
bytes checkData;
bytes triggerConfig;
bytes offchainConfig;
uint96 amount;
}
RegistrarConfig private s_config;
mapping(address => bool) private s_autoApproveAllowedSenders;
event RegistrationRequested(
bytes32 indexed hash,
string name,
bytes encryptedEmail,
address indexed upkeepContract,
uint32 gasLimit,
address adminAddress,
uint8 triggerType,
bytes triggerConfig,
bytes offchainConfig,
bytes checkData,
uint96 amount
);
event RegistrationApproved(bytes32 indexed hash, string displayName, uint256 indexed upkeepId);
event RegistrationRejected(bytes32 indexed hash);
event AutoApproveAllowedSenderSet(address indexed senderAddress, bool allowed);
event ConfigChanged(address keeperRegistry, uint96 minLINKJuels);
event TriggerConfigSet(uint8 triggerType, AutoApproveType autoApproveType, uint32 autoApproveMaxAllowed);
error InvalidAdminAddress();
error RequestNotFound();
error HashMismatch();
error OnlyAdminOrOwner();
error InsufficientPayment();
error RegistrationRequestFailed();
error OnlyLink();
error AmountMismatch();
error SenderMismatch();
error FunctionNotPermitted();
error LinkTransferFailed(address to);
error InvalidDataLength();
constructor(
address LINKAddress,
address keeperRegistry,
uint96 minLINKJuels,
InitialTriggerConfig[] memory triggerConfigs
) ConfirmedOwner(msg.sender) {
LINK = LinkTokenInterface(LINKAddress);
setConfig(keeperRegistry, minLINKJuels);
for (uint256 idx = 0; idx < triggerConfigs.length; idx++) {
setTriggerConfig(
triggerConfigs[idx].triggerType,
triggerConfigs[idx].autoApproveType,
triggerConfigs[idx].autoApproveMaxAllowed
);
}
}
function register(
string memory name,
bytes calldata encryptedEmail,
address upkeepContract,
uint32 gasLimit,
address adminAddress,
uint8 triggerType,
bytes memory checkData,
bytes memory triggerConfig,
bytes memory offchainConfig,
uint96 amount,
address sender
) external onlyLINK {
_register(
RegistrationParams({
name: name,
encryptedEmail: encryptedEmail,
upkeepContract: upkeepContract,
gasLimit: gasLimit,
adminAddress: adminAddress,
triggerType: triggerType,
checkData: checkData,
triggerConfig: triggerConfig,
offchainConfig: offchainConfig,
amount: amount
}),
sender
);
}
function registerUpkeep(RegistrationParams calldata requestParams) external returns (uint256) {
if (requestParams.amount < s_config.minLINKJuels) {
revert InsufficientPayment();
}
LINK.transferFrom(msg.sender, address(this), requestParams.amount);
return _register(requestParams, msg.sender);
}
function approve(
string memory name,
address upkeepContract,
uint32 gasLimit,
address adminAddress,
uint8 triggerType,
bytes calldata checkData,
bytes memory triggerConfig,
bytes calldata offchainConfig,
bytes32 hash
) external onlyOwner {
PendingRequest memory request = s_pendingRequests[hash];
if (request.admin == address(0)) {
revert RequestNotFound();
}
bytes32 expectedHash = keccak256(
abi.encode(upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig)
);
if (hash != expectedHash) {
revert HashMismatch();
}
delete s_pendingRequests[hash];
_approve(
RegistrationParams({
name: name,
encryptedEmail: "",
upkeepContract: upkeepContract,
gasLimit: gasLimit,
adminAddress: adminAddress,
triggerType: triggerType,
checkData: checkData,
triggerConfig: triggerConfig,
offchainConfig: offchainConfig,
amount: request.balance
}),
expectedHash
);
}
function cancel(bytes32 hash) external {
PendingRequest memory request = s_pendingRequests[hash];
if (!(msg.sender == request.admin || msg.sender == owner())) {
revert OnlyAdminOrOwner();
}
if (request.admin == address(0)) {
revert RequestNotFound();
}
delete s_pendingRequests[hash];
bool success = LINK.transfer(request.admin, request.balance);
if (!success) {
revert LinkTransferFailed(request.admin);
}
emit RegistrationRejected(hash);
}
function setConfig(address keeperRegistry, uint96 minLINKJuels) public onlyOwner {
s_config = RegistrarConfig({minLINKJuels: minLINKJuels, keeperRegistry: IKeeperRegistryMaster(keeperRegistry)});
emit ConfigChanged(keeperRegistry, minLINKJuels);
}
function setTriggerConfig(
uint8 triggerType,
AutoApproveType autoApproveType,
uint32 autoApproveMaxAllowed
) public onlyOwner {
s_triggerRegistrations[triggerType].autoApproveType = autoApproveType;
s_triggerRegistrations[triggerType].autoApproveMaxAllowed = autoApproveMaxAllowed;
emit TriggerConfigSet(triggerType, autoApproveType, autoApproveMaxAllowed);
}
function setAutoApproveAllowedSender(address senderAddress, bool allowed) external onlyOwner {
s_autoApproveAllowedSenders[senderAddress] = allowed;
emit AutoApproveAllowedSenderSet(senderAddress, allowed);
}
function getAutoApproveAllowedSender(address senderAddress) external view returns (bool) {
return s_autoApproveAllowedSenders[senderAddress];
}
function getConfig() external view returns (address keeperRegistry, uint256 minLINKJuels) {
RegistrarConfig memory config = s_config;
return (address(config.keeperRegistry), config.minLINKJuels);
}
function getTriggerRegistrationDetails(uint8 triggerType) external view returns (TriggerRegistrationStorage memory) {
return s_triggerRegistrations[triggerType];
}
function getPendingRequest(bytes32 hash) external view returns (address, uint96) {
PendingRequest memory request = s_pendingRequests[hash];
return (request.admin, request.balance);
}
function onTokenTransfer(
address sender,
uint256 amount,
bytes calldata data
)
external
override
onlyLINK
permittedFunctionsForLINK(data)
isActualAmount(amount, data)
isActualSender(sender, data)
{
if (amount < s_config.minLINKJuels) {
revert InsufficientPayment();
}
(bool success, ) = address(this).delegatecall(data);
if (!success) {
revert RegistrationRequestFailed();
}
}
function _register(RegistrationParams memory params, address sender) private returns (uint256) {
if (params.adminAddress == address(0)) {
revert InvalidAdminAddress();
}
bytes32 hash = keccak256(
abi.encode(
params.upkeepContract,
params.gasLimit,
params.adminAddress,
params.triggerType,
params.checkData,
params.triggerConfig,
params.offchainConfig
)
);
emit RegistrationRequested(
hash,
params.name,
params.encryptedEmail,
params.upkeepContract,
params.gasLimit,
params.adminAddress,
params.triggerType,
params.triggerConfig,
params.offchainConfig,
params.checkData,
params.amount
);
uint256 upkeepId;
if (_shouldAutoApprove(s_triggerRegistrations[params.triggerType], sender)) {
s_triggerRegistrations[params.triggerType].approvedCount++;
upkeepId = _approve(params, hash);
} else {
uint96 newBalance = s_pendingRequests[hash].balance + params.amount;
s_pendingRequests[hash] = PendingRequest({admin: params.adminAddress, balance: newBalance});
}
return upkeepId;
}
function _approve(RegistrationParams memory params, bytes32 hash) private returns (uint256) {
IKeeperRegistryMaster keeperRegistry = s_config.keeperRegistry;
uint256 upkeepId = keeperRegistry.registerUpkeep(
params.upkeepContract,
params.gasLimit,
params.adminAddress,
params.triggerType,
params.checkData,
params.triggerConfig,
params.offchainConfig
);
bool success = LINK.transferAndCall(address(keeperRegistry), params.amount, abi.encode(upkeepId));
if (!success) {
revert LinkTransferFailed(address(keeperRegistry));
}
emit RegistrationApproved(hash, params.name, upkeepId);
return upkeepId;
}
function _shouldAutoApprove(TriggerRegistrationStorage memory config, address sender) private view returns (bool) {
if (config.autoApproveType == AutoApproveType.DISABLED) {
return false;
}
if (config.autoApproveType == AutoApproveType.ENABLED_SENDER_ALLOWLIST && (!s_autoApproveAllowedSenders[sender])) {
return false;
}
if (config.approvedCount < config.autoApproveMaxAllowed) {
return true;
}
return false;
}
modifier onlyLINK() {
if (msg.sender != address(LINK)) {
revert OnlyLink();
}
_;
}
modifier permittedFunctionsForLINK(bytes memory _data) {
bytes4 funcSelector;
assembly {
funcSelector := mload(add(_data, 32))
}
if (funcSelector != REGISTER_REQUEST_SELECTOR) {
revert FunctionNotPermitted();
}
_;
}
modifier isActualAmount(uint256 expected, bytes calldata data) {
(, , , , , , , , , uint96 amount, ) = abi.decode(
data[4:],
(string, bytes, address, uint32, address, uint8, bytes, bytes, bytes, uint96, address)
);
if (expected != amount) {
revert AmountMismatch();
}
_;
}
modifier isActualSender(address expected, bytes calldata data) {
(, , , , , , , , , , address sender) = abi.decode(
data[4:],
(string, bytes, address, uint32, address, uint8, bytes, bytes, bytes, uint96, address)
);
if (expected != sender) {
revert SenderMismatch();
}
_;
}
}
文件 12 的 76:AutomationUtils2_1.sol
pragma solidity 0.8.16;
import {KeeperRegistryBase2_1} from "./KeeperRegistryBase2_1.sol";
import {Log} from "../interfaces/ILogAutomation.sol";
struct LogTriggerConfig {
address contractAddress;
uint8 filterSelector;
bytes32 topic0;
bytes32 topic1;
bytes32 topic2;
bytes32 topic3;
}
contract AutomationUtils2_1 {
function _onChainConfig(KeeperRegistryBase2_1.OnchainConfig memory) external {}
function _report(KeeperRegistryBase2_1.Report memory) external {}
function _logTriggerConfig(LogTriggerConfig memory) external {}
function _logTrigger(KeeperRegistryBase2_1.LogTrigger memory) external {}
function _conditionalTrigger(KeeperRegistryBase2_1.ConditionalTrigger memory) external {}
function _log(Log memory) external {}
}
文件 13 的 76:ByteUtil.sol
pragma solidity 0.8.16;
library ByteUtil {
error MalformedData();
function _readUint256(bytes memory data, uint256 offset) internal pure returns (uint256 result) {
if (offset + 32 > data.length) revert MalformedData();
assembly {
result := mload(add(add(data, 32), offset))
}
}
function _readUint192(bytes memory data, uint256 offset) internal pure returns (uint256 result) {
if (offset + 24 > data.length) revert MalformedData();
assembly {
result := mload(add(add(data, 32), offset))
result := shr(64, result)
}
}
function _readUint32(bytes memory data, uint256 offset) internal pure returns (uint256 result) {
if (offset + 4 > data.length) revert MalformedData();
assembly {
result := mload(add(add(data, 32), offset))
result := shr(224, result)
}
}
function _readAddress(bytes memory data, uint256 offset) internal pure returns (address result) {
if (offset + 20 > data.length) revert MalformedData();
assembly {
let word := mload(add(add(data, 32), offset))
result := shr(96, word)
}
}
}
文件 14 的 76:Chainable.sol
pragma solidity 0.8.16;
contract Chainable {
address private immutable i_FALLBACK_ADDRESS;
constructor(address fallbackAddress) {
i_FALLBACK_ADDRESS = fallbackAddress;
}
function fallbackTo() external view returns (address) {
return i_FALLBACK_ADDRESS;
}
fallback() external {
address next = i_FALLBACK_ADDRESS;
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), next, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
}
文件 15 的 76:Common.sol
pragma solidity 0.8.16;
library Common {
struct Asset {
address assetAddress;
uint256 amount;
}
struct AddressAndWeight {
address addr;
uint64 weight;
}
function hasDuplicateAddresses(Common.AddressAndWeight[] memory recipients) internal pure returns (bool) {
for (uint256 i = 0; i < recipients.length; ) {
for (uint256 j = i + 1; j < recipients.length; ) {
if (recipients[i].addr == recipients[j].addr) {
return true;
}
unchecked {
++j;
}
}
unchecked {
++i;
}
}
return false;
}
}
文件 16 的 76:ConfirmedOwner.sol
pragma solidity ^0.8.0;
import "./ConfirmedOwnerWithProposal.sol";
contract ConfirmedOwner is ConfirmedOwnerWithProposal {
constructor(address newOwner) ConfirmedOwnerWithProposal(newOwner, address(0)) {}
}
文件 17 的 76:ConfirmedOwnerWithProposal.sol
pragma solidity ^0.8.0;
import "../interfaces/IOwnable.sol";
contract ConfirmedOwnerWithProposal is IOwnable {
address private s_owner;
address private s_pendingOwner;
event OwnershipTransferRequested(address indexed from, address indexed to);
event OwnershipTransferred(address indexed from, address indexed to);
constructor(address newOwner, address pendingOwner) {
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();
_;
}
}
文件 18 的 76: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;
}
}
文件 19 的 76:DummyProtocol.sol
pragma solidity 0.8.16;
struct LogTriggerConfig {
address contractAddress;
uint8 filterSelector;
bytes32 topic0;
bytes32 topic1;
bytes32 topic2;
bytes32 topic3;
}
contract DummyProtocol {
event LimitOrderSent(uint256 indexed amount, uint256 indexed price, address indexed to);
event LimitOrderWithdrawn(uint256 indexed amount, uint256 indexed price, address indexed from);
event LimitOrderExecuted(uint256 indexed orderId, uint256 indexed amount, address indexed exchange);
function sendLimitedOrder(uint256 amount, uint256 price, address to) public {
emit LimitOrderSent(amount, price, to);
}
function withdrawLimit(uint256 amount, uint256 price, address from) public {
emit LimitOrderSent(amount, price, from);
}
function executeLimitOrder(uint256 orderId, uint256 amount, address exchange) public {
emit LimitOrderExecuted(orderId, amount, exchange);
}
function getBasicLogTriggerConfig(
address targetContract,
bytes32 t0
) external view returns (bytes memory logTrigger) {
LogTriggerConfig memory cfg = LogTriggerConfig({
contractAddress: targetContract,
filterSelector: 0,
topic0: t0,
topic1: 0x000000000000000000000000000000000000000000000000000000000000000,
topic2: 0x000000000000000000000000000000000000000000000000000000000000000,
topic3: 0x000000000000000000000000000000000000000000000000000000000000000
});
return abi.encode(cfg);
}
function getAdvancedLogTriggerConfig(
address targetContract,
uint8 selector,
bytes32 t0,
bytes32 t1,
bytes32 t2,
bytes32 t3
) external view returns (bytes memory logTrigger) {
LogTriggerConfig memory cfg = LogTriggerConfig({
contractAddress: targetContract,
filterSelector: selector,
topic0: t0,
topic1: t1,
topic2: t2,
topic3: t3
});
return abi.encode(cfg);
}
}
文件 20 的 76: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;
}
}
文件 21 的 76:ErroredVerifier.sol
pragma solidity 0.8.16;
import {IVerifier} from "../../interfaces/IVerifier.sol";
import {Common} from "../../libraries/Common.sol";
contract ErroredVerifier is IVerifier {
function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
return interfaceId == this.verify.selector;
}
function verify(
bytes memory,
address
)
external
pure
override
returns (
bytes memory
)
{
revert("Failed to verify");
}
function setConfig(
bytes32,
address[] memory,
bytes32[] memory,
uint8,
bytes memory,
uint64,
bytes memory,
Common.AddressAndWeight[] memory
) external pure override {
revert("Failed to set config");
}
function setConfigFromSource(
bytes32,
uint256,
address,
uint32,
address[] memory,
bytes32[] memory,
uint8,
bytes memory,
uint64,
bytes memory,
Common.AddressAndWeight[] memory
) external pure override {
revert("Failed to set config");
}
function activateConfig(bytes32, bytes32) external pure {
revert("Failed to activate config");
}
function deactivateConfig(bytes32, bytes32) external pure {
revert("Failed to deactivate config");
}
function activateFeed(bytes32) external pure {
revert("Failed to activate feed");
}
function deactivateFeed(bytes32) external pure {
revert("Failed to deactivate feed");
}
function latestConfigDigestAndEpoch(bytes32) external pure override returns (bool, bytes32, uint32) {
revert("Failed to get latest config digest and epoch");
}
function latestConfigDetails(bytes32) external pure override returns (uint32, uint32, bytes32) {
revert("Failed to get latest config details");
}
}
文件 22 的 76: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();
_;
}
}
文件 23 的 76:ExposedVerifier.sol
pragma solidity 0.8.16;
contract ExposedVerifier {
constructor() {}
function _configDigestFromConfigData(
bytes32 feedId,
uint256 chainId,
address contractAddress,
uint64 configCount,
address[] memory signers,
bytes32[] memory offchainTransmitters,
uint8 f,
bytes memory onchainConfig,
uint64 offchainConfigVersion,
bytes memory offchainConfig
) internal pure returns (bytes32) {
uint256 h = uint256(
keccak256(
abi.encode(
feedId,
chainId,
contractAddress,
configCount,
signers,
offchainTransmitters,
f,
onchainConfig,
offchainConfigVersion,
offchainConfig
)
)
);
uint256 prefixMask = type(uint256).max << (256 - 16);
uint256 prefix = 0x0006 << (256 - 16);
return bytes32((prefix & prefixMask) | (h & ~prefixMask));
}
function exposedConfigDigestFromConfigData(
bytes32 _feedId,
uint256 _chainId,
address _contractAddress,
uint64 _configCount,
address[] memory _signers,
bytes32[] memory _offchainTransmitters,
uint8 _f,
bytes calldata _onchainConfig,
uint64 _encodedConfigVersion,
bytes memory _encodedConfig
) public pure returns (bytes32) {
return
_configDigestFromConfigData(
_feedId,
_chainId,
_contractAddress,
_configCount,
_signers,
_offchainTransmitters,
_f,
_onchainConfig,
_encodedConfigVersion,
_encodedConfig
);
}
}
文件 24 的 76:FeeManager.sol
pragma solidity 0.8.16;
import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol";
import {IFeeManager} from "./interfaces/IFeeManager.sol";
import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol";
import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
import {Common} from "./libraries/Common.sol";
import {IRewardManager} from "./interfaces/IRewardManager.sol";
import {IWERC20} from "../shared/interfaces/IWERC20.sol";
import {IERC20} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol";
import {Math} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/Math.sol";
import {SafeERC20} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol";
import {IVerifierFeeManager} from "./interfaces/IVerifierFeeManager.sol";
contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface {
using SafeERC20 for IERC20;
mapping(address => mapping(bytes32 => mapping(address => uint256))) public s_subscriberDiscounts;
mapping(bytes32 => uint256) public s_linkDeficit;
uint64 private constant PERCENTAGE_SCALAR = 1e18;
address public immutable i_linkAddress;
address public immutable i_nativeAddress;
address public immutable i_proxyAddress;
IRewardManager public immutable i_rewardManager;
bytes32 private constant REPORT_VERSION_MASK = 0xffff000000000000000000000000000000000000000000000000000000000000;
bytes32 private constant REPORT_V1 = 0x0001000000000000000000000000000000000000000000000000000000000000;
uint256 public s_nativeSurcharge;
error InvalidSurcharge();
error InvalidDiscount();
error InvalidAddress();
error InvalidDeposit();
error ExpiredReport();
error InvalidQuote();
error Unauthorized();
error ZeroDeficit();
error InvalidReceivingAddress();
event SubscriberDiscountUpdated(address indexed subscriber, bytes32 indexed feedId, address token, uint64 discount);
event NativeSurchargeUpdated(uint64 newSurcharge);
event InsufficientLink(IRewardManager.FeePayment[] rewards);
event Withdraw(address adminAddress, address recipient, address assetAddress, uint192 quantity);
event LinkDeficitCleared(bytes32 indexed configDigest, uint256 linkQuantity);
event DiscountApplied(
bytes32 indexed configDigest,
address indexed subscriber,
Common.Asset fee,
Common.Asset reward,
uint256 appliedDiscount
);
constructor(
address _linkAddress,
address _nativeAddress,
address _proxyAddress,
address _rewardManagerAddress
) ConfirmedOwner(msg.sender) {
if (
_linkAddress == address(0) ||
_nativeAddress == address(0) ||
_proxyAddress == address(0) ||
_rewardManagerAddress == address(0)
) revert InvalidAddress();
i_linkAddress = _linkAddress;
i_nativeAddress = _nativeAddress;
i_proxyAddress = _proxyAddress;
i_rewardManager = IRewardManager(_rewardManagerAddress);
IERC20(i_linkAddress).approve(address(i_rewardManager), type(uint256).max);
}
modifier onlyOwnerOrProxy() {
if (msg.sender != i_proxyAddress && msg.sender != owner()) revert Unauthorized();
_;
}
modifier onlyProxy() {
if (msg.sender != i_proxyAddress) revert Unauthorized();
_;
}
function typeAndVersion() external pure override returns (string memory) {
return "FeeManager 2.0.0";
}
function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
return interfaceId == this.processFee.selector || interfaceId == this.processFeeBulk.selector;
}
function processFee(
bytes calldata payload,
bytes calldata parameterPayload,
address subscriber
) external payable override onlyProxy {
(Common.Asset memory fee, Common.Asset memory reward, uint256 appliedDiscount) = _processFee(
payload,
parameterPayload,
subscriber
);
if (fee.amount == 0) {
_tryReturnChange(subscriber, msg.value);
return;
}
IFeeManager.FeeAndReward[] memory feeAndReward = new IFeeManager.FeeAndReward[](1);
feeAndReward[0] = IFeeManager.FeeAndReward(bytes32(payload), fee, reward, appliedDiscount);
if (fee.assetAddress == i_linkAddress) {
_handleFeesAndRewards(subscriber, feeAndReward, 1, 0);
} else {
_handleFeesAndRewards(subscriber, feeAndReward, 0, 1);
}
}
function processFeeBulk(
bytes[] calldata payloads,
bytes calldata parameterPayload,
address subscriber
) external payable override onlyProxy {
FeeAndReward[] memory feesAndRewards = new IFeeManager.FeeAndReward[](payloads.length);
uint256 numberOfLinkFees;
uint256 numberOfNativeFees;
uint256 feesAndRewardsIndex;
for (uint256 i; i < payloads.length; ++i) {
(Common.Asset memory fee, Common.Asset memory reward, uint256 appliedDiscount) = _processFee(
payloads[i],
parameterPayload,
subscriber
);
if (fee.amount != 0) {
feesAndRewards[feesAndRewardsIndex++] = IFeeManager.FeeAndReward(
bytes32(payloads[i]),
fee,
reward,
appliedDiscount
);
unchecked {
if (fee.assetAddress == i_linkAddress) {
++numberOfLinkFees;
} else {
++numberOfNativeFees;
}
}
}
}
if (numberOfLinkFees != 0 || numberOfNativeFees != 0) {
_handleFeesAndRewards(subscriber, feesAndRewards, numberOfLinkFees, numberOfNativeFees);
} else {
_tryReturnChange(subscriber, msg.value);
}
}
function getFeeAndReward(
address subscriber,
bytes memory report,
address quoteAddress
) public view returns (Common.Asset memory, Common.Asset memory, uint256) {
Common.Asset memory fee;
Common.Asset memory reward;
bytes32 feedId = bytes32(report);
bytes32 reportVersion = _getReportVersion(feedId);
if (reportVersion == REPORT_V1) {
fee.assetAddress = i_nativeAddress;
reward.assetAddress = i_linkAddress;
return (fee, reward, 0);
}
if (quoteAddress != i_nativeAddress && quoteAddress != i_linkAddress) {
revert InvalidQuote();
}
uint256 linkQuantity;
uint256 nativeQuantity;
uint256 expiresAt;
(, , , nativeQuantity, linkQuantity, expiresAt) = abi.decode(
report,
(bytes32, uint32, uint32, uint192, uint192, uint32)
);
if (expiresAt < block.timestamp) {
revert ExpiredReport();
}
uint256 discount = s_subscriberDiscounts[subscriber][feedId][quoteAddress];
reward.assetAddress = i_linkAddress;
reward.amount = Math.ceilDiv(linkQuantity * (PERCENTAGE_SCALAR - discount), PERCENTAGE_SCALAR);
if (quoteAddress == i_linkAddress) {
fee.assetAddress = i_linkAddress;
fee.amount = reward.amount;
} else {
uint256 surchargedFee = Math.ceilDiv(nativeQuantity * (PERCENTAGE_SCALAR + s_nativeSurcharge), PERCENTAGE_SCALAR);
fee.assetAddress = i_nativeAddress;
fee.amount = Math.ceilDiv(surchargedFee * (PERCENTAGE_SCALAR - discount), PERCENTAGE_SCALAR);
}
return (fee, reward, discount);
}
function setFeeRecipients(
bytes32 configDigest,
Common.AddressAndWeight[] calldata rewardRecipientAndWeights
) external onlyOwnerOrProxy {
i_rewardManager.setRewardRecipients(configDigest, rewardRecipientAndWeights);
}
function setNativeSurcharge(uint64 surcharge) external onlyOwner {
if (surcharge > PERCENTAGE_SCALAR) revert InvalidSurcharge();
s_nativeSurcharge = surcharge;
emit NativeSurchargeUpdated(surcharge);
}
function updateSubscriberDiscount(
address subscriber,
bytes32 feedId,
address token,
uint64 discount
) external onlyOwner {
if (discount > PERCENTAGE_SCALAR) revert InvalidDiscount();
if (token != i_linkAddress && token != i_nativeAddress) revert InvalidAddress();
s_subscriberDiscounts[subscriber][feedId][token] = discount;
emit SubscriberDiscountUpdated(subscriber, feedId, token, discount);
}
function withdraw(address assetAddress, address recipient, uint192 quantity) external onlyOwner {
if (assetAddress == address(0)) {
(bool success, ) = payable(recipient).call{value: quantity}("");
if (!success) revert InvalidReceivingAddress();
return;
}
IERC20(assetAddress).safeTransfer(recipient, quantity);
emit Withdraw(msg.sender, recipient, assetAddress, uint192(quantity));
}
function linkAvailableForPayment() external view returns (uint256) {
return IERC20(i_linkAddress).balanceOf(address(this));
}
function _getReportVersion(bytes32 feedId) internal pure returns (bytes32) {
return REPORT_VERSION_MASK & feedId;
}
function _processFee(
bytes calldata payload,
bytes calldata parameterPayload,
address subscriber
) internal view returns (Common.Asset memory, Common.Asset memory, uint256) {
if (subscriber == address(this)) revert InvalidAddress();
(, bytes memory report) = abi.decode(payload, (bytes32[3], bytes));
bytes32 feedId = bytes32(report);
address quote;
if (_getReportVersion(feedId) != REPORT_V1) {
(quote) = abi.decode(parameterPayload, (address));
}
return getFeeAndReward(subscriber, report, quote);
}
function _handleFeesAndRewards(
address subscriber,
FeeAndReward[] memory feesAndRewards,
uint256 numberOfLinkFees,
uint256 numberOfNativeFees
) internal {
IRewardManager.FeePayment[] memory linkRewards = new IRewardManager.FeePayment[](numberOfLinkFees);
IRewardManager.FeePayment[] memory nativeFeeLinkRewards = new IRewardManager.FeePayment[](numberOfNativeFees);
uint256 totalNativeFee;
uint256 totalNativeFeeLinkValue;
uint256 linkRewardsIndex;
uint256 nativeFeeLinkRewardsIndex;
uint256 totalNumberOfFees = numberOfLinkFees + numberOfNativeFees;
for (uint256 i; i < totalNumberOfFees; ++i) {
if (feesAndRewards[i].fee.assetAddress == i_linkAddress) {
linkRewards[linkRewardsIndex++] = IRewardManager.FeePayment(
feesAndRewards[i].configDigest,
uint192(feesAndRewards[i].reward.amount)
);
} else {
nativeFeeLinkRewards[nativeFeeLinkRewardsIndex++] = IRewardManager.FeePayment(
feesAndRewards[i].configDigest,
uint192(feesAndRewards[i].reward.amount)
);
totalNativeFee += feesAndRewards[i].fee.amount;
totalNativeFeeLinkValue += feesAndRewards[i].reward.amount;
}
if (feesAndRewards[i].appliedDiscount != 0) {
emit DiscountApplied(
feesAndRewards[i].configDigest,
subscriber,
feesAndRewards[i].fee,
feesAndRewards[i].reward,
feesAndRewards[i].appliedDiscount
);
}
}
uint256 change;
if (msg.value != 0) {
if (totalNativeFee > msg.value) revert InvalidDeposit();
IWERC20(i_nativeAddress).deposit{value: totalNativeFee}();
unchecked {
change = msg.value - totalNativeFee;
}
} else {
if (totalNativeFee != 0) {
IERC20(i_nativeAddress).safeTransferFrom(subscriber, address(this), totalNativeFee);
}
}
if (linkRewards.length != 0) {
i_rewardManager.onFeePaid(linkRewards, subscriber);
}
if (nativeFeeLinkRewards.length != 0) {
if (totalNativeFeeLinkValue > IERC20(i_linkAddress).balanceOf(address(this))) {
for (uint256 i; i < nativeFeeLinkRewards.length; ++i) {
unchecked {
s_linkDeficit[nativeFeeLinkRewards[i].poolId] += nativeFeeLinkRewards[i].amount;
}
}
emit InsufficientLink(nativeFeeLinkRewards);
} else {
i_rewardManager.onFeePaid(nativeFeeLinkRewards, address(this));
}
}
_tryReturnChange(subscriber, change);
}
function _tryReturnChange(address subscriber, uint256 quantity) internal {
if (quantity != 0) {
payable(subscriber).transfer(quantity);
}
}
function payLinkDeficit(bytes32 configDigest) external onlyOwner {
uint256 deficit = s_linkDeficit[configDigest];
if (deficit == 0) revert ZeroDeficit();
delete s_linkDeficit[configDigest];
IRewardManager.FeePayment[] memory deficitFeePayment = new IRewardManager.FeePayment[](1);
deficitFeePayment[0] = IRewardManager.FeePayment(configDigest, uint192(deficit));
i_rewardManager.onFeePaid(deficitFeePayment, address(this));
emit LinkDeficitCleared(configDigest, deficit);
}
}
文件 25 的 76:FeeManagerProxy.sol
pragma solidity 0.8.16;
import "../../interfaces/IFeeManager.sol";
contract FeeManagerProxy {
IFeeManager internal i_feeManager;
function processFee(bytes calldata payload, bytes calldata parameterPayload) public payable {
i_feeManager.processFee{value: msg.value}(payload, parameterPayload, msg.sender);
}
function processFeeBulk(bytes[] calldata payloads, bytes calldata parameterPayload) public payable {
i_feeManager.processFeeBulk{value: msg.value}(payloads, parameterPayload, msg.sender);
}
function setFeeManager(IFeeManager feeManager) public {
i_feeManager = feeManager;
}
}
文件 26 的 76:IAutomationForwarder.sol
pragma solidity ^0.8.0;
import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
import {IAutomationRegistryConsumer} from "./IAutomationRegistryConsumer.sol";
interface IAutomationForwarder is ITypeAndVersion {
function forward(uint256 gasAmount, bytes memory data) external returns (bool success, uint256 gasUsed);
function updateRegistry(address newRegistry) external;
function getRegistry() external view returns (IAutomationRegistryConsumer);
function getTarget() external view returns (address);
}
文件 27 的 76:IAutomationRegistryConsumer.sol
pragma solidity ^0.8.4;
interface IAutomationRegistryConsumer {
function getBalance(uint256 id) external view returns (uint96 balance);
function getMinBalance(uint256 id) external view returns (uint96 minBalance);
function cancelUpkeep(uint256 id) external;
function pauseUpkeep(uint256 id) external;
function unpauseUpkeep(uint256 id) external;
function addFunds(uint256 id, uint96 amount) external;
function withdrawFunds(uint256 id, address to) external;
}
文件 28 的 76:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 29 的 76:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
文件 30 的 76:IERC677Receiver.sol
pragma solidity ^0.8.6;
interface IERC677Receiver {
function onTokenTransfer(address sender, uint256 amount, bytes calldata data) external;
}
文件 31 的 76:IFeeManager.sol
pragma solidity 0.8.16;
import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
import {Common} from "../libraries/Common.sol";
import {IVerifierFeeManager} from "./IVerifierFeeManager.sol";
interface IFeeManager is IERC165, IVerifierFeeManager {
function getFeeAndReward(
address subscriber,
bytes memory report,
address quoteAddress
) external returns (Common.Asset memory, Common.Asset memory, uint256);
function setNativeSurcharge(uint64 surcharge) external;
function updateSubscriberDiscount(address subscriber, bytes32 feedId, address token, uint64 discount) external;
function withdraw(address assetAddress, address recipientAddress, uint192 quantity) external;
function linkAvailableForPayment() external returns (uint256);
function payLinkDeficit(bytes32 configDigest) external;
struct FeeAndReward {
bytes32 configDigest;
Common.Asset fee;
Common.Asset reward;
uint256 appliedDiscount;
}
struct Quote {
address quoteAddress;
}
}
文件 32 的 76:IKeeperRegistryMaster.sol
pragma solidity ^0.8.4;
interface IKeeperRegistryMaster {
error ArrayHasNoEntries();
error CannotCancel();
error CheckDataExceedsLimit();
error ConfigDigestMismatch();
error DuplicateEntry();
error DuplicateSigners();
error GasLimitCanOnlyIncrease();
error GasLimitOutsideRange();
error IncorrectNumberOfFaultyOracles();
error IncorrectNumberOfSignatures();
error IncorrectNumberOfSigners();
error IndexOutOfRange();
error InsufficientFunds();
error InvalidDataLength();
error InvalidPayee();
error InvalidRecipient();
error InvalidReport();
error InvalidSigner();
error InvalidTransmitter();
error InvalidTrigger();
error InvalidTriggerType();
error MaxCheckDataSizeCanOnlyIncrease();
error MaxPerformDataSizeCanOnlyIncrease();
error MigrationNotPermitted();
error NotAContract();
error OnlyActiveSigners();
error OnlyActiveTransmitters();
error OnlyCallableByAdmin();
error OnlyCallableByLINKToken();
error OnlyCallableByOwnerOrAdmin();
error OnlyCallableByOwnerOrRegistrar();
error OnlyCallableByPayee();
error OnlyCallableByProposedAdmin();
error OnlyCallableByProposedPayee();
error OnlyCallableByUpkeepPrivilegeManager();
error OnlyPausedUpkeep();
error OnlySimulatedBackend();
error OnlyUnpausedUpkeep();
error ParameterLengthError();
error PaymentGreaterThanAllLINK();
error ReentrantCall();
error RegistryPaused();
error RepeatedSigner();
error RepeatedTransmitter();
error TargetCheckReverted(bytes reason);
error TooManyOracles();
error TranscoderNotSet();
error UpkeepAlreadyExists();
error UpkeepCancelled();
error UpkeepNotCanceled();
error UpkeepNotNeeded();
error ValueNotChanged();
event AdminPrivilegeConfigSet(address indexed admin, bytes privilegeConfig);
event CancelledUpkeepReport(uint256 indexed id, bytes trigger);
event ConfigSet(
uint32 previousConfigBlockNumber,
bytes32 configDigest,
uint64 configCount,
address[] signers,
address[] transmitters,
uint8 f,
bytes onchainConfig,
uint64 offchainConfigVersion,
bytes offchainConfig
);
event DedupKeyAdded(bytes32 indexed dedupKey);
event FundsAdded(uint256 indexed id, address indexed from, uint96 amount);
event FundsWithdrawn(uint256 indexed id, uint256 amount, address to);
event InsufficientFundsUpkeepReport(uint256 indexed id, bytes trigger);
event OwnerFundsWithdrawn(uint96 amount);
event OwnershipTransferRequested(address indexed from, address indexed to);
event OwnershipTransferred(address indexed from, address indexed to);
event Paused(address account);
event PayeesUpdated(address[] transmitters, address[] payees);
event PayeeshipTransferRequested(address indexed transmitter, address indexed from, address indexed to);
event PayeeshipTransferred(address indexed transmitter, address indexed from, address indexed to);
event PaymentWithdrawn(address indexed transmitter, uint256 indexed amount, address indexed to, address payee);
event ReorgedUpkeepReport(uint256 indexed id, bytes trigger);
event StaleUpkeepReport(uint256 indexed id, bytes trigger);
event Transmitted(bytes32 configDigest, uint32 epoch);
event Unpaused(address account);
event UpkeepAdminTransferRequested(uint256 indexed id, address indexed from, address indexed to);
event UpkeepAdminTransferred(uint256 indexed id, address indexed from, address indexed to);
event UpkeepCanceled(uint256 indexed id, uint64 indexed atBlockHeight);
event UpkeepCheckDataSet(uint256 indexed id, bytes newCheckData);
event UpkeepGasLimitSet(uint256 indexed id, uint96 gasLimit);
event UpkeepMigrated(uint256 indexed id, uint256 remainingBalance, address destination);
event UpkeepOffchainConfigSet(uint256 indexed id, bytes offchainConfig);
event UpkeepPaused(uint256 indexed id);
event UpkeepPerformed(
uint256 indexed id,
bool indexed success,
uint96 totalPayment,
uint256 gasUsed,
uint256 gasOverhead,
bytes trigger
);
event UpkeepPrivilegeConfigSet(uint256 indexed id, bytes privilegeConfig);
event UpkeepReceived(uint256 indexed id, uint256 startingBalance, address importedFrom);
event UpkeepRegistered(uint256 indexed id, uint32 performGas, address admin);
event UpkeepTriggerConfigSet(uint256 indexed id, bytes triggerConfig);
event UpkeepUnpaused(uint256 indexed id);
fallback() external;
function acceptOwnership() external;
function fallbackTo() external view returns (address);
function latestConfigDetails() external view returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest);
function latestConfigDigestAndEpoch() external view returns (bool scanLogs, bytes32 configDigest, uint32 epoch);
function onTokenTransfer(address sender, uint256 amount, bytes memory data) external;
function owner() external view returns (address);
function setConfig(
address[] memory signers,
address[] memory transmitters,
uint8 f,
bytes memory onchainConfigBytes,
uint64 offchainConfigVersion,
bytes memory offchainConfig
) external;
function setConfigTypeSafe(
address[] memory signers,
address[] memory transmitters,
uint8 f,
KeeperRegistryBase2_1.OnchainConfig memory onchainConfig,
uint64 offchainConfigVersion,
bytes memory offchainConfig
) external;
function simulatePerformUpkeep(
uint256 id,
bytes memory performData
) external view returns (bool success, uint256 gasUsed);
function transferOwnership(address to) external;
function transmit(
bytes32[3] memory reportContext,
bytes memory rawReport,
bytes32[] memory rs,
bytes32[] memory ss,
bytes32 rawVs
) external;
function typeAndVersion() external view returns (string memory);
function addFunds(uint256 id, uint96 amount) external;
function cancelUpkeep(uint256 id) external;
function checkCallback(
uint256 id,
bytes[] memory values,
bytes memory extraData
) external view returns (bool upkeepNeeded, bytes memory performData, uint8 upkeepFailureReason, uint256 gasUsed);
function checkUpkeep(
uint256 id,
bytes memory triggerData
)
external
view
returns (
bool upkeepNeeded,
bytes memory performData,
uint8 upkeepFailureReason,
uint256 gasUsed,
uint256 gasLimit,
uint256 fastGasWei,
uint256 linkNative
);
function checkUpkeep(
uint256 id
)
external
view
returns (
bool upkeepNeeded,
bytes memory performData,
uint8 upkeepFailureReason,
uint256 gasUsed,
uint256 gasLimit,
uint256 fastGasWei,
uint256 linkNative
);
function executeCallback(
uint256 id,
bytes memory payload
) external returns (bool upkeepNeeded, bytes memory performData, uint8 upkeepFailureReason, uint256 gasUsed);
function migrateUpkeeps(uint256[] memory ids, address destination) external;
function receiveUpkeeps(bytes memory encodedUpkeeps) external;
function registerUpkeep(
address target,
uint32 gasLimit,
address admin,
uint8 triggerType,
bytes memory checkData,
bytes memory triggerConfig,
bytes memory offchainConfig
) external returns (uint256 id);
function registerUpkeep(
address target,
uint32 gasLimit,
address admin,
bytes memory checkData,
bytes memory offchainConfig
) external returns (uint256 id);
function setUpkeepTriggerConfig(uint256 id, bytes memory triggerConfig) external;
function acceptPayeeship(address transmitter) external;
function acceptUpkeepAdmin(uint256 id) external;
function getActiveUpkeepIDs(uint256 startIndex, uint256 maxCount) external view returns (uint256[] memory);
function getAdminPrivilegeConfig(address admin) external view returns (bytes memory);
function getAutomationForwarderLogic() external view returns (address);
function getBalance(uint256 id) external view returns (uint96 balance);
function getCancellationDelay() external pure returns (uint256);
function getConditionalGasOverhead() external pure returns (uint256);
function getFastGasFeedAddress() external view returns (address);
function getForwarder(uint256 upkeepID) external view returns (address);
function getLinkAddress() external view returns (address);
function getLinkNativeFeedAddress() external view returns (address);
function getLogGasOverhead() external pure returns (uint256);
function getMaxPaymentForGas(uint8 triggerType, uint32 gasLimit) external view returns (uint96 maxPayment);
function getMinBalance(uint256 id) external view returns (uint96);
function getMinBalanceForUpkeep(uint256 id) external view returns (uint96 minBalance);
function getMode() external view returns (uint8);
function getPeerRegistryMigrationPermission(address peer) external view returns (uint8);
function getPerPerformByteGasOverhead() external pure returns (uint256);
function getPerSignerGasOverhead() external pure returns (uint256);
function getSignerInfo(address query) external view returns (bool active, uint8 index);
function getState()
external
view
returns (
KeeperRegistryBase2_1.State memory state,
KeeperRegistryBase2_1.OnchainConfig memory config,
address[] memory signers,
address[] memory transmitters,
uint8 f
);
function getTransmitterInfo(
address query
) external view returns (bool active, uint8 index, uint96 balance, uint96 lastCollected, address payee);
function getTriggerType(uint256 upkeepId) external pure returns (uint8);
function getUpkeep(uint256 id) external view returns (KeeperRegistryBase2_1.UpkeepInfo memory upkeepInfo);
function getUpkeepPrivilegeConfig(uint256 upkeepId) external view returns (bytes memory);
function getUpkeepTriggerConfig(uint256 upkeepId) external view returns (bytes memory);
function hasDedupKey(bytes32 dedupKey) external view returns (bool);
function pause() external;
function pauseUpkeep(uint256 id) external;
function recoverFunds() external;
function setAdminPrivilegeConfig(address admin, bytes memory newPrivilegeConfig) external;
function setPayees(address[] memory payees) external;
function setPeerRegistryMigrationPermission(address peer, uint8 permission) external;
function setUpkeepCheckData(uint256 id, bytes memory newCheckData) external;
function setUpkeepGasLimit(uint256 id, uint32 gasLimit) external;
function setUpkeepOffchainConfig(uint256 id, bytes memory config) external;
function setUpkeepPrivilegeConfig(uint256 upkeepId, bytes memory newPrivilegeConfig) external;
function transferPayeeship(address transmitter, address proposed) external;
function transferUpkeepAdmin(uint256 id, address proposed) external;
function unpause() external;
function unpauseUpkeep(uint256 id) external;
function upkeepTranscoderVersion() external pure returns (uint8);
function upkeepVersion() external pure returns (uint8);
function withdrawFunds(uint256 id, address to) external;
function withdrawOwnerFunds() external;
function withdrawPayment(address from, address to) external;
}
interface KeeperRegistryBase2_1 {
struct OnchainConfig {
uint32 paymentPremiumPPB;
uint32 flatFeeMicroLink;
uint32 checkGasLimit;
uint24 stalenessSeconds;
uint16 gasCeilingMultiplier;
uint96 minUpkeepSpend;
uint32 maxPerformGas;
uint32 maxCheckDataSize;
uint32 maxPerformDataSize;
uint32 maxRevertDataSize;
uint256 fallbackGasPrice;
uint256 fallbackLinkPrice;
address transcoder;
address[] registrars;
address upkeepPrivilegeManager;
}
struct 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 performGas;
bytes checkData;
uint96 balance;
address admin;
uint64 maxValidBlocknumber;
uint32 lastPerformedBlockNumber;
uint96 amountSpent;
bool paused;
bytes offchainConfig;
}
}
文件 33 的 76:ILogAutomation.sol
pragma solidity ^0.8.0;
struct Log {
uint256 index;
uint256 timestamp;
bytes32 txHash;
uint256 blockNumber;
bytes32 blockHash;
address source;
bytes32[] topics;
bytes data;
}
interface ILogAutomation {
function checkLog(
Log calldata log,
bytes memory checkData
) external returns (bool upkeepNeeded, bytes memory performData);
function performUpkeep(bytes calldata performData) external;
}
文件 34 的 76:IOwnable.sol
pragma solidity ^0.8.0;
interface IOwnable {
function owner() external returns (address);
function transferOwnership(address recipient) external;
function acceptOwnership() external;
}
文件 35 的 76:IRewardManager.sol
pragma solidity 0.8.16;
import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
import {Common} from "../libraries/Common.sol";
interface IRewardManager is IERC165 {
function onFeePaid(FeePayment[] calldata payments, address payee) external;
function claimRewards(bytes32[] calldata poolIds) external;
function setRewardRecipients(bytes32 poolId, Common.AddressAndWeight[] calldata rewardRecipientAndWeights) external;
function updateRewardRecipients(bytes32 poolId, Common.AddressAndWeight[] calldata newRewardRecipients) external;
function payRecipients(bytes32 poolId, address[] calldata recipients) external;
function setFeeManager(address newFeeManager) external;
function getAvailableRewardPoolIds(
address recipient,
uint256 startIndex,
uint256 endIndex
) external view returns (bytes32[] memory);
struct FeePayment {
bytes32 poolId;
uint192 amount;
}
}
文件 36 的 76:ITypeAndVersion.sol
pragma solidity ^0.8.0;
interface ITypeAndVersion {
function typeAndVersion() external pure returns (string memory);
}
文件 37 的 76:IVerifier.sol
pragma solidity 0.8.16;
import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol";
import {Common} from "../../libraries/Common.sol";
interface IVerifier is IERC165 {
function verify(bytes calldata signedReport, address sender) external returns (bytes memory verifierResponse);
function setConfig(
bytes32 feedId,
address[] memory signers,
bytes32[] memory offchainTransmitters,
uint8 f,
bytes memory onchainConfig,
uint64 offchainConfigVersion,
bytes memory offchainConfig,
Common.AddressAndWeight[] memory recipientAddressesAndWeights
) external;
function setConfigFromSource(
bytes32 feedId,
uint256 sourceChainId,
address sourceAddress,
uint32 newConfigCount,
address[] memory signers,
bytes32[] memory offchainTransmitters,
uint8 f,
bytes memory onchainConfig,
uint64 offchainConfigVersion,
bytes memory offchainConfig,
Common.AddressAndWeight[] memory recipientAddressesAndWeights
) external;
function activateConfig(bytes32 feedId, bytes32 configDigest) external;
function deactivateConfig(bytes32 feedId, bytes32 configDigest) external;
function activateFeed(bytes32 feedId) external;
function deactivateFeed(bytes32 feedId) external;
function latestConfigDigestAndEpoch(
bytes32 feedId
) external view returns (bool scanLogs, bytes32 configDigest, uint32 epoch);
function latestConfigDetails(
bytes32 feedId
) external view returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest);
}
文件 38 的 76:IVerifierFeeManager.sol
pragma solidity 0.8.16;
import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol";
import {Common} from "../../libraries/Common.sol";
interface IVerifierFeeManager is IERC165 {
function processFee(bytes calldata payload, bytes calldata parameterPayload, address subscriber) external payable;
function processFeeBulk(
bytes[] calldata payloads,
bytes calldata parameterPayload,
address subscriber
) external payable;
function setFeeRecipients(
bytes32 configDigest,
Common.AddressAndWeight[] calldata rewardRecipientAndWeights
) external;
}
文件 39 的 76:IVerifierProxy.sol
pragma solidity 0.8.16;
import {Common} from "../../libraries/Common.sol";
import {AccessControllerInterface} from "../../shared/interfaces/AccessControllerInterface.sol";
import {IVerifierFeeManager} from "./IVerifierFeeManager.sol";
interface IVerifierProxy {
function verify(
bytes calldata payload,
bytes calldata parameterPayload
) external payable returns (bytes memory verifierResponse);
function verifyBulk(
bytes[] calldata payloads,
bytes calldata parameterPayload
) external payable returns (bytes[] memory verifiedReports);
function initializeVerifier(address verifierAddress) external;
function setVerifier(
bytes32 currentConfigDigest,
bytes32 newConfigDigest,
Common.AddressAndWeight[] memory addressesAndWeights
) external;
function unsetVerifier(bytes32 configDigest) external;
function getVerifier(bytes32 configDigest) external view returns (address verifierAddress);
function setAccessController(AccessControllerInterface accessController) external;
function setFeeManager(IVerifierFeeManager feeManager) external;
}
文件 40 的 76:IWERC20.sol
pragma solidity ^0.8.0;
interface IWERC20 {
function deposit() external payable;
function withdraw(uint256) external;
}
文件 41 的 76:KeeperBase.sol
pragma solidity ^0.8.0;
import {AutomationBase as KeeperBase} from "./AutomationBase.sol";
文件 42 的 76:KeeperCompatibleInterface.sol
pragma solidity ^0.8.0;
import {AutomationCompatibleInterface as KeeperCompatibleInterface} from "./AutomationCompatibleInterface.sol";
文件 43 的 76:KeeperConsumer.sol
pragma solidity 0.8.16;
import "../interfaces/KeeperCompatibleInterface.sol";
import "../KeeperBase.sol";
contract KeeperConsumer is KeeperCompatibleInterface, KeeperBase {
uint public counter;
uint public immutable interval;
uint public lastTimeStamp;
constructor(uint updateInterval) public {
interval = updateInterval;
lastTimeStamp = block.timestamp;
counter = 0;
}
function checkUpkeep(
bytes calldata checkData
) external view override cannotExecute returns (bool upkeepNeeded, bytes memory performData) {
return (true, checkData);
}
function performUpkeep(bytes calldata performData) external override {
counter = counter + 1;
}
}
文件 44 的 76:KeeperConsumerPerformance.sol
pragma solidity 0.8.16;
contract KeeperConsumerPerformance {
event PerformingUpkeep(bool eligible, address from, uint256 initialCall, uint256 nextEligible, uint256 blockNumber);
uint256 public initialCall = 0;
uint256 public nextEligible = 0;
uint256 public testRange;
uint256 public averageEligibilityCadence;
uint256 public checkGasToBurn;
uint256 public performGasToBurn;
mapping(bytes32 => bool) public dummyMap;
uint256 public count = 0;
constructor(
uint256 _testRange,
uint256 _averageEligibilityCadence,
uint256 _checkGasToBurn,
uint256 _performGasToBurn
) {
testRange = _testRange;
averageEligibilityCadence = _averageEligibilityCadence;
checkGasToBurn = _checkGasToBurn;
performGasToBurn = _performGasToBurn;
}
function checkUpkeep(bytes calldata data) external view returns (bool, bytes memory) {
uint256 startGas = gasleft();
bool dummy;
while (startGas - gasleft() < checkGasToBurn) {
dummy = dummy && dummyMap[blockhash(block.number)];
}
return (eligible(), abi.encode(dummy));
}
function performUpkeep(bytes calldata data) external {
uint256 startGas = gasleft();
bool eligible = eligible();
uint256 blockNum = block.number;
emit PerformingUpkeep(eligible, tx.origin, initialCall, nextEligible, blockNum);
require(eligible);
if (initialCall == 0) {
initialCall = blockNum;
}
nextEligible = (blockNum + (rand() % (averageEligibilityCadence * 2))) + 1;
count++;
while (startGas - gasleft() < performGasToBurn) {
dummyMap[blockhash(block.number)] = false;
}
}
function setCheckGasToBurn(uint256 value) public {
checkGasToBurn = value;
}
function setPerformGasToBurn(uint256 value) public {
performGasToBurn = value;
}
function getCountPerforms() public view returns (uint256) {
return count;
}
function eligible() internal view returns (bool) {
return initialCall == 0 || (block.number - initialCall < testRange && block.number > nextEligible);
}
function checkEligible() public view returns (bool) {
return eligible();
}
function reset() external {
initialCall = 0;
count = 0;
}
function setSpread(uint256 _newTestRange, uint256 _newAverageEligibilityCadence) external {
testRange = _newTestRange;
averageEligibilityCadence = _newAverageEligibilityCadence;
}
function rand() private view returns (uint256) {
return uint256(keccak256(abi.encode(blockhash(block.number - 1), address(this))));
}
}
文件 45 的 76:KeeperRegistry2_1.sol
pragma solidity 0.8.16;
import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol";
import {Address} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol";
import {KeeperRegistryBase2_1} from "./KeeperRegistryBase2_1.sol";
import {KeeperRegistryLogicB2_1} from "./KeeperRegistryLogicB2_1.sol";
import {Chainable} from "../Chainable.sol";
import {IERC677Receiver} from "../../shared/interfaces/IERC677Receiver.sol";
import {OCR2Abstract} from "../../shared/ocr2/OCR2Abstract.sol";
contract KeeperRegistry2_1 is KeeperRegistryBase2_1, OCR2Abstract, Chainable, IERC677Receiver {
using Address for address;
using EnumerableSet for EnumerableSet.UintSet;
using EnumerableSet for EnumerableSet.AddressSet;
string public constant override typeAndVersion = "KeeperRegistry 2.1.0";
constructor(
KeeperRegistryLogicB2_1 logicA
)
KeeperRegistryBase2_1(
logicA.getMode(),
logicA.getLinkAddress(),
logicA.getLinkNativeFeedAddress(),
logicA.getFastGasFeedAddress(),
logicA.getAutomationForwarderLogic()
)
Chainable(address(logicA))
{}
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();
if (s_latestConfigDigest != reportContext[0]) revert ConfigDigestMismatch();
if (rs.length != hotVars.f + 1 || rs.length != ss.length) revert IncorrectNumberOfSignatures();
_verifyReportSignature(reportContext, rawReport, rs, ss, rawVs);
Report memory report = _decodeReport(rawReport);
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].triggerType = _getTriggerType(report.upkeepIds[i]);
upkeepTransmitInfo[i].maxLinkPayment = _getMaxLinkPayment(
hotVars,
upkeepTransmitInfo[i].triggerType,
uint32(report.gasLimits[i]),
uint32(report.performDatas[i].length),
report.fastGasWei,
report.linkNative,
true
);
(upkeepTransmitInfo[i].earlyChecksPassed, upkeepTransmitInfo[i].dedupID) = _prePerformChecks(
report.upkeepIds[i],
report.triggers[i],
upkeepTransmitInfo[i]
);
if (upkeepTransmitInfo[i].earlyChecksPassed) {
numUpkeepsPassedChecks += 1;
} else {
continue;
}
(upkeepTransmitInfo[i].performSuccess, upkeepTransmitInfo[i].gasUsed) = _performUpkeep(
upkeepTransmitInfo[i].upkeep.forwarder,
report.gasLimits[i],
report.performDatas[i]
);
gasOverhead -= upkeepTransmitInfo[i].gasUsed;
_updateTriggerMarker(report.upkeepIds[i], upkeepTransmitInfo[i]);
}
if (numUpkeepsPassedChecks == 0) {
return;
}
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,
upkeepTransmitInfo[i].triggerType,
uint32(report.performDatas[i].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,
reimbursement + premium,
upkeepTransmitInfo[i].gasUsed,
upkeepTransmitInfo[i].gasOverhead,
report.triggers[i]
);
}
}
}
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];
(success, gasUsed) = _performUpkeep(upkeep.forwarder, upkeep.performGas, performData);
return (success, gasUsed);
}
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 onchainConfigBytes,
uint64 offchainConfigVersion,
bytes memory offchainConfig
) external override {
setConfigTypeSafe(
signers,
transmitters,
f,
abi.decode(onchainConfigBytes, (OnchainConfig)),
offchainConfigVersion,
offchainConfig
);
}
function setConfigTypeSafe(
address[] memory signers,
address[] memory transmitters,
uint8 f,
OnchainConfig memory onchainConfig,
uint64 offchainConfigVersion,
bytes memory offchainConfig
) public onlyOwner {
if (signers.length > MAX_NUM_ORACLES) revert TooManyOracles();
if (f == 0) revert IncorrectNumberOfFaultyOracles();
if (signers.length != transmitters.length || signers.length <= 3 * f) revert IncorrectNumberOfSigners();
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();
if (signers[i] == ZERO_ADDRESS) revert InvalidSigner();
s_signers[signers[i]] = Signer({active: true, index: uint8(i)});
temp = transmitters[i];
if (temp == ZERO_ADDRESS) revert InvalidTransmitter();
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;
s_hotVars = HotVars({
f: f,
paymentPremiumPPB: onchainConfig.paymentPremiumPPB,
flatFeeMicroLink: onchainConfig.flatFeeMicroLink,
stalenessSeconds: onchainConfig.stalenessSeconds,
gasCeilingMultiplier: onchainConfig.gasCeilingMultiplier,
paused: s_hotVars.paused,
reentrancyGuard: s_hotVars.reentrancyGuard,
totalPremium: totalPremium,
latestEpoch: 0
});
s_storage = Storage({
checkGasLimit: onchainConfig.checkGasLimit,
minUpkeepSpend: onchainConfig.minUpkeepSpend,
maxPerformGas: onchainConfig.maxPerformGas,
transcoder: onchainConfig.transcoder,
maxCheckDataSize: onchainConfig.maxCheckDataSize,
maxPerformDataSize: onchainConfig.maxPerformDataSize,
maxRevertDataSize: onchainConfig.maxRevertDataSize,
upkeepPrivilegeManager: onchainConfig.upkeepPrivilegeManager,
nonce: s_storage.nonce,
configCount: s_storage.configCount,
latestConfigBlockNumber: s_storage.latestConfigBlockNumber,
ownerLinkBalance: s_storage.ownerLinkBalance
});
s_fallbackGasPrice = onchainConfig.fallbackGasPrice;
s_fallbackLinkPrice = onchainConfig.fallbackLinkPrice;
uint32 previousConfigBlockNumber = s_storage.latestConfigBlockNumber;
s_storage.latestConfigBlockNumber = uint32(_blockNum());
s_storage.configCount += 1;
bytes memory onchainConfigBytes = abi.encode(onchainConfig);
s_latestConfigDigest = _configDigestFromConfigData(
block.chainid,
address(this),
s_storage.configCount,
signers,
transmitters,
f,
onchainConfigBytes,
offchainConfigVersion,
offchainConfig
);
for (uint256 idx = 0; idx < s_registrars.length(); idx++) {
s_registrars.remove(s_registrars.at(idx));
}
for (uint256 idx = 0; idx < onchainConfig.registrars.length; idx++) {
s_registrars.add(onchainConfig.registrars[idx]);
}
emit ConfigSet(
previousConfigBlockNumber,
s_latestConfigDigest,
s_storage.configCount,
signers,
transmitters,
f,
onchainConfigBytes,
offchainConfigVersion,
offchainConfig
);
}
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);
}
}
文件 46 的 76:KeeperRegistryBase2_1.sol
pragma solidity 0.8.16;
import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol";
import {Address} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol";
import {ArbGasInfo} from "../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbGasInfo.sol";
import {OVM_GasPriceOracle} from "../../vendor/@eth-optimism/contracts/v0.8.9/contracts/L2/predeploys/OVM_GasPriceOracle.sol";
import {ExecutionPrevention} from "../ExecutionPrevention.sol";
import {ArbSys} from "../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol";
import {StreamsLookupCompatibleInterface} from "../interfaces/StreamsLookupCompatibleInterface.sol";
import {ILogAutomation, Log} from "../interfaces/ILogAutomation.sol";
import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol";
import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol";
import {AggregatorV3Interface} from "../../shared/interfaces/AggregatorV3Interface.sol";
import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol";
import {KeeperCompatibleInterface} from "../interfaces/KeeperCompatibleInterface.sol";
import {UpkeepFormat} from "../interfaces/UpkeepTranscoderInterface.sol";
abstract contract KeeperRegistryBase2_1 is ConfirmedOwner, ExecutionPrevention {
using Address for address;
using EnumerableSet for EnumerableSet.UintSet;
using EnumerableSet for EnumerableSet.AddressSet;
address internal constant ZERO_ADDRESS = address(0);
address internal constant IGNORE_ADDRESS = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF;
bytes4 internal constant CHECK_SELECTOR = KeeperCompatibleInterface.checkUpkeep.selector;
bytes4 internal constant PERFORM_SELECTOR = KeeperCompatibleInterface.performUpkeep.selector;
bytes4 internal constant CHECK_CALLBACK_SELECTOR = StreamsLookupCompatibleInterface.checkCallback.selector;
bytes4 internal constant CHECK_LOG_SELECTOR = ILogAutomation.checkLog.selector;
uint256 internal constant PERFORM_GAS_MIN = 2_300;
uint256 internal constant CANCELLATION_DELAY = 50;
uint256 internal constant PERFORM_GAS_CUSHION = 5_000;
uint256 internal constant PPB_BASE = 1_000_000_000;
uint32 internal constant UINT32_MAX = type(uint32).max;
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 = 3;
bytes internal constant L1_FEE_DATA_PADDING =
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
uint256 internal constant REGISTRY_CONDITIONAL_OVERHEAD = 90_000;
uint256 internal constant REGISTRY_LOG_OVERHEAD = 110_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 = 27_500;
uint256 internal constant ACCOUNTING_PER_SIGNER_GAS_OVERHEAD = 1_100;
uint256 internal constant ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD = 7_000;
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;
address internal immutable i_automationForwarderLogic;
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(bytes32 => bool) internal s_dedupKeys;
EnumerableSet.AddressSet internal s_registrars;
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_upkeepTriggerConfig;
mapping(uint256 => bytes) internal s_upkeepOffchainConfig;
mapping(uint256 => bytes) internal s_upkeepPrivilegeConfig;
mapping(address => bytes) internal s_adminPrivilegeConfig;
error ArrayHasNoEntries();
error CannotCancel();
error CheckDataExceedsLimit();
error ConfigDigestMismatch();
error DuplicateEntry();
error DuplicateSigners();
error GasLimitCanOnlyIncrease();
error GasLimitOutsideRange();
error IncorrectNumberOfFaultyOracles();
error IncorrectNumberOfSignatures();
error IncorrectNumberOfSigners();
error IndexOutOfRange();
error InsufficientFunds();
error InvalidDataLength();
error InvalidTrigger();
error InvalidPayee();
error InvalidRecipient();
error InvalidReport();
error InvalidSigner();
error InvalidTransmitter();
error InvalidTriggerType();
error MaxCheckDataSizeCanOnlyIncrease();
error MaxPerformDataSizeCanOnlyIncrease();
error MigrationNotPermitted();
error NotAContract();
error OnlyActiveSigners();
error OnlyActiveTransmitters();
error OnlyCallableByAdmin();
error OnlyCallableByLINKToken();
error OnlyCallableByOwnerOrAdmin();
error OnlyCallableByOwnerOrRegistrar();
error OnlyCallableByPayee();
error OnlyCallableByProposedAdmin();
error OnlyCallableByProposedPayee();
error OnlyCallableByUpkeepPrivilegeManager();
error OnlyPausedUpkeep();
error OnlyUnpausedUpkeep();
error ParameterLengthError();
error PaymentGreaterThanAllLINK();
error ReentrantCall();
error RegistryPaused();
error RepeatedSigner();
error RepeatedTransmitter();
error TargetCheckReverted(bytes reason);
error TooManyOracles();
error TranscoderNotSet();
error UpkeepAlreadyExists();
error UpkeepCancelled();
error UpkeepNotCanceled();
error UpkeepNotNeeded();
error ValueNotChanged();
enum MigrationPermission {
NONE,
OUTGOING,
INCOMING,
BIDIRECTIONAL
}
enum Mode {
DEFAULT,
ARBITRUM,
OPTIMISM
}
enum Trigger {
CONDITION,
LOG
}
enum UpkeepFailureReason {
NONE,
UPKEEP_CANCELLED,
UPKEEP_PAUSED,
TARGET_CHECK_REVERTED,
UPKEEP_NOT_NEEDED,
PERFORM_DATA_EXCEEDS_LIMIT,
INSUFFICIENT_BALANCE,
CALLBACK_REVERTED,
REVERT_DATA_EXCEEDS_LIMIT,
REGISTRY_PAUSED
}
struct OnchainConfig {
uint32 paymentPremiumPPB;
uint32 flatFeeMicroLink;
uint32 checkGasLimit;
uint24 stalenessSeconds;
uint16 gasCeilingMultiplier;
uint96 minUpkeepSpend;
uint32 maxPerformGas;
uint32 maxCheckDataSize;
uint32 maxPerformDataSize;
uint32 maxRevertDataSize;
uint256 fallbackGasPrice;
uint256 fallbackLinkPrice;
address transcoder;
address[] registrars;
address upkeepPrivilegeManager;
}
struct State {
uint32 nonce;
uint96 ownerLinkBalance;
uint256 expectedLinkBalance;
uint96 totalPremium;
uint256 numUpkeeps;
uint32 configCount;
uint32 latestConfigBlockNumber;
bytes32 latestConfigDigest;
uint32 latestEpoch;
bool paused;
}
struct Upkeep {
bool paused;
uint32 performGas;
uint32 maxValidBlocknumber;
IAutomationForwarder forwarder;
uint96 amountSpent;
uint96 balance;
uint32 lastPerformedBlockNumber;
}
struct UpkeepInfo {
address target;
uint32 performGas;
bytes checkData;
uint96 balance;
address admin;
uint64 maxValidBlocknumber;
uint32 lastPerformedBlockNumber;
uint96 amountSpent;
bool paused;
bytes offchainConfig;
}
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;
uint32 checkGasLimit;
uint32 maxPerformGas;
uint32 nonce;
uint32 configCount;
uint32 latestConfigBlockNumber;
uint32 maxCheckDataSize;
uint32 maxPerformDataSize;
uint32 maxRevertDataSize;
address upkeepPrivilegeManager;
}
struct Report {
uint256 fastGasWei;
uint256 linkNative;
uint256[] upkeepIds;
uint256[] gasLimits;
bytes[] triggers;
bytes[] performDatas;
}
struct UpkeepTransmitInfo {
Upkeep upkeep;
bool earlyChecksPassed;
uint96 maxLinkPayment;
bool performSuccess;
Trigger triggerType;
uint256 gasUsed;
uint256 gasOverhead;
bytes32 dedupID;
}
struct Transmitter {
bool active;
uint8 index;
uint96 balance;
uint96 lastCollected;
}
struct Signer {
bool active;
uint8 index;
}
struct ConditionalTrigger {
uint32 blockNum;
bytes32 blockHash;
}
struct LogTrigger {
bytes32 logBlockHash;
bytes32 txHash;
uint32 logIndex;
uint32 blockNum;
bytes32 blockHash;
}
event AdminPrivilegeConfigSet(address indexed admin, bytes privilegeConfig);
event CancelledUpkeepReport(uint256 indexed id, bytes trigger);
event DedupKeyAdded(bytes32 indexed dedupKey);
event FundsAdded(uint256 indexed id, address indexed from, uint96 amount);
event FundsWithdrawn(uint256 indexed id, uint256 amount, address to);
event InsufficientFundsUpkeepReport(uint256 indexed id, bytes trigger);
event OwnerFundsWithdrawn(uint96 amount);
event Paused(address account);
event PayeesUpdated(address[] transmitters, address[] payees);
event PayeeshipTransferRequested(address indexed transmitter, address indexed from, address indexed to);
event PayeeshipTransferred(address indexed transmitter, address indexed from, address indexed to);
event PaymentWithdrawn(address indexed transmitter, uint256 indexed amount, address indexed to, address payee);
event ReorgedUpkeepReport(uint256 indexed id, bytes trigger);
event StaleUpkeepReport(uint256 indexed id, bytes trigger);
event UpkeepAdminTransferred(uint256 indexed id, address indexed from, address indexed to);
event UpkeepAdminTransferRequested(uint256 indexed id, address indexed from, address indexed to);
event UpkeepCanceled(uint256 indexed id, uint64 indexed atBlockHeight);
event UpkeepCheckDataSet(uint256 indexed id, bytes newCheckData);
event UpkeepGasLimitSet(uint256 indexed id, uint96 gasLimit);
event UpkeepMigrated(uint256 indexed id, uint256 remainingBalance, address destination);
event UpkeepOffchainConfigSet(uint256 indexed id, bytes offchainConfig);
event UpkeepPaused(uint256 indexed id);
event UpkeepPerformed(
uint256 indexed id,
bool indexed success,
uint96 totalPayment,
uint256 gasUsed,
uint256 gasOverhead,
bytes trigger
);
event UpkeepPrivilegeConfigSet(uint256 indexed id, bytes privilegeConfig);
event UpkeepReceived(uint256 indexed id, uint256 startingBalance, address importedFrom);
event UpkeepRegistered(uint256 indexed id, uint32 performGas, address admin);
event UpkeepTriggerConfigSet(uint256 indexed id, bytes triggerConfig);
event UpkeepUnpaused(uint256 indexed id);
event Unpaused(address account);
constructor(
Mode mode,
address link,
address linkNativeFeed,
address fastGasFeed,
address automationForwarderLogic
) ConfirmedOwner(msg.sender) {
i_mode = mode;
i_link = LinkTokenInterface(link);
i_linkNativeFeed = AggregatorV3Interface(linkNativeFeed);
i_fastGasFeed = AggregatorV3Interface(fastGasFeed);
i_automationForwarderLogic = automationForwarderLogic;
}
function _createUpkeep(
uint256 id,
Upkeep memory upkeep,
address admin,
bytes memory checkData,
bytes memory triggerConfig,
bytes memory offchainConfig
) internal {
if (s_hotVars.paused) revert RegistryPaused();
if (checkData.length > s_storage.maxCheckDataSize) revert CheckDataExceedsLimit();
if (upkeep.performGas < PERFORM_GAS_MIN || upkeep.performGas > s_storage.maxPerformGas)
revert GasLimitOutsideRange();
if (address(s_upkeep[id].forwarder) != address(0)) revert UpkeepAlreadyExists();
s_upkeep[id] = upkeep;
s_upkeepAdmin[id] = admin;
s_checkData[id] = checkData;
s_expectedLinkBalance = s_expectedLinkBalance + upkeep.balance;
s_upkeepTriggerConfig[id] = triggerConfig;
s_upkeepOffchainConfig[id] = offchainConfig;
s_upkeepIDs.add(id);
}
function _createID(Trigger triggerType) internal view returns (uint256) {
bytes1 empty;
bytes memory idBytes = abi.encodePacked(
keccak256(abi.encode(_blockHash(_blockNum() - 1), address(this), s_storage.nonce))
);
for (uint256 idx = 4; idx < 15; idx++) {
idBytes[idx] = empty;
}
idBytes[15] = bytes1(uint8(triggerType));
return uint256(bytes32(idBytes));
}
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) {
if (isExecution) {
l1CostWei = ARB_NITRO_ORACLE.getCurrentTxL1GasFees();
} else {
(, uint256 perL1CalldataUnit, , , , ) = ARB_NITRO_ORACLE.getPricesInWei();
l1CostWei = perL1CalldataUnit * s_storage.maxPerformDataSize * 16;
}
}
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,
Trigger triggerType,
uint32 performGas,
uint32 performDataLength,
uint256 fastGasWei,
uint256 linkNative,
bool isExecution
) internal view returns (uint96) {
uint256 gasOverhead = _getMaxGasOverhead(triggerType, performDataLength, hotVars.f);
(uint96 reimbursement, uint96 premium) = _calculatePaymentAmount(
hotVars,
performGas,
gasOverhead,
fastGasWei,
linkNative,
1,
isExecution
);
return reimbursement + premium;
}
function _getMaxGasOverhead(Trigger triggerType, uint32 performDataLength, uint8 f) internal pure returns (uint256) {
uint256 baseOverhead;
if (triggerType == Trigger.CONDITION) {
baseOverhead = REGISTRY_CONDITIONAL_OVERHEAD;
} else if (triggerType == Trigger.LOG) {
baseOverhead = REGISTRY_LOG_OVERHEAD;
} else {
revert InvalidTriggerType();
}
return
baseOverhead +
(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];
if (transmitter.active) {
uint96 uncollected = totalPremium - transmitter.lastCollected;
uint96 due = uncollected / payeeCount;
transmitter.balance += due;
transmitter.lastCollected += due * payeeCount;
s_transmitters[transmitterAddress] = transmitter;
}
return transmitter.balance;
}
function _getTriggerType(uint256 upkeepId) internal pure returns (Trigger) {
bytes32 rawID = bytes32(upkeepId);
bytes1 empty = bytes1(0);
for (uint256 idx = 4; idx < 15; idx++) {
if (rawID[idx] != empty) {
return Trigger.CONDITION;
}
}
return Trigger(uint8(rawID[15]));
}
function _checkPayload(
uint256 upkeepId,
Trigger triggerType,
bytes memory triggerData
) internal view returns (bytes memory) {
if (triggerType == Trigger.CONDITION) {
return abi.encodeWithSelector(CHECK_SELECTOR, s_checkData[upkeepId]);
} else if (triggerType == Trigger.LOG) {
Log memory log = abi.decode(triggerData, (Log));
return abi.encodeWithSelector(CHECK_LOG_SELECTOR, log, s_checkData[upkeepId]);
}
revert InvalidTriggerType();
}
function _decodeReport(bytes calldata rawReport) internal pure returns (Report memory) {
Report memory report = abi.decode(rawReport, (Report));
uint256 expectedLength = report.upkeepIds.length;
if (
report.gasLimits.length != expectedLength ||
report.triggers.length != expectedLength ||
report.performDatas.length != expectedLength
) {
revert InvalidReport();
}
return report;
}
function _prePerformChecks(
uint256 upkeepId,
bytes memory rawTrigger,
UpkeepTransmitInfo memory transmitInfo
) internal returns (bool, bytes32) {
bytes32 dedupID;
if (transmitInfo.triggerType == Trigger.CONDITION) {
if (!_validateConditionalTrigger(upkeepId, rawTrigger, transmitInfo)) return (false, dedupID);
} else if (transmitInfo.triggerType == Trigger.LOG) {
bool valid;
(valid, dedupID) = _validateLogTrigger(upkeepId, rawTrigger, transmitInfo);
if (!valid) return (false, dedupID);
} else {
revert InvalidTriggerType();
}
if (transmitInfo.upkeep.maxValidBlocknumber <= _blockNum()) {
emit CancelledUpkeepReport(upkeepId, rawTrigger);
return (false, dedupID);
}
if (transmitInfo.upkeep.balance < transmitInfo.maxLinkPayment) {
emit InsufficientFundsUpkeepReport(upkeepId, rawTrigger);
return (false, dedupID);
}
return (true, dedupID);
}
function _validateConditionalTrigger(
uint256 upkeepId,
bytes memory rawTrigger,
UpkeepTransmitInfo memory transmitInfo
) internal returns (bool) {
ConditionalTrigger memory trigger = abi.decode(rawTrigger, (ConditionalTrigger));
if (trigger.blockNum < transmitInfo.upkeep.lastPerformedBlockNumber) {
emit StaleUpkeepReport(upkeepId, rawTrigger);
return false;
}
if (
(trigger.blockHash != bytes32("") && _blockHash(trigger.blockNum) != trigger.blockHash) ||
trigger.blockNum >= _blockNum()
) {
emit ReorgedUpkeepReport(upkeepId, rawTrigger);
return false;
}
return true;
}
function _validateLogTrigger(
uint256 upkeepId,
bytes memory rawTrigger,
UpkeepTransmitInfo memory transmitInfo
) internal returns (bool, bytes32) {
LogTrigger memory trigger = abi.decode(rawTrigger, (LogTrigger));
bytes32 dedupID = keccak256(abi.encodePacked(upkeepId, trigger.logBlockHash, trigger.txHash, trigger.logIndex));
if (
(trigger.blockHash != bytes32("") && _blockHash(trigger.blockNum) != trigger.blockHash) ||
trigger.blockNum >= _blockNum()
) {
emit ReorgedUpkeepReport(upkeepId, rawTrigger);
return (false, dedupID);
}
if (s_dedupKeys[dedupID]) {
emit StaleUpkeepReport(upkeepId, rawTrigger);
return (false, dedupID);
}
return (true, dedupID);
}
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 _updateTriggerMarker(uint256 upkeepID, UpkeepTransmitInfo memory upkeepTransmitInfo) internal {
if (upkeepTransmitInfo.triggerType == Trigger.CONDITION) {
s_upkeep[upkeepID].lastPerformedBlockNumber = uint32(_blockNum());
} else if (upkeepTransmitInfo.triggerType == Trigger.LOG) {
s_dedupKeys[upkeepTransmitInfo.dedupID] = true;
emit DedupKeyAdded(upkeepTransmitInfo.dedupID);
}
}
function _performUpkeep(
IAutomationForwarder forwarder,
uint256 performGas,
bytes memory performData
) internal nonReentrant returns (bool success, uint256 gasUsed) {
performData = abi.encodeWithSelector(PERFORM_SELECTOR, performData);
return forwarder.forward(performGas, performData);
}
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,
Trigger triggerType,
uint32 performDataLength,
uint8 f
) internal pure returns (uint256 cappedGasOverhead) {
cappedGasOverhead = _getMaxGasOverhead(triggerType, performDataLength, f);
if (calculatedGasOverhead < cappedGasOverhead) {
return calculatedGasOverhead;
}
return cappedGasOverhead;
}
function _requireAdminAndNotCancelled(uint256 upkeepId) internal view {
if (msg.sender != s_upkeepAdmin[upkeepId]) revert OnlyCallableByAdmin();
if (s_upkeep[upkeepId].maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled();
}
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;
}
}
文件 47 的 76:KeeperRegistryLogicA2_1.sol
pragma solidity 0.8.16;
import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol";
import {Address} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol";
import {KeeperRegistryBase2_1} from "./KeeperRegistryBase2_1.sol";
import {KeeperRegistryLogicB2_1} from "./KeeperRegistryLogicB2_1.sol";
import {Chainable} from "../Chainable.sol";
import {AutomationForwarder} from "./AutomationForwarder.sol";
import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol";
import {UpkeepTranscoderInterfaceV2} from "../interfaces/UpkeepTranscoderInterfaceV2.sol";
import {MigratableKeeperRegistryInterfaceV2} from "../interfaces/MigratableKeeperRegistryInterfaceV2.sol";
contract KeeperRegistryLogicA2_1 is KeeperRegistryBase2_1, Chainable {
using Address for address;
using EnumerableSet for EnumerableSet.UintSet;
using EnumerableSet for EnumerableSet.AddressSet;
constructor(
KeeperRegistryLogicB2_1 logicB
)
KeeperRegistryBase2_1(
logicB.getMode(),
logicB.getLinkAddress(),
logicB.getLinkNativeFeedAddress(),
logicB.getFastGasFeedAddress(),
logicB.getAutomationForwarderLogic()
)
Chainable(address(logicB))
{}
function checkUpkeep(
uint256 id,
bytes memory triggerData
)
public
cannotExecute
returns (
bool upkeepNeeded,
bytes memory performData,
UpkeepFailureReason upkeepFailureReason,
uint256 gasUsed,
uint256 gasLimit,
uint256 fastGasWei,
uint256 linkNative
)
{
Trigger triggerType = _getTriggerType(id);
HotVars memory hotVars = s_hotVars;
Upkeep memory upkeep = s_upkeep[id];
if (hotVars.paused) return (false, bytes(""), UpkeepFailureReason.REGISTRY_PAUSED, 0, upkeep.performGas, 0, 0);
if (upkeep.maxValidBlocknumber != UINT32_MAX)
return (false, bytes(""), UpkeepFailureReason.UPKEEP_CANCELLED, 0, upkeep.performGas, 0, 0);
if (upkeep.paused) return (false, bytes(""), UpkeepFailureReason.UPKEEP_PAUSED, 0, upkeep.performGas, 0, 0);
(fastGasWei, linkNative) = _getFeedData(hotVars);
uint96 maxLinkPayment = _getMaxLinkPayment(
hotVars,
triggerType,
upkeep.performGas,
s_storage.maxPerformDataSize,
fastGasWei,
linkNative,
false
);
if (upkeep.balance < maxLinkPayment) {
return (false, bytes(""), UpkeepFailureReason.INSUFFICIENT_BALANCE, 0, upkeep.performGas, 0, 0);
}
bytes memory callData = _checkPayload(id, triggerType, triggerData);
gasUsed = gasleft();
(bool success, bytes memory result) = upkeep.forwarder.getTarget().call{gas: s_storage.checkGasLimit}(callData);
gasUsed = gasUsed - gasleft();
if (!success) {
if (result.length > s_storage.maxRevertDataSize) {
return (
false,
bytes(""),
UpkeepFailureReason.REVERT_DATA_EXCEEDS_LIMIT,
gasUsed,
upkeep.performGas,
fastGasWei,
linkNative
);
}
return (
upkeepNeeded,
result,
UpkeepFailureReason.TARGET_CHECK_REVERTED,
gasUsed,
upkeep.performGas,
fastGasWei,
linkNative
);
}
(upkeepNeeded, performData) = abi.decode(result, (bool, bytes));
if (!upkeepNeeded)
return (
false,
bytes(""),
UpkeepFailureReason.UPKEEP_NOT_NEEDED,
gasUsed,
upkeep.performGas,
fastGasWei,
linkNative
);
if (performData.length > s_storage.maxPerformDataSize)
return (
false,
bytes(""),
UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT,
gasUsed,
upkeep.performGas,
fastGasWei,
linkNative
);
return (upkeepNeeded, performData, upkeepFailureReason, gasUsed, upkeep.performGas, fastGasWei, linkNative);
}
function checkUpkeep(
uint256 id
)
external
returns (
bool upkeepNeeded,
bytes memory performData,
UpkeepFailureReason upkeepFailureReason,
uint256 gasUsed,
uint256 gasLimit,
uint256 fastGasWei,
uint256 linkNative
)
{
return checkUpkeep(id, bytes(""));
}
function checkCallback(
uint256 id,
bytes[] memory values,
bytes calldata extraData
)
external
cannotExecute
returns (bool upkeepNeeded, bytes memory performData, UpkeepFailureReason upkeepFailureReason, uint256 gasUsed)
{
bytes memory payload = abi.encodeWithSelector(CHECK_CALLBACK_SELECTOR, values, extraData);
return executeCallback(id, payload);
}
function executeCallback(
uint256 id,
bytes memory payload
)
public
cannotExecute
returns (bool upkeepNeeded, bytes memory performData, UpkeepFailureReason upkeepFailureReason, uint256 gasUsed)
{
Upkeep memory upkeep = s_upkeep[id];
gasUsed = gasleft();
(bool success, bytes memory result) = upkeep.forwarder.getTarget().call{gas: s_storage.checkGasLimit}(payload);
gasUsed = gasUsed - gasleft();
if (!success) {
return (false, bytes(""), UpkeepFailureReason.CALLBACK_REVERTED, gasUsed);
}
(upkeepNeeded, performData) = abi.decode(result, (bool, bytes));
if (!upkeepNeeded) {
return (false, bytes(""), UpkeepFailureReason.UPKEEP_NOT_NEEDED, gasUsed);
}
if (performData.length > s_storage.maxPerformDataSize) {
return (false, bytes(""), UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, gasUsed);
}
return (upkeepNeeded, performData, upkeepFailureReason, gasUsed);
}
function registerUpkeep(
address target,
uint32 gasLimit,
address admin,
Trigger triggerType,
bytes calldata checkData,
bytes memory triggerConfig,
bytes memory offchainConfig
) public returns (uint256 id) {
if (msg.sender != owner() && !s_registrars.contains(msg.sender)) revert OnlyCallableByOwnerOrRegistrar();
if (!target.isContract()) revert NotAContract();
id = _createID(triggerType);
IAutomationForwarder forwarder = IAutomationForwarder(
address(new AutomationForwarder(target, address(this), i_automationForwarderLogic))
);
_createUpkeep(
id,
Upkeep({
performGas: gasLimit,
balance: 0,
maxValidBlocknumber: UINT32_MAX,
lastPerformedBlockNumber: 0,
amountSpent: 0,
paused: false,
forwarder: forwarder
}),
admin,
checkData,
triggerConfig,
offchainConfig
);
s_storage.nonce++;
emit UpkeepRegistered(id, gasLimit, admin);
emit UpkeepCheckDataSet(id, checkData);
emit UpkeepTriggerConfigSet(id, triggerConfig);
emit UpkeepOffchainConfigSet(id, offchainConfig);
return (id);
}
function registerUpkeep(
address target,
uint32 gasLimit,
address admin,
bytes calldata checkData,
bytes calldata offchainConfig
) external returns (uint256 id) {
return registerUpkeep(target, gasLimit, admin, Trigger.CONDITION, checkData, bytes(""), offchainConfig);
}
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 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;
address[] memory admins = new address[](ids.length);
Upkeep[] memory upkeeps = new Upkeep[](ids.length);
bytes[] memory checkDatas = new bytes[](ids.length);
bytes[] memory triggerConfigs = new bytes[](ids.length);
bytes[] memory offchainConfigs = new bytes[](ids.length);
for (uint256 idx = 0; idx < ids.length; idx++) {
id = ids[idx];
upkeep = s_upkeep[id];
_requireAdminAndNotCancelled(id);
upkeep.forwarder.updateRegistry(destination);
upkeeps[idx] = upkeep;
admins[idx] = s_upkeepAdmin[id];
checkDatas[idx] = s_checkData[id];
triggerConfigs[idx] = s_upkeepTriggerConfig[id];
offchainConfigs[idx] = s_upkeepOffchainConfig[id];
totalBalanceRemaining = totalBalanceRemaining + upkeep.balance;
delete s_upkeep[id];
delete s_checkData[id];
delete s_upkeepTriggerConfig[id];
delete s_upkeepOffchainConfig[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,
new address[](ids.length),
admins,
checkDatas,
triggerConfigs,
offchainConfigs
);
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,
address[] memory targets,
address[] memory upkeepAdmins,
bytes[] memory checkDatas,
bytes[] memory triggerConfigs,
bytes[] memory offchainConfigs
) = abi.decode(encodedUpkeeps, (uint256[], Upkeep[], address[], address[], bytes[], bytes[], bytes[]));
for (uint256 idx = 0; idx < ids.length; idx++) {
if (address(upkeeps[idx].forwarder) == ZERO_ADDRESS) {
upkeeps[idx].forwarder = IAutomationForwarder(
address(new AutomationForwarder(targets[idx], address(this), i_automationForwarderLogic))
);
}
_createUpkeep(
ids[idx],
upkeeps[idx],
upkeepAdmins[idx],
checkDatas[idx],
triggerConfigs[idx],
offchainConfigs[idx]
);
emit UpkeepReceived(ids[idx], upkeeps[idx].balance, msg.sender);
}
}
function setUpkeepTriggerConfig(uint256 id, bytes calldata triggerConfig) external {
_requireAdminAndNotCancelled(id);
s_upkeepTriggerConfig[id] = triggerConfig;
emit UpkeepTriggerConfigSet(id, triggerConfig);
}
}
文件 48 的 76:KeeperRegistryLogicB2_1.sol
pragma solidity 0.8.16;
import {KeeperRegistryBase2_1} from "./KeeperRegistryBase2_1.sol";
import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol";
import {Address} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol";
import {UpkeepFormat} from "../interfaces/UpkeepTranscoderInterface.sol";
import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol";
contract KeeperRegistryLogicB2_1 is KeeperRegistryBase2_1 {
using Address for address;
using EnumerableSet for EnumerableSet.UintSet;
using EnumerableSet for EnumerableSet.AddressSet;
constructor(
Mode mode,
address link,
address linkNativeFeed,
address fastGasFeed,
address automationForwarderLogic
) KeeperRegistryBase2_1(mode, link, linkNativeFeed, fastGasFeed, automationForwarderLogic) {}
function transferUpkeepAdmin(uint256 id, address proposed) external {
_requireAdminAndNotCancelled(id);
if (proposed == msg.sender) revert ValueNotChanged();
if (s_proposedAdmin[id] != proposed) {
s_proposedAdmin[id] = proposed;
emit UpkeepAdminTransferRequested(id, msg.sender, proposed);
}
}
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 setUpkeepCheckData(uint256 id, bytes calldata newCheckData) external {
_requireAdminAndNotCancelled(id);
if (newCheckData.length > s_storage.maxCheckDataSize) revert CheckDataExceedsLimit();
s_checkData[id] = newCheckData;
emit UpkeepCheckDataSet(id, newCheckData);
}
function setUpkeepGasLimit(uint256 id, uint32 gasLimit) external {
if (gasLimit < PERFORM_GAS_MIN || gasLimit > s_storage.maxPerformGas) revert GasLimitOutsideRange();
_requireAdminAndNotCancelled(id);
s_upkeep[id].performGas = gasLimit;
emit UpkeepGasLimitSet(id, gasLimit);
}
function setUpkeepOffchainConfig(uint256 id, bytes calldata config) external {
_requireAdminAndNotCancelled(id);
s_upkeepOffchainConfig[id] = config;
emit UpkeepOffchainConfigSet(id, config);
}
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 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 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 setUpkeepPrivilegeConfig(uint256 upkeepId, bytes calldata newPrivilegeConfig) external {
if (msg.sender != s_storage.upkeepPrivilegeManager) {
revert OnlyCallableByUpkeepPrivilegeManager();
}
s_upkeepPrivilegeConfig[upkeepId] = newPrivilegeConfig;
emit UpkeepPrivilegeConfigSet(upkeepId, newPrivilegeConfig);
}
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 setPeerRegistryMigrationPermission(address peer, MigrationPermission permission) external onlyOwner {
s_peerRegistryMigrationPermission[peer] = permission;
}
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 setAdminPrivilegeConfig(address admin, bytes calldata newPrivilegeConfig) external {
if (msg.sender != s_storage.upkeepPrivilegeManager) {
revert OnlyCallableByUpkeepPrivilegeManager();
}
s_adminPrivilegeConfig[admin] = newPrivilegeConfig;
emit AdminPrivilegeConfigSet(admin, newPrivilegeConfig);
}
function getConditionalGasOverhead() external pure returns (uint256) {
return REGISTRY_CONDITIONAL_OVERHEAD;
}
function getLogGasOverhead() external pure returns (uint256) {
return REGISTRY_LOG_OVERHEAD;
}
function getPerPerformByteGasOverhead() external pure returns (uint256) {
return REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD;
}
function getPerSignerGasOverhead() external pure returns (uint256) {
return REGISTRY_PER_SIGNER_GAS_OVERHEAD;
}
function getCancellationDelay() external pure returns (uint256) {
return CANCELLATION_DELAY;
}
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 getAutomationForwarderLogic() external view returns (address) {
return i_automationForwarderLogic;
}
function upkeepTranscoderVersion() public pure returns (UpkeepFormat) {
return UPKEEP_TRANSCODER_VERSION_BASE;
}
function upkeepVersion() public pure returns (uint8) {
return UPKEEP_VERSION_BASE;
}
function getUpkeep(uint256 id) external view returns (UpkeepInfo memory upkeepInfo) {
Upkeep memory reg = s_upkeep[id];
address target = address(reg.forwarder) == address(0) ? address(0) : reg.forwarder.getTarget();
upkeepInfo = UpkeepInfo({
target: target,
performGas: reg.performGas,
checkData: s_checkData[id],
balance: reg.balance,
admin: s_upkeepAdmin[id],
maxValidBlocknumber: reg.maxValidBlocknumber,
lastPerformedBlockNumber: reg.lastPerformedBlockNumber,
amountSpent: reg.amountSpent,
paused: reg.paused,
offchainConfig: s_upkeepOffchainConfig[id]
});
return upkeepInfo;
}
function getActiveUpkeepIDs(uint256 startIndex, uint256 maxCount) external view returns (uint256[] memory) {
uint256 numUpkeeps = s_upkeepIDs.length();
if (startIndex >= numUpkeeps) revert IndexOutOfRange();
uint256 endIndex = startIndex + maxCount;
endIndex = endIndex > numUpkeeps || maxCount == 0 ? numUpkeeps : endIndex;
uint256[] memory ids = new uint256[](endIndex - startIndex);
for (uint256 idx = 0; idx < ids.length; idx++) {
ids[idx] = s_upkeepIDs.at(idx + startIndex);
}
return ids;
}
function getTriggerType(uint256 upkeepId) external pure returns (Trigger) {
return _getTriggerType(upkeepId);
}
function getUpkeepTriggerConfig(uint256 upkeepId) public view returns (bytes memory) {
return s_upkeepTriggerConfig[upkeepId];
}
function getTransmitterInfo(
address query
) external view returns (bool active, uint8 index, uint96 balance, uint96 lastCollected, address payee) {
Transmitter memory transmitter = s_transmitters[query];
uint96 pooledShare = 0;
if (transmitter.active) {
uint96 totalDifference = s_hotVars.totalPremium - transmitter.lastCollected;
pooledShare = totalDifference / uint96(s_transmittersList.length);
}
return (
transmitter.active,
transmitter.index,
(transmitter.balance + pooledShare),
transmitter.lastCollected,
s_transmitterPayees[query]
);
}
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
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,
maxRevertDataSize: s_storage.maxRevertDataSize,
fallbackGasPrice: s_fallbackGasPrice,
fallbackLinkPrice: s_fallbackLinkPrice,
transcoder: s_storage.transcoder,
registrars: s_registrars.values(),
upkeepPrivilegeManager: s_storage.upkeepPrivilegeManager
});
return (state, config, s_signersList, s_transmittersList, s_hotVars.f);
}
function getBalance(uint256 id) external view returns (uint96 balance) {
return s_upkeep[id].balance;
}
function getMinBalance(uint256 id) external view returns (uint96) {
return getMinBalanceForUpkeep(id);
}
function getMinBalanceForUpkeep(uint256 id) public view returns (uint96 minBalance) {
return getMaxPaymentForGas(_getTriggerType(id), s_upkeep[id].performGas);
}
function getMaxPaymentForGas(Trigger triggerType, uint32 gasLimit) public view returns (uint96 maxPayment) {
HotVars memory hotVars = s_hotVars;
(uint256 fastGasWei, uint256 linkNative) = _getFeedData(hotVars);
return
_getMaxLinkPayment(hotVars, triggerType, gasLimit, s_storage.maxPerformDataSize, fastGasWei, linkNative, false);
}
function getPeerRegistryMigrationPermission(address peer) external view returns (MigrationPermission) {
return s_peerRegistryMigrationPermission[peer];
}
function getUpkeepPrivilegeConfig(uint256 upkeepId) external view returns (bytes memory) {
return s_upkeepPrivilegeConfig[upkeepId];
}
function getAdminPrivilegeConfig(address admin) external view returns (bytes memory) {
return s_adminPrivilegeConfig[admin];
}
function getForwarder(uint256 upkeepID) external view returns (IAutomationForwarder) {
return s_upkeep[upkeepID].forwarder;
}
function hasDedupKey(bytes32 dedupKey) external view returns (bool) {
return s_dedupKeys[dedupKey];
}
}
文件 49 的 76: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);
}
文件 50 的 76:LogTriggeredStreamsLookup.sol
pragma solidity 0.8.16;
import {ILogAutomation, Log} from "../interfaces/ILogAutomation.sol";
import "../interfaces/StreamsLookupCompatibleInterface.sol";
import {ArbSys} from "../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol";
interface IVerifierProxy {
function verify(bytes memory signedReport) external returns (bytes memory verifierResponse);
}
contract LogTriggeredStreamsLookup is ILogAutomation, StreamsLookupCompatibleInterface {
event PerformingLogTriggerUpkeep(
address indexed from,
uint256 orderId,
uint256 amount,
address exchange,
uint256 blockNumber,
bytes blob,
bytes verified
);
event LimitOrderExecuted(uint256 indexed orderId, uint256 indexed amount, address indexed exchange);
ArbSys internal constant ARB_SYS = ArbSys(0x0000000000000000000000000000000000000064);
IVerifierProxy internal constant VERIFIER = IVerifierProxy(0x09DFf56A4fF44e0f4436260A04F5CFa65636A481);
bytes32 constant sentSig = 0x3e9c37b3143f2eb7e9a2a0f8091b6de097b62efcfe48e1f68847a832e521750a;
bytes32 constant withdrawnSig = 0x0a71b8ed921ff64d49e4d39449f8a21094f38a0aeae489c3051aedd63f2c229f;
bytes32 constant executedSig = 0xd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd;
bool public useArbitrumBlockNum;
bool public verify;
string[] public feedsHex = ["0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"];
string public feedParamKey = "feedIdHex";
string public timeParamKey = "blockNumber";
uint256 public counter;
constructor(bool _useArbitrumBlockNum, bool _verify) {
useArbitrumBlockNum = _useArbitrumBlockNum;
verify = _verify;
counter = 0;
}
function start() public {
emit LimitOrderExecuted(1, 100, address(0x0));
}
function setTimeParamKey(string memory timeParam) external {
timeParamKey = timeParam;
}
function setFeedParamKey(string memory feedParam) external {
feedParamKey = feedParam;
}
function setFeedsHex(string[] memory newFeeds) external {
feedsHex = newFeeds;
}
function checkLog(
Log calldata log,
bytes memory
) external override returns (bool upkeepNeeded, bytes memory performData) {
uint256 blockNum = getBlockNumber();
if (log.topics[0] == executedSig) {
bytes memory t1 = abi.encodePacked(log.topics[1]);
uint256 orderId = abi.decode(t1, (uint256));
bytes memory t2 = abi.encodePacked(log.topics[2]);
uint256 amount = abi.decode(t2, (uint256));
bytes memory t3 = abi.encodePacked(log.topics[3]);
address exchange = abi.decode(t3, (address));
revert StreamsLookup(
feedParamKey,
feedsHex,
timeParamKey,
blockNum,
abi.encode(orderId, amount, exchange, executedSig)
);
}
revert("could not find matching event sig");
}
function performUpkeep(bytes calldata performData) external override {
(bytes[] memory values, bytes memory extraData) = abi.decode(performData, (bytes[], bytes));
(uint256 orderId, uint256 amount, address exchange, bytes32 logTopic0) = abi.decode(
extraData,
(uint256, uint256, address, bytes32)
);
bytes memory verifiedResponse = "";
if (verify) {
verifiedResponse = VERIFIER.verify(values[0]);
}
counter = counter + 1;
if (logTopic0 == executedSig) {
emit LimitOrderExecuted(1, 100, address(0x0));
}
emit PerformingLogTriggerUpkeep(
tx.origin,
orderId,
amount,
exchange,
getBlockNumber(),
values[0],
verifiedResponse
);
}
function checkCallback(
bytes[] memory values,
bytes memory extraData
) external view override returns (bool, bytes memory) {
bytes memory performData = abi.encode(values, extraData);
return (true, performData);
}
function getBlockNumber() internal view returns (uint256) {
if (useArbitrumBlockNum) {
return ARB_SYS.arbBlockNumber();
} else {
return block.number;
}
}
}
文件 51 的 76:Math.sol
pragma solidity ^0.8.0;
library Math {
enum Rounding {
Down,
Up,
Zero
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a & b) + (a ^ b) / 2;
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
return a == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
uint256 prod0;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
return prod0 / denominator;
}
require(denominator > prod1);
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = denominator & (~denominator + 1);
assembly {
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 result = 1 << (log2(a) >> 1);
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}
文件 52 的 76:MigratableKeeperRegistryInterfaceV2.sol
pragma solidity ^0.8.0;
import "../UpkeepFormat.sol";
interface MigratableKeeperRegistryInterfaceV2 {
function migrateUpkeeps(uint256[] calldata upkeepIDs, address destination) external;
function receiveUpkeeps(bytes calldata encodedUpkeeps) external;
function upkeepVersion() external view returns (uint8 version);
}
文件 53 的 76:MockKeeperRegistry2_1.sol
pragma solidity 0.8.16;
import "../interfaces/IAutomationRegistryConsumer.sol";
contract MockKeeperRegistry2_1 is IAutomationRegistryConsumer {
uint96 balance;
uint96 minBalance;
constructor() {}
function getBalance(uint256 id) external view override returns (uint96) {
return balance;
}
function getMinBalance(uint256 id) external view override returns (uint96) {
return minBalance;
}
function cancelUpkeep(uint256 id) external override {}
function pauseUpkeep(uint256 id) external override {}
function unpauseUpkeep(uint256 id) external override {}
function updateCheckData(uint256 id, bytes calldata newCheckData) external {}
function addFunds(uint256 id, uint96 amount) external override {}
function withdrawFunds(uint256 id, address to) external override {}
}
文件 54 的 76:OCR2Abstract.sol
pragma solidity ^0.8.0;
import {ITypeAndVersion} from "../interfaces/ITypeAndVersion.sol";
abstract contract OCR2Abstract is ITypeAndVersion {
uint256 internal constant MAX_NUM_ORACLES = 31;
uint256 private constant PREFIX_MASK = type(uint256).max << (256 - 16);
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 & PREFIX_MASK) | (h & ~PREFIX_MASK));
}
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;
}
文件 55 的 76:OVM_GasPriceOracle.sol
pragma solidity ^0.8.9;
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);
}
}
文件 56 的 76: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() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 57 的 76:PerformDataChecker.sol
pragma solidity 0.8.16;
import "../interfaces/KeeperCompatibleInterface.sol";
contract PerformDataChecker is KeeperCompatibleInterface {
uint256 public counter;
bytes public s_expectedData;
constructor(bytes memory expectedData) {
s_expectedData = expectedData;
}
function setExpectedData(bytes calldata expectedData) external {
s_expectedData = expectedData;
}
function checkUpkeep(
bytes calldata checkData
) external view override returns (bool upkeepNeeded, bytes memory performData) {
return (keccak256(checkData) == keccak256(s_expectedData), checkData);
}
function performUpkeep(bytes calldata performData) external override {
if (keccak256(performData) == keccak256(s_expectedData)) {
counter++;
}
}
}
文件 58 的 76:RewardManager.sol
pragma solidity 0.8.16;
import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol";
import {IRewardManager} from "./interfaces/IRewardManager.sol";
import {IERC20} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol";
import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol";
import {Common} from "./libraries/Common.sol";
import {SafeERC20} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol";
contract RewardManager is IRewardManager, ConfirmedOwner, TypeAndVersionInterface {
using SafeERC20 for IERC20;
mapping(bytes32 => uint256) public s_totalRewardRecipientFees;
mapping(bytes32 => mapping(address => uint256)) public s_totalRewardRecipientFeesLastClaimedAmounts;
mapping(bytes32 => mapping(address => uint256)) public s_rewardRecipientWeights;
mapping(bytes32 => bool) public s_rewardRecipientWeightsSet;
bytes32[] public s_registeredPoolIds;
address public immutable i_linkAddress;
uint64 private constant PERCENTAGE_SCALAR = 1e18;
address public s_feeManagerAddress;
error InvalidWeights();
error InvalidAddress();
error InvalidPoolId();
error Unauthorized();
error InvalidPoolLength();
event RewardRecipientsUpdated(bytes32 indexed poolId, Common.AddressAndWeight[] newRewardRecipients);
event RewardsClaimed(bytes32 indexed poolId, address indexed recipient, uint192 quantity);
event FeeManagerUpdated(address newFeeManagerAddress);
event FeePaid(FeePayment[] payments, address payer);
constructor(address linkAddress) ConfirmedOwner(msg.sender) {
if (linkAddress == address(0)) revert InvalidAddress();
i_linkAddress = linkAddress;
}
function typeAndVersion() external pure override returns (string memory) {
return "RewardManager 1.1.0";
}
function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
return interfaceId == this.onFeePaid.selector;
}
modifier onlyOwnerOrFeeManager() {
if (msg.sender != owner() && msg.sender != s_feeManagerAddress) revert Unauthorized();
_;
}
modifier onlyOwnerOrRecipientInPool(bytes32 poolId) {
if (msg.sender != owner() && s_rewardRecipientWeights[poolId][msg.sender] == 0) revert Unauthorized();
_;
}
modifier onlyFeeManager() {
if (msg.sender != s_feeManagerAddress) revert Unauthorized();
_;
}
function onFeePaid(FeePayment[] calldata payments, address payer) external override onlyFeeManager {
uint256 totalFeeAmount;
for (uint256 i; i < payments.length; ++i) {
unchecked {
s_totalRewardRecipientFees[payments[i].poolId] += payments[i].amount;
totalFeeAmount += payments[i].amount;
}
}
IERC20(i_linkAddress).safeTransferFrom(payer, address(this), totalFeeAmount);
emit FeePaid(payments, payer);
}
function claimRewards(bytes32[] memory poolIds) external override {
_claimRewards(msg.sender, poolIds);
}
function _claimRewards(address recipient, bytes32[] memory poolIds) internal returns (uint256) {
uint256 claimAmount;
for (uint256 i; i < poolIds.length; ++i) {
bytes32 poolId = poolIds[i];
uint256 totalFeesInPot = s_totalRewardRecipientFees[poolId];
unchecked {
if (totalFeesInPot == 0) continue;
uint256 claimableAmount = totalFeesInPot - s_totalRewardRecipientFeesLastClaimedAmounts[poolId][recipient];
uint256 recipientShare = (claimableAmount * s_rewardRecipientWeights[poolId][recipient]) / PERCENTAGE_SCALAR;
if (recipientShare == 0) continue;
claimAmount += recipientShare;
s_totalRewardRecipientFeesLastClaimedAmounts[poolId][recipient] = totalFeesInPot;
emit RewardsClaimed(poolIds[i], recipient, uint192(recipientShare));
}
}
if (claimAmount != 0) {
IERC20(i_linkAddress).safeTransfer(recipient, claimAmount);
}
return claimAmount;
}
function setRewardRecipients(
bytes32 poolId,
Common.AddressAndWeight[] calldata rewardRecipientAndWeights
) external override onlyOwnerOrFeeManager {
if (rewardRecipientAndWeights.length == 0) revert InvalidAddress();
if (s_rewardRecipientWeightsSet[poolId]) revert InvalidPoolId();
s_registeredPoolIds.push(poolId);
s_rewardRecipientWeightsSet[poolId] = true;
_setRewardRecipientWeights(poolId, rewardRecipientAndWeights, PERCENTAGE_SCALAR);
emit RewardRecipientsUpdated(poolId, rewardRecipientAndWeights);
}
function _setRewardRecipientWeights(
bytes32 poolId,
Common.AddressAndWeight[] calldata rewardRecipientAndWeights,
uint256 expectedWeight
) internal {
if (Common._hasDuplicateAddresses(rewardRecipientAndWeights)) revert InvalidAddress();
uint256 totalWeight;
for (uint256 i; i < rewardRecipientAndWeights.length; ++i) {
uint256 recipientWeight = rewardRecipientAndWeights[i].weight;
address recipientAddress = rewardRecipientAndWeights[i].addr;
if (recipientAddress == address(0)) revert InvalidAddress();
s_rewardRecipientWeights[poolId][recipientAddress] = recipientWeight;
unchecked {
totalWeight += recipientWeight;
}
}
if (totalWeight != expectedWeight) revert InvalidWeights();
}
function updateRewardRecipients(
bytes32 poolId,
Common.AddressAndWeight[] calldata newRewardRecipients
) external override onlyOwner {
bytes32[] memory poolIds = new bytes32[](1);
poolIds[0] = poolId;
uint256 existingTotalWeight;
for (uint256 i; i < newRewardRecipients.length; ++i) {
address recipientAddress = newRewardRecipients[i].addr;
uint256 existingWeight = s_rewardRecipientWeights[poolId][recipientAddress];
_claimRewards(newRewardRecipients[i].addr, poolIds);
unchecked {
existingTotalWeight += existingWeight;
}
}
_setRewardRecipientWeights(poolId, newRewardRecipients, existingTotalWeight);
emit RewardRecipientsUpdated(poolId, newRewardRecipients);
}
function payRecipients(bytes32 poolId, address[] calldata recipients) external onlyOwnerOrRecipientInPool(poolId) {
bytes32[] memory poolIdsArray = new bytes32[](1);
poolIdsArray[0] = poolId;
for (uint256 i; i < recipients.length; ++i) {
_claimRewards(recipients[i], poolIdsArray);
}
}
function setFeeManager(address newFeeManagerAddress) external onlyOwner {
if (newFeeManagerAddress == address(0)) revert InvalidAddress();
s_feeManagerAddress = newFeeManagerAddress;
emit FeeManagerUpdated(newFeeManagerAddress);
}
function getAvailableRewardPoolIds(
address recipient,
uint256 startIndex,
uint256 endIndex
) external view returns (bytes32[] memory) {
uint256 registeredPoolIdsLength = s_registeredPoolIds.length;
uint256 lastIndex = endIndex > registeredPoolIdsLength ? registeredPoolIdsLength : endIndex;
if (startIndex > lastIndex) revert InvalidPoolLength();
bytes32[] memory claimablePoolIds = new bytes32[](lastIndex - startIndex);
uint256 poolIdArrayIndex;
for (uint256 i = startIndex; i < lastIndex; ++i) {
bytes32 poolId = s_registeredPoolIds[i];
if (s_rewardRecipientWeights[poolId][recipient] != 0) {
uint256 totalPoolAmount = s_totalRewardRecipientFees[poolId];
unchecked {
if (totalPoolAmount - s_totalRewardRecipientFeesLastClaimedAmounts[poolId][recipient] != 0) {
claimablePoolIds[poolIdArrayIndex++] = poolId;
}
}
}
}
return claimablePoolIds;
}
}
文件 59 的 76:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 60 的 76:StreamsLookupCompatibleInterface.sol
pragma solidity ^0.8.0;
interface StreamsLookupCompatibleInterface {
error StreamsLookup(string feedParamKey, string[] feeds, string timeParamKey, uint256 time, bytes extraData);
function checkCallback(
bytes[] memory values,
bytes memory extraData
) external view returns (bool upkeepNeeded, bytes memory performData);
}
文件 61 的 76:StreamsLookupUpkeep.sol
pragma solidity 0.8.16;
import "../automation/interfaces/AutomationCompatibleInterface.sol";
import "../automation/interfaces/StreamsLookupCompatibleInterface.sol";
import {ArbSys} from "../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol";
interface IVerifierProxy {
function verify(bytes memory signedReport) external returns (bytes memory verifierResponse);
}
contract StreamsLookupUpkeep is AutomationCompatibleInterface, StreamsLookupCompatibleInterface {
event MercuryPerformEvent(address indexed sender, uint256 indexed blockNumber, bytes v0, bytes verifiedV0, bytes ed);
ArbSys internal constant ARB_SYS = ArbSys(0x0000000000000000000000000000000000000064);
IVerifierProxy internal constant PRODUCTION_TESTNET_VERIFIER_PROXY =
IVerifierProxy(0x09DFf56A4fF44e0f4436260A04F5CFa65636A481);
IVerifierProxy internal constant STAGING_TESTNET_VERIFIER_PROXY =
IVerifierProxy(0x60448B880c9f3B501af3f343DA9284148BD7D77C);
uint256 public testRange;
uint256 public interval;
uint256 public previousPerformBlock;
uint256 public initialBlock;
uint256 public counter;
string[] public feeds;
string public feedParamKey;
string public timeParamKey;
bool public immutable useArbBlock;
bool public staging;
bool public verify;
bool public shouldRevertCallback;
bool public callbackReturnBool;
constructor(uint256 _testRange, uint256 _interval, bool _useArbBlock, bool _staging, bool _verify) {
testRange = _testRange;
interval = _interval;
previousPerformBlock = 0;
initialBlock = 0;
counter = 0;
useArbBlock = _useArbBlock;
feedParamKey = "feedIDs";
timeParamKey = "timestamp";
feeds = [
"0x00028c915d6af0fd66bba2d0fc9405226bca8d6806333121a7d9832103d1563c"
];
staging = _staging;
verify = _verify;
callbackReturnBool = true;
}
function setParamKeys(string memory _feedParamKey, string memory _timeParamKey) external {
feedParamKey = _feedParamKey;
timeParamKey = _timeParamKey;
}
function setFeeds(string[] memory _feeds) external {
feeds = _feeds;
}
function setShouldRevertCallback(bool value) public {
shouldRevertCallback = value;
}
function setCallbackReturnBool(bool value) public {
callbackReturnBool = value;
}
function reset() public {
previousPerformBlock = 0;
initialBlock = 0;
counter = 0;
}
function checkCallback(bytes[] memory values, bytes memory extraData) external view returns (bool, bytes memory) {
require(!shouldRevertCallback, "shouldRevertCallback is true");
bytes memory performData = abi.encode(values, extraData);
return (callbackReturnBool, performData);
}
function checkUpkeep(bytes calldata data) external view returns (bool, bytes memory) {
if (!eligible()) {
return (false, data);
}
uint256 timeParam;
if (keccak256(abi.encodePacked(feedParamKey)) == keccak256(abi.encodePacked("feedIdHex"))) {
if (useArbBlock) {
timeParam = ARB_SYS.arbBlockNumber();
} else {
timeParam = block.number;
}
} else {
timeParam = block.timestamp;
}
revert StreamsLookup(feedParamKey, feeds, timeParamKey, timeParam, abi.encodePacked(address(ARB_SYS)));
}
function performUpkeep(bytes calldata performData) external {
uint256 blockNumber;
if (useArbBlock) {
blockNumber = ARB_SYS.arbBlockNumber();
} else {
blockNumber = block.number;
}
if (initialBlock == 0) {
initialBlock = blockNumber;
}
(bytes[] memory values, bytes memory extraData) = abi.decode(performData, (bytes[], bytes));
previousPerformBlock = blockNumber;
counter = counter + 1;
bytes memory v0 = "";
bytes memory v1 = "";
if (verify) {
if (staging) {
v0 = STAGING_TESTNET_VERIFIER_PROXY.verify(values[0]);
} else {
v0 = PRODUCTION_TESTNET_VERIFIER_PROXY.verify(values[0]);
}
}
emit MercuryPerformEvent(msg.sender, blockNumber, values[0], v0, extraData);
}
function eligible() public view returns (bool) {
if (initialBlock == 0) {
return true;
}
uint256 blockNumber;
if (useArbBlock) {
blockNumber = ARB_SYS.arbBlockNumber();
} else {
blockNumber = block.number;
}
return (blockNumber - initialBlock) < testRange && (blockNumber - previousPerformBlock) >= interval;
}
}
文件 62 的 76:StructFactory.sol
pragma solidity 0.8.16;
contract StructFactory {
address internal OWNER;
address internal constant STRANGER = address(999);
}
文件 63 的 76:TypeAndVersionInterface.sol
pragma solidity ^0.8.0;
abstract contract TypeAndVersionInterface {
function typeAndVersion() external pure virtual returns (string memory);
}
文件 64 的 76:UpkeepCounter.sol
pragma solidity 0.8.16;
contract UpkeepCounter {
event PerformingUpkeep(
address indexed from,
uint256 initialBlock,
uint256 lastBlock,
uint256 previousBlock,
uint256 counter
);
uint256 public testRange;
uint256 public interval;
uint256 public lastBlock;
uint256 public previousPerformBlock;
uint256 public initialBlock;
uint256 public counter;
constructor(uint256 _testRange, uint256 _interval) {
testRange = _testRange;
interval = _interval;
previousPerformBlock = 0;
lastBlock = block.number;
initialBlock = 0;
counter = 0;
}
function checkUpkeep(bytes calldata data) external view returns (bool, bytes memory) {
return (eligible(), data);
}
function performUpkeep(bytes calldata performData) external {
if (initialBlock == 0) {
initialBlock = block.number;
}
lastBlock = block.number;
counter = counter + 1;
performData;
emit PerformingUpkeep(tx.origin, initialBlock, lastBlock, previousPerformBlock, counter);
previousPerformBlock = lastBlock;
}
function eligible() public view returns (bool) {
if (initialBlock == 0) {
return true;
}
return (block.number - initialBlock) < testRange && (block.number - lastBlock) >= interval;
}
function setSpread(uint256 _testRange, uint256 _interval) external {
testRange = _testRange;
interval = _interval;
initialBlock = 0;
counter = 0;
}
}
文件 65 的 76:UpkeepFormat.sol
pragma solidity ^0.8.0;
enum UpkeepFormat {
V1,
V2,
V3
}
文件 66 的 76:UpkeepPerformCounterRestrictive.sol
pragma solidity 0.8.16;
contract UpkeepPerformCounterRestrictive {
event PerformingUpkeep(bool eligible, address from, uint256 initialCall, uint256 nextEligible, uint256 blockNumber);
uint256 public initialCall = 0;
uint256 public nextEligible = 0;
uint256 public testRange;
uint256 public averageEligibilityCadence;
uint256 public checkGasToBurn;
uint256 public performGasToBurn;
mapping(bytes32 => bool) public dummyMap;
uint256 private count = 0;
constructor(uint256 _testRange, uint256 _averageEligibilityCadence) {
testRange = _testRange;
averageEligibilityCadence = _averageEligibilityCadence;
}
function checkUpkeep(bytes calldata data) external view returns (bool, bytes memory) {
uint256 startGas = gasleft();
uint256 blockNum = block.number - 1;
bool dummy;
while (startGas - gasleft() < checkGasToBurn) {
dummy = dummy && dummyMap[blockhash(blockNum)];
blockNum--;
}
return (eligible(), abi.encode(dummy));
}
function performUpkeep(bytes calldata) external {
uint256 startGas = gasleft();
bool eligible = eligible();
uint256 blockNum = block.number;
emit PerformingUpkeep(eligible, tx.origin, initialCall, nextEligible, blockNum);
require(eligible);
if (initialCall == 0) {
initialCall = blockNum;
}
nextEligible = (blockNum + (rand() % (averageEligibilityCadence * 2))) + 1;
count++;
blockNum--;
while (startGas - gasleft() < performGasToBurn) {
dummyMap[blockhash(blockNum)] = false;
blockNum--;
}
}
function setCheckGasToBurn(uint256 value) public {
checkGasToBurn = value;
}
function setPerformGasToBurn(uint256 value) public {
performGasToBurn = value;
}
function getCountPerforms() public view returns (uint256) {
return count;
}
function eligible() internal view returns (bool) {
return initialCall == 0 || (block.number - initialCall < testRange && block.number > nextEligible);
}
function checkEligible() public view returns (bool) {
return eligible();
}
function reset() external {
initialCall = 0;
count = 0;
}
function setSpread(uint256 _newTestRange, uint256 _newAverageEligibilityCadence) external {
testRange = _newTestRange;
averageEligibilityCadence = _newAverageEligibilityCadence;
}
function rand() private view returns (uint256) {
return uint256(keccak256(abi.encode(blockhash(block.number - 1), address(this))));
}
}
文件 67 的 76:UpkeepTranscoder4_0.sol
pragma solidity 0.8.16;
import {UpkeepTranscoderInterfaceV2} from "../interfaces/UpkeepTranscoderInterfaceV2.sol";
import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol";
import {KeeperRegistryBase2_1 as R21} from "./KeeperRegistryBase2_1.sol";
import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol";
enum RegistryVersion {
V12,
V13,
V20,
V21
}
struct UpkeepV12 {
uint96 balance;
address lastKeeper;
uint32 executeGas;
uint64 maxValidBlocknumber;
address target;
uint96 amountSpent;
address admin;
}
struct UpkeepV13 {
uint96 balance;
address lastKeeper;
uint96 amountSpent;
address admin;
uint32 executeGas;
uint32 maxValidBlocknumber;
address target;
bool paused;
}
struct UpkeepV20 {
uint32 executeGas;
uint32 maxValidBlocknumber;
bool paused;
address target;
uint96 amountSpent;
uint96 balance;
uint32 lastPerformedBlockNumber;
}
contract UpkeepTranscoder4_0 is UpkeepTranscoderInterfaceV2, TypeAndVersionInterface {
error InvalidTranscoding();
string public constant override typeAndVersion = "UpkeepTranscoder 4.0.0";
uint32 internal constant UINT32_MAX = type(uint32).max;
IAutomationForwarder internal constant ZERO_FORWARDER = IAutomationForwarder(address(0));
function transcodeUpkeeps(
uint8 fromVersion,
uint8,
bytes calldata encodedUpkeeps
) external view override returns (bytes memory) {
if (fromVersion == uint8(RegistryVersion.V12)) {
(uint256[] memory ids, UpkeepV12[] memory upkeepsV12, bytes[] memory checkDatas) = abi.decode(
encodedUpkeeps,
(uint256[], UpkeepV12[], bytes[])
);
if (ids.length != upkeepsV12.length || ids.length != checkDatas.length) {
revert InvalidTranscoding();
}
address[] memory targets = new address[](ids.length);
address[] memory admins = new address[](ids.length);
R21.Upkeep[] memory newUpkeeps = new R21.Upkeep[](ids.length);
UpkeepV12 memory upkeepV12;
for (uint256 idx = 0; idx < ids.length; idx++) {
upkeepV12 = upkeepsV12[idx];
newUpkeeps[idx] = R21.Upkeep({
performGas: upkeepV12.executeGas,
maxValidBlocknumber: UINT32_MAX,
paused: false,
forwarder: ZERO_FORWARDER,
amountSpent: upkeepV12.amountSpent,
balance: upkeepV12.balance,
lastPerformedBlockNumber: 0
});
targets[idx] = upkeepV12.target;
admins[idx] = upkeepV12.admin;
}
return abi.encode(ids, newUpkeeps, targets, admins, checkDatas, new bytes[](ids.length), new bytes[](ids.length));
}
if (fromVersion == uint8(RegistryVersion.V13)) {
(uint256[] memory ids, UpkeepV13[] memory upkeepsV13, bytes[] memory checkDatas) = abi.decode(
encodedUpkeeps,
(uint256[], UpkeepV13[], bytes[])
);
if (ids.length != upkeepsV13.length || ids.length != checkDatas.length) {
revert InvalidTranscoding();
}
address[] memory targets = new address[](ids.length);
address[] memory admins = new address[](ids.length);
R21.Upkeep[] memory newUpkeeps = new R21.Upkeep[](ids.length);
UpkeepV13 memory upkeepV13;
for (uint256 idx = 0; idx < ids.length; idx++) {
upkeepV13 = upkeepsV13[idx];
newUpkeeps[idx] = R21.Upkeep({
performGas: upkeepV13.executeGas,
maxValidBlocknumber: upkeepV13.maxValidBlocknumber,
paused: upkeepV13.paused,
forwarder: ZERO_FORWARDER,
amountSpent: upkeepV13.amountSpent,
balance: upkeepV13.balance,
lastPerformedBlockNumber: 0
});
targets[idx] = upkeepV13.target;
admins[idx] = upkeepV13.admin;
}
return abi.encode(ids, newUpkeeps, targets, admins, checkDatas, new bytes[](ids.length), new bytes[](ids.length));
}
if (fromVersion == uint8(RegistryVersion.V20)) {
(uint256[] memory ids, UpkeepV20[] memory upkeepsV20, bytes[] memory checkDatas, address[] memory admins) = abi
.decode(encodedUpkeeps, (uint256[], UpkeepV20[], bytes[], address[]));
if (ids.length != upkeepsV20.length || ids.length != checkDatas.length) {
revert InvalidTranscoding();
}
R21.Upkeep[] memory newUpkeeps = new R21.Upkeep[](ids.length);
bytes[] memory emptyBytes = new bytes[](ids.length);
address[] memory targets = new address[](ids.length);
UpkeepV20 memory upkeepV20;
for (uint256 idx = 0; idx < ids.length; idx++) {
upkeepV20 = upkeepsV20[idx];
newUpkeeps[idx] = R21.Upkeep({
performGas: upkeepV20.executeGas,
maxValidBlocknumber: upkeepV20.maxValidBlocknumber,
paused: upkeepV20.paused,
forwarder: ZERO_FORWARDER,
amountSpent: upkeepV20.amountSpent,
balance: upkeepV20.balance,
lastPerformedBlockNumber: 0
});
targets[idx] = upkeepV20.target;
}
return abi.encode(ids, newUpkeeps, targets, admins, checkDatas, emptyBytes, emptyBytes);
}
if (fromVersion == uint8(RegistryVersion.V21)) {
return encodedUpkeeps;
}
revert InvalidTranscoding();
}
}
文件 68 的 76:UpkeepTranscoderInterface.sol
import "../UpkeepFormat.sol";
pragma solidity ^0.8.0;
interface UpkeepTranscoderInterface {
function transcodeUpkeeps(
UpkeepFormat fromVersion,
UpkeepFormat toVersion,
bytes calldata encodedUpkeeps
) external view returns (bytes memory);
}
文件 69 的 76:UpkeepTranscoderInterfaceV2.sol
pragma solidity ^0.8.0;
interface UpkeepTranscoderInterfaceV2 {
function transcodeUpkeeps(
uint8 fromVersion,
uint8 toVersion,
bytes calldata encodedUpkeeps
) external view returns (bytes memory);
}
文件 70 的 76:VerifiableLoadBase.sol
pragma solidity ^0.8.16;
import "../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol";
import "../automation/interfaces/v2_1/IKeeperRegistryMaster.sol";
import {ArbSys} from "../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol";
import "../automation/v2_1/AutomationRegistrar2_1.sol";
import {LogTriggerConfig} from "../automation/v2_1/AutomationUtils2_1.sol";
abstract contract VerifiableLoadBase is ConfirmedOwner {
error IndexOutOfRange();
event LogEmitted(uint256 indexed upkeepId, uint256 indexed blockNum, address indexed addr);
event LogEmittedAgain(uint256 indexed upkeepId, uint256 indexed blockNum, address indexed addr);
event UpkeepTopUp(uint256 upkeepId, uint96 amount, uint256 blockNum);
using EnumerableSet for EnumerableSet.UintSet;
ArbSys internal constant ARB_SYS = ArbSys(0x0000000000000000000000000000000000000064);
bytes32 public immutable emittedSig = LogEmitted.selector;
bytes32 public immutable emittedAgainSig = LogEmittedAgain.selector;
mapping(uint256 => uint256) public lastTopUpBlocks;
mapping(uint256 => uint256) public intervals;
mapping(uint256 => uint256) public previousPerformBlocks;
mapping(uint256 => uint256) public firstPerformBlocks;
mapping(uint256 => uint256) public counters;
mapping(uint256 => uint256) public performGasToBurns;
mapping(uint256 => uint256) public checkGasToBurns;
mapping(uint256 => uint256) public performDataSizes;
mapping(uint256 => uint256) public gasLimits;
mapping(bytes32 => bool) public dummyMap;
mapping(uint256 => uint256[]) public delays;
mapping(uint256 => mapping(uint16 => uint256[])) public bucketedDelays;
mapping(uint256 => uint16) public buckets;
EnumerableSet.UintSet internal s_upkeepIDs;
AutomationRegistrar2_1 public registrar;
LinkTokenInterface public linkToken;
IKeeperRegistryMaster public registry;
uint256 public upkeepTopUpCheckInterval = 5;
uint96 public addLinkAmount = 200000000000000000;
uint8 public minBalanceThresholdMultiplier = 20;
bool public immutable useArbitrumBlockNum;
uint16 public immutable BUCKET_SIZE = 100;
string[] public feedsHex = [
"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000",
"0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"
];
string public feedParamKey = "feedIdHex";
string public timeParamKey = "blockNumber";
constructor(AutomationRegistrar2_1 _registrar, bool _useArb) ConfirmedOwner(msg.sender) {
registrar = _registrar;
(address registryAddress, ) = registrar.getConfig();
registry = IKeeperRegistryMaster(payable(address(registryAddress)));
linkToken = registrar.LINK();
useArbitrumBlockNum = _useArb;
}
receive() external payable {}
function setParamKeys(string memory _feedParamKey, string memory _timeParamKey) external {
feedParamKey = _feedParamKey;
timeParamKey = _timeParamKey;
}
function setFeeds(string[] memory _feeds) external {
feedsHex = _feeds;
}
function withdrawLinks() external onlyOwner {
uint256 balance = linkToken.balanceOf(address(this));
linkToken.transfer(msg.sender, balance);
}
function getBlockNumber() internal view returns (uint256) {
if (useArbitrumBlockNum) {
return ARB_SYS.arbBlockNumber();
} else {
return block.number;
}
}
function setConfig(AutomationRegistrar2_1 newRegistrar) external {
registrar = newRegistrar;
(address registryAddress, ) = registrar.getConfig();
registry = IKeeperRegistryMaster(payable(address(registryAddress)));
linkToken = registrar.LINK();
}
function getActiveUpkeepIDsDeployedByThisContract(
uint256 startIndex,
uint256 maxCount
) external view 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 getAllActiveUpkeepIDsOnRegistry(
uint256 startIndex,
uint256 maxCount
) external view returns (uint256[] memory) {
return registry.getActiveUpkeepIDs(startIndex, maxCount);
}
function _registerUpkeep(AutomationRegistrar2_1.RegistrationParams memory params) private returns (uint256) {
uint256 upkeepId = registrar.registerUpkeep(params);
s_upkeepIDs.add(upkeepId);
gasLimits[upkeepId] = params.gasLimit;
return upkeepId;
}
function getLogTriggerConfig(
address addr,
uint8 selector,
bytes32 topic0,
bytes32 topic1,
bytes32 topic2,
bytes32 topic3
) external view returns (bytes memory logTrigger) {
LogTriggerConfig memory cfg = LogTriggerConfig({
contractAddress: addr,
filterSelector: selector,
topic0: topic0,
topic1: topic1,
topic2: topic2,
topic3: topic3
});
return abi.encode(cfg);
}
function batchPreparingUpkeeps(
uint256[] calldata upkeepIds,
uint8 selector,
bytes32 topic0,
bytes32 topic1,
bytes32 topic2,
bytes32 topic3
) external {
uint256 len = upkeepIds.length;
for (uint256 i = 0; i < len; i++) {
uint256 upkeepId = upkeepIds[i];
this.updateUpkeepPipelineData(upkeepId, abi.encode(upkeepId));
uint8 triggerType = registry.getTriggerType(upkeepId);
if (triggerType == 1) {
bytes memory triggerCfg = this.getLogTriggerConfig(address(this), selector, topic0, topic2, topic2, topic3);
registry.setUpkeepTriggerConfig(upkeepId, triggerCfg);
}
}
}
function batchPreparingUpkeepsSimple(uint256[] calldata upkeepIds, uint8 log, uint8 selector) external {
uint256 len = upkeepIds.length;
for (uint256 i = 0; i < len; i++) {
uint256 upkeepId = upkeepIds[i];
this.updateUpkeepPipelineData(upkeepId, abi.encode(upkeepId));
uint8 triggerType = registry.getTriggerType(upkeepId);
if (triggerType == 1) {
bytes32 sig = emittedSig;
if (log != 0) {
sig = emittedAgainSig;
}
bytes memory triggerCfg = this.getLogTriggerConfig(
address(this),
selector,
sig,
bytes32(abi.encode(upkeepId)),
bytes32(0),
bytes32(0)
);
registry.setUpkeepTriggerConfig(upkeepId, triggerCfg);
}
}
}
function updateLogTriggerConfig1(
uint256 upkeepId,
address addr,
uint8 selector,
bytes32 topic0,
bytes32 topic1,
bytes32 topic2,
bytes32 topic3
) external {
registry.setUpkeepTriggerConfig(upkeepId, this.getLogTriggerConfig(addr, selector, topic0, topic1, topic2, topic3));
}
function updateLogTriggerConfig2(uint256 upkeepId, bytes calldata cfg) external {
registry.setUpkeepTriggerConfig(upkeepId, cfg);
}
function batchRegisterUpkeeps(
uint8 number,
uint32 gasLimit,
uint8 triggerType,
bytes memory triggerConfig,
uint96 amount,
uint256 checkGasToBurn,
uint256 performGasToBurn
) external {
AutomationRegistrar2_1.RegistrationParams memory params = AutomationRegistrar2_1.RegistrationParams({
name: "test",
encryptedEmail: bytes(""),
upkeepContract: address(this),
gasLimit: gasLimit,
adminAddress: address(this),
triggerType: triggerType,
checkData: bytes(""),
triggerConfig: triggerConfig,
offchainConfig: bytes(""),
amount: amount
});
linkToken.approve(address(registrar), amount * number);
uint256[] memory upkeepIds = new uint256[](number);
for (uint8 i = 0; i < number; i++) {
uint256 upkeepId = _registerUpkeep(params);
upkeepIds[i] = upkeepId;
checkGasToBurns[upkeepId] = checkGasToBurn;
performGasToBurns[upkeepId] = performGasToBurn;
}
}
function topUpFund(uint256 upkeepId, uint256 blockNum) public {
if (blockNum - lastTopUpBlocks[upkeepId] > upkeepTopUpCheckInterval) {
KeeperRegistryBase2_1.UpkeepInfo memory info = registry.getUpkeep(upkeepId);
uint96 minBalance = registry.getMinBalanceForUpkeep(upkeepId);
if (info.balance < minBalanceThresholdMultiplier * minBalance) {
addFunds(upkeepId, addLinkAmount);
lastTopUpBlocks[upkeepId] = blockNum;
emit UpkeepTopUp(upkeepId, addLinkAmount, blockNum);
}
}
}
function getMinBalanceForUpkeep(uint256 upkeepId) external view returns (uint96) {
return registry.getMinBalanceForUpkeep(upkeepId);
}
function getForwarder(uint256 upkeepID) external view returns (address) {
return registry.getForwarder(upkeepID);
}
function getBalance(uint256 id) external view returns (uint96 balance) {
return registry.getBalance(id);
}
function getTriggerType(uint256 upkeepId) external view returns (uint8) {
return registry.getTriggerType(upkeepId);
}
function burnPerformGas(uint256 upkeepId, uint256 startGas, uint256 blockNum) public {
uint256 performGasToBurn = performGasToBurns[upkeepId];
while (startGas - gasleft() + 10000 < performGasToBurn) {
dummyMap[blockhash(blockNum)] = false;
}
}
function addFunds(uint256 upkeepId, uint96 amount) public {
linkToken.approve(address(registry), amount);
registry.addFunds(upkeepId, amount);
}
function updateUpkeepPipelineData(uint256 upkeepId, bytes calldata pipelineData) external {
registry.setUpkeepCheckData(upkeepId, pipelineData);
}
function withdrawLinks(uint256 upkeepId) external {
registry.withdrawFunds(upkeepId, address(this));
}
function batchWithdrawLinks(uint256[] calldata upkeepIds) external {
uint256 len = upkeepIds.length;
for (uint32 i = 0; i < len; i++) {
this.withdrawLinks(upkeepIds[i]);
}
}
function batchCancelUpkeeps(uint256[] calldata upkeepIds) external {
uint256 len = upkeepIds.length;
for (uint8 i = 0; i < len; i++) {
registry.cancelUpkeep(upkeepIds[i]);
s_upkeepIDs.remove(upkeepIds[i]);
}
}
function eligible(uint256 upkeepId) public view returns (bool) {
if (firstPerformBlocks[upkeepId] == 0) {
return true;
}
return (getBlockNumber() - previousPerformBlocks[upkeepId]) >= intervals[upkeepId];
}
function setPerformDataSize(uint256 upkeepId, uint256 value) public {
performDataSizes[upkeepId] = value;
}
function setUpkeepGasLimit(uint256 upkeepId, uint32 gasLimit) public {
registry.setUpkeepGasLimit(upkeepId, gasLimit);
gasLimits[upkeepId] = gasLimit;
}
function setInterval(uint256 upkeepId, uint256 _interval) external {
intervals[upkeepId] = _interval;
firstPerformBlocks[upkeepId] = 0;
counters[upkeepId] = 0;
delete delays[upkeepId];
uint16 currentBucket = buckets[upkeepId];
for (uint16 i = 0; i <= currentBucket; i++) {
delete bucketedDelays[upkeepId][i];
}
delete buckets[upkeepId];
}
function batchSetIntervals(uint256[] calldata upkeepIds, uint32 interval) external {
uint256 len = upkeepIds.length;
for (uint256 i = 0; i < len; i++) {
this.setInterval(upkeepIds[i], interval);
}
}
function batchUpdatePipelineData(uint256[] calldata upkeepIds) external {
uint256 len = upkeepIds.length;
for (uint256 i = 0; i < len; i++) {
uint256 upkeepId = upkeepIds[i];
this.updateUpkeepPipelineData(upkeepId, abi.encode(upkeepId));
}
}
function batchSendLogs(uint8 log) external {
uint256[] memory upkeepIds = this.getActiveUpkeepIDsDeployedByThisContract(0, 0);
uint256 len = upkeepIds.length;
uint256 blockNum = getBlockNumber();
for (uint256 i = 0; i < len; i++) {
uint256 upkeepId = upkeepIds[i];
uint8 triggerType = registry.getTriggerType(upkeepId);
if (triggerType == 1) {
if (log == 0) {
emit LogEmitted(upkeepId, blockNum, address(this));
} else {
emit LogEmittedAgain(upkeepId, blockNum, address(this));
}
}
}
}
function getUpkeepInfo(uint256 upkeepId) public view returns (KeeperRegistryBase2_1.UpkeepInfo memory) {
return registry.getUpkeep(upkeepId);
}
function getUpkeepTriggerConfig(uint256 upkeepId) public view returns (bytes memory) {
return registry.getUpkeepTriggerConfig(upkeepId);
}
function getUpkeepPrivilegeConfig(uint256 upkeepId) public view returns (bytes memory) {
return registry.getUpkeepPrivilegeConfig(upkeepId);
}
function setUpkeepPrivilegeConfig(uint256 upkeepId, bytes memory cfg) external {
registry.setUpkeepPrivilegeConfig(upkeepId, cfg);
}
function sendLog(uint256 upkeepId, uint8 log) external {
uint256 blockNum = getBlockNumber();
if (log == 0) {
emit LogEmitted(upkeepId, blockNum, address(this));
} else {
emit LogEmittedAgain(upkeepId, blockNum, address(this));
}
}
function getDelaysLength(uint256 upkeepId) public view returns (uint256) {
return delays[upkeepId].length;
}
function getBucketedDelaysLength(uint256 upkeepId) public view returns (uint256) {
uint16 currentBucket = buckets[upkeepId];
uint256 len = 0;
for (uint16 i = 0; i <= currentBucket; i++) {
len += bucketedDelays[upkeepId][i].length;
}
return len;
}
function getDelays(uint256 upkeepId) public view returns (uint256[] memory) {
return delays[upkeepId];
}
function getBucketedDelays(uint256 upkeepId, uint16 bucket) public view returns (uint256[] memory) {
return bucketedDelays[upkeepId][bucket];
}
function getSumDelayLastNPerforms(uint256 upkeepId, uint256 n) public view returns (uint256, uint256) {
uint256[] memory delays = delays[upkeepId];
return getSumDelayLastNPerforms(delays, n);
}
function getSumDelayInBucket(uint256 upkeepId, uint16 bucket) public view returns (uint256, uint256) {
uint256[] memory delays = bucketedDelays[upkeepId][bucket];
return getSumDelayLastNPerforms(delays, delays.length);
}
function getSumDelayLastNPerforms(uint256[] memory delays, uint256 n) internal view returns (uint256, uint256) {
uint256 i;
uint256 len = delays.length;
if (n == 0 || n >= len) {
n = len;
}
uint256 sum = 0;
for (i = 0; i < n; i++) sum = sum + delays[len - i - 1];
return (sum, n);
}
function getPxDelayLastNPerforms(uint256 upkeepId, uint256 p, uint256 n) public view returns (uint256) {
return getPxDelayLastNPerforms(delays[upkeepId], p, n);
}
function getPxDelayLastNPerforms(uint256[] memory delays, uint256 p, uint256 n) internal view returns (uint256) {
uint256 i;
uint256 len = delays.length;
if (n == 0 || n >= len) {
n = len;
}
uint256[] memory subArr = new uint256[](n);
for (i = 0; i < n; i++) subArr[i] = (delays[len - i - 1]);
quickSort(subArr, int256(0), int256(subArr.length - 1));
if (p == 100) {
return subArr[subArr.length - 1];
}
return subArr[(p * subArr.length) / 100];
}
function quickSort(uint256[] memory arr, int256 left, int256 right) private pure {
int256 i = left;
int256 j = right;
if (i == j) return;
uint256 pivot = arr[uint256(left + (right - left) / 2)];
while (i <= j) {
while (arr[uint256(i)] < pivot) i++;
while (pivot < arr[uint256(j)]) j--;
if (i <= j) {
(arr[uint256(i)], arr[uint256(j)]) = (arr[uint256(j)], arr[uint256(i)]);
i++;
j--;
}
}
if (left < j) quickSort(arr, left, j);
if (i < right) quickSort(arr, i, right);
}
}
文件 71 的 76:VerifiableLoadLogTriggerUpkeep.sol
pragma solidity 0.8.16;
import "./VerifiableLoadBase.sol";
import "../automation/interfaces/ILogAutomation.sol";
import "../automation/interfaces/StreamsLookupCompatibleInterface.sol";
contract VerifiableLoadLogTriggerUpkeep is VerifiableLoadBase, StreamsLookupCompatibleInterface, ILogAutomation {
bool public useMercury;
uint8 public logNum;
constructor(
AutomationRegistrar2_1 _registrar,
bool _useArb,
bool _useMercury
) VerifiableLoadBase(_registrar, _useArb) {
useMercury = _useMercury;
logNum = 0;
}
function setLog(uint8 _log) external {
logNum = _log;
}
function checkLog(Log calldata log, bytes memory checkData) external returns (bool, bytes memory) {
uint256 startGas = gasleft();
uint256 blockNum = getBlockNumber();
uint256 uid = abi.decode(checkData, (uint256));
bytes32 sig = emittedSig;
if (logNum != 0) {
sig = emittedAgainSig;
}
if (log.topics[0] == sig) {
bytes memory t1 = abi.encodePacked(log.topics[1]);
uint256 upkeepId = abi.decode(t1, (uint256));
if (upkeepId != uid) {
revert("upkeep ids don't match");
}
bytes memory t2 = abi.encodePacked(log.topics[2]);
uint256 blockNum = abi.decode(t2, (uint256));
bytes memory t3 = abi.encodePacked(log.topics[3]);
address addr = abi.decode(t3, (address));
uint256 checkGasToBurn = checkGasToBurns[upkeepId];
while (startGas - gasleft() + 15000 < checkGasToBurn) {
dummyMap[blockhash(blockNum)] = false;
}
uint256 timeParam;
if (keccak256(abi.encodePacked(feedParamKey)) == keccak256(abi.encodePacked("feedIdHex"))) {
timeParam = blockNum;
} else {
timeParam = block.timestamp;
}
if (useMercury) {
revert StreamsLookup(feedParamKey, feedsHex, timeParamKey, timeParam, abi.encode(upkeepId, blockNum, addr));
}
bytes[] memory values = new bytes[](feedsHex.length);
bytes memory extraData = abi.encode(upkeepId, blockNum, addr);
return (true, abi.encode(values, extraData));
}
revert("unexpected event sig");
}
function performUpkeep(bytes calldata performData) external {
uint256 startGas = gasleft();
(bytes[] memory values, bytes memory extraData) = abi.decode(performData, (bytes[], bytes));
(uint256 upkeepId, uint256 logBlockNumber, address addr) = abi.decode(extraData, (uint256, uint256, address));
uint256 firstPerformBlock = firstPerformBlocks[upkeepId];
uint256 previousPerformBlock = previousPerformBlocks[upkeepId];
uint256 currentBlockNum = getBlockNumber();
if (firstPerformBlock == 0) {
firstPerformBlocks[upkeepId] = currentBlockNum;
} else {
uint256 delay = currentBlockNum - logBlockNumber;
uint16 bucket = buckets[upkeepId];
uint256[] memory bucketDelays = bucketedDelays[upkeepId][bucket];
if (bucketDelays.length == BUCKET_SIZE) {
bucket++;
buckets[upkeepId] = bucket;
}
bucketedDelays[upkeepId][bucket].push(delay);
delays[upkeepId].push(delay);
}
uint256 counter = counters[upkeepId] + 1;
counters[upkeepId] = counter;
previousPerformBlocks[upkeepId] = currentBlockNum;
topUpFund(upkeepId, currentBlockNum);
emit LogEmitted(upkeepId, currentBlockNum, address(this));
burnPerformGas(upkeepId, startGas, currentBlockNum);
}
function checkCallback(
bytes[] memory values,
bytes memory extraData
) external pure override returns (bool, bytes memory) {
bytes memory performData = abi.encode(values, extraData);
return (true, performData);
}
}
文件 72 的 76:VerifiableLoadStreamsLookupUpkeep.sol
pragma solidity 0.8.16;
import "./VerifiableLoadBase.sol";
import "../automation/interfaces/StreamsLookupCompatibleInterface.sol";
contract VerifiableLoadStreamsLookupUpkeep is VerifiableLoadBase, StreamsLookupCompatibleInterface {
constructor(AutomationRegistrar2_1 _registrar, bool _useArb) VerifiableLoadBase(_registrar, _useArb) {}
function checkCallback(
bytes[] memory values,
bytes memory extraData
) external pure override returns (bool, bytes memory) {
bytes memory performData = abi.encode(values, extraData);
return (true, performData);
}
function checkUpkeep(bytes calldata checkData) external returns (bool, bytes memory) {
uint256 startGas = gasleft();
uint256 upkeepId = abi.decode(checkData, (uint256));
uint256 performDataSize = performDataSizes[upkeepId];
uint256 checkGasToBurn = checkGasToBurns[upkeepId];
bytes memory pData = abi.encode(upkeepId, new bytes(performDataSize));
uint256 blockNum = getBlockNumber();
bool needed = eligible(upkeepId);
while (startGas - gasleft() + 10000 < checkGasToBurn) {
dummyMap[blockhash(blockNum)] = false;
}
if (!needed) {
return (false, pData);
}
uint256 timeParam;
if (keccak256(abi.encodePacked(feedParamKey)) == keccak256(abi.encodePacked("feedIdHex"))) {
timeParam = blockNum;
} else {
timeParam = block.timestamp;
}
revert StreamsLookup(feedParamKey, feedsHex, timeParamKey, timeParam, abi.encode(upkeepId));
}
function performUpkeep(bytes calldata performData) external {
uint256 startGas = gasleft();
(bytes[] memory values, bytes memory extraData) = abi.decode(performData, (bytes[], bytes));
uint256 upkeepId = abi.decode(extraData, (uint256));
uint256 firstPerformBlock = firstPerformBlocks[upkeepId];
uint256 previousPerformBlock = previousPerformBlocks[upkeepId];
uint256 blockNum = getBlockNumber();
if (firstPerformBlock == 0) {
firstPerformBlocks[upkeepId] = blockNum;
} else {
uint256 delay = blockNum - previousPerformBlock - intervals[upkeepId];
uint16 bucket = buckets[upkeepId];
uint256[] memory bucketDelays = bucketedDelays[upkeepId][bucket];
if (bucketDelays.length == BUCKET_SIZE) {
bucket++;
buckets[upkeepId] = bucket;
}
bucketedDelays[upkeepId][bucket].push(delay);
delays[upkeepId].push(delay);
}
uint256 counter = counters[upkeepId] + 1;
counters[upkeepId] = counter;
previousPerformBlocks[upkeepId] = blockNum;
topUpFund(upkeepId, blockNum);
burnPerformGas(upkeepId, startGas, blockNum);
}
}
文件 73 的 76:VerifiableLoadUpkeep.sol
pragma solidity 0.8.16;
import "./VerifiableLoadBase.sol";
contract VerifiableLoadUpkeep is VerifiableLoadBase {
constructor(AutomationRegistrar2_1 _registrar, bool _useArb) VerifiableLoadBase(_registrar, _useArb) {}
function checkUpkeep(bytes calldata checkData) external returns (bool, bytes memory) {
uint256 startGas = gasleft();
uint256 upkeepId = abi.decode(checkData, (uint256));
uint256 performDataSize = performDataSizes[upkeepId];
uint256 checkGasToBurn = checkGasToBurns[upkeepId];
bytes memory pData = abi.encode(upkeepId, new bytes(performDataSize));
uint256 blockNum = getBlockNumber();
bool needed = eligible(upkeepId);
while (startGas - gasleft() + 10000 < checkGasToBurn) {
dummyMap[blockhash(blockNum)] = false;
blockNum--;
}
return (needed, pData);
}
function performUpkeep(bytes calldata performData) external {
uint256 startGas = gasleft();
(uint256 upkeepId, ) = abi.decode(performData, (uint256, bytes));
uint256 firstPerformBlock = firstPerformBlocks[upkeepId];
uint256 previousPerformBlock = previousPerformBlocks[upkeepId];
uint256 blockNum = getBlockNumber();
if (firstPerformBlock == 0) {
firstPerformBlocks[upkeepId] = blockNum;
} else {
uint256 delay = blockNum - previousPerformBlock - intervals[upkeepId];
uint16 bucket = buckets[upkeepId];
uint256[] memory bucketDelays = bucketedDelays[upkeepId][bucket];
if (bucketDelays.length == BUCKET_SIZE) {
bucket++;
buckets[upkeepId] = bucket;
}
bucketedDelays[upkeepId][bucket].push(delay);
delays[upkeepId].push(delay);
}
uint256 counter = counters[upkeepId] + 1;
counters[upkeepId] = counter;
previousPerformBlocks[upkeepId] = blockNum;
topUpFund(upkeepId, blockNum);
burnPerformGas(upkeepId, startGas, blockNum);
}
}
文件 74 的 76:Verifier.sol
pragma solidity 0.8.16;
import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol";
import {IVerifier} from "./interfaces/IVerifier.sol";
import {IVerifierProxy} from "./interfaces/IVerifierProxy.sol";
import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol";
import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol";
import {Common} from "../libraries/Common.sol";
uint256 constant MAX_NUM_ORACLES = 31;
contract Verifier is IVerifier, ConfirmedOwner, TypeAndVersionInterface {
uint256 internal constant ORACLE_MASK = 0x0001010101010101010101010101010101010101010101010101010101010101;
enum Role {
Unset,
Signer
}
struct Signer {
uint8 index;
Role role;
}
struct Config {
uint8 f;
bool isActive;
mapping(address => Signer) oracles;
}
struct VerifierState {
uint32 configCount;
uint32 latestConfigBlockNumber;
uint32 latestEpoch;
bool isDeactivated;
bytes32 latestConfigDigest;
mapping(bytes32 => Config) s_verificationDataConfigs;
}
event ReportVerified(bytes32 indexed feedId, address requester);
event ConfigSet(
bytes32 indexed feedId,
uint32 previousConfigBlockNumber,
bytes32 configDigest,
uint64 configCount,
address[] signers,
bytes32[] offchainTransmitters,
uint8 f,
bytes onchainConfig,
uint64 offchainConfigVersion,
bytes offchainConfig
);
event ConfigDeactivated(bytes32 indexed feedId, bytes32 configDigest);
event ConfigActivated(bytes32 indexed feedId, bytes32 configDigest);
event FeedActivated(bytes32 indexed feedId);
event FeedDeactivated(bytes32 indexed feedId);
error AccessForbidden();
error ZeroAddress();
error FeedIdEmpty();
error DigestEmpty();
error DigestNotSet(bytes32 feedId, bytes32 configDigest);
error DigestInactive(bytes32 feedId, bytes32 configDigest);
error FaultToleranceMustBePositive();
error ExcessSigners(uint256 numSigners, uint256 maxSigners);
error InsufficientSigners(uint256 numSigners, uint256 minSigners);
error IncorrectSignatureCount(uint256 numSigners, uint256 expectedNumSigners);
error MismatchedSignatures(uint256 rsLength, uint256 ssLength);
error NonUniqueSignatures();
error BadVerification();
error CannotDeactivateLatestConfig(bytes32 feedId, bytes32 configDigest);
error InactiveFeed(bytes32 feedId);
error InvalidFeed(bytes32 feedId);
address private immutable i_verifierProxyAddr;
mapping(bytes32 => VerifierState) s_feedVerifierStates;
constructor(address verifierProxyAddr) ConfirmedOwner(msg.sender) {
if (verifierProxyAddr == address(0)) revert ZeroAddress();
i_verifierProxyAddr = verifierProxyAddr;
}
modifier checkConfigValid(uint256 numSigners, uint256 f) {
if (f == 0) revert FaultToleranceMustBePositive();
if (numSigners > MAX_NUM_ORACLES) revert ExcessSigners(numSigners, MAX_NUM_ORACLES);
if (numSigners <= 3 * f) revert InsufficientSigners(numSigners, 3 * f + 1);
_;
}
function supportsInterface(bytes4 interfaceId) external pure override returns (bool isVerifier) {
return interfaceId == this.verify.selector;
}
function typeAndVersion() external pure override returns (string memory) {
return "Verifier 1.2.0";
}
function verify(
bytes calldata signedReport,
address sender
) external override returns (bytes memory verifierResponse) {
if (msg.sender != i_verifierProxyAddr) revert AccessForbidden();
(
bytes32[3] memory reportContext,
bytes memory reportData,
bytes32[] memory rs,
bytes32[] memory ss,
bytes32 rawVs
) = abi.decode(signedReport, (bytes32[3], bytes, bytes32[], bytes32[], bytes32));
bytes32 feedId = bytes32(reportData);
VerifierState storage feedVerifierState = s_feedVerifierStates[feedId];
if (feedVerifierState.isDeactivated) {
revert InactiveFeed(feedId);
}
bytes32 configDigest = reportContext[0];
Config storage s_config = feedVerifierState.s_verificationDataConfigs[configDigest];
_validateReport(feedId, configDigest, rs, ss, s_config);
_updateEpoch(reportContext, feedVerifierState);
bytes32 hashedReport = keccak256(reportData);
_verifySignatures(hashedReport, reportContext, rs, ss, rawVs, s_config);
emit ReportVerified(feedId, sender);
return reportData;
}
function _validateReport(
bytes32 feedId,
bytes32 configDigest,
bytes32[] memory rs,
bytes32[] memory ss,
Config storage config
) private view {
uint8 expectedNumSignatures = config.f + 1;
if (!config.isActive) revert DigestInactive(feedId, configDigest);
if (rs.length != expectedNumSignatures) revert IncorrectSignatureCount(rs.length, expectedNumSignatures);
if (rs.length != ss.length) revert MismatchedSignatures(rs.length, ss.length);
}
function _updateEpoch(bytes32[3] memory reportContext, VerifierState storage feedVerifierState) private {
uint40 epochAndRound = uint40(uint256(reportContext[1]));
uint32 epoch = uint32(epochAndRound >> 8);
if (epoch > feedVerifierState.latestEpoch) {
feedVerifierState.latestEpoch = epoch;
}
}
function _verifySignatures(
bytes32 hashedReport,
bytes32[3] memory reportContext,
bytes32[] memory rs,
bytes32[] memory ss,
bytes32 rawVs,
Config storage s_config
) private view {
bytes32 h = keccak256(abi.encodePacked(hashedReport, reportContext));
uint256 signedCount;
Signer memory o;
address signerAddress;
uint256 numSigners = rs.length;
for (uint256 i; i < numSigners; ++i) {
signerAddress = ecrecover(h, uint8(rawVs[i]) + 27, rs[i], ss[i]);
o = s_config.oracles[signerAddress];
if (o.role != Role.Signer) revert BadVerification();
unchecked {
signedCount += 1 << (8 * o.index);
}
}
if (signedCount & ORACLE_MASK != signedCount) revert BadVerification();
}
function setConfig(
bytes32 feedId,
address[] memory signers,
bytes32[] memory offchainTransmitters,
uint8 f,
bytes memory onchainConfig,
uint64 offchainConfigVersion,
bytes memory offchainConfig,
Common.AddressAndWeight[] memory recipientAddressesAndWeights
) external override checkConfigValid(signers.length, f) onlyOwner {
_setConfig(
feedId,
block.chainid,
address(this),
0,
signers,
offchainTransmitters,
f,
onchainConfig,
offchainConfigVersion,
offchainConfig,
recipientAddressesAndWeights
);
}
function setConfigFromSource(
bytes32 feedId,
uint256 sourceChainId,
address sourceAddress,
uint32 newConfigCount,
address[] memory signers,
bytes32[] memory offchainTransmitters,
uint8 f,
bytes memory onchainConfig,
uint64 offchainConfigVersion,
bytes memory offchainConfig,
Common.AddressAndWeight[] memory recipientAddressesAndWeights
) external override checkConfigValid(signers.length, f) onlyOwner {
_setConfig(
feedId,
sourceChainId,
sourceAddress,
newConfigCount,
signers,
offchainTransmitters,
f,
onchainConfig,
offchainConfigVersion,
offchainConfig,
recipientAddressesAndWeights
);
}
function _setConfig(
bytes32 feedId,
uint256 sourceChainId,
address sourceAddress,
uint32 newConfigCount,
address[] memory signers,
bytes32[] memory offchainTransmitters,
uint8 f,
bytes memory onchainConfig,
uint64 offchainConfigVersion,
bytes memory offchainConfig,
Common.AddressAndWeight[] memory recipientAddressesAndWeights
) internal {
VerifierState storage feedVerifierState = s_feedVerifierStates[feedId];
if (newConfigCount > 0) feedVerifierState.configCount = newConfigCount;
else feedVerifierState.configCount++;
bytes32 configDigest = _configDigestFromConfigData(
feedId,
sourceChainId,
sourceAddress,
feedVerifierState.configCount,
signers,
offchainTransmitters,
f,
onchainConfig,
offchainConfigVersion,
offchainConfig
);
feedVerifierState.s_verificationDataConfigs[configDigest].f = f;
feedVerifierState.s_verificationDataConfigs[configDigest].isActive = true;
for (uint8 i; i < signers.length; ++i) {
address signerAddr = signers[i];
if (signerAddr == address(0)) revert ZeroAddress();
bool isSignerAlreadySet = feedVerifierState.s_verificationDataConfigs[configDigest].oracles[signerAddr].role !=
Role.Unset;
if (isSignerAlreadySet) revert NonUniqueSignatures();
feedVerifierState.s_verificationDataConfigs[configDigest].oracles[signerAddr] = Signer({
role: Role.Signer,
index: i
});
}
IVerifierProxy(i_verifierProxyAddr).setVerifier(
feedVerifierState.latestConfigDigest,
configDigest,
recipientAddressesAndWeights
);
emit ConfigSet(
feedId,
feedVerifierState.latestConfigBlockNumber,
configDigest,
feedVerifierState.configCount,
signers,
offchainTransmitters,
f,
onchainConfig,
offchainConfigVersion,
offchainConfig
);
feedVerifierState.latestEpoch = 0;
feedVerifierState.latestConfigBlockNumber = uint32(block.number);
feedVerifierState.latestConfigDigest = configDigest;
}
function _configDigestFromConfigData(
bytes32 feedId,
uint256 sourceChainId,
address sourceAddress,
uint64 configCount,
address[] memory signers,
bytes32[] memory offchainTransmitters,
uint8 f,
bytes memory onchainConfig,
uint64 offchainConfigVersion,
bytes memory offchainConfig
) internal pure returns (bytes32) {
uint256 h = uint256(
keccak256(
abi.encode(
feedId,
sourceChainId,
sourceAddress,
configCount,
signers,
offchainTransmitters,
f,
onchainConfig,
offchainConfigVersion,
offchainConfig
)
)
);
uint256 prefixMask = type(uint256).max << (256 - 16);
uint256 prefix = 0x0006 << (256 - 16);
return bytes32((prefix & prefixMask) | (h & ~prefixMask));
}
function activateConfig(bytes32 feedId, bytes32 configDigest) external onlyOwner {
VerifierState storage feedVerifierState = s_feedVerifierStates[feedId];
if (configDigest == bytes32("")) revert DigestEmpty();
if (feedVerifierState.s_verificationDataConfigs[configDigest].f == 0) revert DigestNotSet(feedId, configDigest);
feedVerifierState.s_verificationDataConfigs[configDigest].isActive = true;
emit ConfigActivated(feedId, configDigest);
}
function deactivateConfig(bytes32 feedId, bytes32 configDigest) external onlyOwner {
VerifierState storage feedVerifierState = s_feedVerifierStates[feedId];
if (configDigest == bytes32("")) revert DigestEmpty();
if (feedVerifierState.s_verificationDataConfigs[configDigest].f == 0) revert DigestNotSet(feedId, configDigest);
if (configDigest == feedVerifierState.latestConfigDigest) {
revert CannotDeactivateLatestConfig(feedId, configDigest);
}
feedVerifierState.s_verificationDataConfigs[configDigest].isActive = false;
emit ConfigDeactivated(feedId, configDigest);
}
function activateFeed(bytes32 feedId) external onlyOwner {
VerifierState storage feedVerifierState = s_feedVerifierStates[feedId];
if (feedVerifierState.configCount == 0) revert InvalidFeed(feedId);
feedVerifierState.isDeactivated = false;
emit FeedActivated(feedId);
}
function deactivateFeed(bytes32 feedId) external onlyOwner {
VerifierState storage feedVerifierState = s_feedVerifierStates[feedId];
if (feedVerifierState.configCount == 0) revert InvalidFeed(feedId);
feedVerifierState.isDeactivated = true;
emit FeedDeactivated(feedId);
}
function latestConfigDigestAndEpoch(
bytes32 feedId
) external view override returns (bool scanLogs, bytes32 configDigest, uint32 epoch) {
VerifierState storage feedVerifierState = s_feedVerifierStates[feedId];
return (false, feedVerifierState.latestConfigDigest, feedVerifierState.latestEpoch);
}
function latestConfigDetails(
bytes32 feedId
) external view override returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest) {
VerifierState storage feedVerifierState = s_feedVerifierStates[feedId];
return (
feedVerifierState.configCount,
feedVerifierState.latestConfigBlockNumber,
feedVerifierState.latestConfigDigest
);
}
}
文件 75 的 76:VerifierProxy.sol
pragma solidity 0.8.16;
import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol";
import {IVerifierProxy} from "./interfaces/IVerifierProxy.sol";
import {IVerifier} from "./interfaces/IVerifier.sol";
import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol";
import {AccessControllerInterface} from "../shared/interfaces/AccessControllerInterface.sol";
import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
import {IVerifierFeeManager} from "./interfaces/IVerifierFeeManager.sol";
import {Common} from "./libraries/Common.sol";
contract VerifierProxy is IVerifierProxy, ConfirmedOwner, TypeAndVersionInterface {
event VerifierSet(bytes32 oldConfigDigest, bytes32 newConfigDigest, address verifierAddress);
event VerifierInitialized(address verifierAddress);
event VerifierUnset(bytes32 configDigest, address verifierAddress);
event AccessControllerSet(address oldAccessController, address newAccessController);
event FeeManagerSet(address oldFeeManager, address newFeeManager);
error AccessForbidden();
error ZeroAddress();
error ConfigDigestAlreadySet(bytes32 configDigest, address verifier);
error VerifierAlreadyInitialized(address verifier);
error VerifierInvalid();
error FeeManagerInvalid();
error VerifierNotFound(bytes32 configDigest);
error BadVerification();
mapping(address => bool) private s_initializedVerifiers;
mapping(bytes32 => address) private s_verifiersByConfig;
AccessControllerInterface public s_accessController;
IVerifierFeeManager public s_feeManager;
constructor(AccessControllerInterface accessController) ConfirmedOwner(msg.sender) {
s_accessController = accessController;
}
modifier checkAccess() {
AccessControllerInterface ac = s_accessController;
if (address(ac) != address(0) && !ac.hasAccess(msg.sender, msg.data)) revert AccessForbidden();
_;
}
modifier onlyInitializedVerifier() {
if (!s_initializedVerifiers[msg.sender]) revert AccessForbidden();
_;
}
modifier onlyValidVerifier(address verifierAddress) {
if (verifierAddress == address(0)) revert ZeroAddress();
if (!IERC165(verifierAddress).supportsInterface(IVerifier.verify.selector)) revert VerifierInvalid();
_;
}
modifier onlyUnsetConfigDigest(bytes32 configDigest) {
address configDigestVerifier = s_verifiersByConfig[configDigest];
if (configDigestVerifier != address(0)) revert ConfigDigestAlreadySet(configDigest, configDigestVerifier);
_;
}
function typeAndVersion() external pure override returns (string memory) {
return "VerifierProxy 2.0.0";
}
function verify(
bytes calldata payload,
bytes calldata parameterPayload
) external payable checkAccess returns (bytes memory) {
IVerifierFeeManager feeManager = s_feeManager;
if (address(feeManager) != address(0)) {
feeManager.processFee{value: msg.value}(payload, parameterPayload, msg.sender);
}
return _verify(payload);
}
function verifyBulk(
bytes[] calldata payloads,
bytes calldata parameterPayload
) external payable checkAccess returns (bytes[] memory verifiedReports) {
IVerifierFeeManager feeManager = s_feeManager;
if (address(feeManager) != address(0)) {
feeManager.processFeeBulk{value: msg.value}(payloads, parameterPayload, msg.sender);
}
verifiedReports = new bytes[](payloads.length);
for (uint256 i; i < payloads.length; ++i) {
verifiedReports[i] = _verify(payloads[i]);
}
return verifiedReports;
}
function _verify(bytes calldata payload) internal returns (bytes memory verifiedReport) {
bytes32 configDigest = bytes32(payload);
address verifierAddress = s_verifiersByConfig[configDigest];
if (verifierAddress == address(0)) revert VerifierNotFound(configDigest);
return IVerifier(verifierAddress).verify(payload, msg.sender);
}
function initializeVerifier(address verifierAddress) external override onlyOwner onlyValidVerifier(verifierAddress) {
if (s_initializedVerifiers[verifierAddress]) revert VerifierAlreadyInitialized(verifierAddress);
s_initializedVerifiers[verifierAddress] = true;
emit VerifierInitialized(verifierAddress);
}
function setVerifier(
bytes32 currentConfigDigest,
bytes32 newConfigDigest,
Common.AddressAndWeight[] calldata addressesAndWeights
) external override onlyUnsetConfigDigest(newConfigDigest) onlyInitializedVerifier {
s_verifiersByConfig[newConfigDigest] = msg.sender;
if (addressesAndWeights.length > 0) {
if (address(s_feeManager) == address(0)) {
revert ZeroAddress();
}
s_feeManager.setFeeRecipients(newConfigDigest, addressesAndWeights);
}
emit VerifierSet(currentConfigDigest, newConfigDigest, msg.sender);
}
function unsetVerifier(bytes32 configDigest) external override onlyOwner {
address verifierAddress = s_verifiersByConfig[configDigest];
if (verifierAddress == address(0)) revert VerifierNotFound(configDigest);
delete s_verifiersByConfig[configDigest];
emit VerifierUnset(configDigest, verifierAddress);
}
function getVerifier(bytes32 configDigest) external view override returns (address) {
return s_verifiersByConfig[configDigest];
}
function setAccessController(AccessControllerInterface accessController) external onlyOwner {
address oldAccessController = address(s_accessController);
s_accessController = accessController;
emit AccessControllerSet(oldAccessController, address(accessController));
}
function setFeeManager(IVerifierFeeManager feeManager) external onlyOwner {
if (address(feeManager) == address(0)) revert ZeroAddress();
if (
!IERC165(feeManager).supportsInterface(IVerifierFeeManager.processFee.selector) ||
!IERC165(feeManager).supportsInterface(IVerifierFeeManager.processFeeBulk.selector)
) revert FeeManagerInvalid();
address oldFeeManager = address(s_feeManager);
s_feeManager = IVerifierFeeManager(feeManager);
emit FeeManagerSet(oldFeeManager, address(feeManager));
}
}
文件 76 的 76:draft-IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
{
"compilationTarget": {
"src/v0.8/llo-feeds/Verifier.sol": "Verifier"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 1000000
},
"remappings": [
":@eth-optimism/=node_modules/@eth-optimism/",
":@openzeppelin/=node_modules/@openzeppelin/",
":ds-test/=foundry-lib/forge-std/lib/ds-test/src/",
":erc4626-tests/=foundry-lib/openzeppelin-contracts/lib/erc4626-tests/",
":forge-std/=foundry-lib/forge-std/src/",
":hardhat/=node_modules/hardhat/",
":openzeppelin-contracts/=foundry-lib/openzeppelin-contracts/contracts/"
]
}
[{"inputs":[{"internalType":"address","name":"verifierProxyAddr","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessForbidden","type":"error"},{"inputs":[],"name":"BadVerification","type":"error"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"}],"name":"CannotDeactivateLatestConfig","type":"error"},{"inputs":[],"name":"DigestEmpty","type":"error"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"}],"name":"DigestInactive","type":"error"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"}],"name":"DigestNotSet","type":"error"},{"inputs":[{"internalType":"uint256","name":"numSigners","type":"uint256"},{"internalType":"uint256","name":"maxSigners","type":"uint256"}],"name":"ExcessSigners","type":"error"},{"inputs":[],"name":"FaultToleranceMustBePositive","type":"error"},{"inputs":[],"name":"FeedIdEmpty","type":"error"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"}],"name":"InactiveFeed","type":"error"},{"inputs":[{"internalType":"uint256","name":"numSigners","type":"uint256"},{"internalType":"uint256","name":"expectedNumSigners","type":"uint256"}],"name":"IncorrectSignatureCount","type":"error"},{"inputs":[{"internalType":"uint256","name":"numSigners","type":"uint256"},{"internalType":"uint256","name":"minSigners","type":"uint256"}],"name":"InsufficientSigners","type":"error"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"}],"name":"InvalidFeed","type":"error"},{"inputs":[{"internalType":"uint256","name":"rsLength","type":"uint256"},{"internalType":"uint256","name":"ssLength","type":"uint256"}],"name":"MismatchedSignatures","type":"error"},{"inputs":[],"name":"NonUniqueSignatures","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"feedId","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"}],"name":"ConfigActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"feedId","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"}],"name":"ConfigDeactivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"feedId","type":"bytes32"},{"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":"bytes32[]","name":"offchainTransmitters","type":"bytes32[]"},{"indexed":false,"internalType":"uint8","name":"f","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"onchainConfig","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"ConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"feedId","type":"bytes32"}],"name":"FeedActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"feedId","type":"bytes32"}],"name":"FeedDeactivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"feedId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"requester","type":"address"}],"name":"ReportVerified","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"}],"name":"activateConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"}],"name":"activateFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"}],"name":"deactivateConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"}],"name":"deactivateFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"}],"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":[{"internalType":"bytes32","name":"feedId","type":"bytes32"}],"name":"latestConfigDigestAndEpoch","outputs":[{"internalType":"bool","name":"scanLogs","type":"bool"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"internalType":"uint32","name":"epoch","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"bytes32[]","name":"offchainTransmitters","type":"bytes32[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"internalType":"bytes","name":"onchainConfig","type":"bytes"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"},{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint64","name":"weight","type":"uint64"}],"internalType":"struct Common.AddressAndWeight[]","name":"recipientAddressesAndWeights","type":"tuple[]"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"},{"internalType":"uint256","name":"sourceChainId","type":"uint256"},{"internalType":"address","name":"sourceAddress","type":"address"},{"internalType":"uint32","name":"newConfigCount","type":"uint32"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"bytes32[]","name":"offchainTransmitters","type":"bytes32[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"internalType":"bytes","name":"onchainConfig","type":"bytes"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"},{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint64","name":"weight","type":"uint64"}],"internalType":"struct Common.AddressAndWeight[]","name":"recipientAddressesAndWeights","type":"tuple[]"}],"name":"setConfigFromSource","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"isVerifier","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"signedReport","type":"bytes"},{"internalType":"address","name":"sender","type":"address"}],"name":"verify","outputs":[{"internalType":"bytes","name":"verifierResponse","type":"bytes"}],"stateMutability":"nonpayable","type":"function"}]