Checkers

Checker serves as a link between the terms and execution of smart contracts. His purpose? Check the conditions and determine whether automation should be performed.

Examples

CheckerBase.sol

The basic contract for any checker. Implements the logic to get the correct checker ID for each address. There is an implementation example in the CheckerBase.sol contract, which shows how to properly inherit CheckerBase. Checkers uses msg.sender for automation AccessControl.

CheckerAaveHF.sol

An example of the implementation of a checker that checks HealthFactor in the Aave pool. The testing and basic principles of CheckerAaveHF.sol are developed in the CheckerAaveHF.t.sol file.

CheckerTime.sol

An example of the implementation of a checker that performs a time check. For example, you want to do automation no more than once an hour. The testing and basic principles of CheckerTime.sol are developed in the CheckerTime.t.sol file.

How to create a checker

Сreate your own Checker in a few simple steps:

  1. Inherit the basic contract for Checker, then define the data structure required for check:

contract CheckerTime is CheckerBase {
    struct CheckerStorage {
        uint128 lastActionTime;
        uint128 timePeriod;
    }

    function _getStorageUnsafe(
        bytes32 pointer
    ) internal pure returns (CheckerStorage storage s) {
        assembly ("memory-safe") {
            s.slot := pointer
        }
    }

    function _getStorage(
        bytes32 pointer
    ) internal view returns (CheckerStorage storage s) {
        s = _getStorageUnsafe(pointer);

        if (s.timePeriod == 0) {
            revert NotInitialized();
        }
    }
}
  1. Write a function for initialization that will accept the conditions for check:

contract CheckerTime is CheckerBase {
    // ...
    function initialize(
        uint128 lastActionTime, 
        uint128 timePeriod
    ) external {
        address vault = msg.sender;
        uint256 nextCheckerId = _getNextCheckerId(vault);
        bytes32 innerPointer = _shakeVaultAndCheckerId(vault, nextCheckerId);
        CheckerStorage storage s = _getStorageUnsafe(innerPointer);
        lastCheckerId[vault] = nextCheckerId;

        s.lastActionTime = lastActionTime;
        s.timePeriod = timePeriod;

        emit Initialized();
    }    
}
  1. Write the main function to check:

contract CheckerTime is CheckerBase {
    // ...
    function checkTime(
        uint256 checkerId
    ) external {
        address vault = msg.sender;
        bytes32 innerPointer = _shakeVaultAndCheckerId(vault, checkerId);
        CheckerStorage storage s = _getStorage(innerPointer);

        bool enoughTimePassed = (uint128(block.timestamp) >= (startTime + period));

        if (!enoughTimePassed) {
            revert NotEnoughTimePassed();
        }

        s.lastActionTime = uint128(block.timestamp);
    }
}

Learn more about how this example works:

Checker workflow:

Last updated