Skip to content

Commit

Permalink
feat: add getMinimumSlashableStake
Browse files Browse the repository at this point in the history
  • Loading branch information
wadealexc committed Nov 13, 2024
1 parent bf0e200 commit dd0293d
Show file tree
Hide file tree
Showing 5 changed files with 283 additions and 6 deletions.
38 changes: 38 additions & 0 deletions src/contracts/core/AllocationManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -738,4 +738,42 @@ contract AllocationManager is

return strategies;
}

/// @inheritdoc IAllocationManager
function getMinimumSlashableStake(
OperatorSet memory operatorSet,
address[] memory operators,
IStrategy[] memory strategies,
uint32 futureBlock
) external view returns (uint256[][] memory slashableStake) {
slashableStake = new uint256[][](operators.length);
uint256[][] memory delegatedStake = delegation.getOperatorsShares(operators, strategies);

for (uint256 i = 0; i < operators.length; i++) {
address operator = operators[i];
slashableStake[i] = new uint256[](strategies.length);

for (uint256 j = 0; j < strategies.length; j++) {
IStrategy strategy = strategies[j];

// Fetch the max magnitude and allocation for the operator/strategy.
// Prevent division by 0 if needed. This mirrors the "FullySlashed" checks
// in the DelegationManager
uint64 maxMagnitude = _maxMagnitudeHistory[operator][strategy].latest();
if (maxMagnitude == 0) {
continue;
}

Allocation memory alloc = getAllocation(operator, operatorSet, strategy);

// If the pending change takes effect before `futureBlock`, include it in `currentMagnitude`
if (alloc.effectBlock <= futureBlock) {
alloc.currentMagnitude = _addInt128(alloc.currentMagnitude, alloc.pendingDiff);
}

uint256 slashableProportion = uint256(alloc.currentMagnitude).divWad(maxMagnitude);
slashableStake[i][j] = delegatedStake[i][j].mulWad(slashableProportion);
}
}
}
}
24 changes: 24 additions & 0 deletions src/contracts/interfaces/IAllocationManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -517,4 +517,28 @@ interface IAllocationManager is ISignatureUtils, IAllocationManagerErrors, IAllo
function getStrategiesInOperatorSet(
OperatorSet memory operatorSet
) external view returns (IStrategy[] memory strategies);

/**
* @notice Returns the minimum amount of stake that will be slashable as of some future block,
* according to each operator's allocation from each strategy to the operator set.
* @dev This method queries actual delegated stakes in the DelegationManager and applies
* each operator's allocation to the stake to produce the slashable stake each allocation
* represents.
* @dev This minimum takes into account `futureBlock`, and will omit any pending magnitude
* diffs that will not be in effect as of `futureBlock`. NOTE that in order to get the true
* minimum slashable stake as of some future block, `futureBlock` MUST be greater than block.number
* @dev NOTE that `futureBlock` should be fewer than `DEALLOCATION_DELAY` blocks in the future,
* or the values returned from this method may not be accurate due to deallocations.
* @param operatorSet the operator set to query
* @param operators the list of operators whose slashable stakes will be returned
* @param strategies the strategies that each slashable stake corresponds to
* @param futureBlock the block at which to get allocation information. Should be a future block.
* @return slashableStake a list of slashable stakes, indexed by [operator][strategy]
*/
function getMinimumSlashableStake(
OperatorSet memory operatorSet,
address[] memory operators,
IStrategy[] memory strategies,
uint32 futureBlock
) external view returns (uint256[][] memory slashableStake);
}
17 changes: 17 additions & 0 deletions src/test/mocks/DelegationManagerMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "forge-std/Test.sol";

import "src/contracts/interfaces/IDelegationManager.sol";
import "src/contracts/interfaces/IStrategyManager.sol";
import "src/contracts/libraries/SlashingLib.sol";

contract DelegationManagerMock is Test {
receive() external payable {}
Expand All @@ -24,11 +25,27 @@ contract DelegationManagerMock is Test {
isOperator[operator] = _isOperatorReturnValue;
}

function decreaseOperatorShares(address operator, IStrategy strategy, uint256 wadSlashed) external {
uint256 amountSlashed = SlashingLib.calcSlashedAmount({
operatorShares: operatorShares[operator][strategy],
wadSlashed: wadSlashed
});

operatorShares[operator][strategy] -= amountSlashed;
}

/// @notice returns the total number of shares in `strategy` that are delegated to `operator`.
function setOperatorShares(address operator, IStrategy strategy, uint256 shares) external {
operatorShares[operator][strategy] = shares;
}

/// @notice returns the total number of shares in `strategy` that are delegated to `operator`.
function setOperatorsShares(address operator, IStrategy[] memory strategies, uint256 shares) external {
for (uint i = 0; i < strategies.length; i++) {
operatorShares[operator][strategies[i]] = shares;
}
}

function delegateTo(address operator, ISignatureUtils.SignatureWithExpiry memory /*approverSignatureAndExpiry*/, bytes32 /*approverSalt*/) external {
delegatedTo[msg.sender] = operator;
}
Expand Down
Loading

0 comments on commit dd0293d

Please sign in to comment.