@@ -200,6 +200,7 @@ contract InstantSlasherTest is Test {
200
200
slashingRegistryCoordinator =
201
201
SlashingRegistryCoordinator (middlewareDeployments.slashingRegistryCoordinator);
202
202
instantSlasher = InstantSlasher (middlewareDeployments.instantSlasher);
203
+ stakeRegistry = StakeRegistry (middlewareDeployments.stakeRegistry);
203
204
204
205
PermissionController (coreDeployment.permissionController).setAppointee (
205
206
address (serviceManager),
@@ -215,6 +216,13 @@ contract InstantSlasherTest is Test {
215
216
AllocationManager.slashOperator.selector
216
217
);
217
218
219
+ PermissionController (coreDeployment.permissionController).setAppointee (
220
+ address (serviceManager),
221
+ address (slashingRegistryCoordinator),
222
+ coreDeployment.allocationManager,
223
+ AllocationManager.deregisterFromOperatorSets.selector
224
+ );
225
+
218
226
PermissionController (coreDeployment.permissionController).setAppointee (
219
227
address (serviceManager),
220
228
proxyAdminOwner,
@@ -262,63 +270,38 @@ contract InstantSlasherTest is Test {
262
270
assertEq (instantSlasher.slasher (), slasher);
263
271
}
264
272
265
- function _createMockSlashingParams ()
266
- internal
267
- view
268
- returns (IAllocationManagerTypes.SlashingParams memory )
269
- {
270
- IStrategy[] memory strategies = new IStrategy [](1 );
271
- strategies[0 ] = mockStrategy;
272
-
273
- uint256 [] memory wadsToSlash = new uint256 [](1 );
274
- wadsToSlash[0 ] = 0.5e18 ; // 50% slash
275
-
276
- return IAllocationManagerTypes.SlashingParams ({
277
- operator: operatorWallet.key.addr,
278
- operatorSetId: 1 ,
279
- strategies: strategies,
280
- wadsToSlash: wadsToSlash,
281
- description: "Test slashing "
282
- });
283
- }
284
-
285
273
function test_fulfillSlashingRequest_revert_notSlasher () public {
286
274
IAllocationManagerTypes.SlashingParams memory params = _createMockSlashingParams ();
287
275
vm.expectRevert (ISlasherErrors.OnlySlasher.selector );
288
276
instantSlasher.fulfillSlashingRequest (params);
289
277
}
290
278
291
279
function test_fulfillSlashingRequest () public {
292
- vm.skip (false );
293
280
vm.startPrank (operatorWallet.key.addr);
294
281
IDelegationManager (coreDeployment.delegationManager).registerAsOperator (
295
282
address (0 ), 1 , "metadata "
296
283
);
297
284
298
- // Mint tokens and deposit into strategy
299
285
uint256 depositAmount = 1 ether ;
300
286
mockToken.mint (operatorWallet.key.addr, depositAmount);
301
287
mockToken.approve (address (coreDeployment.strategyManager), depositAmount);
302
288
IStrategyManager (coreDeployment.strategyManager).depositIntoStrategy (
303
289
mockStrategy, mockToken, depositAmount
304
290
);
305
291
306
- // Set allocation delay
307
292
uint32 minDelay = 1 ;
308
293
IAllocationManager (coreDeployment.allocationManager).setAllocationDelay (
309
294
operatorWallet.key.addr, minDelay
310
295
);
311
296
vm.stopPrank ();
312
297
313
- // Assert operator has allocation delay set
314
298
(bool isSet ,) = IAllocationManager (coreDeployment.allocationManager).getAllocationDelay (
315
299
operatorWallet.key.addr
316
300
);
317
301
assertFalse (isSet, "Operator allocation delay not set " );
318
302
319
303
vm.roll (block .number + ALLOCATION_CONFIGURATION_DELAY + 1 );
320
304
321
- // Set up allocation parameters
322
305
IStrategy[] memory allocStrategies = new IStrategy [](1 );
323
306
allocStrategies[0 ] = mockStrategy;
324
307
@@ -354,7 +337,6 @@ contract InstantSlasherTest is Test {
354
337
355
338
uint32 [] memory operatorSetIds = new uint32 [](1 );
356
339
operatorSetIds[0 ] = 0 ;
357
- // Create BLS signing key params
358
340
bytes32 messageHash = slashingRegistryCoordinator.calculatePubkeyRegistrationMessageHash (
359
341
operatorWallet.key.addr
360
342
);
@@ -367,7 +349,6 @@ contract InstantSlasherTest is Test {
367
349
pubkeyG2: operatorWallet.signingKey.publicKeyG2
368
350
});
369
351
370
- // Encode registration data with socket and pubkey params
371
352
bytes memory registrationData = abi.encode (
372
353
ISlashingRegistryCoordinatorTypes.RegistrationType.NORMAL, "socket " , pubkeyParams
373
354
);
@@ -385,7 +366,6 @@ contract InstantSlasherTest is Test {
385
366
386
367
vm.roll (block .number + 100 );
387
368
388
- // Create slashing params
389
369
IAllocationManagerTypes.SlashingParams memory params = IAllocationManagerTypes
390
370
.SlashingParams ({
391
371
operator: operatorWallet.key.addr,
@@ -395,13 +375,253 @@ contract InstantSlasherTest is Test {
395
375
description: "Test slashing "
396
376
});
397
377
398
- // Set each wad to slash to 1e18 (100% slash)
399
378
for (uint256 i = 0 ; i < params.wadsToSlash.length ; i++ ) {
400
379
params.wadsToSlash[i] = 1e18 ;
401
380
}
402
381
403
- // Execute slashing
404
382
vm.prank (slasher);
405
383
instantSlasher.fulfillSlashingRequest (params);
406
384
}
385
+
386
+ function test_partialSlashUpdatesWeight () public {
387
+ bytes32 operatorId = _setupOperatorForSlashing ();
388
+
389
+ uint96 initialOperatorStake =
390
+ stakeRegistry.weightOfOperatorForQuorum (0 , operatorWallet.key.addr);
391
+ uint96 initialTotalStake = stakeRegistry.getCurrentTotalStake (0 );
392
+
393
+ assertEq (initialOperatorStake, 2 ether, "Initial operator stake is incorrect " );
394
+
395
+ IAllocationManagerTypes.SlashingParams memory params = _getPartialSlashingParams ();
396
+
397
+ vm.prank (slasher);
398
+ instantSlasher.fulfillSlashingRequest (params);
399
+
400
+ uint96 postSlashingStake =
401
+ stakeRegistry.weightOfOperatorForQuorum (0 , operatorWallet.key.addr);
402
+ uint96 totalStakeAfter = stakeRegistry.getCurrentTotalStake (0 );
403
+
404
+ assertEq (postSlashingStake, 1 ether, "Incorrect post-slash stake " );
405
+
406
+ assertEq (totalStakeAfter, initialTotalStake - 1 ether, "Total stake incorrect " );
407
+
408
+ uint192 bitmap = slashingRegistryCoordinator.getCurrentQuorumBitmap (operatorId);
409
+ assertTrue (bitmap & 1 != 0 , "Operator removed from quorum 0 " );
410
+
411
+ ISlashingRegistryCoordinatorTypes.OperatorStatus status =
412
+ slashingRegistryCoordinator.getOperatorStatus (operatorWallet.key.addr);
413
+ assertEq (
414
+ uint256 (status),
415
+ uint256 (ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED),
416
+ "Operator not in REGISTERED status "
417
+ );
418
+ }
419
+
420
+ function test_fullySlashRemovesOperator () public {
421
+ bytes32 operatorId = _setupOperatorForSlashing ();
422
+
423
+ // Verify operator is registered before slashing
424
+ uint96 initialOperatorStake =
425
+ stakeRegistry.weightOfOperatorForQuorum (0 , operatorWallet.key.addr);
426
+ uint96 initialTotalStake = stakeRegistry.getCurrentTotalStake (0 );
427
+
428
+ assertEq (initialOperatorStake, 2 ether, "Initial operator stake is incorrect " );
429
+
430
+ uint192 initialBitmap = slashingRegistryCoordinator.getCurrentQuorumBitmap (operatorId);
431
+ assertTrue (initialBitmap & 1 != 0 , "Operator should be in quorum 0 before slashing " );
432
+
433
+ ISlashingRegistryCoordinatorTypes.OperatorStatus initialStatus =
434
+ slashingRegistryCoordinator.getOperatorStatus (operatorWallet.key.addr);
435
+ assertEq (
436
+ uint256 (initialStatus),
437
+ uint256 (ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED),
438
+ "Operator should be in REGISTERED status before slashing "
439
+ );
440
+
441
+ // Perform full slashing (100%)
442
+ IAllocationManagerTypes.SlashingParams memory params = _getSlashingParams ();
443
+
444
+ vm.prank (slasher);
445
+ instantSlasher.fulfillSlashingRequest (params);
446
+
447
+ // Verify operator is removed after slashing
448
+ uint96 postSlashingStake =
449
+ stakeRegistry.weightOfOperatorForQuorum (0 , operatorWallet.key.addr);
450
+ uint96 totalStakeAfter = stakeRegistry.getCurrentTotalStake (0 );
451
+
452
+ assertEq (postSlashingStake, 0 , "Post-slash stake should be zero " );
453
+ assertEq (
454
+ totalStakeAfter,
455
+ initialTotalStake - 2 ether,
456
+ "Total stake should be reduced by full amount "
457
+ );
458
+
459
+ uint192 finalBitmap = slashingRegistryCoordinator.getCurrentQuorumBitmap (operatorId);
460
+ assertEq (finalBitmap & 1 , 0 , "Operator should be removed from quorum 0 " );
461
+
462
+ ISlashingRegistryCoordinatorTypes.OperatorStatus finalStatus =
463
+ slashingRegistryCoordinator.getOperatorStatus (operatorWallet.key.addr);
464
+ assertEq (
465
+ uint256 (finalStatus),
466
+ uint256 (ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED),
467
+ "Operator should be in DEREGISTERED status after full slashing "
468
+ );
469
+ }
470
+
471
+ function _createMockSlashingParams ()
472
+ internal
473
+ view
474
+ returns (IAllocationManagerTypes.SlashingParams memory )
475
+ {
476
+ IStrategy[] memory strategies = new IStrategy [](1 );
477
+ strategies[0 ] = mockStrategy;
478
+
479
+ uint256 [] memory wadsToSlash = new uint256 [](1 );
480
+ wadsToSlash[0 ] = 0.5e18 ; // 50% slash
481
+
482
+ return IAllocationManagerTypes.SlashingParams ({
483
+ operator: operatorWallet.key.addr,
484
+ operatorSetId: 1 ,
485
+ strategies: strategies,
486
+ wadsToSlash: wadsToSlash,
487
+ description: "Test slashing "
488
+ });
489
+ }
490
+
491
+ function _getSlashingParams ()
492
+ internal
493
+ view
494
+ returns (IAllocationManagerTypes.SlashingParams memory )
495
+ {
496
+ IStrategy[] memory allocStrategies = new IStrategy [](1 );
497
+ allocStrategies[0 ] = mockStrategy;
498
+
499
+ IAllocationManagerTypes.SlashingParams memory params = IAllocationManagerTypes
500
+ .SlashingParams ({
501
+ operator: operatorWallet.key.addr,
502
+ operatorSetId: 0 ,
503
+ strategies: allocStrategies,
504
+ wadsToSlash: new uint256 [](allocStrategies.length ),
505
+ description: "Full slash test "
506
+ });
507
+
508
+ for (uint256 i = 0 ; i < params.wadsToSlash.length ; i++ ) {
509
+ params.wadsToSlash[i] = 1e18 ; // 100% slash
510
+ }
511
+
512
+ return params;
513
+ }
514
+
515
+ function _getPartialSlashingParams ()
516
+ internal
517
+ view
518
+ returns (IAllocationManagerTypes.SlashingParams memory )
519
+ {
520
+ IStrategy[] memory allocStrategies = new IStrategy [](1 );
521
+ allocStrategies[0 ] = mockStrategy;
522
+
523
+ IAllocationManagerTypes.SlashingParams memory params = IAllocationManagerTypes
524
+ .SlashingParams ({
525
+ operator: operatorWallet.key.addr,
526
+ operatorSetId: 0 ,
527
+ strategies: allocStrategies,
528
+ wadsToSlash: new uint256 [](allocStrategies.length ),
529
+ description: "Partial slash test "
530
+ });
531
+
532
+ for (uint256 i = 0 ; i < params.wadsToSlash.length ; i++ ) {
533
+ params.wadsToSlash[i] = 0.5e18 ; // 50% slash
534
+ }
535
+
536
+ return params;
537
+ }
538
+
539
+ function _setupOperatorForSlashing () internal returns (bytes32 ) {
540
+ vm.startPrank (operatorWallet.key.addr);
541
+ IDelegationManager (coreDeployment.delegationManager).registerAsOperator (
542
+ address (0 ), 1 , "metadata "
543
+ );
544
+
545
+ uint256 depositAmount = 2 ether ;
546
+ mockToken.mint (operatorWallet.key.addr, depositAmount);
547
+ mockToken.approve (address (coreDeployment.strategyManager), depositAmount);
548
+ IStrategyManager (coreDeployment.strategyManager).depositIntoStrategy (
549
+ mockStrategy, mockToken, depositAmount
550
+ );
551
+
552
+ uint32 minDelay = 1 ;
553
+ IAllocationManager (coreDeployment.allocationManager).setAllocationDelay (
554
+ operatorWallet.key.addr, minDelay
555
+ );
556
+ vm.stopPrank ();
557
+
558
+ vm.roll (block .number + ALLOCATION_CONFIGURATION_DELAY + 1 );
559
+
560
+ IStrategy[] memory allocStrategies = new IStrategy [](1 );
561
+ allocStrategies[0 ] = mockStrategy;
562
+
563
+ uint64 [] memory magnitudes = new uint64 [](1 );
564
+ magnitudes[0 ] = uint64 (1 ether); // Allocate full magnitude (2 ETH)
565
+
566
+ OperatorSet memory operatorSet = OperatorSet ({avs: address (serviceManager), id: 0 });
567
+
568
+ vm.startPrank (serviceManager);
569
+ IAllocationManagerTypes.CreateSetParams[] memory createParams =
570
+ new IAllocationManagerTypes.CreateSetParams [](1 );
571
+ createParams[0 ] =
572
+ IAllocationManagerTypes.CreateSetParams ({operatorSetId: 0 , strategies: allocStrategies});
573
+ IAllocationManager (coreDeployment.allocationManager).setAVSRegistrar (
574
+ address (serviceManager), IAVSRegistrar (address (slashingRegistryCoordinator))
575
+ );
576
+ vm.stopPrank ();
577
+
578
+ vm.startPrank (operatorWallet.key.addr);
579
+
580
+ IAllocationManagerTypes.AllocateParams[] memory allocParams =
581
+ new IAllocationManagerTypes.AllocateParams [](1 );
582
+ allocParams[0 ] = IAllocationManagerTypes.AllocateParams ({
583
+ operatorSet: operatorSet,
584
+ strategies: allocStrategies,
585
+ newMagnitudes: magnitudes
586
+ });
587
+
588
+ IAllocationManager (coreDeployment.allocationManager).modifyAllocations (
589
+ operatorWallet.key.addr, allocParams
590
+ );
591
+ vm.roll (block .number + 100 );
592
+
593
+ uint32 [] memory operatorSetIds = new uint32 [](1 );
594
+ operatorSetIds[0 ] = 0 ;
595
+ bytes32 messageHash = slashingRegistryCoordinator.calculatePubkeyRegistrationMessageHash (
596
+ operatorWallet.key.addr
597
+ );
598
+ IBLSApkRegistryTypes.PubkeyRegistrationParams memory pubkeyParams = IBLSApkRegistryTypes
599
+ .PubkeyRegistrationParams ({
600
+ pubkeyRegistrationSignature: SigningKeyOperationsLib.sign (
601
+ operatorWallet.signingKey, messageHash
602
+ ),
603
+ pubkeyG1: operatorWallet.signingKey.publicKeyG1,
604
+ pubkeyG2: operatorWallet.signingKey.publicKeyG2
605
+ });
606
+
607
+ bytes memory registrationData = abi.encode (
608
+ ISlashingRegistryCoordinatorTypes.RegistrationType.NORMAL, "socket " , pubkeyParams
609
+ );
610
+
611
+ IAllocationManagerTypes.RegisterParams memory registerParams = IAllocationManagerTypes
612
+ .RegisterParams ({
613
+ avs: address (serviceManager),
614
+ operatorSetIds: operatorSetIds,
615
+ data: registrationData
616
+ });
617
+ IAllocationManager (coreDeployment.allocationManager).registerForOperatorSets (
618
+ operatorWallet.key.addr, registerParams
619
+ );
620
+ vm.stopPrank ();
621
+
622
+ vm.roll (block .number + 100 );
623
+
624
+ bytes32 operatorId = slashingRegistryCoordinator.getOperatorId (operatorWallet.key.addr);
625
+ return operatorId;
626
+ }
407
627
}
0 commit comments