Contract
0x6179b349067af80d0c171f43e6d767e4a00775cd
8
Contract Overview
Balance:
0 MATIC
Token:
My Name Tag:
Not Available
[ Download CSV Export ]
Contract Name:
KeeperRegistry
Compiler Version
v0.7.6+commit.7338295f
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; contract KeeperBase { /** * @notice method that allows it to be simulated via eth_call by checking that * the sender is the zero address. */ function preventExecution() internal view { require(tx.origin == address(0), "only for simulated backend"); } /** * @notice modifier that allows it to be simulated via eth_call by checking * that the sender is the zero address. */ modifier cannotExecute() { preventExecution(); _; } }
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; import "@chainlink/contracts/src/v0.7/interfaces/LinkTokenInterface.sol"; import "@chainlink/contracts/src/v0.7/vendor/SafeMathChainlink.sol"; import "./vendor/Owned.sol"; import "./vendor/Address.sol"; import "./vendor/Pausable.sol"; import "./vendor/ReentrancyGuard.sol"; import "./vendor/SignedSafeMath.sol"; import "./SafeMath96.sol"; import "./KeeperBase.sol"; import "./KeeperCompatibleInterface.sol"; import "./KeeperRegistryInterface.sol"; /** * @notice Registry for adding work for Chainlink Keepers to perform on client * contracts. Clients must support the Upkeep interface. */ contract KeeperRegistry is Owned, KeeperBase, ReentrancyGuard, Pausable, KeeperRegistryExecutableInterface { using Address for address; using SafeMathChainlink for uint256; using SafeMath96 for uint96; using SignedSafeMath for int256; address constant private ZERO_ADDRESS = address(0); address constant private IGNORE_ADDRESS = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF; bytes4 constant private CHECK_SELECTOR = KeeperCompatibleInterface.checkUpkeep.selector; bytes4 constant private PERFORM_SELECTOR = KeeperCompatibleInterface.performUpkeep.selector; uint256 constant private CALL_GAS_MAX = 5_000_000; uint256 constant private CALL_GAS_MIN = 2_300; uint256 constant private CANCELATION_DELAY = 50; uint256 constant private CUSHION = 5_000; uint256 constant private REGISTRY_GAS_OVERHEAD = 80_000; uint256 constant private PPB_BASE = 1_000_000_000; uint64 constant private UINT64_MAX = 2**64 - 1; uint96 constant private LINK_TOTAL_SUPPLY = 1e27; uint256 private s_upkeepCount; uint256[] private s_canceledUpkeepList; address[] private s_keeperList; mapping(uint256 => Upkeep) private s_upkeep; mapping(address => KeeperInfo) private s_keeperInfo; mapping(address => address) private s_proposedPayee; mapping(uint256 => bytes) private s_checkData; Config private s_config; uint256 private s_fallbackGasPrice; // not in config object for gas savings uint256 private s_fallbackLinkPrice; // not in config object for gas savings uint256 private s_expectedLinkBalance; LinkTokenInterface public immutable LINK; AggregatorV3Interface public immutable LINK_ETH_FEED; AggregatorV3Interface public immutable FAST_GAS_FEED; address private s_registrar; struct Upkeep { address target; uint32 executeGas; uint96 balance; address admin; uint64 maxValidBlocknumber; address lastKeeper; } struct KeeperInfo { address payee; uint96 balance; bool active; } struct Config { uint32 paymentPremiumPPB; uint24 blockCountPerTurn; uint32 checkGasLimit; uint24 stalenessSeconds; uint16 gasCeilingMultiplier; } struct PerformParams { address from; uint256 id; bytes performData; uint256 maxLinkPayment; uint256 gasLimit; uint256 adjustedGasWei; uint256 linkEth; } event UpkeepRegistered( uint256 indexed id, uint32 executeGas, address admin ); event UpkeepPerformed( uint256 indexed id, bool indexed success, address indexed from, uint96 payment, bytes performData ); event UpkeepCanceled( uint256 indexed id, uint64 indexed atBlockHeight ); event FundsAdded( uint256 indexed id, address indexed from, uint96 amount ); event FundsWithdrawn( uint256 indexed id, uint256 amount, address to ); event ConfigSet( uint32 paymentPremiumPPB, uint24 blockCountPerTurn, uint32 checkGasLimit, uint24 stalenessSeconds, uint16 gasCeilingMultiplier, uint256 fallbackGasPrice, uint256 fallbackLinkPrice ); event KeepersUpdated( address[] keepers, address[] payees ); event PaymentWithdrawn( address indexed keeper, uint256 indexed amount, address indexed to, address payee ); event PayeeshipTransferRequested( address indexed keeper, address indexed from, address indexed to ); event PayeeshipTransferred( address indexed keeper, address indexed from, address indexed to ); event RegistrarChanged( address indexed from, address indexed to ); /** * @param link address of the LINK Token * @param linkEthFeed address of the LINK/ETH price feed * @param fastGasFeed address of the Fast Gas price feed * @param paymentPremiumPPB payment premium rate oracles receive on top of * being reimbursed for gas, measured in parts per billion * @param blockCountPerTurn number of blocks each oracle has during their turn to * perform upkeep before it will be the next keeper's turn to submit * @param checkGasLimit gas limit when checking for upkeep * @param stalenessSeconds number of seconds that is allowed for feed data to * be stale before switching to the fallback pricing * @param gasCeilingMultiplier multiplier to apply to the fast gas feed price * when calculating the payment ceiling for keepers * @param fallbackGasPrice gas price used if the gas price feed is stale * @param fallbackLinkPrice LINK price used if the LINK price feed is stale */ constructor( address link, address linkEthFeed, address fastGasFeed, uint32 paymentPremiumPPB, uint24 blockCountPerTurn, uint32 checkGasLimit, uint24 stalenessSeconds, uint16 gasCeilingMultiplier, uint256 fallbackGasPrice, uint256 fallbackLinkPrice ) { LINK = LinkTokenInterface(link); LINK_ETH_FEED = AggregatorV3Interface(linkEthFeed); FAST_GAS_FEED = AggregatorV3Interface(fastGasFeed); setConfig( paymentPremiumPPB, blockCountPerTurn, checkGasLimit, stalenessSeconds, gasCeilingMultiplier, fallbackGasPrice, fallbackLinkPrice ); } // ACTIONS /** * @notice adds a new upkeep * @param target address to perform upkeep on * @param gasLimit amount of gas to provide the target contract when * performing upkeep * @param admin address to cancel upkeep and withdraw remaining funds * @param checkData data passed to the contract when checking for upkeep */ function registerUpkeep( address target, uint32 gasLimit, address admin, bytes calldata checkData ) external override onlyOwnerOrRegistrar() returns ( uint256 id ) { require(target.isContract(), "target is not a contract"); require(gasLimit >= CALL_GAS_MIN, "min gas is 2300"); require(gasLimit <= CALL_GAS_MAX, "max gas is 5000000"); id = s_upkeepCount; s_upkeep[id] = Upkeep({ target: target, executeGas: gasLimit, balance: 0, admin: admin, maxValidBlocknumber: UINT64_MAX, lastKeeper: address(0) }); s_checkData[id] = checkData; s_upkeepCount++; emit UpkeepRegistered(id, gasLimit, admin); return id; } /** * @notice simulated by keepers via eth_call to see if the upkeep needs to be * performed. If upkeep is needed, the call then simulates performUpkeep * to make sure it succeeds. Finally, it returns the success status along with * payment information and the perform data payload. * @param id identifier of the upkeep to check * @param from the address to simulate performing the upkeep from */ function checkUpkeep( uint256 id, address from ) external override whenNotPaused() cannotExecute() returns ( bytes memory performData, uint256 maxLinkPayment, uint256 gasLimit, uint256 adjustedGasWei, uint256 linkEth ) { bytes memory callData = abi.encodeWithSelector(CHECK_SELECTOR, s_checkData[id]); ( bool success, bytes memory result ) = s_upkeep[id].target.call{gas: s_config.checkGasLimit}(callData); if (!success) { string memory upkeepRevertReason = getRevertMsg(result); string memory reason = string(abi.encodePacked("call to check target failed: ", upkeepRevertReason)); revert(reason); } ( success, performData ) = abi.decode(result, (bool, bytes)); require(success, "upkeep not needed"); PerformParams memory params = generatePerformParams(from, id, performData, false); success = performUpkeepWithParams(params); require(success, "call to perform upkeep failed"); return (performData, params.maxLinkPayment, params.gasLimit, params.adjustedGasWei, params.linkEth); } /** * @notice executes the upkeep with the perform data returned from * checkUpkeep, validates the keeper's permissions, and pays the keeper. * @param id identifier of the upkeep to execute the data with. * @param performData calldata parameter to be passed to the target upkeep. */ function performUpkeep( uint256 id, bytes calldata performData ) external override returns ( bool success ) { return performUpkeepWithParams(generatePerformParams( msg.sender, id, performData, true )); } /** * @notice prevent an upkeep from being performed in the future * @param id upkeep to be canceled */ function cancelUpkeep( uint256 id ) external override { uint64 maxValid = s_upkeep[id].maxValidBlocknumber; bool notCanceled = maxValid == UINT64_MAX; bool isOwner = msg.sender == owner; require(notCanceled || (isOwner && maxValid > block.number), "too late to cancel upkeep"); require(isOwner || msg.sender == s_upkeep[id].admin, "only owner or admin"); uint256 height = block.number; if (!isOwner) { height = height.add(CANCELATION_DELAY); } s_upkeep[id].maxValidBlocknumber = uint64(height); if (notCanceled) { s_canceledUpkeepList.push(id); } emit UpkeepCanceled(id, uint64(height)); } /** * @notice adds LINK funding for an upkeep by tranferring from the sender's * LINK balance * @param id upkeep to fund * @param amount number of LINK to transfer */ function addFunds( uint256 id, uint96 amount ) external override { require(s_upkeep[id].maxValidBlocknumber == UINT64_MAX, "upkeep must be active"); s_upkeep[id].balance = s_upkeep[id].balance.add(amount); s_expectedLinkBalance = s_expectedLinkBalance.add(amount); LINK.transferFrom(msg.sender, address(this), amount); emit FundsAdded(id, msg.sender, amount); } /** * @notice uses LINK's transferAndCall to LINK and add funding to an upkeep * @dev safe to cast uint256 to uint96 as total LINK supply is under UINT96MAX * @param sender the account which transferred the funds * @param amount number of LINK transfer */ function onTokenTransfer( address sender, uint256 amount, bytes calldata data ) external { require(msg.sender == address(LINK), "only callable through LINK"); require(data.length == 32, "data must be 32 bytes"); uint256 id = abi.decode(data, (uint256)); require(s_upkeep[id].maxValidBlocknumber == UINT64_MAX, "upkeep must be active"); s_upkeep[id].balance = s_upkeep[id].balance.add(uint96(amount)); s_expectedLinkBalance = s_expectedLinkBalance.add(amount); emit FundsAdded(id, sender, uint96(amount)); } /** * @notice removes funding from a canceled upkeep * @param id upkeep to withdraw funds from * @param to destination address for sending remaining funds */ function withdrawFunds( uint256 id, address to ) external validateRecipient(to) { require(s_upkeep[id].admin == msg.sender, "only callable by admin"); require(s_upkeep[id].maxValidBlocknumber <= block.number, "upkeep must be canceled"); uint256 amount = s_upkeep[id].balance; s_upkeep[id].balance = 0; s_expectedLinkBalance = s_expectedLinkBalance.sub(amount); emit FundsWithdrawn(id, amount, to); LINK.transfer(to, amount); } /** * @notice recovers LINK funds improperly transfered to the registry * @dev In principle this function’s execution cost could exceed block * gaslimit. However, in our anticipated deployment, the number of upkeeps and * keepers will be low enough to avoid this problem. */ function recoverFunds() external onlyOwner() { uint256 total = LINK.balanceOf(address(this)); LINK.transfer(msg.sender, total.sub(s_expectedLinkBalance)); } /** * @notice withdraws a keeper's payment, callable only by the keeper's payee * @param from keeper address * @param to address to send the payment to */ function withdrawPayment( address from, address to ) external validateRecipient(to) { KeeperInfo memory keeper = s_keeperInfo[from]; require(keeper.payee == msg.sender, "only callable by payee"); s_keeperInfo[from].balance = 0; s_expectedLinkBalance = s_expectedLinkBalance.sub(keeper.balance); emit PaymentWithdrawn(from, keeper.balance, to, msg.sender); LINK.transfer(to, keeper.balance); } /** * @notice proposes the safe transfer of a keeper's payee to another address * @param keeper address of the keeper to transfer payee role * @param proposed address to nominate for next payeeship */ function transferPayeeship( address keeper, address proposed ) external { require(s_keeperInfo[keeper].payee == msg.sender, "only callable by payee"); require(proposed != msg.sender, "cannot transfer to self"); if (s_proposedPayee[keeper] != proposed) { s_proposedPayee[keeper] = proposed; emit PayeeshipTransferRequested(keeper, msg.sender, proposed); } } /** * @notice accepts the safe transfer of payee role for a keeper * @param keeper address to accept the payee role for */ function acceptPayeeship( address keeper ) external { require(s_proposedPayee[keeper] == msg.sender, "only callable by proposed payee"); address past = s_keeperInfo[keeper].payee; s_keeperInfo[keeper].payee = msg.sender; s_proposedPayee[keeper] = ZERO_ADDRESS; emit PayeeshipTransferred(keeper, past, msg.sender); } /** * @notice signals to keepers that they should not perform upkeeps until the * contract has been unpaused */ function pause() external onlyOwner() { _pause(); } /** * @notice signals to keepers that they can perform upkeeps once again after * having been paused */ function unpause() external onlyOwner() { _unpause(); } // SETTERS /** * @notice updates the configuration of the registry * @param paymentPremiumPPB payment premium rate oracles receive on top of * being reimbursed for gas, measured in parts per billion * @param blockCountPerTurn number of blocks an oracle should wait before * checking for upkeep * @param checkGasLimit gas limit when checking for upkeep * @param stalenessSeconds number of seconds that is allowed for feed data to * be stale before switching to the fallback pricing * @param fallbackGasPrice gas price used if the gas price feed is stale * @param fallbackLinkPrice LINK price used if the LINK price feed is stale */ function setConfig( uint32 paymentPremiumPPB, uint24 blockCountPerTurn, uint32 checkGasLimit, uint24 stalenessSeconds, uint16 gasCeilingMultiplier, uint256 fallbackGasPrice, uint256 fallbackLinkPrice ) onlyOwner() public { s_config = Config({ paymentPremiumPPB: paymentPremiumPPB, blockCountPerTurn: blockCountPerTurn, checkGasLimit: checkGasLimit, stalenessSeconds: stalenessSeconds, gasCeilingMultiplier: gasCeilingMultiplier }); s_fallbackGasPrice = fallbackGasPrice; s_fallbackLinkPrice = fallbackLinkPrice; emit ConfigSet( paymentPremiumPPB, blockCountPerTurn, checkGasLimit, stalenessSeconds, gasCeilingMultiplier, fallbackGasPrice, fallbackLinkPrice ); } /** * @notice update the list of keepers allowed to perform upkeep * @param keepers list of addresses allowed to perform upkeep * @param payees addreses corresponding to keepers who are allowed to * move payments which have been accrued */ function setKeepers( address[] calldata keepers, address[] calldata payees ) external onlyOwner() { require(keepers.length == payees.length, "address lists not the same length"); require(keepers.length >= 2, "not enough keepers"); for (uint256 i = 0; i < s_keeperList.length; i++) { address keeper = s_keeperList[i]; s_keeperInfo[keeper].active = false; } for (uint256 i = 0; i < keepers.length; i++) { address keeper = keepers[i]; KeeperInfo storage s_keeper = s_keeperInfo[keeper]; address oldPayee = s_keeper.payee; address newPayee = payees[i]; require(newPayee != address(0), "cannot set payee to the zero address"); require(oldPayee == ZERO_ADDRESS || oldPayee == newPayee || newPayee == IGNORE_ADDRESS, "cannot change payee"); require(!s_keeper.active, "cannot add keeper twice"); s_keeper.active = true; if (newPayee != IGNORE_ADDRESS) { s_keeper.payee = newPayee; } } s_keeperList = keepers; emit KeepersUpdated(keepers, payees); } /** * @notice update registrar * @param registrar new registrar */ function setRegistrar( address registrar ) external onlyOwnerOrRegistrar() { address previous = s_registrar; require(registrar != previous, "Same registrar"); s_registrar = registrar; emit RegistrarChanged(previous, registrar); } // GETTERS /** * @notice read all of the details about an upkeep */ function getUpkeep( uint256 id ) external view override returns ( address target, uint32 executeGas, bytes memory checkData, uint96 balance, address lastKeeper, address admin, uint64 maxValidBlocknumber ) { Upkeep memory reg = s_upkeep[id]; return ( reg.target, reg.executeGas, s_checkData[id], reg.balance, reg.lastKeeper, reg.admin, reg.maxValidBlocknumber ); } /** * @notice read the total number of upkeep's registered */ function getUpkeepCount() external view override returns ( uint256 ) { return s_upkeepCount; } /** * @notice read the current list canceled upkeep IDs */ function getCanceledUpkeepList() external view override returns ( uint256[] memory ) { return s_canceledUpkeepList; } /** * @notice read the current list of addresses allowed to perform upkeep */ function getKeeperList() external view override returns ( address[] memory ) { return s_keeperList; } /** * @notice read the current registrar */ function getRegistrar() external view returns ( address ) { return s_registrar; } /** * @notice read the current info about any keeper address */ function getKeeperInfo( address query ) external view override returns ( address payee, bool active, uint96 balance ) { KeeperInfo memory keeper = s_keeperInfo[query]; return (keeper.payee, keeper.active, keeper.balance); } /** * @notice read the current configuration of the registry */ function getConfig() external view override returns ( uint32 paymentPremiumPPB, uint24 blockCountPerTurn, uint32 checkGasLimit, uint24 stalenessSeconds, uint16 gasCeilingMultiplier, uint256 fallbackGasPrice, uint256 fallbackLinkPrice ) { Config memory config = s_config; return ( config.paymentPremiumPPB, config.blockCountPerTurn, config.checkGasLimit, config.stalenessSeconds, config.gasCeilingMultiplier, s_fallbackGasPrice, s_fallbackLinkPrice ); } /** * @notice calculates the minimum balance required for an upkeep to remain eligible */ function getMinBalanceForUpkeep( uint256 id ) external view returns ( uint96 minBalance ) { return getMaxPaymentForGas(s_upkeep[id].executeGas); } /** * @notice calculates the maximum payment for a given gas limit */ function getMaxPaymentForGas( uint256 gasLimit ) public view returns ( uint96 maxPayment ) { (uint256 gasWei, uint256 linkEth) = getFeedData(); uint256 adjustedGasWei = adjustGasPrice(gasWei, false); return calculatePaymentAmount(gasLimit, adjustedGasWei, linkEth); } // PRIVATE /** * @dev retrieves feed data for fast gas/eth and link/eth prices. if the feed * data is stale it uses the configured fallback price. Once a price is picked * for gas it takes the min of gas price in the transaction or the fast gas * price in order to reduce costs for the upkeep clients. */ function getFeedData() private view returns ( uint256 gasWei, uint256 linkEth ) { uint32 stalenessSeconds = s_config.stalenessSeconds; bool staleFallback = stalenessSeconds > 0; uint256 timestamp; int256 feedValue; (,feedValue,,timestamp,) = FAST_GAS_FEED.latestRoundData(); if (staleFallback && stalenessSeconds < block.timestamp - timestamp || feedValue <=0) { gasWei = s_fallbackGasPrice; } else { gasWei = uint256(feedValue); } (,feedValue,,timestamp,) = LINK_ETH_FEED.latestRoundData(); if (staleFallback && stalenessSeconds < block.timestamp - timestamp || feedValue <=0) { linkEth = s_fallbackLinkPrice; } else { linkEth = uint256(feedValue); } return (gasWei, linkEth); } /** * @dev calculates LINK paid for gas spent plus a configure premium percentage */ function calculatePaymentAmount( uint256 gasLimit, uint256 gasWei, uint256 linkEth ) private view returns ( uint96 payment ) { uint256 weiForGas = gasWei.mul(gasLimit.add(REGISTRY_GAS_OVERHEAD)); uint256 premium = PPB_BASE.add(s_config.paymentPremiumPPB); uint256 total = weiForGas.mul(1e9).mul(premium).div(linkEth); require(total <= LINK_TOTAL_SUPPLY, "payment greater than all LINK"); return uint96(total); // LINK_TOTAL_SUPPLY < UINT96_MAX } /** * @dev calls target address with exactly gasAmount gas and data as calldata * or reverts if at least gasAmount gas is not available */ function callWithExactGas( uint256 gasAmount, address target, bytes memory data ) private returns ( bool success ) { assembly{ let g := gas() // Compute g -= CUSHION and check for underflow if lt(g, CUSHION) { revert(0, 0) } g := sub(g, CUSHION) // if g - g//64 <= gasAmount, revert // (we subtract g//64 because of EIP-150) if iszero(gt(sub(g, div(g, 64)), gasAmount)) { revert(0, 0) } // solidity calls check that a contract actually exists at the destination, so we do the same if iszero(extcodesize(target)) { revert(0, 0) } // call and return whether we succeeded. ignore return data success := call(gasAmount, target, 0, add(data, 0x20), mload(data), 0, 0) } return success; } /** * @dev calls the Upkeep target with the performData param passed in by the * keeper and the exact gas required by the Upkeep */ function performUpkeepWithParams( PerformParams memory params ) private nonReentrant() validUpkeep(params.id) returns ( bool success ) { require(s_keeperInfo[params.from].active, "only active keepers"); Upkeep memory upkeep = s_upkeep[params.id]; require(upkeep.balance >= params.maxLinkPayment, "insufficient funds"); require(upkeep.lastKeeper != params.from, "keepers must take turns"); uint256 gasUsed = gasleft(); bytes memory callData = abi.encodeWithSelector(PERFORM_SELECTOR, params.performData); success = callWithExactGas(params.gasLimit, upkeep.target, callData); gasUsed = gasUsed - gasleft(); uint96 payment = calculatePaymentAmount(gasUsed, params.adjustedGasWei, params.linkEth); upkeep.balance = upkeep.balance.sub(payment); upkeep.lastKeeper = params.from; s_upkeep[params.id] = upkeep; uint96 newBalance = s_keeperInfo[params.from].balance.add(payment); s_keeperInfo[params.from].balance = newBalance; emit UpkeepPerformed( params.id, success, params.from, payment, params.performData ); return success; } /** * @dev ensures a upkeep is valid */ function validateUpkeep( uint256 id ) private view { require(s_upkeep[id].maxValidBlocknumber > block.number, "invalid upkeep id"); } /** * @dev adjusts the gas price to min(ceiling, tx.gasprice) or just uses the ceiling if tx.gasprice is disabled */ function adjustGasPrice( uint256 gasWei, bool useTxGasPrice ) private view returns(uint256 adjustedPrice) { adjustedPrice = gasWei.mul(s_config.gasCeilingMultiplier); if (useTxGasPrice && tx.gasprice < adjustedPrice) { adjustedPrice = tx.gasprice; } } /** * @dev generates a PerformParams struct for use in performUpkeepWithParams() */ function generatePerformParams( address from, uint256 id, bytes memory performData, bool useTxGasPrice ) private view returns(PerformParams memory) { uint256 gasLimit = s_upkeep[id].executeGas; (uint256 gasWei, uint256 linkEth) = getFeedData(); uint256 adjustedGasWei = adjustGasPrice(gasWei, useTxGasPrice); uint96 maxLinkPayment = calculatePaymentAmount(gasLimit, adjustedGasWei, linkEth); return PerformParams({ from: from, id: id, performData: performData, maxLinkPayment: maxLinkPayment, gasLimit: gasLimit, adjustedGasWei: adjustedGasWei, linkEth: linkEth }); } /** * @dev extracts a revert reason from a call result payload */ function getRevertMsg(bytes memory _payload) private pure returns (string memory) { if (_payload.length < 68) return 'transaction reverted silently'; assembly { _payload := add(_payload, 0x04) } return abi.decode(_payload, (string)); } // MODIFIERS /** * @dev ensures a upkeep is valid */ modifier validUpkeep( uint256 id ) { validateUpkeep(id); _; } /** * @dev ensures that burns don't accidentally happen by sending to the zero * address */ modifier validateRecipient( address to ) { require(to != address(0), "cannot send to zero address"); _; } /** * @dev Reverts if called by anyone other than the contract owner or registrar. */ modifier onlyOwnerOrRegistrar() { require(msg.sender == owner || msg.sender == s_registrar, "Only callable by owner or registrar"); _; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0; interface AggregatorV3Interface { function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint256); // getRoundData and latestRoundData should both raise "No data present" // if they do not have data to report, instead of returning unset values // which could be misinterpreted as actual reported values. function getRoundData(uint80 _roundId) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; interface LinkTokenInterface { function allowance(address owner, address spender) external view returns (uint256 remaining); function approve(address spender, uint256 value) external returns (bool success); function balanceOf(address owner) external view returns (uint256 balance); function decimals() external view returns (uint8 decimalPlaces); function decreaseApproval(address spender, uint256 addedValue) external returns (bool success); function increaseApproval(address spender, uint256 subtractedValue) external; function name() external view returns (string memory tokenName); function symbol() external view returns (string memory tokenSymbol); function totalSupply() external view returns (uint256 totalTokensIssued); function transfer(address to, uint256 value) external returns (bool success); function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool success); function transferFrom(address from, address to, uint256 value) external returns (bool success); }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMathChainlink { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, "SafeMath: division by zero"); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, "SafeMath: modulo by zero"); return a % b; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @title The Owned contract * @notice A contract with helpers for basic contract ownership. */ contract Owned { address public owner; address private pendingOwner; event OwnershipTransferRequested( address indexed from, address indexed to ); event OwnershipTransferred( address indexed from, address indexed to ); constructor() { owner = msg.sender; } /** * @dev Allows an owner to begin transferring ownership to a new address, * pending. */ function transferOwnership(address _to) external onlyOwner() { pendingOwner = _to; emit OwnershipTransferRequested(owner, _to); } /** * @dev Allows an ownership transfer to be completed by the recipient. */ function acceptOwnership() external { require(msg.sender == pendingOwner, "Must be proposed owner"); address oldOwner = owner; owner = msg.sender; pendingOwner = address(0); emit OwnershipTransferred(oldOwner, msg.sender); } /** * @dev Reverts if called by anyone other than the contract owner. */ modifier onlyOwner() { require(msg.sender == owner, "Only callable by owner"); _; } }
// SPDX-License-Identifier: MIT // github.com/OpenZeppelin/[email protected] pragma solidity >=0.6.2 <0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT // github.com/OpenZeppelin/[email protected] pragma solidity >=0.6.0 <0.8.0; import "./Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor () { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!paused(), "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(paused(), "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT // github.com/OpenZeppelin/[email protected] pragma solidity >=0.6.0 <0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor () { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @title SignedSafeMath * @dev Signed math operations with safety checks that revert on error. */ library SignedSafeMath { int256 constant private _INT256_MIN = -2**255; /** * @dev Returns the multiplication of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(int256 a, int256 b) internal pure returns (int256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow"); int256 c = a * b; require(c / a == b, "SignedSafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two signed integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(int256 a, int256 b) internal pure returns (int256) { require(b != 0, "SignedSafeMath: division by zero"); require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow"); int256 c = a / b; return c; } /** * @dev Returns the subtraction of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(int256 a, int256 b) internal pure returns (int256) { int256 c = a - b; require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow"); return c; } /** * @dev Returns the addition of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(int256 a, int256 b) internal pure returns (int256) { int256 c = a + b; require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow"); return c; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * This library is a version of Open Zeppelin's SafeMath, modified to support * unsigned 96 bit integers. */ library SafeMath96 { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint96 a, uint96 b) internal pure returns (uint96) { uint96 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint96 a, uint96 b) internal pure returns (uint96) { require(b <= a, "SafeMath: subtraction overflow"); uint96 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint96 a, uint96 b) internal pure returns (uint96) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (a == 0) { return 0; } uint96 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint96 a, uint96 b) internal pure returns (uint96) { // Solidity only automatically asserts when dividing by 0 require(b > 0, "SafeMath: division by zero"); uint96 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint96 a, uint96 b) internal pure returns (uint96) { require(b != 0, "SafeMath: modulo by zero"); return a % b; } }
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; interface KeeperCompatibleInterface { /** * @notice method that is simulated by the keepers to see if any work actually * needs to be performed. This method does does not actually need to be * executable, and since it is only ever simulated it can consume lots of gas. * @dev To ensure that it is never called, you may want to add the * cannotExecute modifier from KeeperBase to your implementation of this * method. * @param checkData specified in the upkeep registration so it is always the * same for a registered upkeep. This can easilly be broken down into specific * arguments using `abi.decode`, so multiple upkeeps can be registered on the * same contract and easily differentiated by the contract. * @return upkeepNeeded boolean to indicate whether the keeper should call * performUpkeep or not. * @return performData bytes that the keeper should call performUpkeep with, if * upkeep is needed. If you would like to encode data to decode later, try * `abi.encode`. */ function checkUpkeep( bytes calldata checkData ) external returns ( bool upkeepNeeded, bytes memory performData ); /** * @notice method that is actually executed by the keepers, via the registry. * The data returned by the checkUpkeep simulation will be passed into * this method to actually be executed. * @dev The input to this method should not be trusted, and the caller of the * method should not even be restricted to any single registry. Anyone should * be able call it, and the input should be validated, there is no guarantee * that the data passed in is the performData returned from checkUpkeep. This * could happen due to malicious keepers, racing keepers, or simply a state * change while the performUpkeep transaction is waiting for confirmation. * Always validate the data passed in. * @param performData is the data which was passed back from the checkData * simulation. If it is encoded, it can easily be decoded into other types by * calling `abi.decode`. This data should not be trusted, and should be * validated against the contract's current state. */ function performUpkeep( bytes calldata performData ) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; interface KeeperRegistryBaseInterface { function registerUpkeep( address target, uint32 gasLimit, address admin, bytes calldata checkData ) external returns ( uint256 id ); function performUpkeep( uint256 id, bytes calldata performData ) external returns ( bool success ); function cancelUpkeep( uint256 id ) external; function addFunds( uint256 id, uint96 amount ) external; function getUpkeep(uint256 id) external view returns ( address target, uint32 executeGas, bytes memory checkData, uint96 balance, address lastKeeper, address admin, uint64 maxValidBlocknumber ); function getUpkeepCount() external view returns (uint256); function getCanceledUpkeepList() external view returns (uint256[] memory); function getKeeperList() external view returns (address[] memory); function getKeeperInfo(address query) external view returns ( address payee, bool active, uint96 balance ); function getConfig() external view returns ( uint32 paymentPremiumPPB, uint24 checkFrequencyBlocks, uint32 checkGasLimit, uint24 stalenessSeconds, uint16 gasCeilingMultiplier, uint256 fallbackGasPrice, uint256 fallbackLinkPrice ); } /** * @dev The view methods are not actually marked as view in the implementation * but we want them to be easily queried off-chain. Solidity will not compile * if we actually inherrit from this interface, so we document it here. */ interface KeeperRegistryInterface is KeeperRegistryBaseInterface { function checkUpkeep( uint256 upkeepId, address from ) external view returns ( bytes memory performData, uint256 maxLinkPayment, uint256 gasLimit, int256 gasWei, int256 linkEth ); } interface KeeperRegistryExecutableInterface is KeeperRegistryBaseInterface { function checkUpkeep( uint256 upkeepId, address from ) external returns ( bytes memory performData, uint256 maxLinkPayment, uint256 gasLimit, uint256 adjustedGasWei, uint256 linkEth ); }
// SPDX-License-Identifier: MIT // github.com/OpenZeppelin/[email protected] pragma solidity >=0.6.0 <0.8.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "@chainlink/contracts/src/v0.7/interfaces/LinkTokenInterface.sol"; import "./vendor/Owned.sol"; import "./KeeperRegistryInterface.sol"; import "./SafeMath96.sol"; /** * @notice Contract to accept requests for upkeep registrations * @dev There are 2 registration workflows in this contract * Flow 1. auto approve OFF / manual registration - UI calls `register` function on this contract, this contract owner at a later time then manually * calls `approve` to register upkeep and emit events to inform UI and others interested. * Flow 2. auto approve ON / real time registration - UI calls `register` function as before, which calls the `registerUpkeep` function directly on * keeper registry and then emits approved event to finish the flow automatically without manual intervention. * The idea is to have same interface(functions,events) for UI or anyone using this contract irrespective of auto approve being enabled or not. * they can just listen to `RegistrationRequested` & `RegistrationApproved` events and know the status on registrations. */ contract UpkeepRegistrationRequests is Owned { using SafeMath96 for uint96; bytes4 private constant REGISTER_REQUEST_SELECTOR = this.register.selector; uint256 private s_minLINKJuels; mapping(bytes32 => PendingRequest) private s_pendingRequests; LinkTokenInterface public immutable LINK; struct AutoApprovedConfig { bool enabled; uint16 allowedPerWindow; uint32 windowSizeInBlocks; uint64 windowStart; uint16 approvedInCurrentWindow; } struct PendingRequest { address admin; uint96 balance; } AutoApprovedConfig private s_config; KeeperRegistryBaseInterface private s_keeperRegistry; event RegistrationRequested( bytes32 indexed hash, string name, bytes encryptedEmail, address indexed upkeepContract, uint32 gasLimit, address adminAddress, bytes checkData, uint96 amount, uint8 indexed source ); event RegistrationApproved( bytes32 indexed hash, string displayName, uint256 indexed upkeepId ); event RegistrationRejected( bytes32 indexed hash ); event ConfigChanged( bool enabled, uint32 windowSizeInBlocks, uint16 allowedPerWindow, address keeperRegistry, uint256 minLINKJuels ); constructor( address LINKAddress, uint256 minimumLINKJuels ) { LINK = LinkTokenInterface(LINKAddress); s_minLINKJuels = minimumLINKJuels; } //EXTERNAL /** * @notice register can only be called through transferAndCall on LINK contract * @param name string of the upkeep to be registered * @param encryptedEmail email address of upkeep contact * @param upkeepContract address to peform upkeep on * @param gasLimit amount of gas to provide the target contract when performing upkeep * @param adminAddress address to cancel upkeep and withdraw remaining funds * @param checkData data passed to the contract when checking for upkeep * @param amount quantity of LINK upkeep is funded with (specified in Juels) * @param source application sending this request */ function register( string memory name, bytes calldata encryptedEmail, address upkeepContract, uint32 gasLimit, address adminAddress, bytes calldata checkData, uint96 amount, uint8 source ) external onlyLINK() { require(adminAddress != address(0), "invalid admin address"); bytes32 hash = keccak256(abi.encode(upkeepContract, gasLimit, adminAddress, checkData)); emit RegistrationRequested( hash, name, encryptedEmail, upkeepContract, gasLimit, adminAddress, checkData, amount, source ); AutoApprovedConfig memory config = s_config; if (config.enabled && _underApprovalLimit(config)) { _incrementApprovedCount(config); _approve( name, upkeepContract, gasLimit, adminAddress, checkData, amount, hash ); } else { uint96 newBalance = s_pendingRequests[hash].balance.add(amount); s_pendingRequests[hash] = PendingRequest({ admin: adminAddress, balance: newBalance }); } } /** * @dev register upkeep on KeeperRegistry contract and emit RegistrationApproved event */ function approve( string memory name, address upkeepContract, uint32 gasLimit, address adminAddress, bytes calldata checkData, bytes32 hash ) external onlyOwner() { PendingRequest memory request = s_pendingRequests[hash]; require(request.admin != address(0), "request not found"); bytes32 expectedHash = keccak256(abi.encode(upkeepContract, gasLimit, adminAddress, checkData)); require(hash == expectedHash, "hash and payload do not match"); delete s_pendingRequests[hash]; _approve( name, upkeepContract, gasLimit, adminAddress, checkData, request.balance, hash ); } /** * @notice cancel will remove a registration request and return the refunds to the msg.sender * @param hash the request hash */ function cancel( bytes32 hash ) external { PendingRequest memory request = s_pendingRequests[hash]; require(msg.sender == request.admin || msg.sender == owner, "only admin / owner can cancel"); require(request.admin != address(0), "request not found"); delete s_pendingRequests[hash]; require(LINK.transfer(msg.sender, request.balance), "LINK token transfer failed"); emit RegistrationRejected(hash); } /** * @notice owner calls this function to set if registration requests should be sent directly to the Keeper Registry * @param enabled setting for autoapprove registrations * @param windowSizeInBlocks window size defined in number of blocks * @param allowedPerWindow number of registrations that can be auto approved in above window * @param keeperRegistry new keeper registry address */ function setRegistrationConfig( bool enabled, uint32 windowSizeInBlocks, uint16 allowedPerWindow, address keeperRegistry, uint256 minLINKJuels ) external onlyOwner() { s_config = AutoApprovedConfig({ enabled: enabled, allowedPerWindow: allowedPerWindow, windowSizeInBlocks: windowSizeInBlocks, windowStart: 0, approvedInCurrentWindow: 0 }); s_minLINKJuels = minLINKJuels; s_keeperRegistry = KeeperRegistryBaseInterface(keeperRegistry); emit ConfigChanged( enabled, windowSizeInBlocks, allowedPerWindow, keeperRegistry, minLINKJuels ); } /** * @notice read the current registration configuration */ function getRegistrationConfig() external view returns ( bool enabled, uint32 windowSizeInBlocks, uint16 allowedPerWindow, address keeperRegistry, uint256 minLINKJuels, uint64 windowStart, uint16 approvedInCurrentWindow ) { AutoApprovedConfig memory config = s_config; return ( config.enabled, config.windowSizeInBlocks, config.allowedPerWindow, address(s_keeperRegistry), s_minLINKJuels, config.windowStart, config.approvedInCurrentWindow ); } /** * @notice gets the admin address and the current balance of a registration request */ function getPendingRequest(bytes32 hash) external view returns(address, uint96) { PendingRequest memory request = s_pendingRequests[hash]; return (request.admin, request.balance); } /** * @notice Called when LINK is sent to the contract via `transferAndCall` * @param amount Amount of LINK sent (specified in Juels) * @param data Payload of the transaction */ function onTokenTransfer( address, /* sender */ uint256 amount, bytes calldata data ) external onlyLINK() permittedFunctionsForLINK(data) isActualAmount(amount, data) { require(amount >= s_minLINKJuels, "Insufficient payment"); (bool success, ) = address(this).delegatecall(data); // calls register require(success, "Unable to create request"); } //PRIVATE /** * @dev reset auto approve window if passed end of current window */ function _resetWindowIfRequired( AutoApprovedConfig memory config ) private { uint64 blocksPassed = uint64(block.number - config.windowStart); if (blocksPassed >= config.windowSizeInBlocks) { config.windowStart = uint64(block.number); config.approvedInCurrentWindow = 0; s_config = config; } } /** * @dev register upkeep on KeeperRegistry contract and emit RegistrationApproved event */ function _approve( string memory name, address upkeepContract, uint32 gasLimit, address adminAddress, bytes calldata checkData, uint96 amount, bytes32 hash ) private { KeeperRegistryBaseInterface keeperRegistry = s_keeperRegistry; // register upkeep uint256 upkeepId = keeperRegistry.registerUpkeep( upkeepContract, gasLimit, adminAddress, checkData ); // fund upkeep bool success = LINK.transferAndCall( address(keeperRegistry), amount, abi.encode(upkeepId) ); require(success, "failed to fund upkeep"); emit RegistrationApproved(hash, name, upkeepId); } /** * @dev determine approval limits and check if in range */ function _underApprovalLimit( AutoApprovedConfig memory config ) private returns (bool) { _resetWindowIfRequired(config); if (config.approvedInCurrentWindow < config.allowedPerWindow) { return true; } return false; } /** * @dev record new latest approved count */ function _incrementApprovedCount( AutoApprovedConfig memory config ) private { config.approvedInCurrentWindow++; s_config = config; } //MODIFIERS /** * @dev Reverts if not sent from the LINK token */ modifier onlyLINK() { require(msg.sender == address(LINK), "Must use LINK token"); _; } /** * @dev Reverts if the given data does not begin with the `register` function selector * @param _data The data payload of the request */ modifier permittedFunctionsForLINK( bytes memory _data ) { bytes4 funcSelector; assembly { // solhint-disable-next-line avoid-low-level-calls funcSelector := mload(add(_data, 32)) } require( funcSelector == REGISTER_REQUEST_SELECTOR, "Must use whitelisted functions" ); _; } /** * @dev Reverts if the actual amount passed does not match the expected amount * @param expected amount that should match the actual amount * @param data bytes */ modifier isActualAmount( uint256 expected, bytes memory data ) { uint256 actual; assembly{ actual := mload(add(data, 228)) } require(expected == actual, "Amount mismatch"); _; } }
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import './KeeperBase.sol'; import './KeeperCompatibleInterface.sol'; abstract contract KeeperCompatible is KeeperBase, KeeperCompatibleInterface {}
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import '../KeeperCompatible.sol'; contract UpkeepReverter is KeeperCompatible { function checkUpkeep(bytes calldata data) public view override cannotExecute() returns ( bool callable, bytes calldata executedata ) { require(false, "!working"); return (true, data); } function performUpkeep( bytes calldata ) external pure override { require(false, "!working"); } }
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import '../KeeperCompatible.sol'; contract UpkeepMock is KeeperCompatible { bool public canCheck; bool public canPerform; uint256 public checkGasToBurn; uint256 public performGasToBurn; uint256 constant gasBuffer = 1000; // use all but this amount in gas burn loops event UpkeepPerformedWith(bytes upkeepData); function setCanCheck(bool value) public { canCheck = value; } function setCanPerform(bool value) public { canPerform = value; } function setCheckGasToBurn(uint256 value) public { require(value > gasBuffer || value == 0, "checkGasToBurn must be 0 (disabled) or greater than buffer"); checkGasToBurn = value - gasBuffer; } function setPerformGasToBurn(uint256 value) public { require(value > gasBuffer || value == 0, "performGasToBurn must be 0 (disabled) or greater than buffer"); performGasToBurn = value - gasBuffer; } function checkUpkeep(bytes calldata data) external override cannotExecute() returns ( bool callable, bytes calldata executedata ) { uint256 startGas = gasleft(); bool couldCheck = canCheck; setCanCheck(false); // test that state modifcations don't stick while (startGas - gasleft() < checkGasToBurn) {} // burn gas return (couldCheck, data); } function performUpkeep( bytes calldata data ) external override { uint256 startGas = gasleft(); require(canPerform, "Cannot perform"); setCanPerform(false); emit UpkeepPerformedWith(data); while(startGas - gasleft() < performGasToBurn) {} // burn gas } }
{ "optimizer": { "enabled": true, "runs": 1000000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "metadata": { "useLiteralContent": true } }
[{"inputs":[{"internalType":"address","name":"link","type":"address"},{"internalType":"address","name":"linkEthFeed","type":"address"},{"internalType":"address","name":"fastGasFeed","type":"address"},{"internalType":"uint32","name":"paymentPremiumPPB","type":"uint32"},{"internalType":"uint24","name":"blockCountPerTurn","type":"uint24"},{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"paymentPremiumPPB","type":"uint32"},{"indexed":false,"internalType":"uint24","name":"blockCountPerTurn","type":"uint24"},{"indexed":false,"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"indexed":false,"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"indexed":false,"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"}],"name":"ConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"}],"name":"FundsAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"FundsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"keepers","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"payees","type":"address[]"}],"name":"KeepersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"keeper","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"PayeeshipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"keeper","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"PayeeshipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"keeper","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"payee","type":"address"}],"name":"PaymentWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"RegistrarChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint64","name":"atBlockHeight","type":"uint64"}],"name":"UpkeepCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint96","name":"payment","type":"uint96"},{"indexed":false,"internalType":"bytes","name":"performData","type":"bytes"}],"name":"UpkeepPerformed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"executeGas","type":"uint32"},{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"UpkeepRegistered","type":"event"},{"inputs":[],"name":"FAST_GAS_FEED","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LINK","outputs":[{"internalType":"contract LinkTokenInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LINK_ETH_FEED","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"keeper","type":"address"}],"name":"acceptPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint96","name":"amount","type":"uint96"}],"name":"addFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"cancelUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"from","type":"address"}],"name":"checkUpkeep","outputs":[{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"uint256","name":"maxLinkPayment","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"adjustedGasWei","type":"uint256"},{"internalType":"uint256","name":"linkEth","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getCanceledUpkeepList","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getConfig","outputs":[{"internalType":"uint32","name":"paymentPremiumPPB","type":"uint32"},{"internalType":"uint24","name":"blockCountPerTurn","type":"uint24"},{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"query","type":"address"}],"name":"getKeeperInfo","outputs":[{"internalType":"address","name":"payee","type":"address"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint96","name":"balance","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getKeeperList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"gasLimit","type":"uint256"}],"name":"getMaxPaymentForGas","outputs":[{"internalType":"uint96","name":"maxPayment","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getMinBalanceForUpkeep","outputs":[{"internalType":"uint96","name":"minBalance","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRegistrar","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getUpkeep","outputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"executeGas","type":"uint32"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"uint96","name":"balance","type":"uint96"},{"internalType":"address","name":"lastKeeper","type":"address"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"uint64","name":"maxValidBlocknumber","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUpkeepCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onTokenTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"performData","type":"bytes"}],"name":"performUpkeep","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"recoverFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"bytes","name":"checkData","type":"bytes"}],"name":"registerUpkeep","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"paymentPremiumPPB","type":"uint32"},{"internalType":"uint24","name":"blockCountPerTurn","type":"uint24"},{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"keepers","type":"address[]"},{"internalType":"address[]","name":"payees","type":"address[]"}],"name":"setKeepers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"registrar","type":"address"}],"name":"setRegistrar","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"keeper","type":"address"},{"internalType":"address","name":"proposed","type":"address"}],"name":"transferPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawPayment","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60e06040523480156200001157600080fd5b506040516200503e3803806200503e83398181016040526101408110156200003857600080fd5b5080516020820151604083015160608085015160808087015160a08089015160c0808b015160e08c01516101008d0151610120909d0151600080546001600160a01b0319163317905560016002556003805460ff191690556001600160601b03198d8b1b81169098528b8a1b88169095529789901b909516905297989697959693959194919390620000d087878787878787620000e0565b505050505050505050506200024c565b6000546001600160a01b0316331462000140576040805162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015290519081900360640190fd5b6040805160a0808201835263ffffffff8a811680845262ffffff8b81166020808701829052938c16868801819052918b16606080880182905261ffff8c166080988901819052600b805463ffffffff1916871762ffffff60201b191664010000000086021763ffffffff60381b191667010000000000000087021762ffffff60581b19166b01000000000000000000000085021761ffff60701b1916600160701b8302179055600c8c9055600d8b90558951958652958501929092528388019290925282015292830152810184905260c0810183905290517feb3c06937e6595fd80ec1add18a195026d5cf65f122cc3ffedbfb18a9ed80b399160e0908290030190a150505050505050565b60805160601c60a05160601c60c05160601c614d94620002aa60003980610c665280614388525080611bd7528061445b525080610add5280610f0c528061158e52806116635280611b345280611dec5280611eba5250614d946000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c8063a4c0ed361161010f578063c41b813a116100a2578063eb5dcd6c11610071578063eb5dcd6c146109c3578063f2fde38b146109fe578063faab9d3914610a31578063fecf27c914610a64576101f0565b8063c41b813a14610706578063c7c3a19a146107d3578063c8048022146108f2578063da5c67411461090f576101f0565b8063b657bc9c116100de578063b657bc9c146105c7578063b79550be146105e4578063b7fdb436146105ec578063c3f909d4146106ae576101f0565b8063a4c0ed36146104bf578063a710b22114610551578063ad1783611461058c578063b121e14714610594576101f0565b8063744bfe61116101875780638456cb59116101565780638456cb59146104405780638da5cb5b1461044857806393f0c1fc14610450578063948108f71461048e576101f0565b8063744bfe611461033257806379ba50971461036b5780637bbaf1ea1461037357806382105f79146103ea576101f0565b80633f4ba83a116101c35780633f4ba83a146102fc5780634584a419146103065780634d3f73341461030e5780635c975abb14610316576101f0565b806315a126ea146101f55780631b6b6d231461024d5780631e12b8a51461027e5780632cb6864d146102f4575b600080fd5b6101fd610a6c565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610239578181015183820152602001610221565b505050509050019250505060405180910390f35b610255610adb565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6102b16004803603602081101561029457600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610aff565b6040805173ffffffffffffffffffffffffffffffffffffffff909416845291151560208401526bffffffffffffffffffffffff1682820152519081900360600190f35b6101fd610b7d565b610304610bd4565b005b610255610c64565b610255610c88565b61031e610ca4565b604080519115158252519081900360200190f35b6103046004803603604081101561034857600080fd5b508035906020013573ffffffffffffffffffffffffffffffffffffffff16610cad565b610304610fcd565b61031e6004803603604081101561038957600080fd5b813591908101906040810160208201356401000000008111156103ab57600080fd5b8201836020820111156103bd57600080fd5b803590602001918460018302840111640100000000831117156103df57600080fd5b5090925090506110cf565b610304600480360360e081101561040057600080fd5b5063ffffffff813581169162ffffff60208201358116926040830135169160608101359091169061ffff6080820135169060a08101359060c00135611125565b610304611341565b6102556113cf565b61046d6004803603602081101561046657600080fd5b50356113eb565b604080516bffffffffffffffffffffffff9092168252519081900360200190f35b610304600480360360408110156104a457600080fd5b50803590602001356bffffffffffffffffffffffff16611421565b610304600480360360608110156104d557600080fd5b73ffffffffffffffffffffffffffffffffffffffff8235169160208101359181019060608101604082013564010000000081111561051257600080fd5b82018360208201111561052457600080fd5b8035906020019184600183028401116401000000008311171561054657600080fd5b50909250905061164b565b6103046004803603604081101561056757600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160200135166118e7565b610255611bd5565b610304600480360360208110156105aa57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611bf9565b61046d600480360360208110156105dd57600080fd5b5035611d26565b610304611d62565b6103046004803603604081101561060257600080fd5b81019060208101813564010000000081111561061d57600080fd5b82018360208201111561062f57600080fd5b8035906020019184602083028401116401000000008311171561065157600080fd5b91939092909160208101903564010000000081111561066f57600080fd5b82018360208201111561068157600080fd5b803590602001918460208302840111640100000000831117156106a357600080fd5b509092509050611f70565b6106b661250b565b6040805163ffffffff988916815262ffffff9788166020820152959097168588015292909416606084015261ffff16608083015260a082019290925260c081019190915290519081900360e00190f35b61073f6004803603604081101561071c57600080fd5b508035906020013573ffffffffffffffffffffffffffffffffffffffff16612594565b6040518080602001868152602001858152602001848152602001838152602001828103825287818151815260200191508051906020019080838360005b8381101561079457818101518382015260200161077c565b50505050905090810190601f1680156107c15780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390f35b6107f0600480360360208110156107e957600080fd5b5035612bee565b604051808873ffffffffffffffffffffffffffffffffffffffff1681526020018763ffffffff16815260200180602001866bffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018367ffffffffffffffff168152602001828103825287818151815260200191508051906020019080838360005b838110156108b1578181015183820152602001610899565b50505050905090810190601f1680156108de5780820380516001836020036101000a031916815260200191505b509850505050505050505060405180910390f35b6103046004803603602081101561090857600080fd5b5035612d97565b6109b16004803603608081101561092557600080fd5b73ffffffffffffffffffffffffffffffffffffffff823581169263ffffffff6020820135169260408201359092169181019060808101606082013564010000000081111561097257600080fd5b82018360208201111561098457600080fd5b803590602001918460018302840111640100000000831117156109a657600080fd5b509092509050612fd9565b60408051918252519081900360200190f35b610304600480360360408110156109d957600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516613409565b61030460048036036020811015610a1457600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166135d3565b61030460048036036020811015610a4757600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166136cf565b6109b1613863565b60606006805480602002602001604051908101604052809291908181526020018280548015610ad157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610aa6575b5050505050905090565b7f000000000000000000000000000000000000000000000000000000000000000081565b73ffffffffffffffffffffffffffffffffffffffff90811660009081526008602090815260409182902082516060810184528154948516808252740100000000000000000000000000000000000000009095046bffffffffffffffffffffffff1692810183905260019091015460ff16151592018290529192909190565b60606005805480602002602001604051908101604052809291908181526020018280548015610ad157602002820191906000526020600020905b815481526020019060010190808311610bb7575050505050905090565b60005473ffffffffffffffffffffffffffffffffffffffff163314610c5a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015290519081900360640190fd5b610c62613869565b565b7f000000000000000000000000000000000000000000000000000000000000000081565b600f5473ffffffffffffffffffffffffffffffffffffffff1690565b60035460ff1690565b8073ffffffffffffffffffffffffffffffffffffffff8116610d3057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f63616e6e6f742073656e6420746f207a65726f20616464726573730000000000604482015290519081900360640190fd5b6000838152600760205260409020600101546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff163314610dd557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6f6e6c792063616c6c61626c652062792061646d696e00000000000000000000604482015290519081900360640190fd5b6000838152600760205260409020600201544367ffffffffffffffff9091161115610e6157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f75706b656570206d7573742062652063616e63656c6564000000000000000000604482015290519081900360640190fd5b600083815260076020526040902060010180547fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008116909155600e546bffffffffffffffffffffffff90911690610eb89082613957565b600e556040805182815273ffffffffffffffffffffffffffffffffffffffff85166020820152815186927ff3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318928290030190a27f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb84836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015610f9b57600080fd5b505af1158015610faf573d6000803e3d6000fd5b505050506040513d6020811015610fc557600080fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461105357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015290519081900360640190fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600061111d611118338686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250600192506139ce915050565b613a8f565b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146111ab57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015290519081900360640190fd5b6040805160a0808201835263ffffffff8a811680845262ffffff8b81166020808701829052938c16868801819052918b16606080880182905261ffff8c166080988901819052600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001687177fffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffff166401000000008602177fffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffff166701000000000000008702177fffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffff166b0100000000000000000000008502177fffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffff166e0100000000000000000000000000008302179055600c8c9055600d8b90558951958652958501929092528388019290925282015292830152810184905260c0810183905290517feb3c06937e6595fd80ec1add18a195026d5cf65f122cc3ffedbfb18a9ed80b399160e0908290030190a150505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146113c757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015290519081900360640190fd5b610c6261428d565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b60008060006113f8614355565b915091506000611409836000614534565b9050611416858284614576565b93505050505b919050565b60008281526007602052604090206002015467ffffffffffffffff908116146114ab57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f75706b656570206d757374206265206163746976650000000000000000000000604482015290519081900360640190fd5b6000828152600760205260409020600101546114d5906bffffffffffffffffffffffff168261465f565b600083815260076020526040902060010180547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff928316179055600e5461152b9183166146eb565b600e55604080517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526bffffffffffffffffffffffff83166044820152905173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016916323b872dd9160648083019260209291908290030181600087803b1580156115d657600080fd5b505af11580156115ea573d6000803e3d6000fd5b505050506040513d602081101561160057600080fd5b5050604080516bffffffffffffffffffffffff831681529051339184917fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039181900360200190a35050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146116ef57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f6f6e6c792063616c6c61626c65207468726f756768204c494e4b000000000000604482015290519081900360640190fd5b6020811461175e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f64617461206d7573742062652033322062797465730000000000000000000000604482015290519081900360640190fd5b60008282602081101561177057600080fd5b503560008181526007602052604090206002015490915067ffffffffffffffff908116146117ff57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f75706b656570206d757374206265206163746976650000000000000000000000604482015290519081900360640190fd5b600081815260076020526040902060010154611829906bffffffffffffffffffffffff168561465f565b600082815260076020526040902060010180547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff92909216919091179055600e5461188290856146eb565b600e55604080516bffffffffffffffffffffffff86168152905173ffffffffffffffffffffffffffffffffffffffff87169183917fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039181900360200190a35050505050565b8073ffffffffffffffffffffffffffffffffffffffff811661196a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f63616e6e6f742073656e6420746f207a65726f20616464726573730000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff83811660009081526008602090815260409182902082516060810184528154948516808252740100000000000000000000000000000000000000009095046bffffffffffffffffffffffff16928101929092526001015460ff16151591810191909152903314611a5057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6f6e6c792063616c6c61626c6520627920706179656500000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff80851660009081526008602090815260409091208054909216909155810151600e54611a9e916bffffffffffffffffffffffff16613957565b600e819055508273ffffffffffffffffffffffffffffffffffffffff1681602001516bffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167f9819093176a1851202c7bcfa46845809b4e47c261866550e94ed3775d2f4069833604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a47f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8483602001516040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff168152602001826bffffffffffffffffffffffff16815260200192505050602060405180830381600087803b158015610f9b57600080fd5b7f000000000000000000000000000000000000000000000000000000000000000081565b73ffffffffffffffffffffffffffffffffffffffff818116600090815260096020526040902054163314611c8e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f6f6e6c792063616c6c61626c652062792070726f706f73656420706179656500604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff81811660008181526008602090815260408083208054337fffffffffffffffffffffffff000000000000000000000000000000000000000080831682179093556009909452828520805490921690915590519416939092849290917f78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b39190a45050565b600081815260076020526040812054611d5c9074010000000000000000000000000000000000000000900463ffffffff166113eb565b92915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611de857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015290519081900360640190fd5b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611e7157600080fd5b505afa158015611e85573d6000803e3d6000fd5b505050506040513d6020811015611e9b57600080fd5b5051600e5490915073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb903390611eee908590613957565b6040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015611f4157600080fd5b505af1158015611f55573d6000803e3d6000fd5b505050506040513d6020811015611f6b57600080fd5b505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611ff657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015290519081900360640190fd5b82811461204e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180614d3e6021913960400191505060405180910390fd5b60028310156120be57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6e6f7420656e6f756768206b6565706572730000000000000000000000000000604482015290519081900360640190fd5b60005b60065481101561213e576000600682815481106120da57fe5b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff1682526008905260409020600190810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690559190910190506120c1565b5060005b8381101561242857600085858381811061215857fe5b73ffffffffffffffffffffffffffffffffffffffff602091820293909301358316600081815260089092526040822080549195509316915086868681811061219c57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612241576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180614cd66024913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216158061228f57508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b806122af575073ffffffffffffffffffffffffffffffffffffffff818116145b61231a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f63616e6e6f74206368616e676520706179656500000000000000000000000000604482015290519081900360640190fd5b600183015460ff161561238e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f63616e6e6f7420616464206b6565706572207477696365000000000000000000604482015290519081900360640190fd5b600183810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016909117905573ffffffffffffffffffffffffffffffffffffffff818116146124185782547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff82161783555b5050600190920191506121429050565b5061243560068585614b4b565b507f056264c94f28bb06c99d13f0446eb96c67c215d8d707bce2655a98ddf1c0b71f848484846040518080602001806020018381038352878782818152602001925060200280828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169091018481038352858152602090810191508690860280828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018290039850909650505050505050a150505050565b6040805160a081018252600b5463ffffffff808216808452640100000000830462ffffff9081166020860181905267010000000000000085049093169585018690526b010000000000000000000000840416606085018190526e01000000000000000000000000000090930461ffff166080909401849052600c54600d54919692959492909190565b60606000806000806125a4610ca4565b1561261057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b61261861475f565b6000878152600a60209081526040808320905160248101928352815460027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001841615020190911604604482018190527f6e04ff0d0000000000000000000000000000000000000000000000000000000093918291606490910190849080156126e65780601f106126bb576101008083540402835291602001916126e6565b820191906000526020600020905b8154815290600101906020018083116126c957829003601f168201915b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090981697909717875260008f8152600790915281812054600b5492518451949950919788975073ffffffffffffffffffffffffffffffffffffffff909116955063ffffffff6701000000000000009093049290921693508792909182918083835b602083106127fa57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016127bd565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038160008787f1925050503d806000811461285d576040519150601f19603f3d011682016040523d82523d6000602084013e612862565b606091505b5091509150816129fd576000612877826147cc565b905060008160405160200180807f63616c6c20746f20636865636b20746172676574206661696c65643a20000000815250601d0182805190602001908083835b602083106128f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016128b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff018019909216911617905260408051929094018281037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018352938490527f08c379a00000000000000000000000000000000000000000000000000000000084526004840181815282516024860152825192975087965094508493604401925085019080838360005b838110156129c25781810151838201526020016129aa565b50505050905090810190601f1680156129ef5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b808060200190516040811015612a1257600080fd5b815160208301805160405192949293830192919084640100000000821115612a3957600080fd5b908301906020820185811115612a4e57600080fd5b8251640100000000811182820188101715612a6857600080fd5b82525081516020918201929091019080838360005b83811015612a95578181015183820152602001612a7d565b50505050905090810190601f168015612ac25780820380516001836020036101000a031916815260200191505b50604052505050809950819350505081612b3d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f75706b656570206e6f74206e6565646564000000000000000000000000000000604482015290519081900360640190fd5b6000612b4c8a8c8b60006139ce565b9050612b5781613a8f565b925082612bc557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f63616c6c20746f20706572666f726d2075706b656570206661696c6564000000604482015290519081900360640190fd5b6060810151608082015160a083015160c0909301519a9d919c509a509098975095505050505050565b6000818152600760209081526040808320815160c081018352815473ffffffffffffffffffffffffffffffffffffffff8082168084527401000000000000000000000000000000000000000090920463ffffffff168387018190526001808601546bffffffffffffffffffffffff81168689019081526c010000000000000000000000009091048416606080880191825260029889015467ffffffffffffffff811660808a019081526801000000000000000090910490961660a089019081528d8d52600a8c528a8d20935190519251965184548c5161010097821615979097027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01169a909a04601f81018d90048d0286018d01909b528a85528c9b919a8c9a8b9a8b9a8b9a91999098909796949591939091879190830182828015612d765780601f10612d4b57610100808354040283529160200191612d76565b820191906000526020600020905b815481529060010190602001808311612d5957829003601f168201915b50505050509450975097509750975097509750975050919395979092949650565b600081815260076020526040812060020154905467ffffffffffffffff9182169182149073ffffffffffffffffffffffffffffffffffffffff1633148180612df05750808015612df05750438367ffffffffffffffff16115b612e5b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f746f6f206c61746520746f2063616e63656c2075706b65657000000000000000604482015290519081900360640190fd5b8080612e9d57506000848152600760205260409020600101546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1633145b612f0857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f6f6e6c79206f776e6572206f722061646d696e00000000000000000000000000604482015290519081900360640190fd5b4381612f1c57612f198160326146eb565b90505b600085815260076020526040902060020180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff83161790558215612f9b57600580546001810182556000919091527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0018590555b60405167ffffffffffffffff82169086907f91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f79118190600090a35050505050565b6000805473ffffffffffffffffffffffffffffffffffffffff163314806130175750600f5473ffffffffffffffffffffffffffffffffffffffff1633145b61306c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180614cfa6023913960400191505060405180910390fd5b61308b8673ffffffffffffffffffffffffffffffffffffffff166148e3565b6130f657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f746172676574206973206e6f74206120636f6e74726163740000000000000000604482015290519081900360640190fd5b6108fc8563ffffffff16101561316d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6d696e2067617320697320323330300000000000000000000000000000000000604482015290519081900360640190fd5b624c4b408563ffffffff1611156131e557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6d61782067617320697320353030303030300000000000000000000000000000604482015290519081900360640190fd5b506004546040805160c08101825273ffffffffffffffffffffffffffffffffffffffff808916825263ffffffff808916602080850191825260008587018181528b86166060880190815267ffffffffffffffff6080890181815260a08a018581528c8652600787528b86209a518b54985190991674010000000000000000000000000000000000000000027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff998b167fffffffffffffffffffffffff000000000000000000000000000000000000000090991698909817989098169690961789559151600189018054925189166c01000000000000000000000000026bffffffffffffffffffffffff9283167fffffffffffffffffffffffffffffffffffffffff00000000000000000000000090941693909317909116919091179055925160029096018054945190951668010000000000000000027fffffffff0000000000000000000000000000000000000000ffffffffffffffff969093167fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909416939093179490941617909155600a909152206133a1908484614bd3565b506004805460010190556040805163ffffffff8716815273ffffffffffffffffffffffffffffffffffffffff86166020820152815183927fbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d012928290030190a295945050505050565b73ffffffffffffffffffffffffffffffffffffffff82811660009081526008602052604090205416331461349e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6f6e6c792063616c6c61626c6520627920706179656500000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff811633141561352357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f63616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600960205260409020548116908216146135cf5773ffffffffffffffffffffffffffffffffffffffff82811660008181526009602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055513392917f84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e3836791a45b5050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461365957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015290519081900360640190fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60005473ffffffffffffffffffffffffffffffffffffffff1633148061370c5750600f5473ffffffffffffffffffffffffffffffffffffffff1633145b613761576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180614cfa6023913960400191505060405180910390fd5b600f5473ffffffffffffffffffffffffffffffffffffffff9081169082168114156137ed57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f53616d6520726567697374726172000000000000000000000000000000000000604482015290519081900360640190fd5b600f80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84811691821790925560405190918316907f9bf4a5b30267728df68663e14adb47e559863967c419dc6030638883408bed2e90600090a35050565b60045490565b613871610ca4565b6138dc57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015290519081900360640190fd5b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa61392d6148e9565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190a1565b6000828211156139c857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6139d6614c6d565b60008481526007602052604081205474010000000000000000000000000000000000000000900463ffffffff169080613a0d614355565b915091506000613a1d8387614534565b90506000613a2c858385614576565b6040805160e08101825273ffffffffffffffffffffffffffffffffffffffff8d168152602081018c90529081018a90526bffffffffffffffffffffffff909116606082015260808101959095525060a084015260c0830152509050949350505050565b6000600280541415613b0257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b600280556020820151613b14816148ed565b825173ffffffffffffffffffffffffffffffffffffffff1660009081526008602052604090206001015460ff16613bac57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f6f6e6c7920616374697665206b65657065727300000000000000000000000000604482015290519081900360640190fd5b602083810151600090815260078252604090819020815160c081018352815473ffffffffffffffffffffffffffffffffffffffff80821683527401000000000000000000000000000000000000000090910463ffffffff169482019490945260018201546bffffffffffffffffffffffff81169382018490526c010000000000000000000000009004841660608083019190915260029092015467ffffffffffffffff8116608083015268010000000000000000900490931660a08401528501511115613cda57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e73756666696369656e742066756e64730000000000000000000000000000604482015290519081900360640190fd5b836000015173ffffffffffffffffffffffffffffffffffffffff168160a0015173ffffffffffffffffffffffffffffffffffffffff161415613d7d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f6b656570657273206d7573742074616b65207475726e73000000000000000000604482015290519081900360640190fd5b60005a90506000634585e33b60e01b86604001516040516024018080602001828103825283818151815260200191508051906020019080838360005b83811015613dd1578181015183820152602001613db9565b50505050905090810190601f168015613dfe5780820380516001836020036101000a031916815260200191505b50604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009096169590951790945250505060808701518451919250613e93918361497b565b94505a820391506000613eaf838860a001518960c00151614576565b6040850151909150613ecf906bffffffffffffffffffffffff16826149c7565b84604001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff168152505086600001518460a0019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505083600760008960200151815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160010160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550606082015181600101600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060808201518160020160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060a08201518160020160086101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050600061413082600860008b6000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160149054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff1661465f90919063ffffffff16565b905080600860008a6000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550876000015173ffffffffffffffffffffffffffffffffffffffff1687151589602001517fcaacad83e47cc45c280d487ec84184eee2fa3b54ebaa393bda7549f13da228f6858c6040015160405180836bffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561424257818101518382015260200161422a565b50505050905090810190601f16801561426f5780820380516001836020036101000a031916815260200191505b50935050505060405180910390a45050505050506001600255919050565b614295610ca4565b1561430157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861392d6148e9565b6000806000600b600001600b9054906101000a900462ffffff1662ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b1580156143ec57600080fd5b505afa158015614400573d6000803e3d6000fd5b505050506040513d60a081101561441657600080fd5b5060208101516060909101519250905082801561443a57508142038463ffffffff16105b80614446575060008113155b1561445557600c549550614459565b8095505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b1580156144bf57600080fd5b505afa1580156144d3573d6000803e3d6000fd5b505050506040513d60a08110156144e957600080fd5b5060208101516060909101519250905082801561450d57508142038463ffffffff16105b80614519575060008113155b1561452857600d54945061452c565b8094505b505050509091565b600b5460009061455b9084906e010000000000000000000000000000900461ffff16614a54565b90508180156145695750803a105b15611d5c57503a92915050565b60008061459061458986620138806146eb565b8590614a54565b600b549091506000906145b290633b9aca009063ffffffff908116906146eb16565b905060006145d8856145d2846145cc87633b9aca00614a54565b90614a54565b90614ac7565b90506b033b2e3c9fd0803ce800000081111561465557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f7061796d656e742067726561746572207468616e20616c6c204c494e4b000000604482015290519081900360640190fd5b9695505050505050565b60008282016bffffffffffffffffffffffff80851690821610156146e457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6000828201838110156146e457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b3215610c6257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f6f6e6c7920666f722073696d756c61746564206261636b656e64000000000000604482015290519081900360640190fd5b6060604482511015614812575060408051808201909152601d81527f7472616e73616374696f6e2072657665727465642073696c656e746c79000000602082015261141c565b600482018051909260240190602081101561482c57600080fd5b810190808051604051939291908464010000000082111561484c57600080fd5b90830190602082018581111561486157600080fd5b825164010000000081118282018810171561487b57600080fd5b82525081516020918201929091019080838360005b838110156148a8578181015183820152602001614890565b50505050905090810190601f1680156148d55780820380516001836020036101000a031916815260200191505b506040525050509050919050565b3b151590565b3390565b6000818152600760205260409020600201544367ffffffffffffffff9091161161497857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c69642075706b656570206964000000000000000000000000000000604482015290519081900360640190fd5b50565b60005a61138881101561498d57600080fd5b6113888103905084604082048203116149a557600080fd5b50823b6149b157600080fd5b60008083516020850160008789f1949350505050565b6000826bffffffffffffffffffffffff16826bffffffffffffffffffffffff1611156139c857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b600082614a6357506000611d5c565b82820282848281614a7057fe5b04146146e4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180614d1d6021913960400191505060405180910390fd5b6000808211614b3757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b6000828481614b4257fe5b04949350505050565b828054828255906000526020600020908101928215614bc3579160200282015b82811115614bc35781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190614b6b565b50614bcf929150614cc0565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282614c095760008555614bc3565b82601f10614c40578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00823516178555614bc3565b82800160010185558215614bc3579182015b82811115614bc3578235825591602001919060010190614c52565b6040518060e00160405280600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160608152602001600081526020016000815260200160008152602001600081525090565b5b80821115614bcf5760008155600101614cc156fe63616e6e6f742073657420706179656520746f20746865207a65726f20616464726573734f6e6c792063616c6c61626c65206279206f776e6572206f7220726567697374726172536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7761646472657373206c69737473206e6f74207468652073616d65206c656e677468a264697066735822122048c1a5b6e6113663e244952b9cd7102fef5aaaa79c353a17870b49e77c08234564736f6c63430007060033000000000000000000000000326c977e6efc84e512bb9c30f76e30c160ed06fb00000000000000000000000012162c3e810393dec01362abf156d7ecf6159528000000000000000000000000095bf5dbe28535b9eac32f1ecd6784ef1c15d756000000000000000000000000000000000000000000000000000000000bebc20000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000632ea00000000000000000000000000000000000000000000000000000000000015f9000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000002e90edd00000000000000000000000000000000000000000000000000000470de4df820000
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000326c977e6efc84e512bb9c30f76e30c160ed06fb00000000000000000000000012162c3e810393dec01362abf156d7ecf6159528000000000000000000000000095bf5dbe28535b9eac32f1ecd6784ef1c15d756000000000000000000000000000000000000000000000000000000000bebc20000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000632ea00000000000000000000000000000000000000000000000000000000000015f9000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000002e90edd00000000000000000000000000000000000000000000000000000470de4df820000
-----Decoded View---------------
Arg [0] : link (address): 0x326c977e6efc84e512bb9c30f76e30c160ed06fb
Arg [1] : linkEthFeed (address): 0x12162c3e810393dec01362abf156d7ecf6159528
Arg [2] : fastGasFeed (address): 0x095bf5dbe28535b9eac32f1ecd6784ef1c15d756
Arg [3] : paymentPremiumPPB (uint32): 200000000
Arg [4] : blockCountPerTurn (uint24): 20
Arg [5] : checkGasLimit (uint32): 6500000
Arg [6] : stalenessSeconds (uint24): 90000
Arg [7] : gasCeilingMultiplier (uint16): 3
Arg [8] : fallbackGasPrice (uint256): 200000000000
Arg [9] : fallbackLinkPrice (uint256): 20000000000000000
-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 000000000000000000000000326c977e6efc84e512bb9c30f76e30c160ed06fb
Arg [1] : 00000000000000000000000012162c3e810393dec01362abf156d7ecf6159528
Arg [2] : 000000000000000000000000095bf5dbe28535b9eac32f1ecd6784ef1c15d756
Arg [3] : 000000000000000000000000000000000000000000000000000000000bebc200
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [5] : 0000000000000000000000000000000000000000000000000000000000632ea0
Arg [6] : 0000000000000000000000000000000000000000000000000000000000015f90
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [8] : 0000000000000000000000000000000000000000000000000000002e90edd000
Arg [9] : 00000000000000000000000000000000000000000000000000470de4df820000
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|