@@ -11,66 +11,131 @@ contract Integration_Rounding is IntegrationCheckUtils {
1111 AVS badAVS;
1212 IStrategy strategy;
1313 IERC20Metadata token;
14+ User goodStaker;
1415
1516 OperatorSet mOpSet; // "manipOpSet" used for magnitude manipulation
1617 OperatorSet rOpSet; // redistributable opset used to exploit precision loss and trigger redistribution
1718
1819 function _init () internal override {
1920 _configAssetTypes (HOLDS_LST);
2021
21- attacker = new User ("Attacker " );
22+ attacker = new User ("Attacker " ); // attacker can be both operator and staker
2223 badAVS = new AVS ("BadAVS " );
2324 strategy = lstStrats[0 ];
2425 token = IERC20Metadata (address (strategy.underlyingToken ()));
25-
26+ deal (address (token), address (attacker), uint256 (1000000000000000000 )); // TODO: make the balance a fuzzing param
27+
28+ // good staker and operator setup
29+ goodStaker = new User ("goodStaker " );
30+ deal (address (token), address (goodStaker), uint256 (1000000000000000000 )); // TODO: make the balance a fuzzing param
31+
2632 // Register attacker as operator and create attacker-controller AVS/OpSets
2733 attacker.registerAsOperator (0 );
2834 rollForward ({blocks: ALLOCATION_CONFIGURATION_DELAY + 1 });
2935 badAVS.updateAVSMetadataURI ("https://example.com " );
30- mOpSet = badAVS.createOperatorSet (strategy.toArray ());
31- rOpSet = badAVS.createRedistributingOperatorSet (strategy.toArray (), address (attacker));
36+ mOpSet = badAVS.createOperatorSet (strategy.toArray ()); // setup low mag operator
37+ rOpSet = badAVS.createRedistributingOperatorSet (strategy.toArray (), address (attacker)); // execute exploit
3238
3339 // Register for both opsets
3440 attacker.registerForOperatorSet (mOpSet);
3541 attacker.registerForOperatorSet (rOpSet);
42+
43+ // TODO: considerations
44+ // - assets of other users within the opSet
45+ // - calculate total assets entering and leaving the protocol, estimate precision loss (+ or -)
3646
3747 _print ("setup " );
3848 }
3949
40- function test_rounding () public rand (0 ) {
41- _magnitudeManipulation ();
42- _setupFinal ();
43- _final ();
50+ // TODO: parameterize deposits
51+ // TODO: consider manual fuzzing from 1 up to WAD - 1
52+ function test_rounding (uint64 wadToSlash ) public rand (0 ) {
53+ // bound wadToSlash to 1 < wadToSlash < WAD - 1
54+ wadToSlash = uint64 (bound (wadToSlash, 1 , WAD - 1 ));
55+
56+ _magnitudeManipulation (wadToSlash); // get operator to low mag
57+ _setupFinal (wadToSlash); //
58+ _final (wadToSlash);
4459 }
4560
4661 // TODO - another way to mess with rounding/precision loss is to manipulate DSF
47- function _magnitudeManipulation () internal {
62+ function _magnitudeManipulation (uint64 wadToSlash ) internal {
63+
64+ // allocate magnitude to operator set
4865 attacker.modifyAllocations (AllocateParams ({
4966 operatorSet: mOpSet,
5067 strategies: strategy.toArray (),
5168 newMagnitudes: WAD.toArrayU64 ()
5269 }));
70+
71+ // TODO: print "newMagnitudes"
5372
5473 _print ("allocate " );
5574
75+ // slash operator to low mag
5676 badAVS.slashOperator (SlashingParams ({
5777 operator: address (attacker),
5878 operatorSetId: mOpSet.id,
5979 strategies: strategy.toArray (),
60- wadsToSlash: uint (WAD -1 ).toArrayU256 (),
61- description: ""
80+ wadsToSlash: uint (wadToSlash ).toArrayU256 (), // TODO: Make WAD-1 a fuzzing param
81+ description: "manipulation! "
6282 }));
83+
84+ // TODO: print "wadsToSlash"
6385
6486 _print ("slash " );
87+
88+ // deallocate magnitude from operator set
89+ attacker.modifyAllocations (AllocateParams ({
90+ operatorSet: mOpSet,
91+ strategies: strategy.toArray (),
92+ newMagnitudes: 0 .toArrayU64 ()
93+ }));
94+
95+ rollForward ({blocks: DEALLOCATION_DELAY + 1 });
96+
97+ _print ("deallocate " );
6598 }
6699
67- function _setupFinal () internal {
68- // create redistributable opset
69- // deposit assets
100+ function _setupFinal (uint64 wadToSlash ) internal {
101+ // allocate to redistributable opset
102+ attacker.modifyAllocations (AllocateParams ({
103+ operatorSet: rOpSet,
104+ strategies: strategy.toArray (),
105+ newMagnitudes: (WAD - wadToSlash).toArrayU64 ()
106+ }));
107+
108+ // deposit assets and delegate to attacker
109+ attacker.depositIntoEigenlayer (strategy.toArray (), token.balanceOf (address (attacker)).toArrayU256 ());
110+
111+
112+ goodStaker.depositIntoEigenlayer (strategy.toArray (), token.balanceOf (address (goodStaker)).toArrayU256 ());
113+
114+ // TODO: print "initTokenBalances"
115+
116+ _print ("deposit " );
70117 }
71118
72- function _final () internal {
119+ function _final (uint64 wadToSlash ) internal {
73120 // perform final slash on redistributable opset and check for profit
121+ badAVS.slashOperator (SlashingParams ({
122+ operator: address (attacker),
123+ operatorSetId: rOpSet.id,
124+ strategies: strategy.toArray (),
125+ wadsToSlash: uint (WAD - wadToSlash).toArrayU256 (),
126+ description: "final slash "
127+ }));
128+
129+ _print ("slash " );
130+
131+ // roll forward past the escrow delay
132+ rollForward ({blocks: slashEscrowFactory.getGlobalEscrowDelay () + 1 });
133+
134+ // release funds
135+ vm.prank (address (attacker));
136+ slashEscrowFactory.releaseSlashEscrow (rOpSet, 1 ); // 1 is used as it's the first slashId
137+
138+ _print ("release " );
74139 }
75140
76141 function _print (string memory phaseName ) internal {
0 commit comments