Automate

Ditto Automate is a framework that enables statefull automation creation and deployment utilizing Ditto execution layer. It features a set of contracts that solidity developers can integrate.

Ditto Automate provides a connection bridge to the The Ditto Entry Point (DEP). DEP is a contract designed to facilitate the registration of workflows within its storage system and subsequent execution by set of operators. These workflows are then monitored by the Ditto execution layer, a collection of operators that strive to execute the registered workflows whenever feasible. As a developer, you can take advantage of our automation framework to create DEP-compatible automations, register them, and have them executed seamlessly.

Automation Setup for Solidity Developers

Solidity developers can clone the example automation repository. After cloning, run forge install to install the Ditto automation library.

In the src folder, you will find two contracts:

  • Mock: This contract stores a value that can be incremented on every even block.

  • AutomateCounter: This contract inherits from DittoAutomate and enables easy, permissionless execution.

In the test folder, you will see an example of a full integration test in a forked environment on Polygon.

To run the integration test, use the following command to set up rpc url:

export POL_RPC_URL=https://polygon.llamarpc.com

And start the tests:

forge test

Overview

The DittoAutomateIOFramework V1 is a comprehensive automation solution for smart contracts. Below is an overview of its components:

Key Components:

  1. Automate.sol: The parent contract to inherit from, providing core automation functionality.

  2. DEP (Ditto Entry Point): The central contract managing workflow execution and integration.

  3. Custom Contracts: Contracts that inherit from Automate.sol to implement specific automation logic.

  4. CheckerBase: The base contract for implementing custom checkers, including:

    • Time Checker

    • HF (Health Factor) Checker

  5. V1 Showcase: AutomateOracleMock: A demonstration of Automate.sol combined with TimeChecker.

  6. AutomateBaseTest V1: Allows for seamless, close-to-production fork tests of any inherited contracts.

Terms and Definitions

DEP : The Ditto contract enables the execution of real-time automations based on user requests.

Automation : A contract tailored to your personal needs that executes actions on the blockchain using DEP control.

Checker : An additional verification contract that your automation references to ensure that the necessary conditions have been met.

What is Automation?

Automation consists of checkers and action. Checkers allow or revert the workflow executions signaling to execution network that the conditions are not met. To perform a check, it must be initialized beforehand. Checks are optional, so you can create automations without checks.

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.

Automate.sol

A contract that can be inherited to create your own automations. Automate.sol interacts with DittoEntryPoint by creating automation on DittoEntryPoint. Then the executors give the DittoEntryPoint command to execute one or another automation on Automate.sol.

The AutomateOracleMock.sol contract shows you how to properly inherit Automate.sol in order to create your own automation that will perform the tasks you need.

Automate7579.sol

The module of the EIP-7579 standard. The contract works as a layer between DittoEntryPoint and account abstraction of the EIP-4337 standard. Automate7579.sol offers a unified option for creating and executing automations on account abstraction.

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.

AutomateOracleMock.sol

An example of how you can inherit an Automate.sol contract.

The contract will rewrite the test data through the function updateTimestamp. This function can only be called by the contract itself. This is indicated by the onlyItself modifier.

AutomateOracleMock.sol
function updateTimestamp() external onlyItself {
      // Update the mapping with the current block number and timestamp
      blockTimestamps[block.number] = block.timestamp;
}

The main function in the contract creates automation with 60 seconds interval time checker, that will trigger the function on automated contract.

AutomateOracleMock.sol
function startOracle() external onlyOwner {
        // getting the ID for the checker
        uint256 checkerId = CheckerTime(CHECKER).getNextCheckerId(address(this));

        // forming a calldata for initializing the checker
        CallInfo[] memory inits = new CallInfo[](1);
        bytes memory timeCheckerInitializeOnTarget =
            abi.encodeCall(CheckerTime.initialize, (uint128(block.timestamp), 60)); // Update interval in seconds
        inits[0] = CallInfo({ target: address(CHECKER), value: 0, callData: timeCheckerInitializeOnTarget });
        // Prepare the actions for the workflow
        CallInfo[] memory actions = new CallInfo[](2);
        // calldata to check if enough time has passed
        bytes memory checkTimeOnTarget = abi.encodeCall(CheckerTime.checkTime, (checkerId));
        actions[0] = CallInfo({ target: address(CHECKER), value: 0, callData: checkTimeOnTarget });
        // calldata for calling updateTimestamp
        bytes memory updateTimestampOnTarget = abi.encodeCall(this.updateTimestamp, ());
        actions[1] = CallInfo({ target: address(this), value: 0, callData: updateTimestampOnTarget });

        // adding automation to DittoEntryPoint
        _activateWorkflow(
            inits,
            actions,
            ORACLE_UPDATE_WORKFLOW_KEY,
            MAX_GAS_LIMIT_WORKFLOW, // Max gas limit
            MAX_GAS_PRICE_WORKFLOW, // Max gas price
            3 // 3 executions
        );
    } 

AutomateSendMock.sol

A simplified version of AutomateOracleMock.sol that does not include checkers.

How to use framework

There are contracts in the repository that are not recommended to be changed:

  • src/base

  • src/conncet

They should be considered as basic for creating automation.

The src/modules/checkers folder contains examples of checkers that you can use as-is or modify to suit your needs. Additionally, you have the option to create your own checkers tailored specifically to your automation requirements.

The src/modules directory will include functionality for working with DeFi logic and is open to further enhancements.

You can create new types of automation by studying AutoomateOracleMock.sol as an example.

In the tests, we have prepared AutomateBaseTest, which allows for integration testing with DEP on forks:

  • testing of checks;

  • testing the payPrefund function;

  • testing the runWorkflow function;

AutomateBaseTest identifies valid executors and simulates their execution on your contracts.

How to work with Automate7579.sol

Add automation via the addWorkflow function, then this automation will be executed on behalf of DittoEntryPoint.

During the workflow addition process, you can initialize the checker. The request to the checker will be executed before the execution of the main action on the target contract.

function addWorkflow(
    Execution[] memory _inits,
    Execution[] memory _actions,
    uint256 _maxGasPrice,
    uint256 _maxGasLimit,
    uint88 _count
) external;

Initialization of checker is optional. If there is no need for checks, then the _inits array can be left empty.

The tests show an example of how the Automate7579 contract works, as well as installing the Automate7579 module on account abstraction as an executor.

Thus, the user of account abstraction (as kernel or safe7579) installs the Automate7579 module as an executor to enable registration and conditional settlement of calldata by Ditto Execution Network.

Last updated