AVS 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

// 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(uint16 _taskDefinitionId, address _performerAddr, string calldata _proofOfTask, bool _isApproved, bytes calldata _tpSignature, uint256[2] calldata _taSignature, uint256[] calldata _operatorIds) external;
    function beforeTaskSubmission(uint16 _taskDefinitionId, address _performerAddr, string calldata _proofOfTask, bool _isApproved, bytes calldata _tpSignature, uint256[2] calldata _taSignature, uint256[] calldata _operatorIds) external;
}

The interface declares two functions, namely beforeTasksubmission and afterTaskSubmission. As the name suggests, developers can implement their AVS logic in this contract.

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

function _submitTask(TaskInfo calldata _taskInfo, bool _isApproved, bytes calldata _tpSignature, uint256[2] calldata _taSignature, uint256[] calldata _operatorIds) internal {
        IAvsLogic _avsLogic = _getAvsLogic();
        bool _isAvsLogicSet = address(_avsLogic) != address(0);
        if (_isAvsLogicSet) {
            _avsLogic.beforeTaskSubmission(_taskInfo, _isApproved, _tpSignature, _taSignature, _operatorIds);
        } 
        ...
        if (_isAvsLogicSet) {
            _avsLogic.afterTaskSubmission(_taskInfo, _isApproved, _tpSignature, _taSignature, _operatorIds);
        }
    }

Deployment and setup

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

You should deploy the Othentic contracts before deploying the AVS Logic.

// 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));
    }
}

After deploying, you need to call the setAvsLogic function on the AttestationCenter and pass in the address of the AvsLogic as the parameter. 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 they’re completed. 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 can be fetched by other contracts 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 are already 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