Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0 ^0.8.0 ^0.8.1 ^0.8.12 ^0.8.9;
// lib/eigenlayer-middleware/lib/eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol
/**
* @title The interface for common signature utilities.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
*/
interface ISignatureUtils {
// @notice Struct that bundles together a signature and an expiration time for the signature. Used primarily for stack management.
struct SignatureWithExpiry {
// the signature itself, formatted as a single bytes object
bytes signature;
// the expiration timestamp (UTC) of the signature
uint256 expiry;
}
// @notice Struct that bundles together a signature, a salt for uniqueness, and an expiration time for the signature. Used primarily for stack management.
struct SignatureWithSaltAndExpiry {
// the signature itself, formatted as a single bytes object
bytes signature;
// the salt used to generate the signature
bytes32 salt;
// the expiration timestamp (UTC) of the signature
uint256 expiry;
}
}
// lib/eigenlayer-middleware/src/interfaces/IRegistry.sol
/**
* @title Minimal interface for a `Registry`-type contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice Functions related to the registration process itself have been intentionally excluded
* because their function signatures may vary significantly.
*/
interface IRegistry {
function registryCoordinator() external view returns (address);
}
// lib/eigenlayer-middleware/src/interfaces/ISocketRegistry.sol
interface ISocketRegistry {
/// @notice sets the socket for an operator only callable by the RegistryCoordinator
function setOperatorSocket(bytes32 _operatorId, string memory _socket) external;
/// @notice gets the stored socket for an operator
function getOperatorSocket(bytes32 _operatorId) external view returns (string memory);
}
// lib/eigenlayer-middleware/src/libraries/BN254.sol
// several functions are taken or adapted from https://github.com/HarryR/solcrypto/blob/master/contracts/altbn128.sol (MIT license):
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
// The remainder of the code in this library is written by LayrLabs Inc. and is also under an MIT license
/**
* @title Library for operations on the BN254 elliptic curve.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice Contains BN254 parameters, common operations (addition, scalar mul, pairing), and BLS signature functionality.
*/
library BN254 {
// modulus for the underlying field F_p of the elliptic curve
uint256 internal constant FP_MODULUS =
21_888_242_871_839_275_222_246_405_745_257_275_088_696_311_157_297_823_662_689_037_894_645_226_208_583;
// modulus for the underlying field F_r of the elliptic curve
uint256 internal constant FR_MODULUS =
21_888_242_871_839_275_222_246_405_745_257_275_088_548_364_400_416_034_343_698_204_186_575_808_495_617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[1] * i + X[0]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
function generatorG1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
}
// generator of group G2
/// @dev Generator point in F_q2 is of the form: (x0 + ix1, y0 + iy1).
uint256 internal constant G2x1 =
11_559_732_032_986_387_107_991_004_021_392_285_783_925_812_861_821_192_530_917_403_151_452_391_805_634;
uint256 internal constant G2x0 =
10_857_046_999_023_057_135_944_570_762_232_829_481_370_756_359_578_518_086_990_519_993_285_655_852_781;
uint256 internal constant G2y1 =
4_082_367_875_863_433_681_332_203_403_145_435_568_316_851_327_593_401_208_105_741_076_214_120_093_531;
uint256 internal constant G2y0 =
8_495_653_923_123_431_417_604_973_247_489_272_438_418_190_587_263_600_148_770_280_649_306_958_101_930;
/// @notice returns the G2 generator
/// @dev mind the ordering of the 1s and 0s!
/// this is because of the (unknown to us) convention used in the bn254 pairing precompile contract
/// "Elements a * i + b of F_p^2 are encoded as two elements of F_p, (a, b)."
/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-197.md#encoding
function generatorG2() internal pure returns (G2Point memory) {
return G2Point([G2x1, G2x0], [G2y1, G2y0]);
}
// negation of the generator of group G2
/// @dev Generator point in F_q2 is of the form: (x0 + ix1, y0 + iy1).
uint256 internal constant nG2x1 =
11_559_732_032_986_387_107_991_004_021_392_285_783_925_812_861_821_192_530_917_403_151_452_391_805_634;
uint256 internal constant nG2x0 =
10_857_046_999_023_057_135_944_570_762_232_829_481_370_756_359_578_518_086_990_519_993_285_655_852_781;
uint256 internal constant nG2y1 =
17_805_874_995_975_841_540_914_202_342_111_839_520_379_459_829_704_422_454_583_296_818_431_106_115_052;
uint256 internal constant nG2y0 =
13_392_588_948_715_843_804_641_432_497_768_002_650_278_120_570_034_223_513_918_757_245_338_268_106_653;
function negGeneratorG2() internal pure returns (G2Point memory) {
return G2Point([nG2x1, nG2x0], [nG2y1, nG2y0]);
}
bytes32 internal constant powersOfTauMerkleRoot = 0x22c998e49752bbb1918ba87d6d59dd0e83620a311ba91dd4b2cc84990b31b56f;
/**
* @param p Some point in G1.
* @return The negation of `p`, i.e. p.plus(p.negate()) should be zero.
*/
function negate(G1Point memory p) internal pure returns (G1Point memory) {
// The prime q in the base field F_q for G1
if (p.X == 0 && p.Y == 0) {
return G1Point(0, 0);
} else {
return G1Point(p.X, FP_MODULUS - (p.Y % FP_MODULUS));
}
}
/**
* @return r the sum of two points of G1
*/
function plus(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0x80, r, 0x40)
// Use "invalid" to make gas estimation work
switch success
case 0 { invalid() }
}
require(success, "ec-add-failed");
}
/**
* @notice an optimized ecMul implementation that takes O(log_2(s)) ecAdds
* @param p the point to multiply
* @param s the scalar to multiply by
* @dev this function is only safe to use if the scalar is 9 bits or less
*/
function scalar_mul_tiny(BN254.G1Point memory p, uint16 s) internal view returns (BN254.G1Point memory) {
require(s < 2 ** 9, "scalar-too-large");
// if s is 1 return p
if (s == 1) {
return p;
}
// the accumulated product to return
BN254.G1Point memory acc = BN254.G1Point(0, 0);
// the 2^n*p to add to the accumulated product in each iteration
BN254.G1Point memory p2n = p;
// value of most significant bit
uint16 m = 1;
// index of most significant bit
uint8 i = 0;
//loop until we reach the most significant bit
while (s >= m) {
unchecked {
// if the current bit is 1, add the 2^n*p to the accumulated product
if ((s >> i) & 1 == 1) {
acc = plus(acc, p2n);
}
// double the 2^n*p for the next iteration
p2n = plus(p2n, p2n);
// increment the index and double the value of the most significant bit
m <<= 1;
++i;
}
}
// return the accumulated product
return acc;
}
/**
* @return r the product of a point on G1 and a scalar, i.e.
* p == p.scalar_mul(1) and p.plus(p) == p.scalar_mul(2) for all
* points p.
*/
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x60, r, 0x40)
// Use "invalid" to make gas estimation work
switch success
case 0 { invalid() }
}
require(success, "ec-mul-failed");
}
/**
* @return The result of computing the pairing check
* e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
* For example,
* pairing([P1(), P1().negate()], [P2(), P2()]) should return true.
*/
function pairing(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2)
internal
view
returns (bool)
{
G1Point[2] memory p1 = [a1, b1];
G2Point[2] memory p2 = [a2, b2];
uint256[12] memory input;
for (uint256 i = 0; i < 2; i++) {
uint256 j = i * 6;
input[j + 0] = p1[i].X;
input[j + 1] = p1[i].Y;
input[j + 2] = p2[i].X[0];
input[j + 3] = p2[i].X[1];
input[j + 4] = p2[i].Y[0];
input[j + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, input, mul(12, 0x20), out, 0x20)
// Use "invalid" to make gas estimation work
switch success
case 0 { invalid() }
}
require(success, "pairing-opcode-failed");
return out[0] != 0;
}
/**
* @notice This function is functionally the same as pairing(), however it specifies a gas limit
* the user can set, as a precompile may use the entire gas budget if it reverts.
*/
function safePairing(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2, uint256 pairingGas)
internal
view
returns (bool, bool)
{
G1Point[2] memory p1 = [a1, b1];
G2Point[2] memory p2 = [a2, b2];
uint256[12] memory input;
for (uint256 i = 0; i < 2; i++) {
uint256 j = i * 6;
input[j + 0] = p1[i].X;
input[j + 1] = p1[i].Y;
input[j + 2] = p2[i].X[0];
input[j + 3] = p2[i].X[1];
input[j + 4] = p2[i].Y[0];
input[j + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(pairingGas, 8, input, mul(12, 0x20), out, 0x20)
}
//Out is the output of the pairing precompile, either 0 or 1 based on whether the two pairings are equal.
//Success is true if the precompile actually goes through (aka all inputs are valid)
return (success, out[0] != 0);
}
/// @return hashedG1 the keccak256 hash of the G1 Point
/// @dev used for BLS signatures
function hashG1Point(BN254.G1Point memory pk) internal pure returns (bytes32 hashedG1) {
assembly {
mstore(0, mload(pk))
mstore(0x20, mload(add(0x20, pk)))
hashedG1 := keccak256(0, 0x40)
}
}
/// @return the keccak256 hash of the G2 Point
/// @dev used for BLS signatures
function hashG2Point(BN254.G2Point memory pk) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(pk.X[0], pk.X[1], pk.Y[0], pk.Y[1]));
}
/**
* @notice adapted from https://github.com/HarryR/solcrypto/blob/master/contracts/altbn128.sol
*/
function hashToG1(bytes32 _x) internal view returns (G1Point memory) {
uint256 beta = 0;
uint256 y = 0;
uint256 x = uint256(_x) % FP_MODULUS;
while (true) {
(beta, y) = findYFromX(x);
// y^2 == beta
if (beta == mulmod(y, y, FP_MODULUS)) {
return G1Point(x, y);
}
x = addmod(x, 1, FP_MODULUS);
}
return G1Point(0, 0);
}
/**
* Given X, find Y
*
* where y = sqrt(x^3 + b)
*
* Returns: (x^3 + b), y
*/
function findYFromX(uint256 x) internal view returns (uint256, uint256) {
// beta = (x^3 + b) % p
uint256 beta = addmod(mulmod(mulmod(x, x, FP_MODULUS), x, FP_MODULUS), 3, FP_MODULUS);
// y^2 = x^3 + b
// this acts like: y = sqrt(beta) = beta^((p+1) / 4)
uint256 y = expMod(beta, 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52, FP_MODULUS);
return (beta, y);
}
function expMod(uint256 _base, uint256 _exponent, uint256 _modulus) internal view returns (uint256 retval) {
bool success;
uint256[1] memory output;
uint256[6] memory input;
input[0] = 0x20; // baseLen = new(big.Int).SetBytes(getData(input, 0, 32))
input[1] = 0x20; // expLen = new(big.Int).SetBytes(getData(input, 32, 32))
input[2] = 0x20; // modLen = new(big.Int).SetBytes(getData(input, 64, 32))
input[3] = _base;
input[4] = _exponent;
input[5] = _modulus;
assembly {
success := staticcall(sub(gas(), 2000), 5, input, 0xc0, output, 0x20)
// Use "invalid" to make gas estimation work
switch success
case 0 { invalid() }
}
require(success, "BN254.expMod: call failure");
return output[0];
}
}
// lib/eigenlayer-middleware/src/libraries/BitmapUtils.sol
/**
* @title Library for Bitmap utilities such as converting between an array of bytes and a bitmap and finding the number of 1s in a bitmap.
* @author Layr Labs, Inc.
*/
library BitmapUtils {
/**
* @notice Byte arrays are meant to contain unique bytes.
* If the array length exceeds 256, then it's impossible for all entries to be unique.
* This constant captures the max allowed array length (inclusive, i.e. 256 is allowed).
*/
uint256 internal constant MAX_BYTE_ARRAY_LENGTH = 256;
/**
* @notice Converts an ordered array of bytes into a bitmap.
* @param orderedBytesArray The array of bytes to convert/compress into a bitmap. Must be in strictly ascending order.
* @return The resulting bitmap.
* @dev Each byte in the input is processed as indicating a single bit to flip in the bitmap.
* @dev This function will eventually revert in the event that the `orderedBytesArray` is not properly ordered (in ascending order).
* @dev This function will also revert if the `orderedBytesArray` input contains any duplicate entries (i.e. duplicate bytes).
*/
function orderedBytesArrayToBitmap(bytes memory orderedBytesArray) internal pure returns (uint256) {
// sanity-check on input. a too-long input would fail later on due to having duplicate entry(s)
require(
orderedBytesArray.length <= MAX_BYTE_ARRAY_LENGTH,
"BitmapUtils.orderedBytesArrayToBitmap: orderedBytesArray is too long"
);
// return empty bitmap early if length of array is 0
if (orderedBytesArray.length == 0) {
return uint256(0);
}
// initialize the empty bitmap, to be built inside the loop
uint256 bitmap;
// initialize an empty uint256 to be used as a bitmask inside the loop
uint256 bitMask;
// perform the 0-th loop iteration with the ordering check *omitted* (since it is unnecessary / will always pass)
// construct a single-bit mask from the numerical value of the 0th byte of the array, and immediately add it to the bitmap
bitmap = uint256(1 << uint8(orderedBytesArray[0]));
// loop through each byte in the array to construct the bitmap
for (uint256 i = 1; i < orderedBytesArray.length; ++i) {
// construct a single-bit mask from the numerical value of the next byte of the array
bitMask = uint256(1 << uint8(orderedBytesArray[i]));
// check strictly ascending array ordering by comparing the mask to the bitmap so far (revert if mask isn't greater than bitmap)
require(bitMask > bitmap, "BitmapUtils.orderedBytesArrayToBitmap: orderedBytesArray is not ordered");
// add the entry to the bitmap
bitmap = (bitmap | bitMask);
}
return bitmap;
}
/**
* @notice Converts an ordered byte array to a bitmap, validating that all bits are less than `bitUpperBound`
* @param orderedBytesArray The array to convert to a bitmap; must be in strictly ascending order
* @param bitUpperBound The exclusive largest bit. Each bit must be strictly less than this value.
* @dev Reverts if bitmap contains a bit greater than or equal to `bitUpperBound`
*/
function orderedBytesArrayToBitmap(bytes memory orderedBytesArray, uint8 bitUpperBound)
internal
pure
returns (uint256)
{
uint256 bitmap = orderedBytesArrayToBitmap(orderedBytesArray);
require((1 << bitUpperBound) > bitmap, "BitmapUtils.orderedBytesArrayToBitmap: bitmap exceeds max value");
return bitmap;
}
/**
* @notice Utility function for checking if a bytes array is strictly ordered, in ascending order.
* @param bytesArray the bytes array of interest
* @return Returns 'true' if the array is ordered in strictly ascending order, and 'false' otherwise.
* @dev This function returns 'true' for the edge case of the `bytesArray` having zero length.
* It also returns 'false' early for arrays with length in excess of MAX_BYTE_ARRAY_LENGTH (i.e. so long that they cannot be strictly ordered)
*/
function isArrayStrictlyAscendingOrdered(bytes calldata bytesArray) internal pure returns (bool) {
// Return early if the array is too long, or has a length of 0
if (bytesArray.length > MAX_BYTE_ARRAY_LENGTH) {
return false;
}
if (bytesArray.length == 0) {
return true;
}
// Perform the 0-th loop iteration by pulling the 0th byte out of the array
bytes1 singleByte = bytesArray[0];
// For each byte, validate that each entry is *strictly greater than* the previous
// If it isn't, return false as the array is not ordered
for (uint256 i = 1; i < bytesArray.length; ++i) {
if (uint256(uint8(bytesArray[i])) <= uint256(uint8(singleByte))) {
return false;
}
// Pull the next byte out of the array
singleByte = bytesArray[i];
}
return true;
}
/**
* @notice Converts a bitmap into an array of bytes.
* @param bitmap The bitmap to decompress/convert to an array of bytes.
* @return bytesArray The resulting bitmap array of bytes.
* @dev Each byte in the input is processed as indicating a single bit to flip in the bitmap
*/
function bitmapToBytesArray(uint256 bitmap) internal pure returns (bytes memory /*bytesArray*/ ) {
// initialize an empty uint256 to be used as a bitmask inside the loop
uint256 bitMask;
// allocate only the needed amount of memory
bytes memory bytesArray = new bytes(countNumOnes(bitmap));
// track the array index to assign to
uint256 arrayIndex = 0;
/**
* loop through each index in the bitmap to construct the array,
* but short-circuit the loop if we reach the number of ones and thus are done
* assigning to memory
*/
for (uint256 i = 0; (arrayIndex < bytesArray.length) && (i < 256); ++i) {
// construct a single-bit mask for the i-th bit
bitMask = uint256(1 << i);
// check if the i-th bit is flipped in the bitmap
if (bitmap & bitMask != 0) {
// if the i-th bit is flipped, then add a byte encoding the value 'i' to the `bytesArray`
bytesArray[arrayIndex] = bytes1(uint8(i));
// increment the bytesArray slot since we've assigned one more byte of memory
unchecked {
++arrayIndex;
}
}
}
return bytesArray;
}
/// @return count number of ones in binary representation of `n`
function countNumOnes(uint256 n) internal pure returns (uint16) {
uint16 count = 0;
while (n > 0) {
n &= (n - 1); // Clear the least significant bit (turn off the rightmost set bit).
count++; // Increment the count for each cleared bit (each one encountered).
}
return count; // Return the total count of ones in the binary representation of n.
}
/// @notice Returns `true` if `bit` is in `bitmap`. Returns `false` otherwise.
function isSet(uint256 bitmap, uint8 bit) internal pure returns (bool) {
return 1 == ((bitmap >> bit) & 1);
}
/**
* @notice Returns a copy of `bitmap` with `bit` set.
* @dev IMPORTANT: we're dealing with stack values here, so this doesn't modify
* the original bitmap. Using this correctly requires an assignment statement:
* `bitmap = bitmap.setBit(bit);`
*/
function setBit(uint256 bitmap, uint8 bit) internal pure returns (uint256) {
return bitmap | (1 << bit);
}
/**
* @notice Returns true if `bitmap` has no set bits
*/
function isEmpty(uint256 bitmap) internal pure returns (bool) {
return bitmap == 0;
}
/**
* @notice Returns true if `a` and `b` have no common set bits
*/
function noBitsInCommon(uint256 a, uint256 b) internal pure returns (bool) {
return a & b == 0;
}
/**
* @notice Returns true if `a` is a subset of `b`: ALL of the bits in `a` are also in `b`
*/
function isSubsetOf(uint256 a, uint256 b) internal pure returns (bool) {
return a & b == a;
}
/**
* @notice Returns a new bitmap that contains all bits set in either `a` or `b`
* @dev Result is the union of `a` and `b`
*/
function plus(uint256 a, uint256 b) internal pure returns (uint256) {
return a | b;
}
/**
* @notice Returns a new bitmap that clears all set bits of `b` from `a`
* @dev Negates `b` and returns the intersection of the result with `a`
*/
function minus(uint256 a, uint256 b) internal pure returns (uint256) {
return a & ~b;
}
}
// lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20_0 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
// lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-IERC20Permit.sol
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
// lib/openzeppelin-contracts/contracts/utils/Address.sol
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// node_modules/@openzeppelin/contracts/access/IAccessControl.sol
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}
// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20_1 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
// src/core/interfaces/IEigenDASemVer.sol
interface IEigenDASemVer {
/// @notice Returns the semantic version of the contract implementation. Refer to https://semver.org/
function semver() external view returns (uint8 major, uint8 minor, uint8 patch);
}
// src/core/libraries/v3/access-control/AccessControlConstants.sol
/// @notice This library defines constants for access control to use in solidity contracts. Off-chain users should derive the same constants defined here.
library AccessControlConstants {
/// @notice This role manages all other roles, and is all powerful.
bytes32 internal constant OWNER_ROLE = keccak256("OWNER");
/// @notice This is the seed used to derive the quorum owner role for each quorum.
bytes32 internal constant QUORUM_OWNER_SEED = keccak256("QUORUM_OWNER");
/// @dev We simply add the quorum ID to the seed to derive a unique role for each quorum.
function QUORUM_OWNER_ROLE(uint64 quorumId) internal pure returns (bytes32) {
return bytes32(uint256(QUORUM_OWNER_SEED) + quorumId);
}
/// @notice This role is allowed to initiate ejections in the ejection manager.
bytes32 internal constant EJECTOR_ROLE = keccak256("EJECTOR");
}
// src/core/libraries/v3/address-directory/AddressDirectoryConstants.sol
library AddressDirectoryConstants {
/// PROXY ADMIN
string internal constant PROXY_ADMIN_NAME = "PROXY_ADMIN";
/// CORE
string internal constant ACCESS_CONTROL_NAME = "ACCESS_CONTROL";
string internal constant DISPERSER_REGISTRY_NAME = "DISPERSER_REGISTRY";
string internal constant RELAY_REGISTRY_NAME = "RELAY_REGISTRY";
string internal constant SERVICE_MANAGER_NAME = "SERVICE_MANAGER";
string internal constant THRESHOLD_REGISTRY_NAME = "THRESHOLD_REGISTRY";
string internal constant PAYMENT_VAULT_NAME = "PAYMENT_VAULT";
/// MIDDLEWARE
string internal constant REGISTRY_COORDINATOR_NAME = "REGISTRY_COORDINATOR";
string internal constant STAKE_REGISTRY_NAME = "STAKE_REGISTRY";
string internal constant INDEX_REGISTRY_NAME = "INDEX_REGISTRY";
string internal constant SOCKET_REGISTRY_NAME = "SOCKET_REGISTRY";
string internal constant PAUSER_REGISTRY_NAME = "PAUSER_REGISTRY";
string internal constant BLS_APK_REGISTRY_NAME = "BLS_APK_REGISTRY";
string internal constant EJECTION_MANAGER_NAME = "EJECTION_MANAGER";
/// PERIPHERY
string internal constant OPERATOR_STATE_RETRIEVER_NAME = "OPERATOR_STATE_RETRIEVER";
/// @dev This name is prefixed with EIGEN_DA to differentiate it from the previous ejection manager which was vendored from eigenlayer-middlware.
string internal constant EIGEN_DA_EJECTION_MANAGER_NAME = "EIGEN_DA_EJECTION_MANAGER";
string internal constant CERT_VERIFIER_NAME = "CERT_VERIFIER";
string internal constant CERT_VERIFIER_ROUTER_NAME = "CERT_VERIFIER_ROUTER";
/// LEGACY
string internal constant CERT_VERIFIER_LEGACY_V1_NAME = "CERT_VERIFIER_LEGACY_V1";
string internal constant CERT_VERIFIER_LEGACY_V2_NAME = "CERT_VERIFIER_LEGACY_V2";
}
// src/core/libraries/v3/address-directory/AddressDirectoryStorage.sol
/// @notice Defines the storage layout for an address directory based on ERC-7201
/// https://eips.ethereum.org/EIPS/eip-7201
library AddressDirectoryStorage {
/// @custom: storage-location erc7201:address.directory.storage
struct Layout {
mapping(bytes32 => address) addresses;
mapping(bytes32 => string) names;
string[] nameList;
}
string internal constant STORAGE_ID = "address.directory.storage";
bytes32 internal constant STORAGE_POSITION =
keccak256(abi.encode(uint256(keccak256(abi.encodePacked(STORAGE_ID))) - 1)) & ~bytes32(uint256(0xff));
function layout() internal pure returns (Layout storage s) {
bytes32 position = STORAGE_POSITION;
assembly {
s.slot := position
}
}
}
// src/core/libraries/v3/config-registry/ConfigRegistryTypes.sol
library ConfigRegistryTypes {
/// @notice Struct to keep track of names associated with name digests
/// @param names Mapping from name digest to name
/// @param nameList List of all config names
struct NameSet {
mapping(bytes32 => string) names;
string[] nameList;
}
/// @notice Struct to represent checkpoints for fixed-size byte32 configurations
/// @param activationKey The activation key (e.g., block number or timestamp) for the checkpoint
/// @param value The bytes32 configuration value at this checkpoint
struct Bytes32Checkpoint {
uint256 activationKey;
bytes32 value;
}
/// @notice Struct to represent checkpoints for variable-size bytes configurations
/// @param activationKey The activation key (e.g., block number or timestamp) for the checkpoint
/// @param value The bytes configuration value at this checkpoint
struct BytesCheckpoint {
uint256 activationKey;
bytes value;
}
/// @notice Struct to hold all bytes32 configuration checkpoints and associated names
/// @param values Mapping from name digest to array of Bytes32Checkpoint structs. This entire structure is meant to be able to be queried.
/// @param nameSet The NameSet struct to manage names associated with the configuration entries
/// @dev See docs for the structs for more information
struct Bytes32Cfg {
mapping(bytes32 => Bytes32Checkpoint[]) values;
NameSet nameSet;
}
/// @notice Struct to hold all bytes configuration checkpoints and associated names
/// @dev See docs for the structs for more information
struct BytesCfg {
mapping(bytes32 => BytesCheckpoint[]) values;
NameSet nameSet;
}
}
// src/periphery/ejection/libraries/EigenDAEjectionTypes.sol
library EigenDAEjectionTypes {
/// @param ejector The address initiating the ejection
/// @param proceedingTime Timestamp when the proceeding is set to complete
/// @param lastProceedingInitiated Timestamp of when the last proceeding was initiated to enforce cooldowns
/// @param depositAmount The amount of deposit the ejector has commmitted to initiating the ejection.
/// @param quorums The quorums associated with the proceeding.
struct EjectionParams {
address ejector;
uint64 proceedingTime;
uint256 depositAmount;
bytes quorums;
}
/// @param params The ejection parameters
/// @param lastProceedingInitiated Timestamp of when the last proceeding was initiated to enforce cooldowns.
/// @dev The parameters are separated to make the ejection parameters safer to delete.
struct Ejectee {
EjectionParams params;
uint64 lastProceedingInitiated;
}
}
// lib/eigenlayer-middleware/lib/eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol
/**
* @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 {
/**
* @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_1 token, uint8 decimals);
/**
* @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_1 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.
*/
function withdraw(address recipient, IERC20_1 token, uint256 amountShares) external;
/**
* @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
* @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 underlying tokens corresponding to the input `amountShares`
* @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.
* @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 shares corresponding to the input `amountUnderlying`
* @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`
* @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_1);
/// @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-middleware/src/interfaces/IIndexRegistry.sol
/**
* @title Interface for a `Registry`-type contract that keeps track of an ordered list of operators for up to 256 quorums.
* @author Layr Labs, Inc.
*/
interface IIndexRegistry is IRegistry {
// EVENTS
// emitted when an operator's index in the ordered operator list for the quorum with number `quorumNumber` is updated
event QuorumIndexUpdate(bytes32 indexed operatorId, uint8 quorumNumber, uint32 newOperatorIndex);
// DATA STRUCTURES
// struct used to give definitive ordering to operators at each blockNumber.
struct OperatorUpdate {
// blockNumber number from which `operatorIndex` was the operators index
// the operator's index is the first entry such that `blockNumber >= entry.fromBlockNumber`
uint32 fromBlockNumber;
// the operator at this index
bytes32 operatorId;
}
// struct used to denote the number of operators in a quorum at a given blockNumber
struct QuorumUpdate {
// The total number of operators at a `blockNumber` is the first entry such that `blockNumber >= entry.fromBlockNumber`
uint32 fromBlockNumber;
// The number of operators at `fromBlockNumber`
uint32 numOperators;
}
/**
* @notice Registers the operator with the specified `operatorId` for the quorums specified by `quorumNumbers`.
* @param operatorId is the id of the operator that is being registered
* @param quorumNumbers is the quorum numbers the operator is registered for
* @return numOperatorsPerQuorum is a list of the number of operators (including the registering operator) in each of the quorums the operator is registered for
* @dev access restricted to the RegistryCoordinator
* @dev Preconditions (these are assumed, not validated in this contract):
* 1) `quorumNumbers` has no duplicates
* 2) `quorumNumbers.length` != 0
* 3) `quorumNumbers` is ordered in ascending order
* 4) the operator is not already registered
*/
function registerOperator(bytes32 operatorId, bytes calldata quorumNumbers) external returns (uint32[] memory);
/**
* @notice Deregisters the operator with the specified `operatorId` for the quorums specified by `quorumNumbers`.
* @param operatorId is the id of the operator that is being deregistered
* @param quorumNumbers is the quorum numbers the operator is deregistered for
* @dev access restricted to the RegistryCoordinator
* @dev Preconditions (these are assumed, not validated in this contract):
* 1) `quorumNumbers` has no duplicates
* 2) `quorumNumbers.length` != 0
* 3) `quorumNumbers` is ordered in ascending order
* 4) the operator is not already deregistered
* 5) `quorumNumbers` is a subset of the quorumNumbers that the operator is registered for
*/
function deregisterOperator(bytes32 operatorId, bytes calldata quorumNumbers) external;
/**
* @notice Initialize a quorum by pushing its first quorum update
* @param quorumNumber The number of the new quorum
*/
function initializeQuorum(uint8 quorumNumber) external;
/// @notice Returns the OperatorUpdate entry for the specified `operatorIndex` and `quorumNumber` at the specified `arrayIndex`
function getOperatorUpdateAtIndex(uint8 quorumNumber, uint32 operatorIndex, uint32 arrayIndex)
external
view
returns (OperatorUpdate memory);
/// @notice Returns the QuorumUpdate entry for the specified `quorumNumber` at the specified `quorumIndex`
function getQuorumUpdateAtIndex(uint8 quorumNumber, uint32 quorumIndex)
external
view
returns (QuorumUpdate memory);
/// @notice Returns the most recent OperatorUpdate entry for the specified quorumNumber and operatorIndex
function getLatestOperatorUpdate(uint8 quorumNumber, uint32 operatorIndex)
external
view
returns (OperatorUpdate memory);
/// @notice Returns the most recent QuorumUpdate entry for the specified quorumNumber
function getLatestQuorumUpdate(uint8 quorumNumber) external view returns (QuorumUpdate memory);
/// @notice Returns the current number of operators of this service for `quorumNumber`.
function totalOperatorsForQuorum(uint8 quorumNumber) external view returns (uint32);
/// @notice Returns an ordered list of operators of the services for the given `quorumNumber` at the given `blockNumber`
function getOperatorListAtBlockNumber(uint8 quorumNumber, uint32 blockNumber)
external
view
returns (bytes32[] memory);
}
// src/core/interfaces/IEigenDADirectory.sol
interface IEigenDAAddressDirectory {
error AddressAlreadyExists(string name);
error AddressDoesNotExist(string name);
error ZeroAddress();
error NewValueIsOldValue(address value);
event AddressAdded(string name, bytes32 indexed key, address indexed value);
event AddressReplaced(string name, bytes32 indexed key, address indexed oldValue, address indexed newValue);
event AddressRemoved(string name, bytes32 indexed key);
/// @notice Adds a new address to the directory by name.
/// @dev Fails if the address is zero or if an address with the same name already exists.
/// Emits an AddressAdded event on success.
function addAddress(string memory name, address value) external;
/// @notice Replaces an existing address in the directory by name.
/// @dev Fails if the address is zero, if the address with the name does not exist, or if the new value is the same as the old value.
/// Emits an AddressReplaced event on success.
function replaceAddress(string memory name, address value) external;
/// @notice Removes an address from the directory by name.
/// @dev Fails if the address with the name does not exist.
/// Emits an AddressRemoved event on success.
function removeAddress(string memory name) external;
/// @notice Gets the address by keccak256 hash of the name.
/// @dev This entry point is cheaper in gas because it avoids needing to compute the key from the name.
function getAddress(bytes32 key) external view returns (address);
/// @notice Gets the address by name.
function getAddress(string memory name) external view returns (address);
/// @notice Gets the name by keccak256 hash of the name.
function getName(bytes32 key) external view returns (string memory);
/// @notice Gets all names in the directory.
function getAllNames() external view returns (string[] memory);
}
/// @title IEigenDAConfigRegistry
/// @notice Interface for a configuration registry that allows adding and retrieving configuration entries by name.
/// Supports both bytes32 and bytes types for configuration values, and maintains a checkpointed structure for each configuration entry
/// by an arbitrary activation key.
interface IEigenDAConfigRegistry {
/// @notice Adds a 32 byte configuration value to the configuration registry.
/// @param name The name of the configuration entry.
/// @param activationKey The activation key for the configuration entry.
/// This is an arbitrary key defined by the caller to indicate when the configuration should become active.
/// @param value The 32 byte configuration value.
function addConfigBytes32(string memory name, uint256 activationKey, bytes32 value) external;
/// @notice Adds a variable length byte configuration value to the configuration registry.
/// @param name The name of the configuration entry.
/// @param activationKey The activation key for the configuration entry.
/// This is an arbitrary key defin
Submitted on: 2025-10-13 19:03:26
Comments
Log in to comment.
No comments yet.