DEV Community

Suraj975
Suraj975

Posted on

Automate Smart Contracts (Chainlink Keepers )

One of the easiest decentralized ways to automate the smart contract function execution is through chainlink keepers. I have implemented a crypto price pair prediction game which involves execution and adding of new rounds which are completely automated through chainlink keepers. While implementing it I learned a lot of things and like to share them with the community.

Key Features:

  1. It reduces the hassle of implementing a separate centralized backend code to handle these automation processes and hence improving overall efficiency and productivity.

  2. The integrations process is fairly simple and well documented by the chainlink team.

  3. Reduces overall cost and burden of the backend.

How does it work?

There are three things that cover the whole process of the chainlink keepers.

  1. Chainlink Upkeeps are responsible for executing contract function or a specific operation based on certain conditions.
  2. The chainlink keepers need to keep the registry of the contract whose function you want to automate through upkeeps.
  3. Keepers nodes are responsible for tracking all the tasks added in upkeeps, every time when a block gets added to the blockchain.

The blockchain networks that are supported include Ethereum, Polygon, BNB chain, Avalanche and Fantom.

Implementation:
Example taken from chainlink document

    // SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

// KeeperCompatible.sol imports the functions from both ./KeeperBase.sol and
// ./interfaces/KeeperCompatibleInterface.sol
import "@chainlink/contracts/src/v0.8/KeeperCompatible.sol";

/**
 * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY.
 * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE.
 * DO NOT USE THIS CODE IN PRODUCTION.
 */

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 view 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
    }
}


Enter fullscreen mode Exit fullscreen mode

In your contract, there are two functions that need to be implemented which are checkUpkeep and performUpkeep as seen above in the above contract.

  1. Import these functions from KeeperCompatible.sol from openzeplin.
    import "@chainlink/contracts/src/v0.8/KeeperCompatible.sol";

  2. checkUpkeep : This method checks whether a certain condition is met at every block addition. This function runs off-chain to reduce on-chain gas usage and allows you to do gas-intensive calculations off-chain in checkUpkeep and pass the result to performUpkeep on-chain.

function checkUpkeep(
bytes calldata /* checkData */
) external view override returns (bool upkeepNeeded, bytes memory performData) {
upkeepNeeded = false;
uint[] memory lessBalance = new uint[];
for (uint256 i = 0; i < SIZE && !upkeepNeeded; i++) {
if (balances[i] < LIMIT) {
// if one element has a balance < LIMIT then rebalancing is needed
lessBalance.push(balances[i]);
upkeepNeeded = true;
}
}
performData = abi.encode(lessBalance); // This value is received as an argument in performUpkeep function.
return (upkeepNeeded, performData);
}
Enter fullscreen mode Exit fullscreen mode

Two values are returned from the function, one is upkeepNeeded which is a boolean value that determines whether the certain condition is met and the other is performData that you want to send to performUpkeep function when upkeepNeeded is true.

As it runs off-chain, it will always be external and no contract state can be updated which basically makes it a view function.

In the above example when the balance is less than a limit, then a certain action needs to be done which will update the state of the contract.

performUpkeep: This function runs on-chain and is responsible for updating the state of the contract or executing certain contract functions whenever the checkUpkeep returns a true value.
This function is run externally and does not have a view as it modifies the state of the contract.

function performUpkeep(
        bytes calldata /* performData */
    ) external override {
        bool performDataValueRecieved = abi.decode(performData, (bool));

        uint256 increment;
        uint256 _balance;
        for (uint256 i = 0; i < SIZE; i++) {
            _balance = balances[i];
            // best practice: reverify the upkeep is needed
            if (_balance < LIMIT) {
                // calculate the increment needed
                increment = LIMIT - _balance;
                // decrease the contract liquidity accordingly
                liquidity -= increment;
                // rebalance the element
                balances[i] = LIMIT;
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Once the contract is deployed to your preferred chainlink-supported blockchain network.

Get Link Tokens

In order to perform upkeep operation off-chain we need ERC-677 LINK for it to operate. The link token contract is ERC-677 contract, which is an extension of erc20 contract and compatible with erc20 protocol standard. It can carry data during transfer and trigger the business logic of receiving contracts, which can help smart contracts expand application scenarios.

Connect to a blockchain network that supports chainlink keepers. Make sure the account has the tokens.

Visit this link to receive Link tokens.

I am connected to matic testnet, so I will be receiving link tokens in exchange for matic.

Image description

Image description
 
Registering Contract to Chainlink keepers

Chainlink Keepers provide two methods for automating the process. Visit this link to register the new upkeep for your smart contract.
Keepers

Image description
 

Time-based: As the name suggests, it performs operation in upkeep when a certain time condition is met. You need to specify the Cron expression to create time schedule.

Image description  

Image description
 
Image description

Finally, enter upkeep details

Image description

Custom logic: This basically means, that execution is not based on time but on certain pre-defined conditions which when met will execute the upkeep method.

Image description

Image description
 
CheckData is basically static data that you will receive as an argument in your upkeep function.

Fill up the form and then you will see the dashboard which shows the current balance of links and automated transaction events when the upkeep is executed. The link balance gets depleted on every execution of the upkeep method. The ethereum-based contract uses a lot of Link token compared to other blockchain networks.

Image description

Common Issues related to upkeep function not executing

  1. Add the maximum gas limit when filling up the form. Keep a buffer between 300,000 - 500,000.
  2. Check the minimum link balance and refill it.
  3. Double check the condition present on upkeep.

For more in-depth information, please refer these chainlink documents link.

Hope this article would have helped you in implementing a chainlink keepers.

Top comments (0)