Skip to content

Commit 91948f1

Browse files
committed
fix: enumerable map ovewrite
1 parent 727a689 commit 91948f1

File tree

2 files changed

+55
-15
lines changed

2 files changed

+55
-15
lines changed

src/contracts/core/StrategyManager.sol

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -171,26 +171,35 @@ contract StrategyManager is
171171
EnumerableMap.AddressToUintMap storage operatorSetBurnableShares =
172172
_operatorSetBurnableShares[operatorSet.key()][slashId];
173173

174-
// Cache length to avoid sloads.
174+
// Iterate over burnable shares backwards. Iterating with an increasing index can cause
175+
// elements to be missed as the item to remove is swapped and popped with the last element.
175176
uint256 length = operatorSetBurnableShares.length();
176177

177-
// Iterate over all strategies that have burnable shares.
178-
for (uint256 i = 0; i < length; ++i) {
179-
(address strategy, uint256 sharesToBurn) = operatorSetBurnableShares.at(i);
178+
for (uint256 i = length; i >= 0; --i) {
179+
decreaseBurnableShares(operatorSet, slashId, i - 1);
180+
}
181+
}
182+
183+
/// @inheritdoc IStrategyManager
184+
function decreaseBurnableShares(OperatorSet calldata operatorSet, uint256 slashId, uint256 index) public returns (uint256) {
185+
EnumerableMap.AddressToUintMap storage operatorSetBurnableShares =
186+
_operatorSetBurnableShares[operatorSet.key()][slashId];
180187

181-
// Remove the strategy from the operator set burnable shares.
182-
operatorSetBurnableShares.remove(address(strategy));
188+
(address strategy, uint256 sharesToBurn) = operatorSetBurnableShares.at(index);
183189

184-
// Withdraw the shares to the slash escrow.
185-
IStrategy(strategy).withdraw({
186-
recipient: address(slashEscrowFactory.getSlashEscrow(operatorSet, slashId)),
187-
token: IStrategy(strategy).underlyingToken(),
188-
amountShares: sharesToBurn
189-
});
190+
// Withdraw the shares to the slash escrow.
191+
IStrategy(strategy).withdraw({
192+
recipient: address(slashEscrowFactory.getSlashEscrow(operatorSet, slashId)),
193+
token: IStrategy(strategy).underlyingToken(),
194+
amountShares: sharesToBurn
195+
});
190196

191-
// Emit an event to notify the that burnable shares have been decreased.
192-
emit BurnOrRedistributableSharesDecreased(operatorSet, slashId, IStrategy(strategy), sharesToBurn);
193-
}
197+
operatorSetBurnableShares.remove(address(strategy));
198+
199+
// Emit an event to notify the that burnable shares have been decreased.
200+
emit BurnOrRedistributableSharesDecreased(operatorSet, slashId, IStrategy(strategy), sharesToBurn);
201+
202+
return sharesToBurn;
194203
}
195204

196205
/// @inheritdoc IStrategyManager
@@ -208,6 +217,21 @@ contract StrategyManager is
208217
}
209218
}
210219

220+
/// @inheritdoc IStrategyManager
221+
function getBurnOrRedistributableShares(
222+
OperatorSet calldata operatorSet,
223+
uint256 slashId
224+
) external view returns (IStrategy[] memory) {
225+
address[] memory keys = _operatorSetBurnableShares[operatorSet.key()][slashId].keys();
226+
IStrategy[] memory strategies = new IStrategy[](keys.length);
227+
228+
for (uint256 i = 0; i < keys.length; ++i) {
229+
strategies[i] = IStrategy(keys[i]);
230+
}
231+
232+
return strategies;
233+
}
234+
211235
/// @inheritdoc IStrategyManager
212236
function setStrategyWhitelister(
213237
address newStrategyWhitelister

src/contracts/interfaces/IStrategyManager.sol

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,22 @@ interface IStrategyManager is IStrategyManagerErrors, IStrategyManagerEvents, IS
135135
*/
136136
function decreaseBurnableShares(OperatorSet calldata operatorSet, uint256 slashId) external;
137137

138+
/**
139+
* @notice Removes a single strategy's shares from storage and transfers the underlying tokens for the slashId to the slash escrow.
140+
* @param operatorSet The operator set to burn shares in.
141+
* @param slashId The slash ID to burn shares in.
142+
* @param index The index of the strategy to burn shares in. Returns the amount of shares that were burned.
143+
*/
144+
function decreaseBurnableShares(OperatorSet calldata operatorSet, uint256 slashId, uint256 index) external returns (uint256);
145+
146+
/**
147+
* @notice Returns the strategies that have NOT been sent to escrow for a given slashId.
148+
* @param operatorSet The operator set to burn shares in.
149+
* @param slashId The slash ID to burn shares in.
150+
* @return strategies The strategies for the given slashId.
151+
*/
152+
function getBurnOrRedistributableShares(OperatorSet calldata operatorSet, uint256 slashId) external view returns (IStrategy[] memory);
153+
138154
/**
139155
* @notice Owner-only function to change the `strategyWhitelister` address.
140156
* @param newStrategyWhitelister new address for the `strategyWhitelister`.

0 commit comments

Comments
 (0)