Task Logic

Overview

The Othentic Stack allows developers to write an AVSLogic contract, which provides pre and post execution hooks for task submission on-chain, and enables highly configurable and customized logic.

Interface

The interface defines two functions: beforeTaskSubmission and afterTaskSubmission. As their names suggest, these functions allow developers to implement custom AVS logic before and after task submission within the contract.

// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.20;

/*______     __      __                              __      __ 
 /      \   /  |    /  |                            /  |    /  |
/$$$$$$  | _$$ |_   $$ |____    ______   _______   _$$ |_   $$/   _______ 
$$ |  $$ |/ $$   |  $$      \  /      \ /       \ / $$   |  /  | /       |
$$ |  $$ |$$$$$$/   $$$$$$$  |/$$$$$$  |$$$$$$$  |$$$$$$/   $$ |/$$$$$$$/ 
$$ |  $$ |  $$ | __ $$ |  $$ |$$    $$ |$$ |  $$ |  $$ | __ $$ |$$ |
$$ \__$$ |  $$ |/  |$$ |  $$ |$$$$$$$$/ $$ |  $$ |  $$ |/  |$$ |$$ \_____ 
$$    $$/   $$  $$/ $$ |  $$ |$$       |$$ |  $$ |  $$  $$/ $$ |$$       |
 $$$$$$/     $$$$/  $$/   $$/  $$$$$$$/ $$/   $$/    $$$$/  $$/  $$$$$$$/
*/
/**
 * @author Othentic Labs LTD.
 * @notice Terms of Service: https://www.othentic.xyz/terms-of-service
 */
interface IAvsLogic {
    function afterTaskSubmission(IAttestationCenter.TaskInfo calldata _taskInfo, bool _isApproved, bytes calldata _tpSignature, uint256[2] calldata _taSignature, uint256[] calldata _attestersIds) external;
    function beforeTaskSubmission(IAttestationCenter.TaskInfo calldata _taskInfo, bool _isApproved, bytes calldata _tpSignature, uint256[2] calldata _taSignature, uint256[] calldata _attestersIds) external;
}

These functions are called in the submitTask function in AttestationCenter which is called by the aggregator.

function _submitTask(TaskInfo calldata _taskInfo, TaskSubmissionDetails memory _taskSubmissionDetails) internal {
        AttestationCenterStorageData storage _sd = _getStorage();
        IAvsLogic _avsLogic = _sd.avsLogic;
        bool _isAvsLogicSet = address(_avsLogic) != address(0);
        if (_isAvsLogicSet) {
            _avsLogic.beforeTaskSubmission(_taskInfo, _taskSubmissionDetails.isApproved, _taskSubmissionDetails.tpSignature, _taskSubmissionDetails.taSignature, _taskSubmissionDetails.attestersIds);;
        } 
        ...
        if (_isAvsLogicSet) {
            _avsLogic.afterTaskSubmission(_taskInfo, _taskSubmissionDetails.isApproved, _taskSubmissionDetails.tpSignature, _taskSubmissionDetails.taSignature, _taskSubmissionDetails.attestersIds);
        }
    }

Deployment & Setup

After implementation, you can deploy the contract on the same L2 network as the AttestationCenter.

Make sure to deploy the Othentic contracts before deploying the AVS Logic.

After deployment, you must call the setAvsLogic function on the AttestationCenter and provide the address of the AvsLogic contract as the parameter, as shown in the example below.

Note that only the AVS Governance Multisig is authorized to call this function.

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

/*______     __      __                              __      __ 
 /      \   /  |    /  |                            /  |    /  |
/$$$$$$  | _$$ |_   $$ |____    ______   _______   _$$ |_   $$/   _______ 
$$ |  $$ |/ $$   |  $$      \  /      \ /       \ / $$   |  /  | /       |
$$ |  $$ |$$$$$$/   $$$$$$$  |/$$$$$$  |$$$$$$$  |$$$$$$/   $$ |/$$$$$$$/ 
$$ |  $$ |  $$ | __ $$ |  $$ |$$    $$ |$$ |  $$ |  $$ | __ $$ |$$ |
$$ \__$$ |  $$ |/  |$$ |  $$ |$$$$$$$$/ $$ |  $$ |  $$ |/  |$$ |$$ \_____ 
$$    $$/   $$  $$/ $$ |  $$ |$$       |$$ |  $$ |  $$  $$/ $$ |$$       |
 $$$$$$/     $$$$/  $$/   $$/  $$$$$$$/ $$/   $$/    $$$$/  $$/  $$$$$$$/
*/
/**
 * @author Othentic Labs LTD.
 * @notice Terms of Service: https://www.othentic.xyz/terms-of-service
 */

import {Script, console} from "forge-std/Script.sol";
import "../src/IAttestationCenter.sol";
import "../src/AvsLogic.sol";

// forge script AvsLogicScript --rpc-url $L2_RPC --private-key $PRIVATE_KEY
// --broadcast -vvvv --verify --etherscan-api-key $L2_ETHERSCAN_API_KEY --chain
// $L2_CHAIN --verifier-url $L2_VERIFIER_URL --sig="run(address)" $ATTESTATION_CENTER_ADDRESS
contract AvsLogicScript is Script {
    function setUp() public {}

    function run(address attestationCenter) public {
        vm.broadcast();
        AvsLogic avsLogic = new AvsLogic(attestationCenter);
        IAttestationCenter(attestationCenter).setAvsLogic(address(avsLogic));
    }
}

Now, the AVS contracts are set and ready to be used.


Examples

Task Management

There might be a need to manage and/or track tasks after completion. For example, you can have an array of task results such that anyone can fetch task history and data on chain.

This can be implemented using the AVS Logic. Implement the afterTaskSubmission function such that it sets the task details on-chain which other contracts can fetch via a getter function.

An example could be a random number generator. After a task is completed, the random number generated will be updated on the AvsLogic contract via the afterTaskSubmission function.

Another example could be EigenDA . The task is completed when the confirmBatch function is called which adds the batch details into a mapping stored in the contract.

Note that the function also checks the quorum and emits an event, but these steps have already been executed in the submitTask function.

Updating arbitrary contracts

According to your design, your AVS might have an IFTTT architecture where you might need to do post execution tasks on-chain.

For example, the AVS might be an Oracle service that fetches the latest data of a query. After the operators submit the final result and the task is submitted, you might need to update the latest data on a separate Oracle contract.

The AvsLogic can implement this functionality by calling the contract and updating its state to reflect the latest task data.

Last updated