Skip to content

Commit

Permalink
feat: share lib cleanup (#778)
Browse files Browse the repository at this point in the history
* refactor: review changes

* chore: forge fmt src/contracts

* refactor: more explicit share names

* rename share

* fmt

---------

Co-authored-by: gpsanant <[email protected]>
  • Loading branch information
0xClandestine and gpsanant committed Sep 20, 2024
1 parent 4a7de6b commit eb66c86
Show file tree
Hide file tree
Showing 12 changed files with 195 additions and 205 deletions.
17 changes: 8 additions & 9 deletions src/contracts/core/AllocationManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -427,9 +427,9 @@ contract AllocationManager is
function _getLatestTotalMagnitude(address operator, IStrategy strategy) internal returns (uint64) {
(bool exists,, uint224 totalMagnitude) = _totalMagnitudeUpdate[operator][strategy].latestSnapshot();
if (!exists) {
totalMagnitude = PRECISION_FACTOR;
totalMagnitude = WAD;
_totalMagnitudeUpdate[operator][strategy].push({key: uint32(block.timestamp), value: totalMagnitude});
operatorMagnitudeInfo[operator][strategy].freeMagnitude = PRECISION_FACTOR;
operatorMagnitudeInfo[operator][strategy].freeMagnitude = WAD;
}

return uint64(totalMagnitude);
Expand Down Expand Up @@ -623,7 +623,7 @@ contract AllocationManager is
for (uint256 i = 0; i < strategies.length; ++i) {
(bool exists,, uint224 value) = _totalMagnitudeUpdate[operator][strategies[i]].latestSnapshot();
if (!exists) {
totalMagnitudes[i] = PRECISION_FACTOR;
totalMagnitudes[i] = WAD;
} else {
totalMagnitudes[i] = uint64(value);
}
Expand All @@ -645,11 +645,10 @@ contract AllocationManager is
) external view returns (uint64[] memory) {
uint64[] memory totalMagnitudes = new uint64[](strategies.length);
for (uint256 i = 0; i < strategies.length; ++i) {
(uint224 value, uint256 pos) =
_totalMagnitudeUpdate[operator][strategies[i]].upperLookupWithPos(timestamp);
(uint224 value, uint256 pos) = _totalMagnitudeUpdate[operator][strategies[i]].upperLookupWithPos(timestamp);
// if there is no existing total magnitude snapshot
if (value == 0 && pos == 0) {
totalMagnitudes[i] = PRECISION_FACTOR;
totalMagnitudes[i] = WAD;
} else {
totalMagnitudes[i] = uint64(value);
}
Expand All @@ -667,7 +666,7 @@ contract AllocationManager is
uint64 totalMagnitude;
(bool exists,, uint224 value) = _totalMagnitudeUpdate[operator][strategy].latestSnapshot();
if (!exists) {
totalMagnitude = PRECISION_FACTOR;
totalMagnitude = WAD;
} else {
totalMagnitude = uint64(value);
}
Expand All @@ -687,12 +686,12 @@ contract AllocationManager is
IStrategy strategy,
uint32 timestamp
) external view returns (uint64) {
uint64 totalMagnitude = PRECISION_FACTOR;
uint64 totalMagnitude = WAD;
(uint224 value, uint256 pos,) = _totalMagnitudeUpdate[operator][strategy].upperLookupRecentWithPos(timestamp);

// if there is no existing total magnitude snapshot
if (value == 0 && pos == 0) {
totalMagnitude = PRECISION_FACTOR;
totalMagnitude = WAD;
} else {
totalMagnitude = uint64(value);
}
Expand Down
194 changes: 94 additions & 100 deletions src/contracts/core/DelegationManager.sol

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions src/contracts/core/DelegationManagerStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ abstract contract DelegationManagerStorage is IDelegationManager {

/// @notice The AVSDirectory contract for EigenLayer
IAVSDirectory public immutable avsDirectory;

// TODO: Switch these to ShareManagers, but this breaks a lot of tests

/// @notice The StrategyManager contract for EigenLayer
Expand All @@ -56,15 +56,15 @@ abstract contract DelegationManagerStorage is IDelegationManager {
IAllocationManager public immutable allocationManager;

/**
* @notice returns the total number of stakeShares (i.e. shares divided by the `operator`'s
* @notice returns the total number of delegatedShares (i.e. shares divided by the `operator`'s
* totalMagnitude) in `strategy` that are delegated to `operator`.
* @notice Mapping: operator => strategy => total number of stakeShares in the strategy delegated to the operator.
* @notice Mapping: operator => strategy => total number of delegatedShares in the strategy delegated to the operator.
* @dev By design, the following invariant should hold for each Strategy:
* (operator's stakeShares in delegation manager) = sum (stakeShares above zero of all stakers delegated to operator)
* = sum (delegateable stakeShares of all stakers delegated to the operator)
* (operator's delegatedShares in delegation manager) = sum (delegatedShares above zero of all stakers delegated to operator)
* = sum (delegateable delegatedShares of all stakers delegated to the operator)
* @dev FKA `operatorShares`
*/
mapping(address => mapping(IStrategy => uint256)) public operatorStakeShares;
mapping(address => mapping(IStrategy => uint256)) public operatorDelegatedShares;

/**
* @notice Mapping: operator => OperatorDetails struct
Expand Down
4 changes: 2 additions & 2 deletions src/contracts/core/StrategyManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -253,14 +253,14 @@ contract StrategyManager is
}

// add the returned shares to their existing shares for this strategy
uint256 existingDepositShares = stakerStrategyShares[staker][strategy];
uint256 existingPrincipalShares = stakerStrategyShares[staker][strategy];
stakerStrategyShares[staker][strategy] += shares;

// Increase shares delegated to operator, if needed
delegation.increaseDelegatedShares({
staker: staker,
strategy: strategy,
existingDepositShares: existingDepositShares,
existingPrincipalShares: existingPrincipalShares,
addedShares: shares
});

Expand Down
18 changes: 9 additions & 9 deletions src/contracts/interfaces/IDelegationManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ interface IDelegationManager is ISignatureUtils {
uint32 startTimestamp;
// Array of strategies that the Withdrawal contains
IStrategy[] strategies;
// Array containing the amount of staker's stakeShares for withdrawal in each Strategy in the `strategies` array
// Array containing the amount of staker's delegatedShares for withdrawal in each Strategy in the `strategies` array
// Note that these shares need to be multiplied by the operator's totalMagnitude at completion to include
// slashing occurring during the queue withdrawal delay
StakeShares[] stakeShares;
DelegatedShares[] delegatedShares;
}

struct QueuedWithdrawalParams {
Expand Down Expand Up @@ -321,7 +321,7 @@ interface IDelegationManager is ISignatureUtils {
* The staker's depositScalingFactor is updated here.
* @param staker The address to increase the delegated shares for their operator.
* @param strategy The strategy in which to increase the delegated shares.
* @param existingDepositShares The number of deposit shares the staker already has in the strategy. This is the shares amount stored in the
* @param existingPrincipalShares The number of deposit shares the staker already has in the strategy. This is the shares amount stored in the
* StrategyManager/EigenPodManager for the staker's shares.
* @param addedShares The number of shares to added to the staker's shares in the strategy. This amount will be scaled prior to adding
* to the operator's scaled shares.
Expand All @@ -333,7 +333,7 @@ interface IDelegationManager is ISignatureUtils {
function increaseDelegatedShares(
address staker,
IStrategy strategy,
uint256 existingDepositShares,
uint256 existingPrincipalShares,
uint256 addedShares
) external;

Expand Down Expand Up @@ -382,15 +382,15 @@ interface IDelegationManager is ISignatureUtils {
) external view returns (uint256);

/**
* @notice returns the total number of stakeShares (i.e. shares divided by the `operator`'s
* @notice returns the total number of delegatedShares (i.e. shares divided by the `operator`'s
* totalMagnitude) in `strategy` that are delegated to `operator`.
* @notice Mapping: operator => strategy => total number of stakeShares in the strategy delegated to the operator.
* @notice Mapping: operator => strategy => total number of delegatedShares in the strategy delegated to the operator.
* @dev By design, the following invariant should hold for each Strategy:
* (operator's stakeShares in delegation manager) = sum (stakeShares above zero of all stakers delegated to operator)
* = sum (delegateable stakeShares of all stakers delegated to the operator)
* (operator's delegatedShares in delegation manager) = sum (delegatedShares above zero of all stakers delegated to operator)
* = sum (delegateable delegatedShares of all stakers delegated to the operator)
* @dev FKA `operatorShares`
*/
function operatorStakeShares(address operator, IStrategy strategy) external view returns (uint256);
function operatorDelegatedShares(address operator, IStrategy strategy) external view returns (uint256);

/**
* @notice Returns 'true' if `staker` *is* actively delegated, and 'false' otherwise.
Expand Down
2 changes: 1 addition & 1 deletion src/contracts/interfaces/IEigenPodManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,4 @@ interface IEigenPodManager is IShareManager, IPausable {

/// @notice returns canonical, virtual beaconChainETH strategy
function beaconChainETHStrategy() external view returns (IStrategy);
}
}
2 changes: 1 addition & 1 deletion src/contracts/interfaces/IShareManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ interface IShareManager {
/// @dev strategy must be beaconChainETH when talking to the EigenPodManager
/// @dev returns 0 if the user has negative shares
function stakerStrategyShares(address user, IStrategy strategy) external view returns (uint256 shares);
}
}
112 changes: 49 additions & 63 deletions src/contracts/libraries/SlashingLib.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;

import "@openzeppelin/contracts/utils/math/Math.sol";

/// @dev the stakerScalingFactor and totalMagnitude have initial default values to 1e18 as "1"
/// to preserve precision with uint256 math. We use `PRECISION_FACTOR` where these variables are used
/// to preserve precision with uint256 math. We use `WAD` where these variables are used
/// and divide to represent as 1
uint64 constant PRECISION_FACTOR = 1e18;
uint64 constant WAD = 1e18;

/// @dev Delay before deallocations are completable and can be added back into freeMagnitude
/// This is also the same delay for withdrawals to be completable
Expand All @@ -19,95 +21,79 @@ uint32 constant DEALLOCATION_DELAY = 17.5 days;
* - These are comparable between operators and stakers.
* - These live in the storage of StrategyManager strategies:
* - `totalShares` is the total amount of shares delegated to a strategy
* 2. stakeShares
* 2. delegatedShares
* - These can be converted to shares given an operator and a strategy
* - by multiplying by the operator's totalMagnitude for the strategy
* - These values automatically update their conversion into tokens
* - when the operator's total magnitude for the strategy is decreased upon slashing
* - These live in the storage of the DelegationManager:
* - `stakeShares` is the total amount of stakeShares delegated to an operator for a strategy
* - `withdrawal.stakeShares` is the amount of stakeShares in a withdrawal
* 3. depositShares
* - These can be converted into stakeShares given a staker and a strategy
* - `delegatedShares` is the total amount of delegatedShares delegated to an operator for a strategy
* - `withdrawal.delegatedShares` is the amount of delegatedShares in a withdrawal
* 3. principalShares
* - These can be converted into delegatedShares given a staker and a strategy
* - by multiplying by the staker's depositScalingFactor for the strategy
* - These values automatically update their conversion into tokens
* - when the staker's depositScalingFactor for the strategy is increased upon new deposits
* - or when the staker's operator's total magnitude for the strategy is decreased upon slashing
* - These represent the total amount of shares the staker would have of a strategy if they were never slashed
* - These live in the storage of the StrategyManager/EigenPodManager
* - `stakerStrategyShares` in the SM is the staker's depositShares that have not been queued for withdrawal in a strategy
* - `podOwnerShares` in the EPM is the staker's depositShares that have not been queued for withdrawal in the beaconChainETHStrategy
* - `stakerStrategyShares` in the SM is the staker's principalShares that have not been queued for withdrawal in a strategy
* - `podOwnerShares` in the EPM is the staker's principalShares that have not been queued for withdrawal in the beaconChainETHStrategy
*/
struct StakeShares {
uint256 stakeShares;
}

struct DepositShares {
uint256 depositShares;
}
type Shares is uint256;

struct Shares {
uint256 shares;
}
type DelegatedShares is uint256;

library SlashingLib {
function createShares(uint256 shares) internal pure returns (Shares memory) {
return Shares({
shares: shares
});
}
type PrincipalShares is uint256;

function toUint256(Shares memory shares) internal pure returns (uint256) {
return shares.shares;
}
using SlashingLib for Shares global;
using SlashingLib for DelegatedShares global;
using SlashingLib for PrincipalShares global;

function createStakeShares(uint256 stakeShares) internal pure returns (StakeShares memory) {
return StakeShares({
stakeShares: stakeShares
});
}
library SlashingLib {
using Math for uint256;
using SlashingLib for uint256;

function toUint256(StakeShares memory stakeShares) internal pure returns (uint256) {
return stakeShares.stakeShares;
function toPrincipalShares(
DelegatedShares delegatedShares,
uint256 depositScalingFactor
) internal pure returns (PrincipalShares) {
if (depositScalingFactor == 0) {
depositScalingFactor = WAD;
}
return PrincipalShares.wrap(DelegatedShares.unwrap(delegatedShares).divWad(depositScalingFactor));
}

function createDepositShares(uint256 depositShares) internal pure returns (DepositShares memory) {
return DepositShares({
depositShares: depositShares
});
function toDelegatedShares(
PrincipalShares principalShares,
uint256 depositScalingFactor
) internal pure returns (DelegatedShares) {
if (depositScalingFactor == 0) {
depositScalingFactor = WAD;
}
return DelegatedShares.wrap(PrincipalShares.unwrap(principalShares).mulWad(depositScalingFactor));
}

function toUint256(DepositShares memory depositShares) internal pure returns (uint256) {
return depositShares.depositShares;
function toShares(DelegatedShares delegatedShares, uint256 magnitude) internal pure returns (Shares) {
return Shares.wrap(DelegatedShares.unwrap(delegatedShares).mulWad(magnitude));
}

function toStakeShares(Shares memory shares, uint256 magnitude) internal pure returns (StakeShares memory) {
return StakeShares({
stakeShares: shares.shares * PRECISION_FACTOR / magnitude
});
function toPrincipalShares(Shares shares, uint256 magnitude) internal pure returns (DelegatedShares) {
return DelegatedShares.wrap(Shares.unwrap(shares).divWad(magnitude));
}

function toDepositShares(StakeShares memory stakeShares, uint256 depositScalingFactor) internal pure returns (DepositShares memory) {
if (depositScalingFactor == 0) {
depositScalingFactor = PRECISION_FACTOR;
}
return DepositShares({
depositShares: stakeShares.stakeShares * PRECISION_FACTOR / depositScalingFactor
});
function toDelegatedShares(Shares shares, uint256 magnitude) internal pure returns (DelegatedShares) {
return DelegatedShares.wrap(Shares.unwrap(shares).divWad(magnitude));
}

function toStakeShares(DepositShares memory depositShares, uint256 depositScalingFactor) internal pure returns (StakeShares memory) {
if (depositScalingFactor == 0) {
depositScalingFactor = PRECISION_FACTOR;
}
return StakeShares({
stakeShares: depositShares.depositShares * depositScalingFactor / PRECISION_FACTOR
});
// WAD MATH

function mulWad(uint256 a, uint256 b) internal pure returns (uint256) {
return a.mulDiv(b, WAD);
}

function toShares(StakeShares memory stakeShares, uint256 magnitude) internal pure returns (Shares memory) {
return Shares({
shares: stakeShares.stakeShares * magnitude / PRECISION_FACTOR
});
function divWad(uint256 a, uint256 b) internal pure returns (uint256) {
return a.mulDiv(WAD, b);
}
}
}
24 changes: 10 additions & 14 deletions src/contracts/pods/EigenPodManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ contract EigenPodManager is
staker: podOwner,
strategy: beaconChainETHStrategy,
// existing shares from standpoint of the DelegationManager
existingDepositShares: currentPodOwnerShares < 0 ? 0 : uint256(currentPodOwnerShares),
existingPrincipalShares: currentPodOwnerShares < 0 ? 0 : uint256(currentPodOwnerShares),
addedShares: uint256(changeInDelegatableShares)
});
}
Expand Down Expand Up @@ -168,11 +168,11 @@ contract EigenPodManager is
* @dev Reverts if `shares` is not a whole Gwei amount
*/
function addShares(
address staker,
IERC20 token,
IStrategy strategy,
address staker,
IERC20 token,
IStrategy strategy,
uint256 shares
) external onlyDelegationManager {
) external onlyDelegationManager {
require(strategy == beaconChainETHStrategy, InvalidStrategy());
require(staker != address(0), InputAddressZero());
require(int256(shares) >= 0, SharesNegative());
Expand All @@ -184,12 +184,8 @@ contract EigenPodManager is
emit PodSharesUpdated(staker, int256(shares));
emit NewTotalShares(staker, updatedShares);

uint256 increaseInDelegateableShares = uint256(
_calculateChangeInDelegatableShares({
sharesBefore: currentShares,
sharesAfter: updatedShares
})
);
uint256 increaseInDelegateableShares =
uint256(_calculateChangeInDelegatableShares({sharesBefore: currentShares, sharesAfter: updatedShares}));

// TODO: ADD SHARES BACK TO DM
}
Expand All @@ -202,9 +198,9 @@ contract EigenPodManager is
* we do not need to update the podOwnerShares if `currentPodOwnerShares` is positive
*/
function withdrawSharesAsTokens(
address recipient,
IStrategy strategy,
uint256 shares,
address recipient,
IStrategy strategy,
uint256 shares,
IERC20
) external onlyDelegationManager {
require(strategy == beaconChainETHStrategy, InvalidStrategy());
Expand Down
3 changes: 3 additions & 0 deletions src/test/mocks/DelegationManagerMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ contract DelegationManagerMock is IDelegationManager, Test {
mapping(address => bool) public isOperator;
mapping(address => mapping(IStrategy => uint256)) public operatorShares;


function operatorDelegatedShares(address operator, IStrategy strategy) external view returns (uint256) {}

function setIsOperator(address operator, bool _isOperatorReturnValue) external {
isOperator[operator] = _isOperatorReturnValue;
}
Expand Down
Loading

0 comments on commit eb66c86

Please sign in to comment.