Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/middlewareV2/tableCalculator/ECDSATableCalculator.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import {OperatorSet} from "eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol";
import {IAllocationManager} from
"eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
import {IKeyRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IKeyRegistrar.sol";
import "./ECDSATableCalculatorBase.sol";
/**
* @title ECDSATableCalculator
* @notice Implementation that calculates ECDSA operator tables using the sum of the minimum slashable stake weights
* @dev This contract assumes that slashable stake is valued the **same** across all strategies.
*/
contract ECDSATableCalculator is ECDSATableCalculatorBase {
// Immutables
/// @notice AllocationManager contract for managing operator allocations
IAllocationManager public immutable allocationManager;
/// @notice The default lookahead blocks for the slashable stake lookup
uint256 public immutable LOOKAHEAD_BLOCKS;
/**
* @notice Constructor to initialize the ECDSATableCalculator
* @param _keyRegistrar The KeyRegistrar contract for managing operator ECDSA keys
* @param _allocationManager The AllocationManager contract for operator allocations and slashable stake
* @param _LOOKAHEAD_BLOCKS The number of blocks to look ahead when calculating minimum slashable stake
* @dev The lookahead blocks parameter helps ensure stake calculations account for future slashing events
*/
constructor(
IKeyRegistrar _keyRegistrar,
IAllocationManager _allocationManager,
uint256 _LOOKAHEAD_BLOCKS
) ECDSATableCalculatorBase(_keyRegistrar) {
allocationManager = _allocationManager;
LOOKAHEAD_BLOCKS = _LOOKAHEAD_BLOCKS;
}
/**
* @notice Get the operator weights for a given operatorSet based on the minimum slashable stake.
* @param operatorSet The operatorSet to get the weights for
* @return operators The addresses of the operators in the operatorSet with non-zero slashable stake
* @return weights The weights for each operator in the operatorSet, this is a 2D array where the first index is the operator
* and the second index is the type of weight. In this case it's of length 1 and returns the slashable stake for the operatorSet.
* @dev This implementation sums the minimum slashable stake across all strategies for each operator
* @dev Only includes operators with non-zero total slashable stake to optimize gas usage
* @dev The weights array contains only one element per operator representing their total slashable stake
*/
function _getOperatorWeights(
OperatorSet calldata operatorSet
) internal view override returns (address[] memory operators, uint256[][] memory weights) {
// Get all operators & strategies in the operatorSet
address[] memory registeredOperators = allocationManager.getMembers(operatorSet);
IStrategy[] memory strategies = allocationManager.getStrategiesInOperatorSet(operatorSet);
// Get the minimum slashable stake for each operator
uint256[][] memory minSlashableStake = allocationManager.getMinimumSlashableStake({
operatorSet: operatorSet,
operators: registeredOperators,
strategies: strategies,
futureBlock: uint32(block.number + LOOKAHEAD_BLOCKS)
});
operators = new address[](registeredOperators.length);
weights = new uint256[][](registeredOperators.length);
uint256 operatorCount = 0;
for (uint256 i = 0; i < registeredOperators.length; ++i) {
// For the given operator, loop through the strategies and sum together to calculate the operator's weight for the operatorSet
uint256 totalWeight;
for (uint256 stratIndex = 0; stratIndex < strategies.length; ++stratIndex) {
totalWeight += minSlashableStake[i][stratIndex];
}
// If the operator has nonzero slashable stake, add them to the operators array
if (totalWeight > 0) {
// Initialize operator weights array of length 1 just for slashable stake
weights[operatorCount] = new uint256[](1);
weights[operatorCount][0] = totalWeight;
// Add the operator to the operators array
operators[operatorCount] = registeredOperators[i];
operatorCount++;
}
}
// Resize arrays to be the size of the number of operators with nonzero slashable stake
assembly {
mstore(operators, operatorCount)
mstore(weights, operatorCount)
}
return (operators, weights);
}
}
"
},
"lib/eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
using OperatorSetLib for OperatorSet global;
/**
* @notice An operator set identified by the AVS address and an identifier
* @param avs The address of the AVS this operator set belongs to
* @param id The unique identifier for the operator set
*/
struct OperatorSet {
address avs;
uint32 id;
}
library OperatorSetLib {
function key(
OperatorSet memory os
) internal pure returns (bytes32) {
return bytes32(abi.encodePacked(os.avs, uint96(os.id)));
}
function decode(
bytes32 _key
) internal pure returns (OperatorSet memory) {
/// forgefmt: disable-next-item
return OperatorSet({
avs: address(uint160(uint256(_key) >> 96)),
id: uint32(uint256(_key) & type(uint96).max)
});
}
}
"
},
"lib/eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import {OperatorSet} from "../libraries/OperatorSetLib.sol";
import "./IPauserRegistry.sol";
import "./IStrategy.sol";
import "./IAVSRegistrar.sol";
import "./ISemVerMixin.sol";
interface IAllocationManagerErrors {
/// Input Validation
/// @dev Thrown when `wadToSlash` is zero or greater than 1e18
error InvalidWadToSlash();
/// @dev Thrown when two array parameters have mismatching lengths.
error InputArrayLengthMismatch();
/// @dev Thrown when the AVSRegistrar is not correctly configured to prevent an AVSRegistrar contract
/// from being used with the wrong AVS
error InvalidAVSRegistrar();
/// @dev Thrown when an invalid strategy is provided.
error InvalidStrategy();
/// @dev Thrown when an invalid redistribution recipient is provided.
error InvalidRedistributionRecipient();
/// Caller
/// @dev Thrown when caller is not authorized to call a function.
error InvalidCaller();
/// Operator Status
/// @dev Thrown when an invalid operator is provided.
error InvalidOperator();
/// @dev Thrown when an invalid avs whose metadata is not registered is provided.
error NonexistentAVSMetadata();
/// @dev Thrown when an operator's allocation delay has yet to be set.
error UninitializedAllocationDelay();
/// @dev Thrown when attempting to slash an operator when they are not slashable.
error OperatorNotSlashable();
/// @dev Thrown when trying to add an operator to a set they are already a member of
error AlreadyMemberOfSet();
/// @dev Thrown when trying to slash/remove an operator from a set they are not a member of
error NotMemberOfSet();
/// Operator Set Status
/// @dev Thrown when an invalid operator set is provided.
error InvalidOperatorSet();
/// @dev Thrown when provided `strategies` are not in ascending order.
error StrategiesMustBeInAscendingOrder();
/// @dev Thrown when trying to add a strategy to an operator set that already contains it.
error StrategyAlreadyInOperatorSet();
/// @dev Thrown when a strategy is referenced that does not belong to an operator set.
error StrategyNotInOperatorSet();
/// Modifying Allocations
/// @dev Thrown when an operator attempts to set their allocation for an operatorSet to the same value
error SameMagnitude();
/// @dev Thrown when an allocation is attempted for a given operator when they have pending allocations or deallocations.
error ModificationAlreadyPending();
/// @dev Thrown when an allocation is attempted that exceeds a given operators total allocatable magnitude.
error InsufficientMagnitude();
}
interface IAllocationManagerTypes {
/**
* @notice Defines allocation information from a strategy to an operator set, for an operator
* @param currentMagnitude the current magnitude allocated from the strategy to the operator set
* @param pendingDiff a pending change in magnitude, if it exists (0 otherwise)
* @param effectBlock the block at which the pending magnitude diff will take effect
*/
struct Allocation {
uint64 currentMagnitude;
int128 pendingDiff;
uint32 effectBlock;
}
/**
* @notice Struct containing allocation delay metadata for a given operator.
* @param delay Current allocation delay
* @param isSet Whether the operator has initially set an allocation delay. Note that this could be false but the
* block.number >= effectBlock in which we consider their delay to be configured and active.
* @param pendingDelay The delay that will take effect after `effectBlock`
* @param effectBlock The block number after which a pending delay will take effect
*/
struct AllocationDelayInfo {
uint32 delay;
bool isSet;
uint32 pendingDelay;
uint32 effectBlock;
}
/**
* @notice Contains registration details for an operator pertaining to an operator set
* @param registered Whether the operator is currently registered for the operator set
* @param slashableUntil If the operator is not registered, they are still slashable until
* this block is reached.
*/
struct RegistrationStatus {
bool registered;
uint32 slashableUntil;
}
/**
* @notice Contains allocation info for a specific strategy
* @param maxMagnitude the maximum magnitude that can be allocated between all operator sets
* @param encumberedMagnitude the currently-allocated magnitude for the strategy
*/
struct StrategyInfo {
uint64 maxMagnitude;
uint64 encumberedMagnitude;
}
/**
* @notice Struct containing parameters to slashing
* @param operator the address to slash
* @param operatorSetId the ID of the operatorSet the operator is being slashed on behalf of
* @param strategies the set of strategies to slash
* @param wadsToSlash the parts in 1e18 to slash, this will be proportional to the operator's
* slashable stake allocation for the operatorSet
* @param description the description of the slashing provided by the AVS for legibility
*/
struct SlashingParams {
address operator;
uint32 operatorSetId;
IStrategy[] strategies;
uint256[] wadsToSlash;
string description;
}
/**
* @notice struct used to modify the allocation of slashable magnitude to an operator set
* @param operatorSet the operator set to modify the allocation for
* @param strategies the strategies to modify allocations for
* @param newMagnitudes the new magnitude to allocate for each strategy to this operator set
*/
struct AllocateParams {
OperatorSet operatorSet;
IStrategy[] strategies;
uint64[] newMagnitudes;
}
/**
* @notice Parameters used to register for an AVS's operator sets
* @param avs the AVS being registered for
* @param operatorSetIds the operator sets within the AVS to register for
* @param data extra data to be passed to the AVS to complete registration
*/
struct RegisterParams {
address avs;
uint32[] operatorSetIds;
bytes data;
}
/**
* @notice Parameters used to deregister from an AVS's operator sets
* @param operator the operator being deregistered
* @param avs the avs being deregistered from
* @param operatorSetIds the operator sets within the AVS being deregistered from
*/
struct DeregisterParams {
address operator;
address avs;
uint32[] operatorSetIds;
}
/**
* @notice Parameters used by an AVS to create new operator sets
* @param operatorSetId the id of the operator set to create
* @param strategies the strategies to add as slashable to the operator set
*/
struct CreateSetParams {
uint32 operatorSetId;
IStrategy[] strategies;
}
}
interface IAllocationManagerEvents is IAllocationManagerTypes {
/// @notice Emitted when operator updates their allocation delay.
event AllocationDelaySet(address operator, uint32 delay, uint32 effectBlock);
/// @notice Emitted when an operator's magnitude is updated for a given operatorSet and strategy
event AllocationUpdated(
address operator, OperatorSet operatorSet, IStrategy strategy, uint64 magnitude, uint32 effectBlock
);
/// @notice Emitted when operator's encumbered magnitude is updated for a given strategy
event EncumberedMagnitudeUpdated(address operator, IStrategy strategy, uint64 encumberedMagnitude);
/// @notice Emitted when an operator's max magnitude is updated for a given strategy
event MaxMagnitudeUpdated(address operator, IStrategy strategy, uint64 maxMagnitude);
/// @notice Emitted when an operator is slashed by an operator set for a strategy
/// `wadSlashed` is the proportion of the operator's total delegated stake that was slashed
event OperatorSlashed(
address operator, OperatorSet operatorSet, IStrategy[] strategies, uint256[] wadSlashed, string description
);
/// @notice Emitted when an AVS configures the address that will handle registration/deregistration
event AVSRegistrarSet(address avs, IAVSRegistrar registrar);
/// @notice Emitted when an AVS updates their metadata URI (Uniform Resource Identifier).
/// @dev The URI is never stored; it is simply emitted through an event for off-chain indexing.
event AVSMetadataURIUpdated(address indexed avs, string metadataURI);
/// @notice Emitted when an operator set is created by an AVS.
event OperatorSetCreated(OperatorSet operatorSet);
/// @notice Emitted when an operator is added to an operator set.
event OperatorAddedToOperatorSet(address indexed operator, OperatorSet operatorSet);
/// @notice Emitted when an operator is removed from an operator set.
event OperatorRemovedFromOperatorSet(address indexed operator, OperatorSet operatorSet);
/// @notice Emitted when a redistributing operator set is created by an AVS.
event RedistributionAddressSet(OperatorSet operatorSet, address redistributionRecipient);
/// @notice Emitted when a strategy is added to an operator set.
event StrategyAddedToOperatorSet(OperatorSet operatorSet, IStrategy strategy);
/// @notice Emitted when a strategy is removed from an operator set.
event StrategyRemovedFromOperatorSet(OperatorSet operatorSet, IStrategy strategy);
}
interface IAllocationManager is IAllocationManagerErrors, IAllocationManagerEvents, ISemVerMixin {
/**
* @dev Initializes the initial owner and paused status.
*/
function initialize(
uint256 initialPausedStatus
) external;
/**
* @notice Called by an AVS to slash an operator in a given operator set. The operator must be registered
* and have slashable stake allocated to the operator set.
*
* @param avs The AVS address initiating the slash.
* @param params The slashing parameters, containing:
* - operator: The operator to slash.
* - operatorSetId: The ID of the operator set the operator is being slashed from.
* - strategies: Array of strategies to slash allocations from (must be in ascending order).
* - wadsToSlash: Array of proportions to slash from each strategy (must be between 0 and 1e18).
* - description: Description of why the operator was slashed.
*
* @return slashId The ID of the slash.
* @return shares The amount of shares that were slashed for each strategy.
*
* @dev For each strategy:
* 1. Reduces the operator's current allocation magnitude by wadToSlash proportion.
* 2. Reduces the strategy's max and encumbered magnitudes proportionally.
* 3. If there is a pending deallocation, reduces it proportionally.
* 4. Updates the operator's shares in the DelegationManager.
*
* @dev Small slashing amounts may not result in actual token burns due to
* rounding, which will result in small amounts of tokens locked in the contract
* rather than fully burning through the burn mechanism.
*/
function slashOperator(
address avs,
SlashingParams calldata params
) external returns (uint256 slashId, uint256[] memory shares);
/**
* @notice Modifies the proportions of slashable stake allocated to an operator set from a list of strategies
* Note that deallocations remain slashable for DEALLOCATION_DELAY blocks therefore when they are cleared they may
* free up less allocatable magnitude than initially deallocated.
* @param operator the operator to modify allocations for
* @param params array of magnitude adjustments for one or more operator sets
* @dev Updates encumberedMagnitude for the updated strategies
*/
function modifyAllocations(address operator, AllocateParams[] calldata params) external;
/**
* @notice This function takes a list of strategies and for each strategy, removes from the deallocationQueue
* all clearable deallocations up to max `numToClear` number of deallocations, updating the encumberedMagnitude
* of the operator as needed.
*
* @param operator address to clear deallocations for
* @param strategies a list of strategies to clear deallocations for
* @param numToClear a list of number of pending deallocations to clear for each strategy
*
* @dev can be called permissionlessly by anyone
*/
function clearDeallocationQueue(
address operator,
IStrategy[] calldata strategies,
uint16[] calldata numToClear
) external;
/**
* @notice Allows an operator to register for one or more operator sets for an AVS. If the operator
* has any stake allocated to these operator sets, it immediately becomes slashable.
* @dev After registering within the ALM, this method calls the AVS Registrar's `IAVSRegistrar.
* registerOperator` method to complete registration. This call MUST succeed in order for
* registration to be successful.
*/
function registerForOperatorSets(address operator, RegisterParams calldata params) external;
/**
* @notice Allows an operator or AVS to deregister the operator from one or more of the AVS's operator sets.
* If the operator has any slashable stake allocated to the AVS, it remains slashable until the
* DEALLOCATION_DELAY has passed.
* @dev After deregistering within the ALM, this method calls the AVS Registrar's `IAVSRegistrar.
* deregisterOperator` method to complete deregistration. This call MUST succeed in order for
* deregistration to be successful.
*/
function deregisterFromOperatorSets(
DeregisterParams calldata params
) external;
/**
* @notice Called by the delegation manager OR an operator to set an operator's allocation delay.
* This is set when the operator first registers, and is the number of blocks between an operator
* allocating magnitude to an operator set, and the magnitude becoming slashable.
* @param operator The operator to set the delay on behalf of.
* @param delay the allocation delay in blocks
*/
function setAllocationDelay(address operator, uint32 delay) external;
/**
* @notice Called by an AVS to configure the address that is called when an operator registers
* or is deregistered from the AVS's operator sets. If not set (or set to 0), defaults
* to the AVS's address.
* @param registrar the new registrar address
*/
function setAVSRegistrar(address avs, IAVSRegistrar registrar) external;
/**
* @notice Called by an AVS to emit an `AVSMetadataURIUpdated` event indicating the information has updated.
*
* @param metadataURI The URI for metadata associated with an AVS.
*
* @dev Note that the `metadataURI` is *never stored* and is only emitted in the `AVSMetadataURIUpdated` event.
*/
function updateAVSMetadataURI(address avs, string calldata metadataURI) external;
/**
* @notice Allows an AVS to create new operator sets, defining strategies that the operator set uses
*/
function createOperatorSets(address avs, CreateSetParams[] calldata params) external;
/**
* @notice Allows an AVS to create new Redistribution operator sets.
* @param avs The AVS creating the new operator sets.
* @param params An array of operator set creation parameters.
* @param redistributionRecipients An array of addresses that will receive redistributed funds when operators are slashed.
* @dev Same logic as `createOperatorSets`, except `redistributionRecipients` corresponding to each operator set are stored.
* Additionally, emits `RedistributionOperatorSetCreated` event instead of `OperatorSetCreated` for each created operator set.
*/
function createRedistributingOperatorSets(
address avs,
CreateSetParams[] calldata params,
address[] calldata redistributionRecipients
) external;
/**
* @notice Allows an AVS to add strategies to an operator set
* @dev Strategies MUST NOT already exist in the operator set
* @dev If the operatorSet is redistributing, the `BEACONCHAIN_ETH_STRAT` may not be added, since redistribution is not supported for native eth
* @param avs the avs to set strategies for
* @param operatorSetId the operator set to add strategies to
* @param strategies the strategies to add
*/
function addStrategiesToOperatorSet(address avs, uint32 operatorSetId, IStrategy[] calldata strategies) external;
/**
* @notice Allows an AVS to remove strategies from an operator set
* @dev Strategies MUST already exist in the operator set
* @param avs the avs to remove strategies for
* @param operatorSetId the operator set to remove strategies from
* @param strategies the strategies to remove
*/
function removeStrategiesFromOperatorSet(
address avs,
uint32 operatorSetId,
IStrategy[] calldata strategies
) external;
/**
*
* VIEW FUNCTIONS
*
*/
/**
* @notice Returns the number of operator sets for the AVS
* @param avs the AVS to query
*/
function getOperatorSetCount(
address avs
) external view returns (uint256);
/**
* @notice Returns the list of operator sets the operator has current or pending allocations/deallocations in
* @param operator the operator to query
* @return the list of operator sets the operator has current or pending allocations/deallocations in
*/
function getAllocatedSets(
address operator
) external view returns (OperatorSet[] memory);
/**
* @notice Returns the list of strategies an operator has current or pending allocations/deallocations from
* given a specific operator set.
* @param operator the operator to query
* @param operatorSet the operator set to query
* @return the list of strategies
*/
function getAllocatedStrategies(
address operator,
OperatorSet memory operatorSet
) external view returns (IStrategy[] memory);
/**
* @notice Returns the current/pending stake allocation an operator has from a strategy to an operator set
* @param operator the operator to query
* @param operatorSet the operator set to query
* @param strategy the strategy to query
* @return the current/pending stake allocation
*/
function getAllocation(
address operator,
OperatorSet memory operatorSet,
IStrategy strategy
) external view returns (Allocation memory);
/**
* @notice Returns the current/pending stake allocations for multiple operators from a strategy to an operator set
* @param operators the operators to query
* @param operatorSet the operator set to query
* @param strategy the strategy to query
* @return each operator's allocation
*/
function getAllocations(
address[] memory operators,
OperatorSet memory operatorSet,
IStrategy strategy
) external view returns (Allocation[] memory);
/**
* @notice Given a strategy, returns a list of operator sets and corresponding stake allocations.
* @dev Note that this returns a list of ALL operator sets the operator has allocations in. This means
* some of the returned allocations may be zero.
* @param operator the operator to query
* @param strategy the strategy to query
* @return the list of all operator sets the operator has allocations for
* @return the corresponding list of allocations from the specific `strategy`
*/
function getStrategyAllocations(
address operator,
IStrategy strategy
) external view returns (OperatorSet[] memory, Allocation[] memory);
/**
* @notice For a strategy, get the amount of magnitude that is allocated across one or more operator sets
* @param operator the operator to query
* @param strategy the strategy to get allocatable magnitude for
* @return currently allocated magnitude
*/
function getEncumberedMagnitude(address operator, IStrategy strategy) external view returns (uint64);
/**
* @notice For a strategy, get the amount of magnitude not currently allocated to any operator set
* @param operator the operator to query
* @param strategy the strategy to get allocatable magnitude for
* @return magnitude available to be allocated to an operator set
*/
function getAllocatableMagnitude(address operator, IStrategy strategy) external view returns (uint64);
/**
* @notice Returns the maximum magnitude an operator can allocate for the given strategy
* @dev The max magnitude of an operator starts at WAD (1e18), and is decreased anytime
* the operator is slashed. This value acts as a cap on the max magnitude of the operator.
* @param operator the operator to query
* @param strategy the strategy to get the max magnitude for
* @return the max magnitude for the strategy
*/
function getMaxMagnitude(address operator, IStrategy strategy) external view returns (uint64);
/**
* @notice Returns the maximum magnitude an operator can allocate for the given strategies
* @dev The max magnitude of an operator starts at WAD (1e18), and is decreased anytime
* the operator is slashed. This value acts as a cap on the max magnitude of the operator.
* @param operator the operator to query
* @param strategies the strategies to get the max magnitudes for
* @return the max magnitudes for each strategy
*/
function getMaxMagnitudes(
address operator,
IStrategy[] calldata strategies
) external view returns (uint64[] memory);
/**
* @notice Returns the maximum magnitudes each operator can allocate for the given strategy
* @dev The max magnitude of an operator starts at WAD (1e18), and is decreased anytime
* the operator is slashed. This value acts as a cap on the max magnitude of the operator.
* @param operators the operators to query
* @param strategy the strategy to get the max magnitudes for
* @return the max magnitudes for each operator
*/
function getMaxMagnitudes(
address[] calldata operators,
IStrategy strategy
) external view returns (uint64[] memory);
/**
* @notice Returns the maximum magnitude an operator can allocate for the given strategies
* at a given block number
* @dev The max magnitude of an operator starts at WAD (1e18), and is decreased anytime
* the operator is slashed. This value acts as a cap on the max magnitude of the operator.
* @param operator the operator to query
* @param strategies the strategies to get the max magnitudes for
* @param blockNumber the blockNumber at which to check the max magnitudes
* @return the max magnitudes for each strategy
*/
function getMaxMagnitudesAtBlock(
address operator,
IStrategy[] calldata strategies,
uint32 blockNumber
) external view returns (uint64[] memory);
/**
* @notice Returns the time in blocks between an operator allocating slashable magnitude
* and the magnitude becoming slashable. If the delay has not been set, `isSet` will be false.
* @dev The operator must have a configured delay before allocating magnitude
* @param operator The operator to query
* @return isSet Whether the operator has configured a delay
* @return delay The time in blocks between allocating magnitude and magnitude becoming slashable
*/
function getAllocationDelay(
address operator
) external view returns (bool isSet, uint32 delay);
/**
* @notice Returns the number of blocks between an operator deallocating magnitude and the magnitude becoming
* unslashable and then being able to be reallocated to another operator set. Note that unlike the allocation delay
* which is configurable by the operator, the DEALLOCATION_DELAY is globally fixed and cannot be changed.
*/
function DEALLOCATION_DELAY() external view returns (uint32 delay);
/**
* @notice Returns a list of all operator sets the operator is registered for
* @param operator The operator address to query.
*/
function getRegisteredSets(
address operator
) external view returns (OperatorSet[] memory operatorSets);
/**
* @notice Returns whether the operator is registered for the operator set
* @param operator The operator to query
* @param operatorSet The operator set to query
*/
function isMemberOfOperatorSet(address operator, OperatorSet memory operatorSet) external view returns (bool);
/**
* @notice Returns whether the operator set exists
*/
function isOperatorSet(
OperatorSet memory operatorSet
) external view returns (bool);
/**
* @notice Returns all the operators registered to an operator set
* @param operatorSet The operatorSet to query.
*/
function getMembers(
OperatorSet memory operatorSet
) external view returns (address[] memory operators);
/**
* @notice Returns the number of operators registered to an operatorSet.
* @param operatorSet The operatorSet to get the member count for
*/
function getMemberCount(
OperatorSet memory operatorSet
) external view returns (uint256);
/**
* @notice Returns the address that handles registration/deregistration for the AVS
* If not set, defaults to the input address (`avs`)
*/
function getAVSRegistrar(
address avs
) external view returns (IAVSRegistrar);
/**
* @notice Returns an array of strategies in the operatorSet.
* @param operatorSet The operatorSet to query.
*/
function getStrategiesInOperatorSet(
OperatorSet memory operatorSet
) external view returns (IStrategy[] memory strategies);
/**
* @notice Returns the minimum amount of stake that will be slashable as of some future block,
* according to each operator's allocation from each strategy to the operator set. Note that this function
* will return 0 for the slashable stake if the operator is not slashable at the time of the call.
* @dev This method queries actual delegated stakes in the DelegationManager and applies
* each operator's allocation to the stake to produce the slashable stake each allocation
* represents. This method does not consider slashable stake in the withdrawal queue even though there could be
* slashable stake in the queue.
* @dev This minimum takes into account `futureBlock`, and will omit any pending magnitude
* diffs that will not be in effect as of `futureBlock`. NOTE that in order to get the true
* minimum slashable stake as of some future block, `futureBlock` MUST be greater than block.number
* @dev NOTE that `futureBlock` should be fewer than `DEALLOCATION_DELAY` blocks in the future,
* or the values returned from this method may not be accurate due to deallocations.
* @param operatorSet the operator set to query
* @param operators the list of operators whose slashable stakes will be returned
* @param strategies the strategies that each slashable stake corresponds to
* @param futureBlock the block at which to get allocation information. Should be a future block.
*/
function getMinimumSlashableStake(
OperatorSet memory operatorSet,
address[] memory operators,
IStrategy[] memory strategies,
uint32 futureBlock
) external view returns (uint256[][] memory slashableStake);
/**
* @notice Returns the current allocated stake, irrespective of the operator's slashable status for the operatorSet.
* @param operatorSet the operator set to query
* @param operators the operators to query
* @param strategies the strategies to query
*/
function getAllocatedStake(
OperatorSet memory operatorSet,
address[] memory operators,
IStrategy[] memory strategies
) external view returns (uint256[][] memory slashableStake);
/**
* @notice Returns whether an operator is slashable by an operator set.
* This returns true if the operator is registered or their slashableUntil block has not passed.
* This is because even when operators are deregistered, they still remain slashable for a period of time.
* @param operator the operator to check slashability for
* @param operatorSet the operator set to check slashability for
*/
function isOperatorSlashable(address operator, OperatorSet memory operatorSet) external view returns (bool);
/**
* @notice Returns the address where slashed funds will be sent for a given operator set.
* @param operatorSet The Operator Set to query.
* @return For redistributing Operator Sets, returns the configured redistribution address set during Operator Set creation.
* For non-redistributing operator sets, returns the `DEFAULT_BURN_ADDRESS`.
*/
function getRedistributionRecipient(
OperatorSet memory operatorSet
) external view returns (address);
/**
* @notice Returns whether a given operator set supports redistribution
* or not when funds are slashed and burned from EigenLayer.
* @param operatorSet The Operator Set to query.
* @return For redistributing Operator Sets, returns true.
* For non-redistributing Operator Sets, returns false.
*/
function isRedistributingOperatorSet(
OperatorSet memory operatorSet
) external view returns (bool);
/**
* @notice Returns the number of slashes for a given operator set.
* @param operatorSet The operator set to query.
* @return The number of slashes for the operator set.
*/
function getSlashCount(
OperatorSet memory operatorSet
) external view returns (uint256);
/**
* @notice Returns whether an operator is slashable by a redistributing operator set.
* @param operator The operator to query.
*/
function isOperatorRedistributable(
address operator
) external view returns (bool);
}
"
},
"lib/eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../libraries/SlashingLib.sol";
import "./ISemVerMixin.sol";
interface IStrategyErrors {
/// @dev Thrown when called by an account that is not strategy manager.
error OnlyStrategyManager();
/// @dev Thrown when new shares value is zero.
error NewSharesZero();
/// @dev Thrown when total shares exceeds max.
error TotalSharesExceedsMax();
/// @dev Thrown when amount shares is greater than total shares.
error WithdrawalAmountExceedsTotalDeposits();
/// @dev Thrown when attempting an action with a token that is not accepted.
error OnlyUnderlyingToken();
/// StrategyBaseWithTVLLimits
/// @dev Thrown when `maxPerDeposit` exceeds max.
error MaxPerDepositExceedsMax();
/// @dev Thrown when balance exceeds max total deposits.
error BalanceExceedsMaxTotalDeposits();
}
interface IStrategyEvents {
/**
* @notice Used to emit an event for the exchange rate between 1 share and underlying token in a strategy contract
* @param rate is the exchange rate in wad 18 decimals
* @dev Tokens that do not have 18 decimals must have offchain services scale the exchange rate by the proper magnitude
*/
event ExchangeRateEmitted(uint256 rate);
/**
* Used to emit the underlying token and its decimals on strategy creation
* @notice token
* @param token is the ERC20 token of the strategy
* @param decimals are the decimals of the ERC20 token in the strategy
*/
event StrategyTokenSet(IERC20 token, uint8 decimals);
}
/**
* @title Minimal interface for an `Strategy` contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice Custom `Strategy` implementations may expand extensively on this interface.
*/
interface IStrategy is IStrategyErrors, IStrategyEvents, ISemVerMixin {
/**
* @notice Used to deposit tokens into this Strategy
* @param token is the ERC20 token being deposited
* @param amount is the amount of token being deposited
* @dev This function is only callable by the strategyManager contract. It is invoked inside of the strategyManager's
* `depositIntoStrategy` function, and individual share balances are recorded in the strategyManager as well.
* @return newShares is the number of new shares issued at the current exchange ratio.
*/
function deposit(IERC20 token, uint256 amount) external returns (uint256);
/**
* @notice Used to withdraw tokens from this Strategy, to the `recipient`'s address
* @param recipient is the address to receive the withdrawn funds
* @param token is the ERC20 token being transferred out
* @param amountShares is the amount of shares being withdrawn
* @dev This function is only callable by the strategyManager contract. It is invoked inside of the strategyManager's
* other functions, and individual share balances are recorded in the strategyManager as well.
* @return amountOut is the amount of tokens being transferred out.
*/
function withdraw(address recipient, IERC20 token, uint256 amountShares) external returns (uint256);
/**
* @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
* For a staker using this function and trying to calculate the amount of underlying tokens they have in total they
* should input into `amountShares` their withdrawable shares read from the `DelegationManager` contract.
* @notice In contrast to `sharesToUnderlyingView`, this function **may** make state modifications
* @param amountShares is the amount of shares to calculate its conversion into the underlying token
* @return The amount of underlying tokens corresponding to the input `amountShares`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function sharesToUnderlying(
uint256 amountShares
) external returns (uint256);
/**
* @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
* @notice In contrast to `underlyingToSharesView`, this function **may** make state modifications
* @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
* @return The amount of shares corresponding to the input `amountUnderlying`. This is used as deposit shares
* in the `StrategyManager` contract.
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function underlyingToShares(
uint256 amountUnderlying
) external returns (uint256);
/**
* @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
* this strategy. In contrast to `userUnderlyingView`, this function **may** make state modifications
*/
function userUnderlying(
address user
) external returns (uint256);
/**
* @notice convenience function for fetching the current total shares of `user` in this strategy, by
* querying the `strategyManager` contract
*/
function shares(
address user
) external view returns (uint256);
/**
* @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
* For a staker using this function and trying to calculate the amount of underlying tokens they have in total they
* should input into `amountShares` their withdrawable shares read from the `DelegationManager` contract.
* @notice In contrast to `sharesToUnderlying`, this function guarantees no state modifications
* @param amountShares is the amount of shares to calculate its conversion into the underlying token
* @return The amount of underlying tokens corresponding to the input `amountShares`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function sharesToUnderlyingView(
uint256 amountShares
) external view returns (uint256);
/**
* @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
* @notice In contrast to `underlyingToShares`, this function guarantees no state modifications
* @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
* @return The amount of shares corresponding to the input `amountUnderlying`. This is used as deposit shares
* in the `StrategyManager` contract.
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function underlyingToSharesView(
uint256 amountUnderlying
) external view returns (uint256);
/**
* @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
* this strategy. In contrast to `userUnderlying`, this function guarantees no state modifications
*/
function userUnderlyingView(
address user
) external view returns (uint256);
/// @notice The underlying token for shares in this Strategy
function underlyingToken() external view returns (IERC20);
/// @notice The total number of extant shares in this Strategy
function totalShares() external view returns (uint256);
/// @notice Returns either a brief string explaining the strategy's goal & purpose, or a link to metadata that explains in more detail.
function explanation() external view returns (string memory);
}
"
},
"lib/eigenlayer-contracts/src/contracts/interfaces/IKeyRegistrar.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import {OperatorSet} from "../libraries/OperatorSetLib.sol";
import {BN254} from "../libraries/BN254.sol";
import "./ISemVerMixin.sol";
interface IKeyRegistrarErrors {
/// @notice Error thrown when a key is already registered
/// @dev Error code: 0x18f78402
/// @dev We prevent duplicate key registrations to maintain global key uniqueness and avoid conflicting operator-key mappings
error KeyAlreadyRegistered();
/// @notice Error thrown when an operator is already registered
/// @dev Error code: 0x42ee68b5
/// @dev We prevent duplicate operator registrations to prevent re-registrations with a new key
error OperatorAlreadyRegistered();
/// @notice Error thrown when the key format is invalid
/// @dev Error code: 0xd1091181
/// @dev We enforce proper key formats (20 bytes for ECDSA, valid G1/G2 points for BN254) to ensure cryptographic validity and prevent malformed key data
error InvalidKeyFormat();
/// @notice Error thrown when the address is zero
/// @dev Error code: 0xd92e233d
error ZeroAddress();
/// @notice Error thrown when the public key is zero
/// @dev Error code: 0x4935505f
error ZeroPubkey();
/// @notice Error thrown when the curve type is invalid
/// @dev Error code: 0xfdea7c09
/// @dev We require valid curve types (ECDSA or BN254)
error InvalidCurveType();
/// @notice Error thrown when the keypair is invalid
/// @dev Error code: 0x1b56a68b
error InvalidKeypair();
/// @notice Error thrown when the configuration is already set
/// @dev Error code: 0x0081f09f
/// @dev We prevent reconfiguration of operator sets to maintain consistency and avoid conflicting curve type settings
error ConfigurationAlreadySet();
/// @notice Error thrown when the operator set is not configured
/// @dev Error code: 0xb9a620da
/// @dev We require operator sets to be configured before key operations to ensure proper curve type validation and prevent operations on unconfigured sets
error OperatorSetNotConfigured();
/// @notice Error thrown when the key is not found
/// @dev Error code: 0x2e40e187
/// @dev We require existing key registrations for deregistration operations to ensure meaningful state changes and prevent operations on non-existent keys
error KeyNotFound(OperatorSet operatorSet, address operator);
/// @notice Error thrown when the operator is still slashable when trying to deregister a key
/// @dev Error code: 0x10702879
/// @dev We prevent key deregistration while operators are slashable to avoid race conditions and ensure operators cannot escape slashing by deregistering keys
error OperatorStillSlashable(OperatorSet operatorSet, address operator);
}
interface IKeyRegistrarTypes {
/// @dev Enum defining supported curve types
enum CurveType {
NONE,
ECDSA,
BN254
}
/// @dev Structure to store key information
struct KeyInfo {
bool isRegistered;
bytes keyData; // Flexible storage for different curve types
}
}
interface IKeyRegistrarEvents is IKeyRegistrarTypes {
/// @notice Emitted when a key is registered
event KeyRegistered(OperatorSet operatorSet, address indexed operator, CurveType curveType, bytes pubkey);
/// @notice Emitted when a key is deregistered
event KeyDeregistered(OperatorSet operatorSet, address indexed operator, CurveType curveType);
/// @notice Emitted when the aggregate BN254 key is updated
event AggregateBN254KeyUpdated(OperatorSet operatorSet, BN254.G1Point newAggregateKey);
/// @notice Emitted when an operator set is configured
event OperatorSetConfigured(OperatorSet operatorSet, CurveType curveType);
}
/// @notice The `KeyRegistrar` is used by AVSs to set their key type and by operators to register and deregister keys to operatorSets
/// @notice The integration pattern is as follows:
/// 1. The AVS calls `configureOperatorSet` to set the key type for their operatorSet
/// 2. Operators call `registerKey` to register their keys to the operatorSet
/// @dev This contract requires that keys are unique across all operatorSets, globally
/// @dev For the multichain protocol, the key type of the operatorSet must be set in the `KeyRegistrar`, but the
/// AVS is not required to use the KeyRegistrar for operator key management and can implement its own registry
interface IKeyRegistrar is IKeyRegistrarErrors, IKeyRegistrarEvents, ISemVerMixin {
/**
* @notice Configures an operator set with curve type
* @param operatorSet The operator set to configure
* @param curveType Type of curve (ECDSA, BN254)
* @dev Only authorized callers for the AVS can configure operator sets
* @dev Reverts for:
* - InvalidPermissions: Caller is not authorized for the AVS (via the PermissionController)
* - InvalidCurveType: The curve type is not ECDSA or BN254
* - ConfigurationAlreadySet: The operator set is already configured
* @dev Emits the following events:
* - OperatorSetConfigured: When the operator set is successfully configured with a curve type
*/
function configureOperatorSet(OperatorSet memory operatorSet, CurveType curveType) external;
/**
* @notice Registers a cryptographic key for an operator with a specific operator set
* @param operator Address of the operator to register key for
* @param operatorSet The operator set to register the key for
* @param pubkey Public key bytes. For ECDSA, this is the address of the key. For BN254, this is the G1 and G2 key combined (see `encodeBN254KeyData`)
* @param signature Signature proving ownership. For ECDSA this is a signature of the `getECDSAKeyRegistrationMessageHash`. For BN254 this is a signature of the `getBN254KeyRegistrationMessageHash`.
* @dev Can be called by operator directly or by addresses they've authorized via the `PermissionController`
* @dev There exist no restriction on the state of the operator with respect to the operatorSet. That is, an operator
* does not have to be registered for the operator in the `AllocationManager` to register a key for it
* @dev For ECDSA, we allow a smart contract to be the pubkey (via ERC1271 signatures), but note that the multichain protocol DOES NOT support smart contract signatures
* @dev Reverts for:
* - InvalidPermissions: Caller is not the operator or authorized via the PermissionController
* - OperatorSetNotConfigured: The operator set is not configured
* - OperatorAlreadyRegistered: The operator is already registered for the operatorSet in the KeyRegistrar
* - InvalidKeyFormat: For ECDSA: The key is not exactly 20 bytes
* - ZeroAddress: For ECDSA: The key is the zero address
* - KeyAlreadyRegistered: For ECDSA: The key is already registered globally by hash
* - InvalidSignature: For ECDSA: The signature is not valid
* - InvalidKeyFormat: For BN254: The key data is not exactly 192 bytes
* - InvalidSignature: For BN254: The signature is not exactly 64 bytes
* - ZeroPubkey: For BN254: The G1 point is the zero point
* - InvalidSignature: For BN254: The signature is not valid
* - KeyAlreadyRegistered: For BN254: The key is already registered globally by hash
* @dev Emits the following events:
* - KeyRegistered: When the key is successfully registered for the operator and operatorSet
*/
function registerKey(
address operator,
OperatorSet memory operatorSet,
bytes calldata pubkey,
bytes calldata signature
) external;
/**
* @notice Deregisters a cryptographic key for an operator with a specific operator set
* @param operator Address of the operator to deregister key for
* @param operatorSet The operator set to deregister the key from
* @dev Can be called by the operator directly or by addresses they've authorized via the `PermissionController`
* @dev Keys remain in global key registry to prevent reuse
* @dev Reverts for:
* - InvalidPermissions: Caller is not authorized for the operator (via the PermissionController)
* - OperatorStillSlashable: The operator is still slashable for the AVS
* - OperatorSetNotConfigured: The operator set is not configured
* - KeyNotFound: The operator does not have a registered key for this operator set
* @dev Emits the following events:
* - KeyDeregistered: When the key is successfully deregistered for the operator and operatorSet
*/
function deregisterKey(address operator, OperatorSet memory operatorSet) external;
/**
* @notice Checks if a key is registered for an operator with a specific operator set
* @param operatorSet The operator set to check
* @param operator Address of the operator
* @return True if the key is registered, false otherwise
* @dev If the operatorSet is not configured, this function will return false
*/
function isRegistered(OperatorSet memory operatorSet, address operator) external view returns (bool);
/**
* @notice Gets the curve type for an operator set
* @param operatorSet The operator set to get the curve type for
* @return The curve type, either ECDSA, BN254, or NONE
*/
function getOperatorSetCurveType(
OperatorSet memory operatorSet
) external view returns (CurveType);
/**
* @notice Gets the BN254 public key for an operator with a specific operator set
* @param operatorSet The operator set to get the key for
* @param operator Address of the operator
* @return g1Point The BN254 G1 public key
* @return g2Point The BN254 G2 public key
* @dev Reverts for:
* - InvalidCurveType: The operatorSet is not configured for BN254
* @dev Returns empty points if the operator has not registered a key for the operatorSet. We
* recommend calling `isRegistered` first to check if the operator has a key registered
*/
function getBN254Key(
OperatorSet memory operatorSet,
address operator
) external view returns (BN254.G1Point memory g1Point, BN254.G2Point memory g2Point);
/**
* @notice Gets the ECDSA public key for an operator with a specific operator set as bytes
* @param operatorSet The operator set to get the key for
* @param operator Address of the operator
* @return pubkey The ECDSA public key in bytes format
* @dev Reverts for:
* - InvalidCurveType: The operatorSet is not configured for ECDSA
* @dev Returns 0x0 if the operator has not registered a key for the operatorSet. We
* recommend calling `isRegistered` first to check if the operator has a key registered
*/
function getECDSAKey(OperatorSet memory operatorSet, address operator) external view returns (bytes memory);
/**
* @notice Gets the ECDSA public key for an operator with a specific operator set
* @param operatorSet The operator set to get the key for
* @param operator Address of the operator
* @return pubkey The ECDSA public key in address format
* @dev Reverts for:
* - InvalidCurveType: The operatorSet is not configured for ECDSA
* @dev Returns 0x0 if the operator has not registered a key for the operatorSet. We
* recommend calling `isRegistered` first to check if the operator has a key registered
*/
function getECDSAAddress(OperatorSet memory operatorSet, address operator) external view returns (address);
/**
* @notice Checks if a key hash is globally registered
* @param keyHash Hash of the key
* @return True if the key is globally registered
*/
function isKeyGloballyRegistered(
bytes32 keyHash
) external view returns (bool);
/**
* @notice Gets the key hash for an operator with a specific operator set
* @param operatorSet The operator set to get the key hash for
* @param operator Address of the operator
* @return keyHash The key hash
*/
function getKeyHash(OperatorSet memory operatorSet, address operator) external view returns (bytes32);
/**
* @notice Gets the operator from signing key
* @param operatorSet The operator set to get the operator for
* @param keyData The key data. For ECDSA, this is the signing key address. For BN254, this can be either the G1 key or the G1 and G2 key combined.
* @return operator. Returns 0x0 if the key is not registered
* @return status registration status. Returns false if the key is not registered
* @dev This function decodes the key data based on the curve type of the operator set
* @dev This function will return the operator address even if the operator is not registered for the operator set
* @dev Reverts for:
* - InvalidCurveType: The CurveType is not configured
*/
function getOperatorFromSigningKey(
OperatorSet memory operatorSet,
bytes memory keyData
) external view returns (address, bool);
/**
* @notice Returns the message hash for ECDSA key registration, which must be signed by the operator when registering an ECDSA key
* @param operator The operator address
* @param operatorSet The operator set
* @param keyAddress The address of the key
* @return The message hash for signing
*/
function getECDSAKeyRegistrationMessageHash(
address operator,
OperatorSet memory operatorSet,
address keyAddress
) external view returns (bytes32);
/**
* @notice Returns the message hash for BN254 key registration, which must be signed by the operator when registering a BN254 key
* @param operator The operator address
* @param operatorSet The operator set
* @param keyData The BN254 key data
* @return The message hash for signing
*/
function getBN254KeyRegistrationMessageHash(
address operator,
OperatorSet memory operatorSet,
bytes calldata keyData
) external view returns (bytes32);
/**
* @notice Encodes the BN254 key data into a bytes array
* @param g1Point The BN254 G1 public key
* @param g2Point The BN254 G2 public key
* @return The encoded key data
*/
function encodeBN254KeyData(
BN254.G1Point memory g1Point,
BN254.G2Point memory g2Point
) external pure returns (bytes memory);
}
"
},
"src/middlewareV2/tableCalculator/ECDSATableCalculatorBase.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import {OperatorSet} from "eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol";
import {IOperatorTableCalculator} from
"eigenlayer-contracts/src/contracts/interfaces/IOperatorTableCalculator.sol";
import {IKeyRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IKeyRegistrar.sol";
import {IECDSATableCalculator} from "../../interfaces/IECDSATableCalculator.sol";
/**
* @title ECDSATableCalculatorBase
* @notice Abstract contract that provides base functionality for calculating ECDSA operator tables
* @dev This contract contains all the core logic for operator table calculations,
* with weight calculation left to be implemented by derived contracts
*/
abstract contract ECDSATableCalculatorBase is IECDSATableCalculator {
// Immutables
/// @notice KeyRegistrar contract for managing operator keys
IKeyRegistrar public immutable keyRegistrar;
/**
* @notice Constructor to initialize the ECDSATableCalculatorBase
* @param _keyRegistrar The KeyRegistrar contract for managing operator ECDSA public keys
*/
constructor(
IKeyRegistrar _keyRegistrar
) {
keyRegistrar = _keyRegistrar;
}
/// @inheritdoc IECDSATableCalculator
/**
* @dev Only returns operators that have registered their ECDSA keys with the KeyRegistrar and have non-zero stake
*/
function calculateOperatorTable(
OperatorSet calldata operatorSet
) external view virtual returns (ECDSAOperatorInfo[] memory operatorInfos) {
return _calculateOperatorTable(operatorSet);
}
/// @inheritdoc IOperatorTableCalculator
function calculateOperatorTableBytes(
OperatorSet calldata operatorSet
) external view virtual returns (bytes memory operatorTableBytes) {
return abi.encode(_calculateOperatorTable(operatorSet));
}
/// @inheritdoc IOperatorTableCalculator
function getOperatorSetWeights(
OperatorSet calldata operatorSet
) external view virtual returns (address[] memory operators, uint256[][] memory weights) {
return _getOperatorWeights(operatorSet);
}
/// @inheritdoc IOperatorTableCalculator
function getOperatorWeights(
OperatorSet calldata operatorSet,
address operator
) external view virtual returns (uint256[] memory) {
(address[] memory operators, uint256[][] memory weights) = _getOperatorWeights(operatorSet);
// Find the index of the operator in the operators array
for (uint256 i = 0; i < operators.length; i++) {
if (operators[i] == operator) {
return weights[i];
}
}
return new uint256[](0);
}
/**
* @notice Abstract function to get the operator weights for 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, this is a 2D array where the first index is the operator
* and the second index is the type of weight
* @dev Each single `weights` array is as a list of arbitrary stake types. For example,
* it can be [slashable_stake, delegated_stake, strategy_i_stake, ...]. Each stake type is an index in the array
* @dev Must be implemented by derived contracts to define specific weight calculation logic
* @dev The certificate verification assumes the composition weights array for each operator is the same.
* If the length of the array is different or the stake types are different, then verification issues can arise
*/
function _getOperatorWeights(
OperatorSet calldata operatorSet
) internal view virtual returns (address[] memory operators, uint256[][] memory weights);
/**
* @notice Calculates the operator table for a given operatorSet
* @param operatorSet The operatorSet to calculate the operator table for
* @return operatorInfos The array of ECDSAOperatorInfo structs for operators with registered ECDSA keys
* @dev This function:
* 1. Gets operator weights from the weight calculator
* 2. Creates ECDSAOperatorInfo structs for each operator with registered ECDSA keys
* @dev Returns empty array if no operators have registered keys or non-zero weights
*/
function _calculateOperatorTable(
OperatorSet calldata operatorSet
) internal view returns (ECDSAOperatorInfo[] memory operatorInfos) {
// Get the weights for all operators in the operatorSet
(address[] memory operators, uint256[][] memory weights) = _getOperatorWeights(operatorSet);
// If there are no weights, ret
Submitted on: 2025-09-25 10:16:18
Comments
Log in to comment.
No comments yet.