Skip to content
This repository was archived by the owner on Mar 2, 2026. It is now read-only.

Commit 11f1554

Browse files
author
FromTheRain
authored
feat: hgctl uam & rewards support (#227)
## User Access Management (UAM) Commands Implements comprehensive User Access Management functionality for EigenLayer PermissionController integration. Features Admin Management - Multi-admin support with two-step acceptance workflow - Commands: add, accept, remove-admin, remove-pending, is-admin, is-pending, list-admins, list-pending - Last admin protection prevents removing the final admin Appointee Management - Grant/revoke granular function-level permissions on target contracts - Commands: set, remove, list, list-permissions, can-call - Support for multiple appointees per function selector Testing - 13 admin lifecycle integration tests - 18 appointee lifecycle integration tests covering multi-selector scenarios - All tests passing with proper output capture Documentation - Comprehensive README section with lifecycle examples - Added 8 UAM commands to Key Commands Overview table - Detailed usage examples for both admin and appointee workflows Implementation Notes - Structured logging for proper test harness integration - Follows existing hgctl patterns and conventions ## Rewards Support - Feature parity with Eigenlayer-cli. ### Testing Added comprehensive unit test coverage for rewards commands (setClaimer, claim, show): - Set up mock generation infrastructure using gomock - Refactored commands to extract testable business logic functions - Created 14 unit tests covering success paths, defaults, validation errors, and client failures - All tests use interface-based mocking to bypass middleware - Created test logger utility for clean test output
2 parents b58857c + a1ad376 commit 11f1554

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+3989
-118
lines changed

contracts/script/local/CheckL1State.s.sol

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,10 @@ contract CheckL1State is Script {
108108
console.log("");
109109
}
110110

111-
function checkOperatorSetConfig(address avs, uint32 operatorSetId) internal view {
111+
function checkOperatorSetConfig(
112+
address avs,
113+
uint32 operatorSetId
114+
) internal view {
112115
OperatorSet memory operatorSet = OperatorSet({avs: avs, id: operatorSetId});
113116

114117
// Check if table calculator is configured
@@ -170,7 +173,10 @@ contract CheckL1State is Script {
170173
console.log("");
171174
}
172175

173-
function checkStakerState(address staker, IStrategy strategy) internal view {
176+
function checkStakerState(
177+
address staker,
178+
IStrategy strategy
179+
) internal view {
174180
console.log("Address:", staker);
175181

176182
// Check deposited shares
@@ -215,7 +221,11 @@ contract CheckL1State is Script {
215221
console.log("");
216222
}
217223

218-
function checkOperatorState(address operator, address avs, uint32 operatorSetId) internal view {
224+
function checkOperatorState(
225+
address operator,
226+
address avs,
227+
uint32 operatorSetId
228+
) internal view {
219229
console.log("Address:", operator);
220230

221231
OperatorSet memory operatorSet = OperatorSet({avs: avs, id: operatorSetId});
@@ -228,9 +238,9 @@ contract CheckL1State is Script {
228238
}
229239

230240
// Check allocated magnitude for STETH strategy
231-
try ALLOCATION_MANAGER.getAllocation(operator, operatorSet, STETH_STRATEGY) returns (
232-
IAllocationManager.Allocation memory allocation
233-
) {
241+
try ALLOCATION_MANAGER.getAllocation(
242+
operator, operatorSet, STETH_STRATEGY
243+
) returns (IAllocationManager.Allocation memory allocation) {
234244
console.log("STETH allocation - current magnitude:", allocation.currentMagnitude);
235245
console.log("STETH allocation - pending diff:", uint256(uint128(allocation.pendingDiff)));
236246
console.log("STETH allocation - effect block:", allocation.effectBlock);
@@ -239,9 +249,9 @@ contract CheckL1State is Script {
239249
}
240250

241251
// Check allocated magnitude for WETH strategy
242-
try ALLOCATION_MANAGER.getAllocation(operator, operatorSet, WETH_STRATEGY) returns (
243-
IAllocationManager.Allocation memory allocation
244-
) {
252+
try ALLOCATION_MANAGER.getAllocation(
253+
operator, operatorSet, WETH_STRATEGY
254+
) returns (IAllocationManager.Allocation memory allocation) {
245255
console.log("WETH allocation - current magnitude:", allocation.currentMagnitude);
246256
console.log("WETH allocation - pending diff:", uint256(uint128(allocation.pendingDiff)));
247257
console.log("WETH allocation - effect block:", allocation.effectBlock);
@@ -274,9 +284,10 @@ contract CheckL1State is Script {
274284
console.log("\n--- Executor Operator Set (ID: 1) ---");
275285

276286
// Try to get operator infos
277-
try IBN254TableCalculator(BN254_TABLE_CALCULATOR).getOperatorInfos(executorOpSet) returns (
278-
IOperatorTableCalculatorTypes.BN254OperatorInfo[] memory operatorInfos
279-
) {
287+
try IBN254TableCalculator(BN254_TABLE_CALCULATOR)
288+
.getOperatorInfos(
289+
executorOpSet
290+
) returns (IOperatorTableCalculatorTypes.BN254OperatorInfo[] memory operatorInfos) {
280291
console.log("Number of operators with BN254 keys:", operatorInfos.length);
281292

282293
if (operatorInfos.length == 0) {
@@ -301,9 +312,10 @@ contract CheckL1State is Script {
301312

302313
// Try to calculate the full operator table
303314
console.log("\n--- Calculated Operator Table ---");
304-
try IBN254TableCalculator(BN254_TABLE_CALCULATOR).calculateOperatorTable(executorOpSet) returns (
305-
IOperatorTableCalculatorTypes.BN254OperatorSetInfo memory opSetInfo
306-
) {
315+
try IBN254TableCalculator(BN254_TABLE_CALCULATOR)
316+
.calculateOperatorTable(
317+
executorOpSet
318+
) returns (IOperatorTableCalculatorTypes.BN254OperatorSetInfo memory opSetInfo) {
307319
console.log("Operator Info Tree Root:");
308320
console.logBytes32(opSetInfo.operatorInfoTreeRoot);
309321
console.log("Number of operators:", opSetInfo.numOperators);
@@ -341,10 +353,11 @@ contract CheckL1State is Script {
341353
for (uint256 i = 0; i < potentialVerifiers.length && verifierAddress == address(0); i++) {
342354
if (potentialVerifiers[i] == address(0)) continue;
343355

344-
try IBN254CertificateVerifier(potentialVerifiers[i]).getOperatorSetInfo(
345-
executorOpSet,
346-
0 // timestamp 0 as a probe
347-
) returns (IOperatorTableCalculatorTypes.BN254OperatorSetInfo memory) {
356+
try IBN254CertificateVerifier(potentialVerifiers[i])
357+
.getOperatorSetInfo(
358+
executorOpSet,
359+
0 // timestamp 0 as a probe
360+
) returns (IOperatorTableCalculatorTypes.BN254OperatorSetInfo memory) {
348361
verifierAddress = potentialVerifiers[i];
349362
} catch {
350363
// This address doesn't work, try next
@@ -372,9 +385,10 @@ contract CheckL1State is Script {
372385
}
373386

374387
// Try to get operator set info for the executor operator set
375-
try IBN254CertificateVerifier(verifierAddress).getOperatorSetInfo(executorOpSet, latestTimestamp) returns (
376-
IOperatorTableCalculatorTypes.BN254OperatorSetInfo memory opSetInfo
377-
) {
388+
try IBN254CertificateVerifier(verifierAddress)
389+
.getOperatorSetInfo(
390+
executorOpSet, latestTimestamp
391+
) returns (IOperatorTableCalculatorTypes.BN254OperatorSetInfo memory opSetInfo) {
378392
console.log("\n--- Stored Operator Set Info ---");
379393
console.log("Operator Info Tree Root:");
380394
console.logBytes32(opSetInfo.operatorInfoTreeRoot);

contracts/script/local/CheckL2State.s.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ contract CheckL2State is Script {
8080

8181
IBN254CertificateVerifier verifier = IBN254CertificateVerifier(bn254Verifier);
8282

83-
try verifier.getOperatorSetInfo(bn254OpSet, timestamp) returns (
84-
IBN254CertificateVerifier.BN254OperatorSetInfo memory info
85-
) {
83+
try verifier.getOperatorSetInfo(
84+
bn254OpSet, timestamp
85+
) returns (IBN254CertificateVerifier.BN254OperatorSetInfo memory info) {
8686
console.log("\nOperator Set Info Retrieved:");
8787
console.log(" Number of operators:", info.numOperators);
8888

contracts/script/local/CreateTask.s.sol

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ import {ITaskMailbox, ITaskMailboxTypes} from "@eigenlayer-contracts/src/contrac
99
contract CreateTask is Script {
1010
function setUp() public {}
1111

12-
function run(address taskMailbox, address avs) public {
12+
function run(
13+
address taskMailbox,
14+
address avs
15+
) public {
1316
// Load the private key from the environment variable
1417
uint256 appPrivateKey = vm.envUint("PRIVATE_KEY_APP");
1518
address app = vm.addr(appPrivateKey);
@@ -20,9 +23,7 @@ contract CreateTask is Script {
2023
// Call createTask
2124
OperatorSet memory executorOperatorSet = OperatorSet({avs: avs, id: 1});
2225
ITaskMailboxTypes.TaskParams memory taskParams = ITaskMailboxTypes.TaskParams({
23-
refundCollector: app,
24-
executorOperatorSet: executorOperatorSet,
25-
payload: bytes("Hello World")
26+
refundCollector: app, executorOperatorSet: executorOperatorSet, payload: bytes("Hello World")
2627
});
2728
bytes32 taskHash = ITaskMailbox(taskMailbox).createTask(taskParams);
2829
console.log("Created task with hash:");

contracts/script/local/DeployAVSL1Contracts.s.sol

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@ contract DeployAVSL1Contracts is Script {
3737
uint32[] memory executorOperatorSetIds = new uint32[](1);
3838
executorOperatorSetIds[0] = 1;
3939
ITaskAVSRegistrarBaseTypes.AvsConfig memory initialConfig = ITaskAVSRegistrarBaseTypes.AvsConfig({
40-
aggregatorOperatorSetId: 0,
41-
executorOperatorSetIds: executorOperatorSetIds
40+
aggregatorOperatorSetId: 0, executorOperatorSetIds: executorOperatorSetIds
4241
});
4342

4443
// Deploy ProxyAdmin

contracts/script/local/DeployTaskMailbox.s.sol

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ contract DeployTaskMailbox is Script {
1616

1717
IAllocationManager public ALLOCATION_MANAGER = IAllocationManager(0x948a420b8CC1d6BFd0B6087C2E7c344a2CD0bc39);
1818

19-
function run(address bn254CertVerifier, address ecdsaCertVerifier) public {
19+
function run(
20+
address bn254CertVerifier,
21+
address ecdsaCertVerifier
22+
) public {
2023
// Load the private key from the environment variable
2124
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY_DEPLOYER");
2225
address deployer = vm.addr(deployerPrivateKey);

contracts/script/local/RegisterOperator.s.sol

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,7 @@ contract RegisterOperator is Script {
6565
ALLOCATION_MANAGER.registerForOperatorSets(
6666
operator,
6767
IAllocationManagerTypes.RegisterParams({
68-
avs: avsAddr,
69-
operatorSetIds: operatorSetIds,
70-
data: abi.encode(socket)
68+
avs: avsAddr, operatorSetIds: operatorSetIds, data: abi.encode(socket)
7169
})
7270
);
7371
console.log(

contracts/script/local/SetupAVSTaskMailboxConfig.s.sol

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ import {IAVSTaskHook} from "@eigenlayer-contracts/src/contracts/interfaces/IAVST
1313
contract SetupAVSTaskMailboxConfig is Script {
1414
function setUp() public {}
1515

16-
function run(address taskMailbox, address taskHook) public {
16+
function run(
17+
address taskMailbox,
18+
address taskHook
19+
) public {
1720
// Load the private key from the environment variable
1821
uint256 avsPrivateKey = vm.envUint("PRIVATE_KEY_AVS");
1922
address avs = vm.addr(avsPrivateKey);
@@ -22,19 +25,19 @@ contract SetupAVSTaskMailboxConfig is Script {
2225
console.log("AVS address:", avs);
2326

2427
// Set the Executor Operator Set Task Config
25-
ITaskMailboxTypes.ExecutorOperatorSetTaskConfig memory executorOperatorSetTaskConfig = ITaskMailboxTypes
26-
.ExecutorOperatorSetTaskConfig({
27-
taskHook: IAVSTaskHook(taskHook),
28-
taskSLA: 60,
29-
feeToken: IERC20(address(0)),
30-
curveType: IKeyRegistrarTypes.CurveType.BN254,
31-
feeCollector: address(0),
32-
consensus: ITaskMailboxTypes.Consensus({
33-
consensusType: ITaskMailboxTypes.ConsensusType.STAKE_PROPORTION_THRESHOLD,
34-
value: abi.encode(uint16(10_000))
35-
}),
36-
taskMetadata: bytes("")
37-
});
28+
ITaskMailboxTypes.ExecutorOperatorSetTaskConfig memory executorOperatorSetTaskConfig =
29+
ITaskMailboxTypes.ExecutorOperatorSetTaskConfig({
30+
taskHook: IAVSTaskHook(taskHook),
31+
taskSLA: 60,
32+
feeToken: IERC20(address(0)),
33+
curveType: IKeyRegistrarTypes.CurveType.BN254,
34+
feeCollector: address(0),
35+
consensus: ITaskMailboxTypes.Consensus({
36+
consensusType: ITaskMailboxTypes.ConsensusType.STAKE_PROPORTION_THRESHOLD,
37+
value: abi.encode(uint16(10_000))
38+
}),
39+
taskMetadata: bytes("")
40+
});
3841
ITaskMailbox(taskMailbox).setExecutorOperatorSetTaskConfig(OperatorSet(avs, 1), executorOperatorSetTaskConfig);
3942
ITaskMailboxTypes.ExecutorOperatorSetTaskConfig memory executorOperatorSetTaskConfigStored =
4043
ITaskMailbox(taskMailbox).getExecutorOperatorSetTaskConfig(OperatorSet(avs, 1));

hgctl-go/Makefile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,20 @@ lint: ## Run linter
6666
@go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
6767
@golangci-lint run $(GO_PACKAGES)
6868

69+
.PHONY: deps
70+
deps: ## Install development dependencies
71+
@echo "Installing mockgen..."
72+
@$(GO) install go.uber.org/mock/mockgen@latest
73+
@echo "Dependencies installed"
74+
75+
.PHONY: gen-mocks
76+
gen-mocks: ## Generate mocks for testing
77+
@echo "Generating mocks..."
78+
@mkdir -p internal/mocks
79+
@mockgen -source=internal/client/rewards.go -destination=internal/mocks/mock_rewards_client.go -package=mocks RewardsClientInterface
80+
@mockgen -source=internal/client/contract.go -destination=internal/mocks/mock_contract_client.go -package=mocks ContractClientInterface
81+
@echo "Mocks generated successfully"
82+
6983
install: build ## Install binary
7084
@mkdir -p ~/bin
7185
@cp $(BIN)/$(APP_NAME) ~/bin/

0 commit comments

Comments
 (0)