@@ -89,25 +89,57 @@ contract SlashEscrowFactory is Initializable, SlashEscrowFactoryStorage, Ownable
89
89
) external onlyWhenNotPaused (PAUSED_RELEASE_ESCROW) {
90
90
address redistributionRecipient = allocationManager.getRedistributionRecipient (operatorSet);
91
91
92
- // If the redistribution recipient is not the default burn address...
93
- if (redistributionRecipient != DEFAULT_BURN_ADDRESS) {
94
- require (msg .sender == redistributionRecipient, OnlyRedistributionRecipient ());
95
- }
96
-
97
- // Assert that the slash ID is not paused
98
- require (! isEscrowPaused (operatorSet, slashId), IPausable.CurrentlyPaused ());
99
-
100
- // Assert that the escrow delay has elapsed
101
- require (block .number >= getEscrowCompleteBlock (operatorSet, slashId), EscrowDelayNotElapsed ());
92
+ _checkReleaseSlashEscrow (operatorSet, slashId, redistributionRecipient);
102
93
103
94
// Calling `clearBurnOrRedistributableShares` will transfer the underlying tokens to the `SlashEscrow`.
104
95
// NOTE: While `clearBurnOrRedistributableShares` may have already been called, we call it again to ensure that the
105
96
// underlying tokens are actually in escrow before processing and removing storage (which would otherwise prevent
106
97
// the tokens from being released).
107
98
strategyManager.clearBurnOrRedistributableShares (operatorSet, slashId);
108
99
109
- // Release the slashEscrow. The `SlashEscrow` is deployed in `initiateSlashEscrow`.
110
- _processSlashEscrow (operatorSet, slashId, getSlashEscrow (operatorSet, slashId), redistributionRecipient);
100
+ // Process the slash escrow for each strategy.
101
+ address [] memory strategies = _pendingStrategiesForSlashId[operatorSet.key ()][slashId].values ();
102
+ for (uint256 i = 0 ; i < strategies.length ; ++ i) {
103
+ _processSlashEscrowByStrategy ({
104
+ operatorSet: operatorSet,
105
+ slashId: slashId,
106
+ slashEscrow: getSlashEscrow (operatorSet, slashId),
107
+ redistributionRecipient: redistributionRecipient,
108
+ strategy: IStrategy (strategies[i])
109
+ });
110
+ }
111
+
112
+ // Update the slash escrow storage.
113
+ _updateSlashEscrowStorage (operatorSet, slashId);
114
+ }
115
+
116
+ /// @inheritdoc ISlashEscrowFactory
117
+ function releaseSlashEscrowByStrategy (
118
+ OperatorSet calldata operatorSet ,
119
+ uint256 slashId ,
120
+ IStrategy strategy
121
+ ) external virtual onlyWhenNotPaused (PAUSED_RELEASE_ESCROW) {
122
+ address redistributionRecipient = allocationManager.getRedistributionRecipient (operatorSet);
123
+
124
+ _checkReleaseSlashEscrow (operatorSet, slashId, redistributionRecipient);
125
+
126
+ // Calling `clearBurnOrRedistributableSharesByStrategy` will transfer the underlying tokens to the `SlashEscrow`.
127
+ // NOTE: While the strategy may have already been cleared, we call it again to ensure that the
128
+ // underlying tokens are actually in escrow before processing and removing storage (which would otherwise prevent
129
+ // the tokens from being released).
130
+ strategyManager.clearBurnOrRedistributableSharesByStrategy (operatorSet, slashId, strategy);
131
+
132
+ // Release the slashEscrow.
133
+ _processSlashEscrowByStrategy ({
134
+ operatorSet: operatorSet,
135
+ slashId: slashId,
136
+ slashEscrow: getSlashEscrow (operatorSet, slashId),
137
+ redistributionRecipient: redistributionRecipient,
138
+ strategy: strategy
139
+ });
140
+
141
+ // Update the slash escrow storage.
142
+ _updateSlashEscrowStorage (operatorSet, slashId);
111
143
}
112
144
113
145
/**
@@ -155,48 +187,68 @@ contract SlashEscrowFactory is Initializable, SlashEscrowFactoryStorage, Ownable
155
187
*
156
188
*/
157
189
158
- /// @notice Processes the slash escrow.
159
- function _processSlashEscrow (
190
+ /// @notice Checks that the slash escrow can be released .
191
+ function _checkReleaseSlashEscrow (
160
192
OperatorSet calldata operatorSet ,
161
193
uint256 slashId ,
162
- ISlashEscrow slashEscrow ,
163
194
address redistributionRecipient
195
+ ) internal view {
196
+ // If the redistribution recipient is not the default burn address...
197
+ if (redistributionRecipient != DEFAULT_BURN_ADDRESS) {
198
+ require (msg .sender == redistributionRecipient, OnlyRedistributionRecipient ());
199
+ }
200
+
201
+ // Assert that the slash ID is not paused
202
+ require (! isEscrowPaused (operatorSet, slashId), IPausable.CurrentlyPaused ());
203
+
204
+ // Assert that the escrow delay has elapsed
205
+ require (block .number >= getEscrowCompleteBlock (operatorSet, slashId), EscrowDelayNotElapsed ());
206
+ }
207
+
208
+ /// @notice Processes the slash escrow for a single strategy.
209
+ function _processSlashEscrowByStrategy (
210
+ OperatorSet calldata operatorSet ,
211
+ uint256 slashId ,
212
+ ISlashEscrow slashEscrow ,
213
+ address redistributionRecipient ,
214
+ IStrategy strategy
164
215
) internal {
165
- // Create storage pointers for readability.
166
- EnumerableSet.Bytes32Set storage pendingOperatorSets = _pendingOperatorSets;
167
- EnumerableSet.UintSet storage pendingSlashIds = _pendingSlashIds[operatorSet.key ()];
216
+ // Create storage pointer for readability.
168
217
EnumerableSet.AddressSet storage pendingStrategiesForSlashId =
169
218
_pendingStrategiesForSlashId[operatorSet.key ()][slashId];
170
219
171
- // Iterate over the escrow array in reverse order and pop the processed entries from storage.
172
- uint256 totalPendingForSlashId = pendingStrategiesForSlashId.length ();
173
- for (uint256 i = totalPendingForSlashId; i > 0 ; -- i) {
174
- address strategy = pendingStrategiesForSlashId.at (i - 1 );
175
-
176
- // Burn or redistribute the underlying tokens for the strategy.
177
- slashEscrow.releaseTokens (
178
- ISlashEscrowFactory (address (this )),
179
- slashEscrowImplementation,
180
- operatorSet,
181
- slashId,
182
- redistributionRecipient,
183
- IStrategy (strategy)
184
- );
185
-
186
- // Remove the strategy and underlying amount from the pending burn or redistributions map.
187
- pendingStrategiesForSlashId.remove (strategy);
188
- emit EscrowComplete (operatorSet, slashId, IStrategy (strategy), redistributionRecipient);
189
- }
220
+ // Burn or redistribute the underlying tokens for the strategy.
221
+ slashEscrow.releaseTokens ({
222
+ slashEscrowFactory: ISlashEscrowFactory (address (this )),
223
+ slashEscrowImplementation: slashEscrowImplementation,
224
+ operatorSet: operatorSet,
225
+ slashId: slashId,
226
+ recipient: redistributionRecipient,
227
+ strategy: strategy
228
+ });
229
+
230
+ // Remove the strategy and underlying amount from the pending strategies escrow map.
231
+ pendingStrategiesForSlashId.remove (address (strategy));
232
+ emit EscrowComplete (operatorSet, slashId, strategy, redistributionRecipient);
233
+ }
234
+
235
+ function _updateSlashEscrowStorage (OperatorSet calldata operatorSet , uint256 slashId ) internal {
236
+ // Create storage pointers for readability.
237
+ EnumerableSet.Bytes32Set storage pendingOperatorSets = _pendingOperatorSets;
238
+ EnumerableSet.UintSet storage pendingSlashIds = _pendingSlashIds[operatorSet.key ()];
239
+ uint256 totalPendingForSlashId = _pendingStrategiesForSlashId[operatorSet.key ()][slashId].length ();
190
240
191
- // Remove the slash ID from the pending slash IDs set.
192
- pendingSlashIds.remove (slashId);
241
+ // If there are no more strategies to process, remove the slash ID from the pending slash IDs set.
242
+ if (totalPendingForSlashId == 0 ) {
243
+ pendingSlashIds.remove (slashId);
193
244
194
- // Delete the start block for the slash ID.
195
- delete _slashIdToStartBlock[operatorSet.key ()][slashId];
245
+ // Delete the start block for the slash ID.
246
+ delete _slashIdToStartBlock[operatorSet.key ()][slashId];
196
247
197
- // Remove the operator set from the pending operator sets set if there are no more pending slash IDs.
198
- if (pendingSlashIds.length () == 0 ) {
199
- pendingOperatorSets.remove (operatorSet.key ());
248
+ // If there are no more slash IDs for the operator set, remove the operator set from the pending operator sets set.
249
+ if (pendingSlashIds.length () == 0 ) {
250
+ pendingOperatorSets.remove (operatorSet.key ());
251
+ }
200
252
}
201
253
}
202
254
0 commit comments