Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

eigenpods slashing updates #745

Merged
merged 3 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 51 additions & 38 deletions src/contracts/core/DelegationManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@
_;
}

modifier onlyEigenPodManager() {
require(msg.sender == address(eigenPodManager), OnlyEigenPodManager());
_;
}

/**
*
* INITIALIZING FUNCTIONS
Expand Down Expand Up @@ -283,7 +288,7 @@

// all shares and queued withdrawn and no delegated operator
// reset staker's depositScalingFactor to default
depositScalingFactors[staker][strategies[i]] = WAD;
stakerScalingFactors[staker][strategies[i]].depositScalingFactor = WAD;
}
}

Expand Down Expand Up @@ -400,37 +405,41 @@
}
}

// IGNORE THIS FUNCTION
/**
* @notice Decreases a staker's delegated delegatedShares for a strategy.
* @param staker The address to increase the delegated scaled shares for their operator.
* @param strategy The strategy in which to decrease the delegated scaled shares.
* @param removedOwnedShares The number of shares to decremented for the strategy in the
* StrategyManager/EigenPodManager
* @notice Decreases a native restaker's delegated share balance in a strategy due to beacon chain slashing. This updates their beaconChainScalingFactor.
* Their operator's stakeShares are also updated (if they are delegated).
* @param staker The address to increase the delegated stakeShares for their operator.
* @param existingShares The number of shares the staker already has in the EPM. This does not change upon decreasing shares.
* @param proportionOfOldBalance The current pod owner shares proportion of the previous pod owner shares
*
* @dev *If the staker is actively delegated*, then decreases the `staker`'s delegated delegatedShares in `strategy` by `scaledShares`. Otherwise does nothing.
* @dev Callable only by the StrategyManager or EigenPodManager.
* @dev *If the staker is actively delegated*, then decreases the `staker`'s delegated stakeShares in `strategy` by `proportionPodBalanceDecrease` proportion. Otherwise does nothing.
* @dev Callable only by the EigenPodManager.
*/
function decreaseDelegatedShares(
function decreaseBeaconChainScalingFactor(
address staker,
IStrategy strategy,
OwnedShares removedOwnedShares
) external onlyStrategyManagerOrEigenPodManager {
// if the staker is delegated to an operator
// if (isDelegated(staker)) {
// address operator = delegatedTo[staker];
Shares existingShares,
uint64 proportionOfOldBalance
) external onlyEigenPodManager {
DelegatedShares delegatedSharesBefore = existingShares.toDelegatedShares(stakerScalingFactors[staker][beaconChainETHStrategy]);

// uint64 totalMagnitude = allocationManager.getTotalMagnitude(operator, strategy);
// decrease the staker's beaconChainScalingFactor proportionally
// forgefmt: disable-next-item
stakerScalingFactors[staker][beaconChainETHStrategy].decreaseBeaconChainScalingFactor(proportionOfOldBalance);

// // subtract strategy shares from delegated scaled shares
// _decreaseOperatorScaledShares({
// operator: operator,
// staker: staker,
// strategy: strategy,
// shares: removedOwnedShares,
// totalMagnitude: totalMagnitude
// });
// }
DelegatedShares delegatedSharesAfter = existingShares.toDelegatedShares(stakerScalingFactors[staker][beaconChainETHStrategy]);

// if the staker is delegated to an operators
if (isDelegated(staker)) {
address operator = delegatedTo[staker];

// subtract strategy shares from delegated scaled shares
_decreaseDelegation({
operator: operator,
staker: staker,
strategy: beaconChainETHStrategy,
delegatedShares: delegatedSharesBefore.sub(delegatedSharesAfter)
});
}
}

/**
Expand Down Expand Up @@ -553,9 +562,11 @@

for (uint256 i = 0; i < withdrawal.strategies.length; i++) {
IShareManager shareManager = _getShareManager(withdrawal.strategies[i]);

// forgefmt: disable-next-line
OwnedShares ownedSharesToWithdraw = withdrawal.delegatedShares[i].toOwnedShares(totalMagnitudes[i]);
OwnedShares ownedSharesToWithdraw =
withdrawal.delegatedShares[i]
.scaleForCompleteWithdrawal(stakerScalingFactors[withdrawal.staker][withdrawal.strategies[i]])
.toOwnedShares(totalMagnitudes[i]);

if (receiveAsTokens) {
// Withdraws `shares` in `strategy` to `withdrawer`. If the shares are virtual beaconChainETH shares,
// then a call is ultimately forwarded to the `staker`s EigenPod; otherwise a call is ultimately forwarded
Expand Down Expand Up @@ -659,9 +670,9 @@
IShareManager shareManager = _getShareManager(strategies[i]);

// delegatedShares for staker to place into queueWithdrawal
delegatedSharesToWithdraw[i] = ownedSharesToWithdraw[i].toDelegatedShares(totalMagnitudes[i]);

Shares sharesToWithdraw = delegatedSharesToWithdraw[i].toShares(depositScalingFactors[staker][strategies[i]]);
DelegatedShares delegatedSharesToRemove = ownedSharesToWithdraw[i].toDelegatedShares(totalMagnitudes[i]);
// TODO: should this include beaconChainScalingFactor?
Shares sharesToWithdraw = delegatedSharesToRemove.toShares(stakerScalingFactors[staker][strategies[i]]);
// TODO: maybe have a getter to get shares for all strategies, like getDelegatableShares
// check sharesToWithdraw is valid
// but for inputted strategies
Expand All @@ -675,9 +686,10 @@
operator: operator,
staker: staker,
strategy: strategies[i],
delegatedShares: delegatedSharesToWithdraw[i]
delegatedShares: delegatedSharesToRemove
});
}
delegatedSharesToWithdraw[i] = delegatedSharesToRemove.scaleForQueueWithdrawal(stakerScalingFactors[staker][strategies[i]]);

// Remove active shares from EigenPodManager/StrategyManager
// EigenPodManager: this call will revert if it would reduce the Staker's virtual beacon chain ETH shares below zero
Expand Down Expand Up @@ -758,25 +770,26 @@
//
// newShares
// = newPrincipalShares.toDelegatedShares(stakerScalingFactors[staker][strategy).toOwnedShares(totalMagnitude)
// = newPrincipalShares * newDepositScalingFactor / WAD * totalMagnitude / WAD
// = (existingPrincipalShares + addedShares) * newDepositScalingFactor / WAD * totalMagnitude / WAD
// = newPrincipalShares * newDepositScalingFactor / WAD * beaonChainScalingFactor / WAD * totalMagnitude / WAD
// = (existingPrincipalShares + addedShares) * newDepositScalingFactor / WAD * beaonChainScalingFactor / WAD * totalMagnitude / WAD
//
// we can solve for
//
OwnedShares existingOwnedShares =
existingShares
.toDelegatedShares(depositScalingFactors[staker][strategy])
.toDelegatedShares(stakerScalingFactors[staker][strategy])
.toOwnedShares(totalMagnitude);
newDepositScalingFactor =
existingOwnedShares
.add(addedOwnedShares)
.unwrap()
.divWad(existingShares.unwrap() + addedOwnedShares.unwrap())
.divWad(stakerScalingFactors[staker][strategy].getBeaconChainScalingFactor())
.divWad(totalMagnitude);
}

// update the staker's depositScalingFactor
depositScalingFactors[staker][strategy] = newDepositScalingFactor;
stakerScalingFactors[staker][strategy].depositScalingFactor = newDepositScalingFactor;
}

function _getShareManager(
Expand Down Expand Up @@ -885,7 +898,7 @@

// forgefmt: disable-next-item
ownedShares[i] = shares
.toDelegatedShares(depositScalingFactors[staker][strategies[i]])
.toDelegatedShares(stakerScalingFactors[staker][strategies[i]])
.toOwnedShares(totalMagnitude);
}
}
Expand Down
10 changes: 7 additions & 3 deletions src/contracts/core/DelegationManagerStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,13 @@ abstract contract DelegationManagerStorage is IDelegationManager {
*/
mapping(IStrategy => uint256) private __deprecated_strategyWithdrawalDelayBlocks;

/// @notice Mapping: staker => strategy => scaling factor used to calculate the staker's shares in the strategy.
/// This is updated upon each deposit based on the staker's currently delegated operator's totalMagnitude.
mapping(address => mapping(IStrategy => uint256)) public depositScalingFactors;
/// @notice Mapping: staker => strategy =>
/// (
/// scaling factor used to calculate the staker's shares in the strategy,
/// beacon chain scaling factor used to calculate the staker's withdrawable shares in the strategy.
/// )
/// Note that we don't need the beaconChainScalingFactor for non beaconChainETHStrategy strategies, but it's nicer syntactically to keep it.
mapping(address => mapping(IStrategy => StakerScalingFactors)) public stakerScalingFactors;

constructor(
IStrategyManager _strategyManager,
Expand Down
26 changes: 15 additions & 11 deletions src/contracts/interfaces/IDelegationManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import "../libraries/SlashingLib.sol";
interface IDelegationManager is ISignatureUtils {
/// @dev Thrown when msg.sender is not allowed to call a function
error UnauthorizedCaller();
/// @dev Thrown when msg.sender is not the EigenPodManager
error OnlyEigenPodManager();

/// Delegation Status

Expand Down Expand Up @@ -362,19 +364,21 @@ interface IDelegationManager is ISignatureUtils {
OwnedShares addedOwnedShares
) external;

/**
* @notice Decreases a staker's delegated share balance in a strategy. Note that before removing from operator shares,
* the delegated shares are scaled according to the operator's total magnitude as part of slashing accounting. Unlike
* `increaseDelegatedShares`, the staker's depositScalingFactor is not updated here.
* @param staker The address to increase the delegated scaled shares for their operator.
* @param strategy The strategy in which to decrease the delegated scaled shares.
* @param removedOwnedShares The number of shares to decremented for the strategy in the
* StrategyManager/EigenPodManager
/**
* @notice Decreases a native restaker's delegated share balance in a strategy due to beacon chain slashing. This updates their beaconChainScalingFactor.
* Their operator's stakeShares are also updated (if they are delegated).
* @param staker The address to increase the delegated stakeShares for their operator.
* @param existingShares The number of shares the staker already has in the EPM. This does not change upon decreasing shares.
* @param proportionOfOldBalance The current pod owner shares proportion of the previous pod owner shares
*
* @dev *If the staker is actively delegated*, then decreases the `staker`'s delegated scaled shares in `strategy` by `scaledShares`. Otherwise does nothing.
* @dev Callable only by the StrategyManager or EigenPodManager.
* @dev *If the staker is actively delegated*, then decreases the `staker`'s delegated stakeShares in `strategy` by `proportionPodBalanceDecrease` proportion. Otherwise does nothing.
* @dev Callable only by the EigenPodManager.
*/
function decreaseDelegatedShares(address staker, IStrategy strategy, OwnedShares removedOwnedShares) external;
function decreaseBeaconChainScalingFactor(
address staker,
Shares existingShares,
uint64 proportionOfOldBalance
) external;

/**
* @notice returns the address of the operator that `staker` is delegated to.
Expand Down
17 changes: 14 additions & 3 deletions src/contracts/interfaces/IEigenPod.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
* to account balances in terms of gwei in the EigenPod contract and convert to wei when making calls to other contracts
*/
interface IEigenPod {
/// @dev Thrown when msg.sender is not allowed to call a function
error UnauthorizedCaller();
/// @dev Thrown when msg.sender is not the EPM.
error OnlyEigenPodManager();
/// @dev Thrown when msg.sender is not the pod owner.
error OnlyEigenPodOwner();
/// @dev Thrown when msg.sender is not owner or the proof submitter.
error OnlyEigenPodOwnerOrProofSubmitter();
/// @dev Thrown when attempting an action that is currently paused.
error CurrentlyPaused();

Expand Down Expand Up @@ -98,7 +102,14 @@ interface IEigenPod {
bytes32 beaconBlockRoot;
uint24 proofsRemaining;
uint64 podBalanceGwei;
int128 balanceDeltasGwei;
// this used to be an int128 before the slashing release
// now it is an int64. (2^63 - 1) gwei * 1e-9 eth/gwei = 9_223_372_036.85 eth = 9 billion eth
int64 balanceDeltasGwei;
uint64 beaconChainBalanceBeforeGwei;
}

struct ExtendedCheckpoint {
uint128 beaconChainBalanceBefore;
}

/**
Expand Down
10 changes: 9 additions & 1 deletion src/contracts/interfaces/IEigenPodManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ interface IEigenPodManager is IShareManager, IPausable {
error SharesNegative();
/// @dev Thrown when the strategy is not the beaconChainETH strategy.
error InvalidStrategy();
/// @dev Thrown when the pods shares are negative and a beacon chain balance update is attempted.
/// The podOwner should complete legacy withdrawal first.
error LegacyWithdrawalsNotCompleted();

/// @notice Emitted to notify the deployment of an EigenPod
event PodDeployed(address indexed eigenPod, address indexed podOwner);
Expand Down Expand Up @@ -72,10 +75,15 @@ interface IEigenPodManager is IShareManager, IPausable {
* to ensure that delegated shares are also tracked correctly
* @param podOwner is the pod owner whose balance is being updated.
* @param sharesDelta is the change in podOwner's beaconChainETHStrategy shares
* @param proportionPodBalanceDecrease is the proportion (of WAD) of the podOwner's balance that has changed
* @dev Callable only by the podOwner's EigenPod contract.
* @dev Reverts if `sharesDelta` is not a whole Gwei amount
*/
function recordBeaconChainETHBalanceUpdate(address podOwner, int256 sharesDelta) external;
function recordBeaconChainETHBalanceUpdate(
address podOwner,
int256 sharesDelta,
uint64 proportionPodBalanceDecrease
) external;

/// @notice Returns the address of the `podOwner`'s EigenPod if it has been deployed.
function ownerToPod(
Expand Down
Loading
Loading