|
| 1 | +// SPDX-License-Identifier: MIT |
| 2 | +pragma solidity ^0.8.19; |
| 3 | + |
| 4 | +import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol"; |
| 5 | +import {AutomationCompatible} from "@chainlink/contracts/src/v0.8/AutomationCompatible.sol"; |
| 6 | +/** |
| 7 | + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. |
| 8 | + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. |
| 9 | + * DO NOT USE THIS CODE IN PRODUCTION. |
| 10 | + */ |
| 11 | + |
| 12 | +error LessThanMinimumAmount(uint256 required); |
| 13 | +error UpkeepIsAlreadyInPausedState(); |
| 14 | +error UpkeepIsAlreadyInUnpausedOrActiveState(); |
| 15 | +error UpkeepIsNotRegisteredYet(); |
| 16 | +error UpkeepIsAlreadyCancelled(); |
| 17 | +error UpkeepNeedsToBeCancelledFirst(); |
| 18 | + |
| 19 | +struct RegistrationParams { |
| 20 | + string name; |
| 21 | + bytes encryptedEmail; |
| 22 | + address upkeepContract; |
| 23 | + uint32 gasLimit; |
| 24 | + address adminAddress; |
| 25 | + uint8 triggerType; |
| 26 | + bytes checkData; |
| 27 | + bytes triggerConfig; |
| 28 | + bytes offchainConfig; |
| 29 | + uint96 amount; |
| 30 | +} |
| 31 | + |
| 32 | +/** |
| 33 | + * string name = "test upkeep"; |
| 34 | + * bytes encryptedEmail = 0x; |
| 35 | + * address upkeepContract = 0x...; |
| 36 | + * uint32 gasLimit = 500000; |
| 37 | + * address adminAddress = 0x....; |
| 38 | + * uint8 triggerType = 0; |
| 39 | + * bytes checkData = 0x; |
| 40 | + * bytes triggerConfig = 0x; |
| 41 | + * bytes offchainConfig = 0x; |
| 42 | + * uint96 amount = 1000000000000000000; |
| 43 | + */ |
| 44 | +interface AutomationRegistrarInterface { |
| 45 | + function registerUpkeep(RegistrationParams calldata requestParams) external returns (uint256); |
| 46 | +} |
| 47 | + |
| 48 | +interface KeeperRegistryInterface { |
| 49 | + function addFunds(uint256 id, uint96 amount) external; |
| 50 | + |
| 51 | + function pauseUpkeep(uint256 id) external; |
| 52 | + |
| 53 | + function unpauseUpkeep(uint256 id) external; |
| 54 | + |
| 55 | + function cancelUpkeep(uint256 id) external; |
| 56 | + |
| 57 | + function setUpkeepGasLimit(uint256 id, uint32 gasLimit) external; |
| 58 | + |
| 59 | + function withdrawFunds(uint256 id, address to) external; |
| 60 | +} |
| 61 | + |
| 62 | +contract UpkeepIDConditionalExample is AutomationCompatible { |
| 63 | + LinkTokenInterface public immutable i_link; |
| 64 | + AutomationRegistrarInterface public immutable i_registrar; |
| 65 | + KeeperRegistryInterface public immutable i_keeperRegistry; |
| 66 | + |
| 67 | + uint256 public s_numberOfPerformUpkeepCallsForLatestUpkeep; |
| 68 | + uint256 constant endDate = 1715781439; |
| 69 | + uint256 public s_latestUpkeepId; |
| 70 | + bool public s_isLatestUpkeepPaused; |
| 71 | + bool public s_isLatestUpkeepCancelled; |
| 72 | + |
| 73 | + // For Eth-Sepolia network |
| 74 | + // linkToken: 0x779877A7B0D9E8603169DdbD7836e478b4624789 |
| 75 | + // registrar: 0xb0E49c5D0d05cbc241d68c05BC5BA1d1B7B72976 |
| 76 | + // keeperRegistry: 0x86EFBD0b6736Bed994962f9797049422A3A8E8Ad |
| 77 | + constructor(address linkToken, address registrar, address keeperRegistry) { |
| 78 | + i_link = LinkTokenInterface(linkToken); |
| 79 | + i_registrar = AutomationRegistrarInterface(registrar); |
| 80 | + i_keeperRegistry = KeeperRegistryInterface(keeperRegistry); |
| 81 | + } |
| 82 | + |
| 83 | + // Note: The upkeep that will be registered here won't be visible in the Automation UI (https://automation.chain.link/) because the adminAddress is being set to the address of this contract (not to any wallet). |
| 84 | + function registerUpkeep(string memory upkeepName, uint96 initialAmount, uint32 gasLimit) external { |
| 85 | + s_numberOfPerformUpkeepCallsForLatestUpkeep = 0; |
| 86 | + s_isLatestUpkeepPaused = false; |
| 87 | + s_isLatestUpkeepCancelled = false; |
| 88 | + |
| 89 | + bytes memory encryptedEmail = ""; |
| 90 | + address upkeepContract = address(this); |
| 91 | + address adminAddress = address(this); // Note: Setting adminAddress as address of this contract, so as to have the authorization to call the management functions like pause, unpause, cancel, etc. as they can be called only by the admin. |
| 92 | + uint8 triggerType = 0; |
| 93 | + bytes memory checkData = ""; |
| 94 | + bytes memory triggerConfig = ""; |
| 95 | + bytes memory offchainConfig = ""; |
| 96 | + |
| 97 | + RegistrationParams memory params = RegistrationParams( |
| 98 | + upkeepName, |
| 99 | + encryptedEmail, |
| 100 | + upkeepContract, |
| 101 | + gasLimit, |
| 102 | + adminAddress, |
| 103 | + triggerType, |
| 104 | + checkData, |
| 105 | + triggerConfig, |
| 106 | + offchainConfig, |
| 107 | + initialAmount |
| 108 | + ); |
| 109 | + |
| 110 | + // LINKs must be approved for transfer - this can be done every time or once |
| 111 | + // with an infinite approval |
| 112 | + if (params.amount < 1e18) { |
| 113 | + revert LessThanMinimumAmount(1e18); |
| 114 | + } |
| 115 | + i_link.approve(address(i_registrar), params.amount); |
| 116 | + uint256 upkeepID = i_registrar.registerUpkeep(params); |
| 117 | + if (upkeepID != 0) { |
| 118 | + // DEV - Use the upkeepID however you see fit |
| 119 | + s_latestUpkeepId = upkeepID; |
| 120 | + } else { |
| 121 | + revert("auto-approve disabled"); |
| 122 | + } |
| 123 | + } |
| 124 | + |
| 125 | + function addFundsToUpkeep(uint96 amount) external { |
| 126 | + if (s_latestUpkeepId == 0) revert UpkeepIsNotRegisteredYet(); |
| 127 | + if (s_isLatestUpkeepCancelled) revert UpkeepIsAlreadyCancelled(); |
| 128 | + i_link.approve(address(i_keeperRegistry), amount); |
| 129 | + i_keeperRegistry.addFunds(s_latestUpkeepId, amount); |
| 130 | + } |
| 131 | + |
| 132 | + function withdrawFundsFromUpkeep(address to) external { |
| 133 | + if (s_latestUpkeepId == 0) revert UpkeepIsNotRegisteredYet(); |
| 134 | + if (!s_isLatestUpkeepCancelled) revert UpkeepNeedsToBeCancelledFirst(); |
| 135 | + |
| 136 | + i_keeperRegistry.withdrawFunds(s_latestUpkeepId, to); |
| 137 | + } |
| 138 | + |
| 139 | + function pauseUpkeep() external { |
| 140 | + if (s_latestUpkeepId == 0) revert UpkeepIsNotRegisteredYet(); |
| 141 | + if (s_isLatestUpkeepCancelled) revert UpkeepIsAlreadyCancelled(); |
| 142 | + if (s_isLatestUpkeepPaused) revert UpkeepIsAlreadyInPausedState(); |
| 143 | + i_keeperRegistry.pauseUpkeep(s_latestUpkeepId); |
| 144 | + s_isLatestUpkeepPaused = true; |
| 145 | + } |
| 146 | + |
| 147 | + function unpauseUpkeep() external { |
| 148 | + if (s_latestUpkeepId == 0) revert UpkeepIsNotRegisteredYet(); |
| 149 | + if (s_isLatestUpkeepCancelled) revert UpkeepIsAlreadyCancelled(); |
| 150 | + if (!s_isLatestUpkeepPaused) { |
| 151 | + revert UpkeepIsAlreadyInUnpausedOrActiveState(); |
| 152 | + } |
| 153 | + i_keeperRegistry.unpauseUpkeep(s_latestUpkeepId); |
| 154 | + s_isLatestUpkeepPaused = false; |
| 155 | + } |
| 156 | + |
| 157 | + function editUpkeepGasLimit(uint32 newGasLimit) external { |
| 158 | + if (s_latestUpkeepId == 0) revert UpkeepIsNotRegisteredYet(); |
| 159 | + if (s_isLatestUpkeepCancelled) revert UpkeepIsAlreadyCancelled(); |
| 160 | + i_keeperRegistry.setUpkeepGasLimit(s_latestUpkeepId, newGasLimit); |
| 161 | + } |
| 162 | + |
| 163 | + function cancelUpkeep() external { |
| 164 | + if (s_latestUpkeepId == 0) revert UpkeepIsNotRegisteredYet(); |
| 165 | + if (s_isLatestUpkeepCancelled) revert UpkeepIsAlreadyCancelled(); |
| 166 | + i_keeperRegistry.cancelUpkeep(s_latestUpkeepId); |
| 167 | + s_isLatestUpkeepPaused = false; |
| 168 | + s_isLatestUpkeepCancelled = true; |
| 169 | + } |
| 170 | + |
| 171 | + function checkUpkeep(bytes memory /*checkdata*/ ) |
| 172 | + public |
| 173 | + view |
| 174 | + override |
| 175 | + returns (bool upkeepNeeded, bytes memory /* performData*/ ) |
| 176 | + { |
| 177 | + upkeepNeeded = block.timestamp > endDate && s_numberOfPerformUpkeepCallsForLatestUpkeep == 0; |
| 178 | + return (upkeepNeeded, ""); |
| 179 | + } |
| 180 | + |
| 181 | + function performUpkeep(bytes calldata /* performData */ ) external override { |
| 182 | + (bool upkeepNeeded,) = checkUpkeep(""); |
| 183 | + if (upkeepNeeded) { |
| 184 | + // requestRandomWords(); |
| 185 | + s_numberOfPerformUpkeepCallsForLatestUpkeep += 1; |
| 186 | + } |
| 187 | + } |
| 188 | +} |
0 commit comments