Skip to content

Commit 58f041e

Browse files
SyedAsadKazmiSyed Asad Kazmi
and
Syed Asad Kazmi
authored
Added a utility contract and a JS script for upkeep interactions. (#76)
* Added a utility contract and a JS script for upkeep interactions * Changes done in upkeep-interactions as suggested by Andrej --------- Co-authored-by: Syed Asad Kazmi <[email protected]>
1 parent e3d1f92 commit 58f041e

File tree

5 files changed

+412
-0
lines changed

5 files changed

+412
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules
2+
package-lock.json
3+
.env.enc
4+
.env
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Custom Logic Upkeep Interactions
2+
3+
### UpkeepInteractions.sol
4+
5+
A solidity contract showcasing the interaction with `AutomationRegistrar` and `KeeperRegistry` contracts, for **registration** of **Custom Logic Upkeep** and performing other operations like **pause upkeep**, **unpause upkeep**, **cancel upkeep**, **add funds to upkeep**, **withdraw funds from upkeep**, and **edit gas limit of upkeep**.
6+
7+
**Note:** The upkeep that will be registered using the contract won't be visible in the [Automation UI](https://automation.chain.link/) because the `adminAddress` is being set to the address of the contract (not to any wallet).
8+
9+
### upkeepInteractions.js
10+
11+
A script in JS containing the functions to interact with the registered **Custom Logic Upkeep**.
12+
13+
Run the script using this command:
14+
15+
```js
16+
node upkeepInteractions.js ${KEEPER_REGISTRY_ADDRESS} ${LINK_TOKEN_ADDRESS}
17+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
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+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"dependencies": {
3+
"@chainlink/env-enc": "^1.0.5",
4+
"ethers": "^6.13.2"
5+
}
6+
}

0 commit comments

Comments
 (0)