@@ -200,6 +200,7 @@ contract InstantSlasherTest is Test {
200200 slashingRegistryCoordinator =
201201 SlashingRegistryCoordinator (middlewareDeployments.slashingRegistryCoordinator);
202202 instantSlasher = InstantSlasher (middlewareDeployments.instantSlasher);
203+ stakeRegistry = StakeRegistry (middlewareDeployments.stakeRegistry);
203204
204205 PermissionController (coreDeployment.permissionController).setAppointee (
205206 address (serviceManager),
@@ -215,6 +216,13 @@ contract InstantSlasherTest is Test {
215216 AllocationManager.slashOperator.selector
216217 );
217218
219+ PermissionController (coreDeployment.permissionController).setAppointee (
220+ address (serviceManager),
221+ address (slashingRegistryCoordinator),
222+ coreDeployment.allocationManager,
223+ AllocationManager.deregisterFromOperatorSets.selector
224+ );
225+
218226 PermissionController (coreDeployment.permissionController).setAppointee (
219227 address (serviceManager),
220228 proxyAdminOwner,
@@ -262,63 +270,38 @@ contract InstantSlasherTest is Test {
262270 assertEq (instantSlasher.slasher (), slasher);
263271 }
264272
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-
285273 function test_fulfillSlashingRequest_revert_notSlasher () public {
286274 IAllocationManagerTypes.SlashingParams memory params = _createMockSlashingParams ();
287275 vm.expectRevert (ISlasherErrors.OnlySlasher.selector );
288276 instantSlasher.fulfillSlashingRequest (params);
289277 }
290278
291279 function test_fulfillSlashingRequest () public {
292- vm.skip (false );
293280 vm.startPrank (operatorWallet.key.addr);
294281 IDelegationManager (coreDeployment.delegationManager).registerAsOperator (
295282 address (0 ), 1 , "metadata "
296283 );
297284
298- // Mint tokens and deposit into strategy
299285 uint256 depositAmount = 1 ether ;
300286 mockToken.mint (operatorWallet.key.addr, depositAmount);
301287 mockToken.approve (address (coreDeployment.strategyManager), depositAmount);
302288 IStrategyManager (coreDeployment.strategyManager).depositIntoStrategy (
303289 mockStrategy, mockToken, depositAmount
304290 );
305291
306- // Set allocation delay
307292 uint32 minDelay = 1 ;
308293 IAllocationManager (coreDeployment.allocationManager).setAllocationDelay (
309294 operatorWallet.key.addr, minDelay
310295 );
311296 vm.stopPrank ();
312297
313- // Assert operator has allocation delay set
314298 (bool isSet ,) = IAllocationManager (coreDeployment.allocationManager).getAllocationDelay (
315299 operatorWallet.key.addr
316300 );
317301 assertFalse (isSet, "Operator allocation delay not set " );
318302
319303 vm.roll (block .number + ALLOCATION_CONFIGURATION_DELAY + 1 );
320304
321- // Set up allocation parameters
322305 IStrategy[] memory allocStrategies = new IStrategy [](1 );
323306 allocStrategies[0 ] = mockStrategy;
324307
@@ -354,7 +337,6 @@ contract InstantSlasherTest is Test {
354337
355338 uint32 [] memory operatorSetIds = new uint32 [](1 );
356339 operatorSetIds[0 ] = 0 ;
357- // Create BLS signing key params
358340 bytes32 messageHash = slashingRegistryCoordinator.calculatePubkeyRegistrationMessageHash (
359341 operatorWallet.key.addr
360342 );
@@ -367,7 +349,6 @@ contract InstantSlasherTest is Test {
367349 pubkeyG2: operatorWallet.signingKey.publicKeyG2
368350 });
369351
370- // Encode registration data with socket and pubkey params
371352 bytes memory registrationData = abi.encode (
372353 ISlashingRegistryCoordinatorTypes.RegistrationType.NORMAL, "socket " , pubkeyParams
373354 );
@@ -385,7 +366,6 @@ contract InstantSlasherTest is Test {
385366
386367 vm.roll (block .number + 100 );
387368
388- // Create slashing params
389369 IAllocationManagerTypes.SlashingParams memory params = IAllocationManagerTypes
390370 .SlashingParams ({
391371 operator: operatorWallet.key.addr,
@@ -395,13 +375,253 @@ contract InstantSlasherTest is Test {
395375 description: "Test slashing "
396376 });
397377
398- // Set each wad to slash to 1e18 (100% slash)
399378 for (uint256 i = 0 ; i < params.wadsToSlash.length ; i++ ) {
400379 params.wadsToSlash[i] = 1e18 ;
401380 }
402381
403- // Execute slashing
404382 vm.prank (slasher);
405383 instantSlasher.fulfillSlashingRequest (params);
406384 }
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+ }
407627}
0 commit comments