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
The interface defines two functions: calculateBaseRewardFees
and calculateFeesPerId
.
You should select one of these options.
Copy // 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);
}
These functions are invoked within the AttestationCenter
contract as part of the submitTask
function by the Task Aggregator.
calculateBaseRewardFees
function is called in the _calculateBaseRewardFees
function.
Copy 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
is called in the _submitTaskBusinessLogic
function.
Copy 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.
After deployment, you must call the setFeeCalculator function in the AttestationCenter
and provide the address of the FeeCalculator
contract as the parameter, as shown in the example below.
Note that only the AVS Governance Multisig is authorized to call this function.
Copy // 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));
}
}
Now, the contracts are set and ready to be used.
Last updated 2 months ago