Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added script/input/.gitkeep
Empty file.
1 change: 1 addition & 0 deletions script/input/operatorSets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"operatorSets":[{"id":0,"avs":"0x06f682439e6893a96d70b45f66ffb9ac6fd0f593"},{"id":0,"avs":"0x0d1d5ea331091236f5896f4fea551e0642dc8eac"},{"id":0,"avs":"0x0ff79d6c694e732eac3a54cf646bb9fb0851b49b"},{"id":0,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":0,"avs":"0x54b12f8fe6c1f327d1ae1039b77bc14d27f0376b"},{"id":0,"avs":"0x90c68bf0caca6b2a8ba7ede549c911f907b9ef79"},{"id":0,"avs":"0x9d2b13f5694e98c8dcd4ab09fbec93d46a543dda"},{"id":0,"avs":"0xafbd64968c344dcbbe620b1b156b9ee0b8c0182f"},{"id":0,"avs":"0xafe783e9bcec2993898e70906434d5bc8de3357b"},{"id":0,"avs":"0xb8c7bb2fb48974d9d36ad8e1edb89fc64f79b0e9"},{"id":0,"avs":"0xf07f83ff977dd004060f00ecefb80a9f92775098"},{"id":0,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":1,"avs":"0x06f682439e6893a96d70b45f66ffb9ac6fd0f593"},{"id":1,"avs":"0x0d1d5ea331091236f5896f4fea551e0642dc8eac"},{"id":1,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":1,"avs":"0x26ddbf2a2f0bf8a7f656fa6f63aa9571af002551"},{"id":1,"avs":"0x35a868765c5aaa37d7769af5544a149fffd6d93d"},{"id":1,"avs":"0x9d2b13f5694e98c8dcd4ab09fbec93d46a543dda"},{"id":1,"avs":"0xafbd64968c344dcbbe620b1b156b9ee0b8c0182f"},{"id":1,"avs":"0xb8c7bb2fb48974d9d36ad8e1edb89fc64f79b0e9"},{"id":1,"avs":"0xe65c3eccd18879e103dbc96d854e376ced4cc7dd"},{"id":1,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":2,"avs":"0x0d1d5ea331091236f5896f4fea551e0642dc8eac"},{"id":2,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":2,"avs":"0x9d2b13f5694e98c8dcd4ab09fbec93d46a543dda"},{"id":2,"avs":"0xe65c3eccd18879e103dbc96d854e376ced4cc7dd"},{"id":2,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":3,"avs":"0x0d1d5ea331091236f5896f4fea551e0642dc8eac"},{"id":3,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":3,"avs":"0x9d2b13f5694e98c8dcd4ab09fbec93d46a543dda"},{"id":3,"avs":"0xe65c3eccd18879e103dbc96d854e376ced4cc7dd"},{"id":3,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":4,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":4,"avs":"0x9d2b13f5694e98c8dcd4ab09fbec93d46a543dda"},{"id":4,"avs":"0xe65c3eccd18879e103dbc96d854e376ced4cc7dd"},{"id":4,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":5,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":5,"avs":"0x9d2b13f5694e98c8dcd4ab09fbec93d46a543dda"},{"id":5,"avs":"0xe65c3eccd18879e103dbc96d854e376ced4cc7dd"},{"id":5,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":6,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":6,"avs":"0xe65c3eccd18879e103dbc96d854e376ced4cc7dd"},{"id":6,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":7,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":7,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":8,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":8,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":9,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":9,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":10,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":10,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":11,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":11,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":12,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":12,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":13,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":13,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":14,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":14,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":15,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":15,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":16,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":16,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":17,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":17,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":18,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":18,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":19,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":19,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":20,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":20,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":21,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":21,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":22,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":22,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":23,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":23,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":24,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":24,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":25,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":25,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":26,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":26,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":27,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":27,"avs":"0xf32d566cc95d4a7b3e1ef211c1373f729ca18c86"},{"id":28,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":29,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":30,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":31,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"},{"id":32,"avs":"0x115c1d01133337f311c793c8ea1f8b6f11415500"}]}
128 changes: 128 additions & 0 deletions script/tasks/get_operatorSet_appointees.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;

import "../../src/contracts/interfaces/IPermissionController.sol";
import "../../src/contracts/interfaces/IAllocationManager.sol";

import "forge-std/Script.sol";
import "forge-std/Test.sol";

/// @title GetOperatorSetAppointees
/// @notice Queries PermissionController to find appointees for slashOperator across operator sets
/// @dev Usage:
/// 1. Fetch operator sets from API and save to JSON:
/// curl -H "Accept: application/json" \
/// "https://sidecar-rpc.eigenlayer.xyz/mainnet/v1/operatorSets" \
/// > script/input/operatorSets.json
///
/// 2. Run the script:
/// forge script script/tasks/get_operatorSet_appointees.s.sol \
/// --rpc-url $RPC_MAINNET \
/// --sig "run(string memory)" \
/// -- script/input/operatorSets.json

/// @notice As of 1/27 there are no appointees. You can sanity check that there is at least one for a different selector with the following command:
/// cast call 0x25E5F8B1E7aDf44518d35D5B2271f114e081f0E5 "getAppointees(address,address,bytes4)(address[])" 0xF07F83Ff977Dd004060F00ecefB80A9F92775098 0x948a420b8CC1d6BFd0B6087C2E7c344a2CD0bc39 0x36352057 --rpc-url $RPC_MAINNET
contract GetOperatorSetAppointees is Script, Test {
// Mainnet addresses
address constant PERMISSION_CONTROLLER = 0x25E5F8B1E7aDf44518d35D5B2271f114e081f0E5;
address constant ALLOCATION_MANAGER = 0x948a420b8CC1d6BFd0B6087C2E7c344a2CD0bc39;

IPermissionController permissionController = IPermissionController(PERMISSION_CONTROLLER);

function run(
string memory inputFile
) public view {
// Read JSON file
string memory json = vm.readFile(inputFile);

// Parse operator sets from JSON
// Expected format: { "operatorSets": [{ "id": 0, "avs": "0x..." }, ...] }
bytes memory operatorSetsRaw = vm.parseJson(json, ".operatorSets");

// Decode into array of OperatorSetData
OperatorSetData[] memory operatorSets = abi.decode(operatorSetsRaw, (OperatorSetData[]));

console.log("Total operator sets in input:", operatorSets.length);
console.log("---");

// Get unique AVS addresses
address[] memory uniqueAvs = _getUniqueAvs(operatorSets);
console.log("Unique AVS addresses:", uniqueAvs.length);
console.log("---");

// Get the slashOperator selector
// slashOperator(address,SlashingParams) => 0x38c29160
bytes4 slashOperatorSelector = IAllocationManagerActions.slashOperator.selector;

uint256 totalAppointees = 0;
uint256 avsWithAppointees = 0;

// Query appointees for each AVS
for (uint256 i = 0; i < uniqueAvs.length; i++) {
address avs = uniqueAvs[i];

address[] memory appointees =
permissionController.getAppointees(avs, ALLOCATION_MANAGER, slashOperatorSelector);

if (appointees.length > 0) {
avsWithAppointees++;
totalAppointees += appointees.length;

console.log("AVS:", avs);
console.log(" Appointees:", appointees.length);

for (uint256 j = 0; j < appointees.length; j++) {
console.log(" -", appointees[j]);
}
}
}

console.log("---");
console.log("Summary:");
console.log(" Total operator sets:", operatorSets.length);
console.log(" Unique AVS addresses:", uniqueAvs.length);
console.log(" AVS with slasher appointees:", avsWithAppointees);
console.log(" Total slasher appointees:", totalAppointees);
}

/// @notice Struct to decode operator set data from JSON
struct OperatorSetData {
uint256 id;
address avs;
}

/// @notice Extract unique AVS addresses from operator sets
function _getUniqueAvs(
OperatorSetData[] memory operatorSets
) internal pure returns (address[] memory) {
// First pass: count unique addresses
address[] memory temp = new address[](operatorSets.length);
uint256 uniqueCount = 0;

for (uint256 i = 0; i < operatorSets.length; i++) {
address avs = operatorSets[i].avs;
bool found = false;

for (uint256 j = 0; j < uniqueCount; j++) {
if (temp[j] == avs) {
found = true;
break;
}
}

if (!found) {
temp[uniqueCount] = avs;
uniqueCount++;
}
}

// Second pass: copy to correctly sized array
address[] memory result = new address[](uniqueCount);
for (uint256 i = 0; i < uniqueCount; i++) {
result[i] = temp[i];
}

return result;
}
}
Loading