Rewards Fee Calculator

Overview

The Othentic Stack enables developers to create a FeeCalculator contract, which functions as a hook for calculating task submission rewards on-chain, offering flexible and customizable logic tailored to specific needs.

Interface

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

/*______     __      __                              __      __ 
 /      \   /  |    /  |                            /  |    /  |
/$$$$$$  | _$$ |_   $$ |____    ______   _______   _$$ |_   $$/   _______ 
$$ |  $$ |/ $$   |  $$      \  /      \ /       \ / $$   |  /  | /       |
$$ |  $$ |$$$$$$/   $$$$$$$  |/$$$$$$  |$$$$$$$  |$$$$$$/   $$ |/$$$$$$$/ 
$$ |  $$ |  $$ | __ $$ |  $$ |$$    $$ |$$ |  $$ |  $$ | __ $$ |$$ |
$$ \__$$ |  $$ |/  |$$ |  $$ |$$$$$$$$/ $$ |  $$ |  $$ |/  |$$ |$$ \_____ 
$$    $$/   $$  $$/ $$ |  $$ |$$       |$$ |  $$ |  $$  $$/ $$ |$$       |
 $$$$$$/     $$$$/  $$/   $$/  $$$$$$$/ $$/   $$/    $$$$/  $$/  $$$$$$$/
*/

/**
 * @author Othentic Labs LTD.
 * @notice Terms of Service: https://www.othentic.xyz/terms-of-service
 * @notice Depending on the application, it may be necessary to add reentrancy gaurds to hooks
 */
 
import { IAttestationCenter } from "@othentic/NetworkManagement/L2/interfaces/IAttestationCenter.sol";

interface IFeeCalculator {

    struct FeeCalculatorData {
        IAttestationCenter.TaskInfo data;
        uint256 aggregatorId;
        uint256 performerId;
        uint256[] attestersIds;
    }

    struct FeePerId {
        uint256 index;
        uint256 fee;
    }

    function calculateBaseRewardFees(FeeCalculatorData calldata _feeCalculatorData) external returns (uint256 baseRewardFeeForAttesters, uint256 baseRewardFeeForAggregator, uint256 baseRewardFeeForPerformer);
    function calculateFeesPerId(FeeCalculatorData calldata _feeCalculatorData) external returns (FeePerId[] memory feesPerId);
    function isBaseRewardFee() external pure returns (bool);
}

The interface defines two functions: calculateBaseRewardFees and calculateFeesPerId. You should select one of these options.

These functions can be called in the AttestationCenter inside the submitTask function by the Task Aggregator.

calculateBaseRewardFees example:

    function _calculateBaseRewardFees(AttestationCenterStorageData storage _sd, uint16 _taskDefinitionId, TaskDefinition memory _taskDefinition, IFeeCalculator.FeeCalculatorData memory _feeCalculatorData) private returns (uint256 _baseRewardFeeForAttesters, uint256 _baseRewardFeeForPerformer, uint256 _baseRewardFeeForAggregator) {
        IFeeCalculator _feeCalculator = _sd.feeCalculator;
        bool _isFeeCalculatorSet = address(_feeCalculator) != address(0);
        if(_isFeeCalculatorSet){
            (_baseRewardFeeForAttesters, 
            _baseRewardFeeForPerformer, 
            _baseRewardFeeForAggregator) = _feeCalculator.calculateBaseRewardFees(_feeCalculatorData);
        }
        ...
    }

calculateFeesPerId example:

    function _submitTaskBusinessLogic(AttestationCenterStorageData storage _sd, TaskInfo calldata _taskInfo, TaskDefinition memory _taskDefinition, bool _isApproved, uint256[] memory _attestersIds) private {
        ...
        IFeeCalculator _feeCalculator = _sd.feeCalculator;
        bool _isFeeCalculatorSet = address(_feeCalculator) != address(0);
        if (!_isFeeCalculatorSet || (_isFeeCalculatorSet && _feeCalculator.isBaseRewardFee())) {
            ...
        }
        else {
            IFeeCalculator.FeePerId[] memory _feesPerId = _feeCalculator.calculateFeesPerId(_feeCalculatorData);
            _accumulateRewardsForOperatorsById(_sd, _feesPerId, _taskNumber);
        }

Deployment and setup

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

You should deploy the AVS contracts before deploying the IFeeCalculator.

// 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/FeeCalculator.sol";

// forge script FeeCalculatorScript --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 FeeCalculatorScript is Script {
    function setUp() public {}

    function run(address attestationCenter) public {
        vm.broadcast();
        FeeCalculator feeCalculator = new FeeCalculator(attestationCenter);
        IAttestationCenter(attestationCenter).setFeeCalculator(address(feeCalculator));
    }
}

After deploying, you need to call the setFeeCalculator function on the AttestationCenter and pass in the address of the FeeCalculator as the parameter. Now, the contracts are set and ready to be used.

Last updated