diff --git a/src/interfaces/multichain/IBN254CertificateVerifier.sol b/src/interfaces/multichain/IBN254CertificateVerifier.sol new file mode 100644 index 00000000..185f0b9b --- /dev/null +++ b/src/interfaces/multichain/IBN254CertificateVerifier.sol @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import {BN254} from "../../libraries/BN254.sol"; +import {OperatorSet} from "eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol"; +import {IBN254TableCalculatorTypes} from "./IBN254TableCalculator.sol"; +import {ICertificateVerifier} from "./ICertificateVerifier.sol"; + +interface IBN254CertificateVerifierTypes is IBN254TableCalculatorTypes { + /** + * @notice A witness for an operator + * @param operatorIndex the index of the nonsigner in the `BN254OperatorInfo` tree + * @param operatorInfoProofs merkle proofs of the nonsigner at the index. Empty if operator is in cache. + * @param operatorInfo the `BN254OperatorInfo` for the operator + */ + struct BN254OperatorInfoWitness { + uint32 operatorIndex; + bytes operatorInfoProof; + BN254OperatorInfo operatorInfo; + } + + /** + * @notice A BN254 Certificate + * @param referenceTimestamp the timestamp at which the certificate was created + * @param messageHash the hash of the message that was signed by operators and used to verify the aggregated signature + * @param signature the G1 signature of the message + * @param apk the G2 aggregate public key + * @param nonSignerWitnesses an array of witnesses of non-signing operators + */ + struct BN254Certificate { + uint32 referenceTimestamp; + bytes32 messageHash; + BN254.G1Point signature; + BN254.G2Point apk; + BN254OperatorInfoWitness[] nonSignerWitnesses; + } +} + +interface IBN254CertificateVerifierEvents is IBN254CertificateVerifierTypes { + /// @notice Emitted when a table is updated + event TableUpdated(uint32 referenceTimestamp, BN254OperatorSetInfo operatorSetInfo); +} + +/// @notice A base table manager interface that handles operator table updates +/// @dev We separate out this interface for forwards-compatibility with a future `TableManager` contract that stores all operatorSet's tables on a chain +interface IBN254TableManager is IBN254CertificateVerifierTypes { + /** + * @notice updates the operator table + * @param operatorSet the operatorSet to update the operator table for + * @param referenceTimestamp the timestamp at which the operatorSetInfo and + * operatorInfoTreeRoot were sourced + * @param operatorSetInfo the aggregate information about the operatorSet + * @dev only callable by the operatorTableUpdater + * @dev We pass in an `operatorSet` for future-proofing a global `TableManager` contract + */ + function updateOperatorTable( + OperatorSet calldata operatorSet, + uint32 referenceTimestamp, + BN254OperatorSetInfo memory operatorSetInfo + ) external; + + /** + * @notice ejects operators from the operatorSet + * @param referenceTimestamp the timestamp of the operator tbale against which + * the ejection is being done + * @param operatorIndices the indices of the operators to eject + * @param witnesses for the operators that are not already in storage + * @dev only callable by the ejector + * @dev We pass in an `operatorSet` for future-proofing a global `TableManager` contract + */ + function ejectOperators( + OperatorSet calldata operatorSet, + uint32 referenceTimestamp, + uint32[] calldata operatorIndices, + BN254OperatorInfoWitness[] calldata witnesses + ) external; +} + +interface IBN254CertificateVerifier is + ICertificateVerifier, + IBN254TableManager, + IBN254CertificateVerifierEvents +{ + /** + * @notice verifies a certificate + * @param cert a certificate + * @return signedStakes amount of stake that signed the certificate for each stake + * type + */ + function verifyCertificate( + BN254Certificate memory cert + ) external returns (uint96[] memory signedStakes); + + /** + * @notice verifies a certificate and makes sure that the signed stakes meet + * provided portions of the total stake on the AVS + * @param cert a certificate + * @param totalStakeProportionThresholds the proportion of total stake that + * the signed stake of the certificate should meet + * @return whether or not certificate is valid and meets thresholds + */ + function verifyCertificateProportion( + BN254Certificate memory cert, + uint16[] memory totalStakeProportionThresholds + ) external returns (bool); + + /** + * @notice verifies a certificate and makes sure that the signed stakes meet + * provided nominal stake thresholds + * @param cert a certificate + * @param totalStakeNominalThresholds the nominal amount of stake that + * the signed stake of the certificate should meet + * @return whether or not certificate is valid and meets thresholds + */ + function verifyCertificateNominal( + BN254Certificate memory cert, + uint96[] memory totalStakeNominalThresholds + ) external returns (bool); +} diff --git a/src/interfaces/multichain/IBN254TableCalculator.sol b/src/interfaces/multichain/IBN254TableCalculator.sol new file mode 100644 index 00000000..af0ef22d --- /dev/null +++ b/src/interfaces/multichain/IBN254TableCalculator.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import {BN254} from "../../libraries/BN254.sol"; +import {OperatorSet} from "eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol"; +import {IOperatorTableCalculator} from "./IOperatorTableCalculator.sol"; + +interface IBN254TableCalculatorTypes { + /** + * @notice A struct that contains information about a single operator + * @param pubkey The G1 public key of the operator. + * @param weights The weights of the operator for a single operatorSet. + * @dev The `weights` array can be defined as a list of arbitrary groupings. For example, + * it can be [slashable_stake, delegated_stake, strategy_i_stake, ...] + */ + struct BN254OperatorInfo { + BN254.G1Point pubkey; + uint96[] weights; + } + + /** + * @notice A struct that contains information about all operators for a given operatorSet + * @param operatorInfoTreeRoot The root of the operatorInfo tree. + * @param numOperators The number of operators in the operatorSet. + * @param aggregatePubkey The aggregate G1 public key of the operators in the operatorSet. + * @param totalWeights The total weights of the operators in the operatorSet. + * + * @dev The operatorInfoTreeRoot is the root of a merkle tree that contains the operatorInfos for each operator in the operatorSet. + * It is calculated in this function and used by the `IBN254CertificateVerifier` to verify stakes against the non-signing operators + * + * @dev Retrieval of the `aggregatePubKey` depends on maintaining a key registry contract, see `BLSAPKRegistry` for an example implementation. + * + * @dev The `totalWeights` array should be the same length as each individual `weights` array in `operatorInfos`. + */ + struct BN254OperatorSetInfo { + bytes32 operatorInfoTreeRoot; + uint256 numOperators; + BN254.G1Point aggregatePubkey; + uint96[] totalWeights; + } +} + +interface IBN254TableCalculator is IOperatorTableCalculator, IBN254TableCalculatorTypes { + /** + * @notice calculates the operatorInfos for a given operatorSet + * @param operatorSet the operatorSet to calculate the operator table for + * @return operatorSetInfo the operatorSetInfo for the given operatorSet + * @dev The output of this function is converted to bytes via the `calculateOperatorTableBytes` function + */ + function calculateOperatorTable( + OperatorSet calldata operatorSet + ) external view returns (BN254OperatorSetInfo memory operatorSetInfo); + + /** + * @notice Get the operatorInfos for a given operatorSet + * @param operatorSet the operatorSet to get the operatorInfos for + * @return operatorInfos the operatorInfos for the given operatorSet + */ + function getOperatorInfos( + OperatorSet calldata operatorSet + ) external view returns (BN254OperatorInfo[] memory operatorInfos); +} diff --git a/src/interfaces/multichain/ICertificateVerifier.sol b/src/interfaces/multichain/ICertificateVerifier.sol new file mode 100644 index 00000000..37ae5f29 --- /dev/null +++ b/src/interfaces/multichain/ICertificateVerifier.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import {OperatorSet} from "eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol"; + +interface ICertificateVerifierErrors { + /// @notice Thrown when the table updater is not caller + error OnlyTableUpdater(); + /// @notice Thrown when the table is too stale + error TableStale(); + /// @notice Thrown when certificate verification fails + error CertVerificationFailed(); +} + +/// @notice A base interface that verifies certificates for a given operatorSet +/// @notice This is a base interface that all curve certificate verifiers (eg. BN254, ECDSA) must implement +/// @dev A single `CertificateVerifier` can be used for ONLY 1 operatorSet +interface ICertificateVerifier is ICertificateVerifierErrors { + /** + * @notice sets the operator table updater + * @param operatorTableUpdater the address of the operator table updater + * @dev only callable by the owner + */ + function setOperatorTableUpdater( + address operatorTableUpdater + ) external; + + /** + * @notice Sets the ejector + * @param ejector the address of the ejector + * @dev only callable by the owner + */ + function setEjector( + address ejector + ) external; + + /** + * @notice sets the max operator table staleness + * @param maxOperatorTableStaleness the max operator table staleness + * @dev only callable by the owner + */ + function setMaxOperatorTableStaleness( + uint32 maxOperatorTableStaleness + ) external; + + /// @notice the operatorSet the CertificateVerifier is for + function operatorSet() external returns (OperatorSet memory); + + /// @notice the address of the entity that can update the operator table + function operatorTableUpdater() external returns (address); + + /// @notice the address of the entity that can eject operators + function ejector() external returns (address); + + /// @return the maximum amount of seconds that a operator table can be in the past + function maxOperatorTableStaleness() external returns (uint32); + + /// @notice The latest reference timestamp of the operator table + function latestReferenceTimestamp() external returns (uint32); +} diff --git a/src/interfaces/multichain/IECDSACertificateVerifier.sol b/src/interfaces/multichain/IECDSACertificateVerifier.sol new file mode 100644 index 00000000..01dd370e --- /dev/null +++ b/src/interfaces/multichain/IECDSACertificateVerifier.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import {OperatorSet} from "eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol"; +import {ICertificateVerifier} from "./ICertificateVerifier.sol"; +import {IECDSATableCalculatorTypes} from "./IECDSATableCalculator.sol"; + +interface IECDSCertificateVerifierTypes is IECDSATableCalculatorTypes { + /** + * @notice A ECDSA Certificate + * @param referenceTimestamp the timestamp at which the certificate was created + * @param messageHash the hash of the message that was signed by operators + * @param signature the concatenated signature of each signing operator + */ + struct ECDSACertificate { + uint32 referenceTimestamp; + bytes32 messageHash; + bytes sig; + } +} + +interface IECDSACertificateVerifierEvents is IECDSCertificateVerifierTypes { + /// @notice Emitted when a table is updated + event TableUpdated(uint32 referenceTimestamp, ECDSAOperatorInfo[] operatorInfos); +} + +/// @notice A base table manager interface that handles operator table updates +/// @dev We separate out this interface for forwards-compatibility with a future `TableManager` contract that stores all operatorSet's tables on a chain +interface IECDSATableManager is IECDSCertificateVerifierTypes { + /** + * @notice updates the operator table + * @param operatorSet the operatorSet to update the operator table for + * @param referenceTimestamp the timestamp at which the operatorInfos were sourced + * @param operatorInfos the operatorInfos to update the operator table with + * @dev only callable by the operatorTableUpdater + * @dev We pass in an `operatorSet` for future-proofing a global `TableManager` contract + */ + function updateOperatorTable( + OperatorSet calldata operatorSet, + uint32 referenceTimestamp, + ECDSAOperatorInfo[] calldata operatorInfos + ) external; + + /** + * @notice ejects operators from the operatorSet + * @param operatorSet the operatorSet to eject operators from + * @param referenceTimestamp the timestamp of the operator table against which + * the ejection is being done + * @param operatorIndices the indices of the operators to eject + * @dev only callable by the ejector + * @dev We pass in an `operatorSet` for future-proofing a global `TableManager` contract + */ + function ejectOperators( + OperatorSet calldata operatorSet, + uint32 referenceTimestamp, + uint32[] calldata operatorIndices + ) external; +} + +interface IECDSACertificateVerifier is + ICertificateVerifier, + IECDSATableManager, + IECDSACertificateVerifierEvents +{ + /** + * @notice verifies a certificate + * @param cert a certificate + * @return signedStakes amount of stake that signed the certificate for each stake + * type + */ + function verifyCertificate( + ECDSACertificate memory cert + ) external returns (uint96[] memory signedStakes); + + /** + * @notice verifies a certificate and makes sure that the signed stakes meet + * provided portions of the total stake on the AVS + * @param cert a certificate + * @param totalStakeProportionThresholds the proportion of total stake that + * the signed stake of the certificate should meet + * @return whether or not certificate is valid and meets thresholds + */ + function verifyCertificateProportion( + ECDSACertificate memory cert, + uint16[] memory totalStakeProportionThresholds + ) external returns (bool); + + /** + * @notice verifies a certificate and makes sure that the signed stakes meet + * provided portions of the total stake on the AVS + * @param cert a certificate + * @param totalStakeNominalThresholds the proportion of total stake that + * the signed stake of the certificate should meet + * @return whether or not certificate is valid and meets thresholds + */ + function verifyCertificateNominal( + ECDSACertificate memory cert, + uint96[] memory totalStakeNominalThresholds + ) external returns (bool); +} diff --git a/src/interfaces/multichain/IECDSATableCalculator.sol b/src/interfaces/multichain/IECDSATableCalculator.sol new file mode 100644 index 00000000..929b73c6 --- /dev/null +++ b/src/interfaces/multichain/IECDSATableCalculator.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import {OperatorSet} from "eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol"; +import {IOperatorTableCalculator} from "./IOperatorTableCalculator.sol"; + +interface IECDSATableCalculatorTypes { + /** + * @notice A struct that contains information about a single operator + * @param pubkey The address of the operator + * @param weights The weights of the operator for a single operatorSet + * @dev The `weights` array can be defined as a list of arbitrary groupings. For example, + * it can be [slashable_stake, delegated_stake, strategy_i_stake, ...] + */ + struct ECDSAOperatorInfo { + address pubkey; + uint96[] weights; + } +} + +interface IECDSATableCalculator is IOperatorTableCalculator, IECDSATableCalculatorTypes { + /** + * @notice calculates the operatorInfos for a given operatorSet + * @param operatorSet the operatorSet to calculate the operator table for + * @return operatorInfos the list of operatorInfos for the given operatorSet + * @dev The output of this function is converted to bytes via the `calculateOperatorTableBytes` function + */ + function calculateOperatorTable( + OperatorSet calldata operatorSet + ) external view returns (ECDSAOperatorInfo[] memory operatorInfos); +} diff --git a/src/interfaces/multichain/IOperatorTableCalculator.sol b/src/interfaces/multichain/IOperatorTableCalculator.sol new file mode 100644 index 00000000..1fbf1ed4 --- /dev/null +++ b/src/interfaces/multichain/IOperatorTableCalculator.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + +import {OperatorSet} from "eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol"; +import {IOperatorWeightCalculator} from "./IOperatorWeightCalculator.sol"; + +/// @notice A base interface that calculates an operator table for a given operatorSet and returns its bytes representation +/// @notice This is a base interface that all curve table calculators (eg. BN254, ECDSA) must implement +/// @dev A single `OperatorTableCalculator` can be used for multiple operatorSets of an AVS +interface IOperatorTableCalculator { + /// @notice Thrown when the operatorSet does not exist. + error InvalidOperatorSet(); + + /** + * @notice Sets the operatorWeightCalculator for a given operatorSet + * @param operatorSet The operatorSet to set the operatorWeightCalculator for + * @param operatorWeightCalculator The operatorWeightCalculator to set for the given operatorSet + * @dev This function is only callable by the owner of the contract + */ + function setOperatorWeightCalculator( + OperatorSet calldata operatorSet, + IOperatorWeightCalculator operatorWeightCalculator + ) external; + + /** + * @notice calculates the operatorTableBytes for a given operatorSet + * @param operatorSet the operatorSet to calculate the operatorTableBytes for + * @return operatorTableBytes The operatorTable bytes + */ + function calculateOperatorTableBytes( + OperatorSet calldata operatorSet + ) external view returns (bytes memory operatorTableBytes); + + /** + * @notice For a given operatorSet, returns the operatorWeightCalculator + * @param operatorSet The operatorSet to get the operatorWeightCalculator for + * @return operatorWeightCalculator The operatorWeightCalculator for the given operatorSet + * @dev This contract + */ + function getOperatorWeightCalculator( + OperatorSet calldata operatorSet + ) external view returns (IOperatorWeightCalculator); +} diff --git a/src/interfaces/multichain/IOperatorWeightCalculator.sol b/src/interfaces/multichain/IOperatorWeightCalculator.sol new file mode 100644 index 00000000..020c9d9a --- /dev/null +++ b/src/interfaces/multichain/IOperatorWeightCalculator.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import {OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; + +/// @notice A contract that calculates the weights for all operators in a given operatorSet +/// @notice This is a base interface to send operator weights to the `IOperatorTableCalculator` +/// @notice We separate this out to be able to plug-in different operator weight calculators for each operatorSet +interface IOperatorWeightCalculator { + /** + * @notice Get the weights for all operators in a given operatorSet + * @param operatorSet The operatorSet to get the weights for + * @return operators The addresses of the operators in the operatorSet + * @return weights The weights for each operator in the operatorSet + */ + function getOperatorWeights( + OperatorSet calldata operatorSet + ) external view returns (address[] memory operators, uint96[][] memory weights); +}