How do I configure the perform upkeep to know which function to call in chainlink keepers?

504 Views Asked by At

I want the Chainlink Keeper to call a function based on some paramters, so my checkUpkeep function is as follows:

function checkUpkeep(
        bytes calldata checkData
    ) external view override returns (
        bool upkeepNeeded, bytes memory performData
    ) {
        if (getPrice() == roundMoonPrice[coinRound]) {
            upkeepNeeded = true;
            return (true, performData) ;`//should perform upkeep for the setTime() function`
        } if (roundWinningIndex[coinRound].length != 0) {
            upkeepNeeded = true;
            return (true, performData);`//should perform upkep for the a withdrawal function
        }

How do I configure the perform upkeep to know which function to call? How do I make sure it calls the correct function?

1

There are 1 best solutions below

0
On

There are a number of ways you can have the keepers call the correct function. One way would be to add information in your performData designating which function to call.

The performUpkeep looks like this:

function performUpkeep(bytes calldata performData) external override {
        // conditional to call one function
        // conditional to call a different function
    }

1. The Better way

When the Chainlink keepers call checkUpkeep they pass the returned information of performData to the input of performUpkeep. You can encode just about anything to pass as inputs to the performUpkeep function.

For example, you could pass a number to performUpkeep that corresponds with which function to call:

function checkUpkeep(
        bytes calldata checkData
    ) external view override returns (
        bool upkeepNeeded, bytes memory performData
    ) {
        if (getPrice() == roundMoonPrice[coinRound]) {
            upkeepNeeded = true;
            performData = abi.encodePacked(uint256(0); // This is the new line
            return (true, performData) ;
        } if (roundWinningIndex[coinRound].length != 0) {
            upkeepNeeded = true;
            performData = abi.encodePacked(uint256(1); // This is the new line
            return (true, performData);
        }

Then, in your performUpkeep:

function performUpkeep(bytes calldata performData) external override {
        uint256 decodedValue = abi.decode(performData, (uint256));
        if(decodedValue == 0){
            setTime();
        } 
        if(decodedValue == 1){
            withdraw();
        }
    }

We encode and decode our performData object. In fact, we can use multiple parameters as well using more clever encoding per the solidity docs.

2. The not as good, but easier to understand way

Otherwise, you could do something with storage variables if the encoding is too tricky. This isn't ideal, because multiple calls of performUpkeep will fight for the storage variable.

For example:

uint256 public functionToCall = 0;

function checkUpkeep(
        bytes calldata checkData
    ) external view override returns (
        bool upkeepNeeded, bytes memory performData
    ) {
        if (getPrice() == roundMoonPrice[coinRound]) {
            upkeepNeeded = true;
            functionToCall = 0;
            return (true, performData) ;
        } if (roundWinningIndex[coinRound].length != 0) {
            upkeepNeeded = true;
            functionToCall = 1;
            return (true, performData);
        }

Then:

function performUpkeep(bytes calldata performData) external override {
        if(functionToCall == 0){
            setTime();
        } 
        if(functionToCall == 1){
            withdraw();
        }
    }