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

feat: burn erc20s on slashing #881

Merged
merged 17 commits into from
Nov 20, 2024
Merged

feat: burn erc20s on slashing #881

merged 17 commits into from
Nov 20, 2024

Conversation

8sunyuan
Copy link
Collaborator

@8sunyuan 8sunyuan commented Nov 8, 2024

Synchronous Burning

One solution for burning slashed shares is to simply take the existing logic, take the sharesToDecrement in calcSlashedAmount and just burn that amount. But for all shares that were withdrawn and are still slashable for MIN_WITHDRAWAL_DELAY_BLOCKS, they would have to be slashed and burned when those withdrawals are completed.

Instead, completed withdrawals don't burn and we calculate all the shares to burn upon slashing. We burn synchronously all those slashabe shares in the queue by reading all the cumulative withdrawn shares from the time of slashing and MIN_WITHDRAWAL_DELAY_BLOCKS into the past. Here is where checkpointed values come into play again.

Changes:

  • Snapshots.sol: Added back OZ CheckpointsUpgradeable library for blocknumbers to the Snapshots library. The reasoning is because we want to keep track of cumulative queue withdrawn shares from an operator for a specific strategy and not using a default WAD value like we use for magnitudes.
  • DelegationManager.sol: renamed function decreaseAndBurnOperatorShares which will now read all the slashable shares queue withdrawn from an operator for a specific strategy, calculate amount of shares to burn, and call StrategyManager.burnShares.
  • StrategyManager.sol: burnShares function is exact same as the withdraw function but with the destination address being the DEFAULT_BURN_ADDRESS (address 0).
  • SlashingLib.sol: Changed calcSlashedAmount back to taking in as input prevMaxMagnitude and newMaxMagnitude because the way that burned shares are calculated with cumulative scaled shares.

Note: The call trace begins from ALM.slashOperator -> DM.decreaseAndBurnOperatorShares -> SM.burnShares -> Strategy.withdraw -> underlyingToken.transfer Each of these calls are permissioned by the core contracts in the protocol with the exception of slashOperator which is only callable by the AVS. We may want to additionally consider for a reentrancy guard on slashOperator as a result.

TODO:

  • Added unit and integration tests

@@ -26,6 +26,9 @@ abstract contract StrategyManagerStorage is IStrategyManager {
// index for flag that pauses deposits when set
uint8 internal constant PAUSED_DEPOSITS = 0;

/// @notice default address for burning slashed shares and transferring underlying tokens
address public constant DEFAULT_BURN_ADDRESS = address(0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we do some analysis on if this is ok for LSTs?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's for sure not, placeholder value for now. Personally a fan of 0xdeadbeef

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

91a806b
0xDeaDBeef

Copy link
Collaborator

@ypatil12 ypatil12 Nov 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should at least do 0x000000000000000000000000000000000000dEaD or address(0) since other protocols use that. Working with Matt Nelson to get feedback

Copy link
Collaborator

@ypatil12 ypatil12 Nov 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we cannot do address(0) given that stETH's contract uses this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0x E 1 6 E 4 (eigen)

* withdrawal snapshot is probably "recent", defined as being among the last sqrt(N) withdrawal snapshots where N is the number of
* withdrawal snapshots.
*/
function getAtProbablyRecentBlock(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just do upperLookup imo. is this any different?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the same logic but named more clearly for blocknumber usage. I can change this back though to be more consistent with DefaultWadHistory.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changing the name makes it clearer to me imo

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -685,6 +699,26 @@ contract DelegationManager is
_beaconChainSlashingFactor[staker] = bsf;
}

/// @dev Calculate amount of withdrawable shares from an operator for a strategy that is still in the queue
/// and therefore slashable.
function _getSlashableSharesInQueue(address operator, IStrategy strategy) internal view returns (uint256) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we expose a public view func for this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IStrategy strategy,
uint256 queueWithdrawnShares
) internal {
uint256 currCumulativeWithdrawalShares = uint256(_cumulativeWithdrawalsHistory[operator][strategy].latest());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this PR looks nice!

my main feedback is that we should store cumulative scaled shares queued for withdrawal, not shares.

Upon burning we should multiply the scaled shares in the withdrawal queue by the slashed magnitude. This would make it so that view functions for introspection into the withdrawal queue automatically update to reflect correct values after slashing

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

138eef7
Added, had to change calcSlashedAmount back to old interface but it is more consistent with the way scaledShares are also calculated.

Copy link

Reading tracefile ./lcov.info.pruned
                                        |Lines       |Functions  |Branches    
Filename                                  |Rate     Num|Rate    Num|Rate     Num
================================================================================
[src/contracts/]
core/AVSDirectory.sol                     | 100%     16| 100%     7|    -      0
core/AllocationManager.sol                |90.0%    229|89.2%    37|    -      0
core/DelegationManager.sol                |91.4%    222|87.8%    41|    -      0
core/RewardsCoordinator.sol               |94.3%    123|87.1%    31|    -      0
core/StrategyManager.sol                  |88.1%     67|82.6%    23|    -      0
libraries/BeaconChainProofs.sol           | 100%     22| 100%    11|    -      0
libraries/BytesLib.sol                    | 0.0%    156| 0.0%    14|    -      0
libraries/Endian.sol                      | 100%      2| 100%     1|    -      0
libraries/Merkle.sol                      | 100%     38| 100%     5|    -      0
libraries/OperatorSetLib.sol              | 100%      2| 100%     2|    -      0
libraries/SlashingLib.sol                 | 100%     19| 100%    10|    -      0
libraries/Snapshots.sol                   |76.3%     59|87.5%     8|    -      0
mixins/SignatureUtils.sol                 | 100%      7| 100%     5|    -      0
permissions/Pausable.sol                  |94.7%     19|90.0%    10|    -      0
permissions/PauserRegistry.sol            | 100%     12| 100%     6|    -      0
pods/EigenPod.sol                         | 100%    131|96.2%    26|    -      0
pods/EigenPodManager.sol                  | 100%     68|93.3%    15|    -      0
strategies/EigenStrategy.sol              | 0.0%     10| 0.0%     4|    -      0
strategies/StrategyBase.sol               |90.9%     44|78.9%    19|    -      0
strategies/StrategyBaseTVLLimits.sol      | 100%     12| 100%     5|    -      0
strategies/StrategyFactory.sol            | 100%     32| 100%     8|    -      0
token/BackingEigen.sol                    |83.3%     30|69.2%    13|    -      0
token/Eigen.sol                           |45.0%     40|61.5%    13|    -      0
================================================================================
                                  Total:|80.2%   1360|83.4%   314|    -      0

1 similar comment
Copy link

Reading tracefile ./lcov.info.pruned
                                        |Lines       |Functions  |Branches    
Filename                                  |Rate     Num|Rate    Num|Rate     Num
================================================================================
[src/contracts/]
core/AVSDirectory.sol                     | 100%     16| 100%     7|    -      0
core/AllocationManager.sol                |90.0%    229|89.2%    37|    -      0
core/DelegationManager.sol                |91.4%    222|87.8%    41|    -      0
core/RewardsCoordinator.sol               |94.3%    123|87.1%    31|    -      0
core/StrategyManager.sol                  |88.1%     67|82.6%    23|    -      0
libraries/BeaconChainProofs.sol           | 100%     22| 100%    11|    -      0
libraries/BytesLib.sol                    | 0.0%    156| 0.0%    14|    -      0
libraries/Endian.sol                      | 100%      2| 100%     1|    -      0
libraries/Merkle.sol                      | 100%     38| 100%     5|    -      0
libraries/OperatorSetLib.sol              | 100%      2| 100%     2|    -      0
libraries/SlashingLib.sol                 | 100%     19| 100%    10|    -      0
libraries/Snapshots.sol                   |76.3%     59|87.5%     8|    -      0
mixins/SignatureUtils.sol                 | 100%      7| 100%     5|    -      0
permissions/Pausable.sol                  |94.7%     19|90.0%    10|    -      0
permissions/PauserRegistry.sol            | 100%     12| 100%     6|    -      0
pods/EigenPod.sol                         | 100%    131|96.2%    26|    -      0
pods/EigenPodManager.sol                  | 100%     68|93.3%    15|    -      0
strategies/EigenStrategy.sol              | 0.0%     10| 0.0%     4|    -      0
strategies/StrategyBase.sol               |90.9%     44|78.9%    19|    -      0
strategies/StrategyBaseTVLLimits.sol      | 100%     12| 100%     5|    -      0
strategies/StrategyFactory.sol            | 100%     32| 100%     8|    -      0
token/BackingEigen.sol                    |83.3%     30|69.2%    13|    -      0
token/Eigen.sol                           |45.0%     40|61.5%    13|    -      0
================================================================================
                                  Total:|80.2%   1360|83.4%   314|    -      0

Base automatically changed from alex/dm-refactor to slashing-magnitudes November 14, 2024 16:03
Copy link

Reading tracefile ./lcov.info.pruned
                                        |Lines       |Functions  |Branches    
Filename                                  |Rate     Num|Rate    Num|Rate     Num
================================================================================
[src/contracts/]
core/AVSDirectory.sol                     | 100%     16| 100%     7|    -      0
core/AllocationManager.sol                |90.0%    229|89.2%    37|    -      0
core/DelegationManager.sol                |91.5%    223|87.8%    41|    -      0
core/RewardsCoordinator.sol               |94.3%    123|87.1%    31|    -      0
core/StrategyManager.sol                  |88.1%     67|82.6%    23|    -      0
libraries/BeaconChainProofs.sol           | 100%     22| 100%    11|    -      0
libraries/BytesLib.sol                    | 0.0%    156| 0.0%    14|    -      0
libraries/Endian.sol                      | 100%      2| 100%     1|    -      0
libraries/Merkle.sol                      | 100%     38| 100%     5|    -      0
libraries/OperatorSetLib.sol              | 100%      2| 100%     2|    -      0
libraries/SlashingLib.sol                 | 100%     19| 100%    10|    -      0
libraries/Snapshots.sol                   |76.3%     59|87.5%     8|    -      0
mixins/SignatureUtils.sol                 | 100%      7| 100%     5|    -      0
permissions/Pausable.sol                  |94.7%     19|90.0%    10|    -      0
permissions/PauserRegistry.sol            | 100%     12| 100%     6|    -      0
pods/EigenPod.sol                         | 100%    131|96.2%    26|    -      0
pods/EigenPodManager.sol                  | 100%     68|93.3%    15|    -      0
strategies/EigenStrategy.sol              | 0.0%     10| 0.0%     4|    -      0
strategies/StrategyBase.sol               |90.9%     44|78.9%    19|    -      0
strategies/StrategyBaseTVLLimits.sol      | 100%     12| 100%     5|    -      0
strategies/StrategyFactory.sol            | 100%     32| 100%     8|    -      0
token/BackingEigen.sol                    |83.3%     30|69.2%    13|    -      0
token/Eigen.sol                           |45.0%     40|61.5%    13|    -      0
================================================================================
                                  Total:|80.2%   1361|83.4%   314|    -      0


/// @dev Update the cumulative withdrawn scaled shares from an operator for a given strategy
function _updateCumulativeScaledShares(address operator, IStrategy strategy, uint256 scaledShares) internal {
if (strategy != beaconChainETHStrategy) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would beacon chain stuff also not be added?

Do we add it to this array eventually when we have burning for native ETH?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At minimum, in the burnOperatorShares method we wouldn't be able to use these cumulative scaled shares to efficiently burn beaconChain shares in a callback like the one we make to the StrategyManager.
However, the scaled shares does take into account slashing factors and therefore the bcsf. We could potentially store this value as well?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO let's make this call in a separate PR once we have a better idea of the direction we want to take for beacon chain eth

Copy link

Reading tracefile ./lcov.info.pruned
                                        |Lines       |Functions  |Branches    
Filename                                  |Rate     Num|Rate    Num|Rate     Num
================================================================================
[src/contracts/]
core/AVSDirectory.sol                     | 100%     16| 100%     7|    -      0
core/AllocationManager.sol                |96.3%    245|97.4%    39|    -      0
core/DelegationManager.sol                |94.4%    216|90.0%    40|    -      0
core/RewardsCoordinator.sol               |94.3%    123|87.1%    31|    -      0
core/StrategyManager.sol                  |91.0%     67|86.4%    22|    -      0
libraries/BeaconChainProofs.sol           | 100%     22| 100%    11|    -      0
libraries/BytesLib.sol                    | 0.0%    156| 0.0%    14|    -      0
libraries/Endian.sol                      | 100%      2| 100%     1|    -      0
libraries/Merkle.sol                      | 100%     38| 100%     5|    -      0
libraries/OperatorSetLib.sol              | 100%      2| 100%     2|    -      0
libraries/SlashingLib.sol                 | 100%     17| 100%     9|    -      0
libraries/Snapshots.sol                   |88.0%     25|85.7%     7|    -      0
mixins/SignatureUtils.sol                 | 100%      7| 100%     5|    -      0
permissions/Pausable.sol                  |94.7%     19|90.0%    10|    -      0
permissions/PauserRegistry.sol            | 100%     12| 100%     6|    -      0
pods/EigenPod.sol                         | 100%    131|96.2%    26|    -      0
pods/EigenPodManager.sol                  | 100%     70|93.3%    15|    -      0
strategies/EigenStrategy.sol              | 0.0%     10| 0.0%     4|    -      0
strategies/StrategyBase.sol               |90.9%     44|78.9%    19|    -      0
strategies/StrategyBaseTVLLimits.sol      | 100%     12| 100%     5|    -      0
strategies/StrategyFactory.sol            | 100%     32| 100%     8|    -      0
token/BackingEigen.sol                    |83.3%     30|69.2%    13|    -      0
token/Eigen.sol                           |45.0%     40|61.5%    13|    -      0
================================================================================
                                  Total:|82.4%   1336|84.9%   312|    -      0

src/test/unit/DelegationUnit.t.sol Outdated Show resolved Hide resolved
src/test/unit/DelegationUnit.t.sol Show resolved Hide resolved
src/test/unit/StrategyManagerUnit.t.sol Outdated Show resolved Hide resolved
src/test/unit/DelegationUnit.t.sol Outdated Show resolved Hide resolved
8sunyuan and others added 4 commits November 19, 2024 13:09
* refactor: remove unused return values from _insert
* also removes safe cast
* refactor: pull unrelated operations out and condense library method usage
@8sunyuan 8sunyuan merged commit eed61f2 into slashing-magnitudes Nov 20, 2024
7 of 11 checks passed
@8sunyuan 8sunyuan deleted the burn-erc20s branch November 20, 2024 02:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants