Because smart contracts are not self-executing, they need an externally owned account, oracle, or contract for initiation of their own functions. This is a problem for many dApps that require that their smart contracts are executing at regular time intervals (e.g. every 24 hours), when predefined conditions are met (e.g. Ethereum hitting a specific price), or following a coalculation (e.g. a loan is calculated to be undercollateralized).
In the past, developers would solve this problem by creating and maintaining their own centralized scripts to trigger their smart contracts, or trigger them manually. However, this effectively undermines the purpose of building a decentralized blockchain application, and opens up the possibility of downtime if the centralized script or manual triggering process fails.
In this tutorial you will learn how to use Chainlink Keepers to automate your smart contract execution in a reliable and decentralized manner.
Why Every Smart Contract Developer Should Use Decentralized Automation
Chainlink Keepers unlock a new form of decentralized smart contract automation, enabling developers to transform the way they build and maintain dApps. There are three main benefits to decentralized smart contract automation.
Firstly, it is essential to remove any centralized points of failure in your operations. Chainlink Keepers is powered by a decentralized network of Keeper nodes—the same hyper-reliable nodes that currently secure tens of billions in value across DeFi via Chainlink Data Feeds—removing centralized points of failure.
Secondly, rather than investing time and resources in creating scripts for on-chain monitoring and contract execution, developers can plug into Chainlink Keepers’s optimized infrastructure by simply creating a Keeper-compatible contract and registering it. This saves time, reduces the DevOps workload, and allows developers to focus on writing more great code.
Lastly, by using Chainlink Keepers, developers can enhance the security of their protocol. Developers no longer have to risk exposing their own private key when initiating transactions from centralized servers—the nodes on the Chainlink Keeper Network will sign on-chain transactions.
Get Started With Chainlink Keepers
You can automate your smart contracts with Chainlink Keepers in two steps:
- Create and deploy a Keeper-compatible contract
- Register the contract on the Chainlink Keepers app to create an Upkeep
After these steps have been completed, Chainlink Keepers will perform the Upkeep job as specified without any further input.
If you are new to Solidity, we recommend following some of the beginner tutorials before continuing. This tutorial is particularly comprehensive and useful. We will now show you how to make your contract Keeper-compatible. If you prefer watching a video on the topic please watch our video tutorial.
How To Write a Keeper-Compatible Contract
Keeper-compatible contracts have a checkUpkeep
function and a performUpkeep
function with the required inputs and outputs expected by Chainlink Keepers. To help prevent errors we will use the Keeper-compatible interface before we specify what our check and perform functions should do.
Importing the Keeper-Compatible Interface
Start by importing the KeeperCompatibleInterface
into your contract.
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // KeeperCompatible.sol imports the functions from both ./KeeperBase.sol and // ./interfaces/KeeperCompatibleInterface.sol import "@chainlink/contracts/src/v0.8/KeeperCompatible.sol";
There are two functions to this interface:
The checkUpkeep
Function
Chainlink Keepers use a decentralized network to monitor the checkUpkeep
function securely and cost-efficiently off-chain during every block and then initiate an on-chain transaction to execute the smart contract function when predefined conditions are met.
function checkUpkeep( bytes calldata checkData ) external returns ( bool upkeepNeeded, bytes memory performData );
The checkUpkeep
function takes a bytes parameter named checkData
that is set when you register your Upkeep on the Keepers app. This value is optional and can be used in your logic to determine if checkUpkeep
returns true
.
checkUpkeep
returns a bool called upkeepNeeded
. When true, this will call performUpkeep
. It also returns performData
in Bytes format (optional additional data) that the Keeper should call performUpkeep
with if Upkeep is needed. For more information, see the Developer Documentation.
The performUpkeep
Function
If the off-chain simulation of your checkUpkeep
confirms your predefined conditions are met (upkeepNeeded == true
from checkUpkeep
), the Keeper will broadcast a transaction to the blockchain executing the performUpkeep
with performData
as an input.
function performUpkeep( bytes calldata performData ) external;
A rotating node selection process prevents gas price auction wars between nodes and stabilizes costs of automating your contracts.
Here is an example contract snippet from Chainlink Keepers user Entropyfi where checkUpkeep
checks whether the Entropyfi prediction game is due for settlement.
/** * @dev chainlink keeper checkUpkeep function to constantly check whether we need function call **/ function checkUpkeep(bytes calldata checkData) external override returns (bool upkeepNeeded, bytes memory performData) { PoolStatus currState = status.currState; uint256 lastUpdateTimestamp = status.lastUpdateTimestamp; uint256 durationOfGame = status.durationOfGame; uint256 durationOfBidding = status.durationOfBidding; if (currState == PoolStatus.Accepting && block.timestamp > lastUpdateTimestamp.add(durationOfBidding)) { upkeepNeeded = true; } else if (currState == PoolStatus.Locked && block.timestamp > lastUpdateTimestamp.add(durationOfGame)) { upkeepNeeded = true; } else { upkeepNeeded = false; } performData = checkData; }
Chainlink Keepers will constantly call the checkUpkeep
function, and if the upkeepNeeded
is evaluated to true
, then the nodes will execute the performUpkeep
function.
/** * @dev once checkUpKeep been triggered, keeper will call performUpKeep **/ function performUpkeep(bytes calldata performData) external override { PoolStatus currState = status.currState; uint256 lastUpdateTimestamp = status.lastUpdateTimestamp; uint256 durationOfGame = status.durationOfGame; uint256 durationOfBidding = status.durationOfBidding; if (currState == PoolStatus.Accepting && block.timestamp > lastUpdateTimestamp.add(durationOfBidding)) { startGame(); } if (currState == PoolStatus.Locked && block.timestamp > lastUpdateTimestamp.add(durationOfGame)) { endGame(); } performData; }
Start With Some Sample Code
Whether you are creating a new contract or already have a contract deployed that contains a function that needs to be automated there are guides to help you get started in the Chainlink Keepers Developer Documentation.
Start with the example contract here. The example below represents a simple counter contract.
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; // KeeperCompatible.sol imports the functions from both ./KeeperBase.sol and // ./interfaces/KeeperCompatibleInterface.sol import "@chainlink/contracts/src/v0.7/KeeperCompatible.sol"; contract Counter is KeeperCompatibleInterface { /** * Public counter variable */ uint public counter; /** * Use an interval in seconds and a timestamp to slow execution of Upkeep */ uint public immutable interval; uint public lastTimeStamp; constructor(uint updateInterval) { interval = updateInterval; lastTimeStamp = block.timestamp; counter = 0; } function checkUpkeep(bytes calldata /* checkData */) external override returns (bool upkeepNeeded, bytes memory /* performData */) { upkeepNeeded = (block.timestamp - lastTimeStamp) > interval; // We don't use the checkData in this example. The checkData is defined when the Upkeep was registered. } function performUpkeep(bytes calldata /* performData */) external override { //We highly recommend revalidating the upkeep in the performUpkeep function if ((block.timestamp - lastTimeStamp) > interval ) { lastTimeStamp = block.timestamp; counter = counter + 1; } // We don't use the performData in this example. The performData is generated by the Keeper's call to your checkUpkeep function } }
Chainlink Keepers can monitor the state of any on-chain or off-chain condition, such as the passage of time (e.g. did 24 hours pass?) or a computation (e.g. is the loan calculated to be undercollateralized?). Once a condition is met, Chainlink Keepers submit a transaction on-chain to trigger the function to execute.
You can also start with a Chainlink Keepers utility contract such as the EthBalanceMonitor contract or these examples.
How to Register Your Contract as an Upkeep on the Network
Once you have your Keeper-compatible contract, head over to the Chainlink Keepers app and click “Register new Upkeep”.
For a detailed step-by-step guide on how to register, see the Chainlink Developer Documentation.
Important note (for non-ETH chains): your Upkeep must be funded with ERC-677 LINK (not ERC-20, which is common across many token bridges). Use PegSwap to make your LINK tokens ERC-677 compatible.
Once registered and approved, you can add additional funds and see all the details for your Upkeep on the Chainlink Keepers app.
Get Started Today
Now that you know how easy it is to automate your smart contracts with Chainlink Keepers, you can get started with integrating Keepers and unlock a huge range of use cases, such as DEX limit orders, cross-chain NFT minting, rebasing and rebalancing tokens, and much more.
Learn more by visiting the developer documentation and joining the technical discussion in Discord. If you want to schedule a call to discuss the integration more in-depth, reach out here.
To learn more, visit chain.link, subscribe to the Chainlink newsletter, and follow Chainlink on Twitter, YouTube, and Reddit.
Originally posted here: https://blog.chain.link/how-to-automate-smart-contract-execution-using-chainlink-keepers/