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: AllocationManager Storage Simplification #787

Merged
merged 8 commits into from
Oct 1, 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
1 change: 1 addition & 0 deletions lib/openzeppelin-contracts
Submodule openzeppelin-contracts added at 3b8b4b
1 change: 1 addition & 0 deletions lib/openzeppelin-contracts-upgradeable
Submodule openzeppelin-contracts-upgradeable added at 6b9807
381 changes: 144 additions & 237 deletions src/contracts/core/AllocationManager.sol

Large diffs are not rendered by default.

15 changes: 6 additions & 9 deletions src/contracts/core/AllocationManagerStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,14 @@ abstract contract AllocationManagerStorage is IAllocationManager {
/// Note that totalMagnitude is monotonically decreasing and only gets updated upon slashing
mapping(address => mapping(IStrategy => Snapshots.History)) internal _totalMagnitudeUpdate;

/// @notice Mapping: operator => strategy => operatorSet (encoded) => snapshotted magnitude
mapping(address => mapping(IStrategy => mapping(bytes32 => Snapshots.History))) internal _magnitudeUpdate;

/// @notice Mapping: operator => strategy => OperatorMagnitudeInfo to keep track of info regarding pending magnitude allocations.
mapping(address => mapping(IStrategy => OperatorMagnitudeInfo)) public operatorMagnitudeInfo;
mapping(address => mapping(IStrategy => FreeMagnitudeInfo)) public operatorFreeMagnitudeInfo;

/// @notice Mapping: operator => strategy => PendingFreeMagnitude[] to keep track of pending free magnitude from deallocations
mapping(address => mapping(IStrategy => PendingFreeMagnitude[])) internal _pendingFreeMagnitude;
/// @notice Mapping: operator => strategy => operatorSet (encoded) => MagnitudeInfo
mapping(address => mapping(IStrategy => mapping(bytes32 => MagnitudeInfo))) internal _operatorMagnitudeInfo;

/// @notice Mapping: operator => strategy => operatorSet (encoded) => list of queuedDeallocation indices
mapping(address => mapping(IStrategy => mapping(bytes32 => uint256[]))) internal _queuedDeallocationIndices;
/// @notice Mapping: operator => strategy => operatorSet[] (encoded) to keep track of pending free magnitude for operatorSet from deallocations
mapping(address => mapping(IStrategy => bytes32[])) internal _pendingDeallocationOperatorSets;

/// @notice Mapping: operator => allocation delay (in seconds) for the operator.
/// This determines how long it takes for allocations to take effect in the future.
Expand All @@ -78,5 +75,5 @@ abstract contract AllocationManagerStorage is IAllocationManager {
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[42] private __gap;
uint256[44] private __gap;
}
31 changes: 22 additions & 9 deletions src/contracts/interfaces/IAllocationManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ interface IAllocationManager is ISignatureUtils {
/// @dev Thrown when an operator attempts to set their allocation for an operatorSet to the same value
error SameMagnitude();
/// @dev Thrown when an allocation is attempted for a given operator when they have pending allocations or deallocations.
error PendingAllocationOrDeallocation();
error ModificationAlreadyPending();
/// @dev Thrown when an allocation is attempted that exceeds a given operators total allocatable magnitude.
error InsufficientAllocatableMagnitude();
/// @dev Thrown when attempting to use an expired eip-712 signature.
Expand Down Expand Up @@ -53,18 +53,30 @@ interface IAllocationManager is ISignatureUtils {
* @param magnitudeDiff the amount of magnitude to deallocate
* @param completableTimestamp the timestamp at which the deallocation can be completed, 21 days from when queued
*/
struct PendingFreeMagnitude {
uint64 magnitudeDiff;
uint32 completableTimestamp;
// struct PendingFreeMagnitude {
// uint64 magnitudeDiff;
// uint32 completableTimestamp;
// }

/**
* @notice struct used for operator magnitude updates. Stored in _operatorMagnitudeInfo mapping
* @param currentMagnitude the current magnitude of the operator
* @param pendingMagnitudeIdff the pending magnitude difference of the operator
* @param effectTimestamp the timestamp at which the pending magnitude will take effect
*/
struct MagnitudeInfo {
int128 pendingMagnitudeDiff;
uint64 currentMagnitude;
uint32 effectTimestamp;
}

/**
* @notice Struct containing info regarding free allocatable magnitude.
* @param nextPendingFreeMagnitudeIndex The next available update index.
* @param nextPendingIndex The next available update index.
* @param freeMagnitude The total amount of free allocatable magnitude.
*/
struct OperatorMagnitudeInfo {
uint192 nextPendingFreeMagnitudeIndex;
struct FreeMagnitudeInfo {
uint192 nextPendingIndex;
uint64 freeMagnitude;
}

Expand Down Expand Up @@ -239,13 +251,14 @@ interface IAllocationManager is ISignatureUtils {
* @param operator the operator to get the pending deallocations for
* @param strategy the strategy to get the pending deallocations for
* @param operatorSets the operatorSets to get the pending deallocations for
* @return pendingMagnitudes the latest pending deallocation
* @return pendingMagnitudeDiffs the pending deallocation diffs for each operatorSet
* @return timestamps the timestamps for each pending dealloction
*/
function getPendingDeallocations(
address operator,
IStrategy strategy,
OperatorSet[] calldata operatorSets
) external view returns (PendingFreeMagnitude[] memory);
) external view returns (uint64[] memory, uint32[] memory);

/**
* @notice operator is slashable by operatorSet if currently registered OR last deregistered within 21 days
Expand Down
30 changes: 15 additions & 15 deletions src/test/events/IRewardsCoordinatorEvents.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ interface IRewardsCoordinatorEvents {
);
event ActivationDelaySet(uint32 oldActivationDelay, uint32 newActivationDelay);
event GlobalCommissionBipsSet(uint16 oldGlobalCommissionBips, uint16 newGlobalCommissionBips);
/// @notice emitted when an operator commission is set for a specific OperatorSet
event OperatorCommissionUpdated(
address indexed operator,
OperatorSet indexed operatorSet,
IRewardsCoordinator.RewardType rewardType,
uint16 newCommissionBips,
uint32 effectTimestamp
);
// /// @notice emitted when an operator commission is set for a specific OperatorSet
// event OperatorCommissionUpdated(
// address indexed operator,
// OperatorSet indexed operatorSet,
// IRewardsCoordinator.RewardType rewardType,
// uint16 newCommissionBips,
// uint32 effectTimestamp
// );
event ClaimerForSet(address indexed earner, address indexed oldClaimer, address indexed claimer);
/// @notice rootIndex is the specific array index of the newly created root in the storage array
event DistributionRootSubmitted(
Expand All @@ -62,13 +62,13 @@ interface IRewardsCoordinatorEvents {
IERC20 token,
uint256 claimedAmount
);
/// @notice emitted when an AVS creates a valid OperatorSetRewardsSubmission
event OperatorSetRewardCreated(
address indexed avs,
uint256 indexed submissionNonce,
bytes32 indexed rewardsSubmissionHash,
IRewardsCoordinator.OperatorSetRewardsSubmission rewardsSubmission
);
// /// @notice emitted when an AVS creates a valid OperatorSetRewardsSubmission
// event OperatorSetRewardCreated(
// address indexed avs,
// uint256 indexed submissionNonce,
// bytes32 indexed rewardsSubmissionHash,
// IRewardsCoordinator.OperatorSetRewardsSubmission rewardsSubmission
// );



Expand Down
4 changes: 2 additions & 2 deletions src/test/mocks/DelegationManagerMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ contract DelegationManagerMock is IDelegationManager, Test {
IStrategy strategy,
OwnedShares shares
) external {
strategyManager.addShares(staker, token, strategy, shares);
strategyManager.addOwnedShares(staker, strategy, token, shares);
}

function removeShares(
Expand All @@ -198,6 +198,6 @@ contract DelegationManagerMock is IDelegationManager, Test {
OwnedShares shares,
IERC20 token
) external {
strategyManager.withdrawSharesAsTokens(recipient, strategy, shares, token);
strategyManager.withdrawSharesAsTokens(recipient, strategy, token, shares);
}
}
4 changes: 2 additions & 2 deletions src/test/mocks/EigenPodManagerMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ contract EigenPodManagerMock is IEigenPodManager, Test, Pausable {

function removeShares(address staker, IStrategy strategy, Shares shares) external {}

function addShares(address staker, IERC20 token, IStrategy strategy, OwnedShares shares) external {}
function addOwnedShares(address staker, IStrategy strategy, IERC20 token, OwnedShares shares) external {}

function withdrawSharesAsTokens(address recipient, IStrategy strategy, OwnedShares shares, IERC20 token) external {}
function withdrawSharesAsTokens(address recipient, IStrategy strategy, IERC20 token, OwnedShares shares) external {}

function stakerStrategyShares(address user, IStrategy strategy) external view returns (Shares shares) {}

Expand Down
4 changes: 2 additions & 2 deletions src/test/mocks/StrategyManagerMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,9 @@ contract StrategyManagerMock is

function removeShares(address staker, IStrategy strategy, Shares shares) external {}

function addShares(address staker, IERC20 token, IStrategy strategy, OwnedShares shares) external {}
function addOwnedShares(address staker, IStrategy strategy, IERC20 token, OwnedShares shares) external {}

function withdrawSharesAsTokens(address recipient, IStrategy strategy, OwnedShares shares, IERC20 token) external {}
function withdrawSharesAsTokens(address recipient, IStrategy strategy, IERC20 token, OwnedShares shares) external {}

/// @notice returns the enshrined beaconChainETH Strategy
function beaconChainETHStrategy() external view returns (IStrategy) {}
Expand Down
16 changes: 8 additions & 8 deletions src/test/unit/EigenPodManagerUnit.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -194,28 +194,28 @@ contract EigenPodManagerUnitTests_ShareUpdateTests is EigenPodManagerUnitTests {
cheats.assume(notDelegationManager != address(delegationManagerMock));
cheats.prank(notDelegationManager);
cheats.expectRevert("EigenPodManager.onlyDelegationManager: not the DelegationManager");
eigenPodManager.addShares(defaultStaker, 0);
eigenPodManager.addOwnedShares(defaultStaker, 0);
}

function test_addShares_revert_podOwnerInputAddressZero() public {
cheats.prank(address(delegationManagerMock));
cheats.expectRevert("EigenPodManager.addShares: podOwner cannot be zero address");
eigenPodManager.addShares(address(0), 0);
cheats.expectRevert("EigenPodManager.addOwnedShares: podOwner cannot be zero address");
eigenPodManager.addOwnedShares(address(0), 0);
}

function testFuzz_addShares_revert_sharesNegative(int256 shares) public {
cheats.assume(shares < 0);
cheats.prank(address(delegationManagerMock));
cheats.expectRevert("EigenPodManager.addShares: shares cannot be negative");
eigenPodManager.addShares(defaultStaker, uint256(shares));
cheats.expectRevert("EigenPodManager.addOwnedShares: shares cannot be negative");
eigenPodManager.addOwnedShares(defaultStaker, uint256(shares));
}

function testFuzz_addShares_revert_sharesNotWholeGwei(uint256 shares) public {
cheats.assume(int256(shares) >= 0);
cheats.assume(shares % GWEI_TO_WEI != 0);
cheats.prank(address(delegationManagerMock));
cheats.expectRevert("EigenPodManager.addShares: shares must be a whole Gwei amount");
eigenPodManager.addShares(defaultStaker, shares);
cheats.expectRevert("EigenPodManager.addOwnedShares: shares must be a whole Gwei amount");
eigenPodManager.addOwnedShares(defaultStaker, shares);
}

function testFuzz_addShares(uint256 shares) public {
Expand All @@ -226,7 +226,7 @@ contract EigenPodManagerUnitTests_ShareUpdateTests is EigenPodManagerUnitTests {

// Add shares
cheats.prank(address(delegationManagerMock));
eigenPodManager.addShares(defaultStaker, shares);
eigenPodManager.addOwnedShares(defaultStaker, shares);

// Check storage update
assertEq(eigenPodManager.podOwnerShares(defaultStaker), int256(shares), "Incorrect number of shares added");
Expand Down
12 changes: 6 additions & 6 deletions src/test/unit/StrategyManagerUnit.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -979,18 +979,18 @@ contract StrategyManagerUnitTests_addShares is StrategyManagerUnitTests {
function test_Revert_DelegationManagerModifier() external {
DelegationManagerMock invalidDelegationManager = new DelegationManagerMock();
cheats.expectRevert("StrategyManager.onlyDelegationManager: not the DelegationManager");
invalidDelegationManager.addShares(strategyManager, address(this), dummyToken, dummyStrat, 1);
invalidDelegationManager.addOwnedShares(strategyManager, address(this), dummyToken, dummyStrat, 1);
}

function testFuzz_Revert_StakerZeroAddress(uint256 amount) external {
cheats.expectRevert("StrategyManager._addShares: staker cannot be zero address");
delegationManagerMock.addShares(strategyManager, address(0), dummyToken, dummyStrat, amount);
delegationManagerMock.addOwnedShares(strategyManager, address(0), dummyToken, dummyStrat, amount);
}

function testFuzz_Revert_ZeroShares(address staker) external filterFuzzedAddressInputs(staker) {
cheats.assume(staker != address(0));
cheats.expectRevert("StrategyManager._addShares: shares should not be zero!");
delegationManagerMock.addShares(strategyManager, staker, dummyToken, dummyStrat, 0);
delegationManagerMock.addOwnedShares(strategyManager, staker, dummyToken, dummyStrat, 0);
}

function testFuzz_AppendsStakerStrategyList(
Expand All @@ -1003,7 +1003,7 @@ contract StrategyManagerUnitTests_addShares is StrategyManagerUnitTests {
assertEq(sharesBefore, 0, "Staker has already deposited into this strategy");
assertFalse(_isDepositedStrategy(staker, dummyStrat), "strategy should not be deposited");

delegationManagerMock.addShares(strategyManager, staker, dummyToken, dummyStrat, amount);
delegationManagerMock.addOwnedShares(strategyManager, staker, dummyToken, dummyStrat, amount);
uint256 stakerStrategyListLengthAfter = strategyManager.stakerStrategyListLength(staker);
uint256 sharesAfter = strategyManager.stakerStrategyShares(staker, dummyStrat);
assertEq(
Expand All @@ -1028,7 +1028,7 @@ contract StrategyManagerUnitTests_addShares is StrategyManagerUnitTests {
assertEq(sharesBefore, initialAmount, "Staker has not deposited amount into strategy");
assertTrue(_isDepositedStrategy(staker, strategy), "strategy should be deposited");

delegationManagerMock.addShares(strategyManager, staker, dummyToken, dummyStrat, sharesAmount);
delegationManagerMock.addOwnedShares(strategyManager, staker, dummyToken, dummyStrat, sharesAmount);
uint256 stakerStrategyListLengthAfter = strategyManager.stakerStrategyListLength(staker);
uint256 sharesAfter = strategyManager.stakerStrategyShares(staker, dummyStrat);
assertEq(
Expand Down Expand Up @@ -1077,7 +1077,7 @@ contract StrategyManagerUnitTests_addShares is StrategyManagerUnitTests {

cheats.prank(staker);
cheats.expectRevert("StrategyManager._addShares: deposit would exceed MAX_STAKER_STRATEGY_LIST_LENGTH");
delegationManagerMock.addShares(strategyManager, staker, dummyToken, strategy, amount);
delegationManagerMock.addOwnedShares(strategyManager, staker, dummyToken, strategy, amount);

cheats.expectRevert("StrategyManager._addShares: deposit would exceed MAX_STAKER_STRATEGY_LIST_LENGTH");
strategyManager.depositIntoStrategy(strategy, token, amount);
Expand Down
Loading