@@ -767,6 +767,130 @@ contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests
767767 assertEq (0 , mInfos[0 ].effectTimestamp, "effectTimestamp should be 0 " );
768768 }
769769
770+ /**
771+ * Allocates 100% magnitude for a single strategy to an operatorSet.
772+ * First slashes 99% from the operatorSet, slashes 99.99% a second time, and on the third slash, slashes
773+ * 99.9999999999999% which should get rounded up to 100% or 1e18 wadSlashed leaving the operator with no magnitude
774+ * in the operatorSet, 0 encumbered magnitude, and 0 max magnitude.
775+ *
776+ * Asserts that:
777+ * 1. Events are emitted
778+ * 2. Encumbered mag is updated
779+ * 3. Max mag is updated
780+ * 4. Calculations for `getAllocatableMagnitude` and `getAllocationInfo` are correct
781+ * 5. Slashed amounts are rounded up to ensure magnitude is always slashed
782+ */
783+ function test_slashTwoOperatorSets () public {
784+ // Generate allocation for `strategyMock`, we allocate 100% to opSet 0
785+ IAllocationManagerTypes.MagnitudeAllocation[] memory allocations = _generateMagnitudeAllocationCalldataForOpSet ({
786+ avsToSet: defaultAVS,
787+ operatorSetId: 0 ,
788+ magnitudeToSet: 1e18 ,
789+ expectedMaxMagnitude: 1e18
790+ });
791+
792+ cheats.prank (defaultOperator);
793+ allocationManager.modifyAllocations (allocations);
794+ cheats.warp (block .timestamp + DEFAULT_OPERATOR_ALLOCATION_DELAY);
795+
796+ // 1. Slash operator for 99% in opSet 0 bringing their magnitude to 1e16
797+ SlashingParams memory slashingParams = SlashingParams ({
798+ operator: defaultOperator,
799+ operatorSetId: allocations[0 ].operatorSets[0 ].operatorSetId,
800+ strategies: _strategyMockArray (),
801+ wadToSlash: 99e16 ,
802+ description: "test "
803+ });
804+ avsDirectoryMock.setIsOperatorSlashable (slashingParams.operator, defaultAVS, slashingParams.operatorSetId, true );
805+ uint64 expectedEncumberedMagnitude = 1e16 ; // After slashing 99%, only 1% expected encumberedMagnitude
806+ uint64 magnitudeAfterSlash = 1e16 ;
807+ uint64 maxMagnitudeAfterSlash = 1e16 ; // 1e15 is maxMagnitude
808+ uint256 [] memory wadSlashed = new uint256 [](1 );
809+ wadSlashed[0 ] = 99e16 ;
810+
811+ // Slash Operator
812+ cheats.expectEmit (true , true , true , true , address (allocationManager));
813+ emit EncumberedMagnitudeUpdated (defaultOperator, strategyMock, expectedEncumberedMagnitude);
814+ cheats.expectEmit (true , true , true , true , address (allocationManager));
815+ emit OperatorSetMagnitudeUpdated (defaultOperator, allocations[0 ].operatorSets[0 ], strategyMock, magnitudeAfterSlash, uint32 (block .timestamp ));
816+ cheats.expectEmit (true , true , true , true , address (allocationManager));
817+ emit MaxMagnitudeUpdated (defaultOperator, strategyMock, maxMagnitudeAfterSlash);
818+ cheats.expectEmit (true , true , true , true , address (allocationManager));
819+ emit OperatorSlashed (slashingParams.operator, _operatorSet (defaultAVS, slashingParams.operatorSetId), slashingParams.strategies, wadSlashed, slashingParams.description);
820+ cheats.prank (defaultAVS);
821+ allocationManager.slashOperator (slashingParams);
822+
823+ // Check storage
824+ assertEq (expectedEncumberedMagnitude, allocationManager.encumberedMagnitude (defaultOperator, strategyMock), "encumberedMagnitude not updated " );
825+ assertEq (maxMagnitudeAfterSlash, allocationManager.getMaxMagnitudes (defaultOperator, _strategyMockArray ())[0 ], "maxMagnitude not updated " );
826+ MagnitudeInfo[] memory mInfos = allocationManager.getAllocationInfo (defaultOperator, strategyMock, allocations[0 ].operatorSets);
827+ assertEq (magnitudeAfterSlash, mInfos[0 ].currentMagnitude, "currentMagnitude not updated " );
828+
829+ // 2. Slash operator again for 99.99% in opSet 0 bringing their magnitude to 1e14
830+ slashingParams = SlashingParams ({
831+ operator: defaultOperator,
832+ operatorSetId: allocations[0 ].operatorSets[0 ].operatorSetId,
833+ strategies: _strategyMockArray (),
834+ wadToSlash: 9999e14 ,
835+ description: "test "
836+ });
837+ expectedEncumberedMagnitude = 1e12 ; // After slashing 99.99%, only 0.01% expected encumberedMagnitude
838+ magnitudeAfterSlash = 1e12 ;
839+ maxMagnitudeAfterSlash = 1e12 ;
840+ wadSlashed[0 ] = 9999e14 ;
841+
842+ cheats.expectEmit (true , true , true , true , address (allocationManager));
843+ emit EncumberedMagnitudeUpdated (defaultOperator, strategyMock, expectedEncumberedMagnitude);
844+ cheats.expectEmit (true , true , true , true , address (allocationManager));
845+ emit OperatorSetMagnitudeUpdated (defaultOperator, allocations[0 ].operatorSets[0 ], strategyMock, magnitudeAfterSlash, uint32 (block .timestamp ));
846+ cheats.expectEmit (true , true , true , true , address (allocationManager));
847+ emit MaxMagnitudeUpdated (defaultOperator, strategyMock, maxMagnitudeAfterSlash);
848+ cheats.expectEmit (true , true , true , true , address (allocationManager));
849+ emit OperatorSlashed (slashingParams.operator, _operatorSet (defaultAVS, slashingParams.operatorSetId), slashingParams.strategies, wadSlashed, slashingParams.description);
850+ cheats.prank (defaultAVS);
851+ allocationManager.slashOperator (slashingParams);
852+
853+ // Check storage
854+ assertEq (expectedEncumberedMagnitude, allocationManager.encumberedMagnitude (defaultOperator, strategyMock), "encumberedMagnitude not updated " );
855+ assertEq (maxMagnitudeAfterSlash, allocationManager.getMaxMagnitudes (defaultOperator, _strategyMockArray ())[0 ], "maxMagnitude not updated " );
856+ mInfos = allocationManager.getAllocationInfo (defaultOperator, strategyMock, allocations[0 ].operatorSets);
857+ assertEq (magnitudeAfterSlash, mInfos[0 ].currentMagnitude, "currentMagnitude not updated " );
858+
859+ // 3. Slash operator again for 99.9999999999999% in opSet 0
860+ slashingParams = SlashingParams ({
861+ operator: defaultOperator,
862+ operatorSetId: allocations[0 ].operatorSets[0 ].operatorSetId,
863+ strategies: _strategyMockArray (),
864+ wadToSlash: 1e18 - 1e3 ,
865+ description: "test "
866+ });
867+ // Should technically be 1e3 remaining but with rounding error and rounding up slashed amounts
868+ // the remaining magnitude is 0
869+ expectedEncumberedMagnitude = 0 ; // Should technically be 1e3 remaining but with rounding error and rounding up slashed amounts.
870+ magnitudeAfterSlash = 0 ;
871+ maxMagnitudeAfterSlash = 0 ;
872+ // wadSlashed is rounded up from the 1e18 - 1e3 amount
873+ wadSlashed[0 ] = 1e18 ;
874+
875+ // Slash Operator
876+ cheats.expectEmit (true , true , true , true , address (allocationManager));
877+ emit EncumberedMagnitudeUpdated (defaultOperator, strategyMock, expectedEncumberedMagnitude);
878+ cheats.expectEmit (true , true , true , true , address (allocationManager));
879+ emit OperatorSetMagnitudeUpdated (defaultOperator, allocations[0 ].operatorSets[0 ], strategyMock, magnitudeAfterSlash, uint32 (block .timestamp ));
880+ cheats.expectEmit (true , true , true , true , address (allocationManager));
881+ emit MaxMagnitudeUpdated (defaultOperator, strategyMock, maxMagnitudeAfterSlash);
882+ cheats.expectEmit (true , true , true , true , address (allocationManager));
883+ emit OperatorSlashed (slashingParams.operator, _operatorSet (defaultAVS, slashingParams.operatorSetId), slashingParams.strategies, wadSlashed, slashingParams.description);
884+ cheats.prank (defaultAVS);
885+ allocationManager.slashOperator (slashingParams);
886+
887+ // Check storage
888+ assertEq (expectedEncumberedMagnitude, allocationManager.encumberedMagnitude (defaultOperator, strategyMock), "encumberedMagnitude not updated " );
889+ assertEq (maxMagnitudeAfterSlash, allocationManager.getMaxMagnitudes (defaultOperator, _strategyMockArray ())[0 ], "maxMagnitude not updated " );
890+ mInfos = allocationManager.getAllocationInfo (defaultOperator, strategyMock, allocations[0 ].operatorSets);
891+ assertEq (magnitudeAfterSlash, mInfos[0 ].currentMagnitude, "currentMagnitude not updated " );
892+ }
893+
770894 /**
771895 * Allocates all of magnitude to a single strategy to an operatorSet. Deallocate half. Finally, slash while deallocation is pending
772896 * Asserts that:
0 commit comments