diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts new file mode 160000 index 000000000..3b8b4ba82 --- /dev/null +++ b/lib/openzeppelin-contracts @@ -0,0 +1 @@ +Subproject commit 3b8b4ba82c880c31cd3b96dd5e15741d7e26658e diff --git a/lib/openzeppelin-contracts-upgradeable b/lib/openzeppelin-contracts-upgradeable new file mode 160000 index 000000000..6b9807b06 --- /dev/null +++ b/lib/openzeppelin-contracts-upgradeable @@ -0,0 +1 @@ +Subproject commit 6b9807b0639e1dd75e07fa062e9432eb3f35dd8c diff --git a/src/contracts/core/AllocationManager.sol b/src/contracts/core/AllocationManager.sol index d23ff445e..6ce393197 100644 --- a/src/contracts/core/AllocationManager.sol +++ b/src/contracts/core/AllocationManager.sol @@ -22,10 +22,6 @@ contract AllocationManager is /// @dev BIPS factor for slashable bips uint256 internal constant BIPS_FACTOR = 10_000; - /// @dev Maximum number of pending updates that can be queued for allocations/deallocations - /// Note this max applies for a single (operator, strategy, operatorSet) tuple. - uint256 public constant MAX_PENDING_UPDATES = 1; - /// @dev Returns the chain ID from the time the contract was deployed. uint256 internal immutable ORIGINAL_CHAIN_ID; @@ -138,7 +134,7 @@ contract AllocationManager is // effect timestamp for allocations to take effect. This is configurable by operators uint32 allocationEffectTimestamp = uint32(block.timestamp) + delay; // completable timestamp for deallocations - uint32 deallocationCompletableTimestamp = uint32(block.timestamp) + DEALLOCATION_DELAY; + uint32 deallocationEffectTimestamp = uint32(block.timestamp) + DEALLOCATION_DELAY; for (uint256 i = 0; i < allocations.length; ++i) { // 1. For the given (operator,strategy) clear all pending free magnitude for the strategy and update freeMagnitude @@ -159,7 +155,7 @@ contract AllocationManager is operator: operator, allocation: allocations[i], allocationEffectTimestamp: allocationEffectTimestamp, - deallocationCompletableTimestamp: deallocationCompletableTimestamp + deallocationEffectTimestamp: deallocationEffectTimestamp }); } } @@ -186,50 +182,28 @@ contract AllocationManager is require(isOperatorSlashable(operator, operatorSet), InvalidOperator()); for (uint256 i = 0; i < strategies.length; ++i) { - // 1. Get pendingAllocations/Deallocations - (uint256 numPendingAllocations, uint256 numPendingDeallocations) = - _getPendingAllocationsAndDeallocations(operator, strategies[i], operatorSetKey); - uint64 slashedMagnitude; - - // 2. If there are pending allocations or deallocations, decrement accordingly - if (numPendingAllocations != 0) { - Snapshots.History storage magnitudeUpdates = _magnitudeUpdate[operator][strategies[i]][operatorSetKey]; - uint64 currentMagnitude = uint64(magnitudeUpdates.upperLookupRecent(uint32(block.timestamp))); - // skip if no actively allocated magnitude to slash - if (currentMagnitude != 0) { - /// TODO: add wrapping library for rounding up for slashing accounting - slashedMagnitude = uint64(uint256(bipsToSlash) * uint256(currentMagnitude) / BIPS_FACTOR); - - // propagate slashing to current and future and allocations for the (operator, strategy, operatorSet) - magnitudeUpdates.decrementAtAndFutureSnapshots({ - key: uint32(block.timestamp), - decrementValue: slashedMagnitude - }); - } - - // There can be at most 1 pending allocation + deallocation at a time, hence the else-if statement - } else if (numPendingDeallocations != 0) { - // Get the number of queued deallocations that can be completed - uint256 queuedDeallocationIndicesLen = - _queuedDeallocationIndices[operator][strategies[i]][operatorSetKey].length; - - // index of pendingFreeMagnitude/deallocation to check for slashing - uint256 index = _queuedDeallocationIndices[operator][strategies[i]][operatorSetKey][queuedDeallocationIndicesLen - 1]; - PendingFreeMagnitude storage pendingFreeMagnitude = - _pendingFreeMagnitude[operator][strategies[i]][index]; - - // The most recent deallocation may not be completable and, therefore, slashable - if (block.timestamp < pendingFreeMagnitude.completableTimestamp) { - // slash the pending deallocation proportionally and store the updated magnitudeDiff - uint64 slashedAmount = - uint64(uint256(bipsToSlash) * uint256(pendingFreeMagnitude.magnitudeDiff) / BIPS_FACTOR); - pendingFreeMagnitude.magnitudeDiff -= slashedAmount; - // keep track of total slashed magnitude - slashedMagnitude += slashedAmount; + // 1. Slash from pending deallocations and allocations + MagnitudeInfo memory opsetMagnitudeInfo = _operatorMagnitudeInfo[operator][strategies[i]][operatorSetKey]; + if (opsetMagnitudeInfo.effectTimestamp <= block.timestamp) { + if (opsetMagnitudeInfo.pendingMagnitudeDiff >= 0) { + opsetMagnitudeInfo.currentMagnitude = opsetMagnitudeInfo.currentMagnitude + uint64(opsetMagnitudeInfo.pendingMagnitudeDiff); + } else { + opsetMagnitudeInfo.currentMagnitude = opsetMagnitudeInfo.currentMagnitude - uint64(-opsetMagnitudeInfo.pendingMagnitudeDiff); } + opsetMagnitudeInfo.pendingMagnitudeDiff = 0; + } + + uint64 slashedMagnitude = uint64(uint256(opsetMagnitudeInfo.currentMagnitude) * bipsToSlash / BIPS_FACTOR); + opsetMagnitudeInfo.currentMagnitude -= slashedMagnitude; + // if there is a pending deallocation, slash pending deallocation proportionally + if (opsetMagnitudeInfo.pendingMagnitudeDiff < 0) { + uint256 pendingMagnitudeDiff = uint256(uint64(-opsetMagnitudeInfo.pendingMagnitudeDiff)) * (BIPS_FACTOR - bipsToSlash) / BIPS_FACTOR; + opsetMagnitudeInfo.pendingMagnitudeDiff += -int64(uint64(pendingMagnitudeDiff)); } + // update operatorMagnitudeInfo + _operatorMagnitudeInfo[operator][strategies[i]][operatorSetKey] = opsetMagnitudeInfo; - // 3. update totalMagnitude, get total magnitude and subtract slashedMagnitude + // 2. update totalMagnitude, get total magnitude and subtract slashedMagnitude // this will be reflected in the conversion of delegatedShares to shares in the DM Snapshots.History storage totalMagnitudes = _totalMagnitudeUpdate[operator][strategies[i]]; totalMagnitudes.push({key: uint32(block.timestamp), value: totalMagnitudes.latest() - slashedMagnitude}); @@ -278,14 +252,14 @@ contract AllocationManager is * In addition to updating freeMagnitude, updates next starting index to read from for pending free magnitudes after completing */ function _updateFreeMagnitude(address operator, IStrategy strategy, uint16 numToComplete) internal { - OperatorMagnitudeInfo memory info = operatorMagnitudeInfo[operator][strategy]; + FreeMagnitudeInfo memory freeInfo = operatorFreeMagnitudeInfo[operator][strategy]; (uint64 freeMagnitudeToAdd, uint192 completed) = - _getPendingFreeMagnitude(operator, strategy, numToComplete, info.nextPendingFreeMagnitudeIndex); - info.freeMagnitude += freeMagnitudeToAdd; - info.nextPendingFreeMagnitudeIndex += completed; + _getPendingFreeMagnitude(operator, strategy, numToComplete, freeInfo.nextPendingIndex); + freeInfo.freeMagnitude += freeMagnitudeToAdd; + freeInfo.nextPendingIndex += completed; - operatorMagnitudeInfo[operator][strategy] = info; + operatorFreeMagnitudeInfo[operator][strategy] = freeInfo; } /** @@ -293,7 +267,7 @@ contract AllocationManager is * @param operator address to modify allocations for * @param allocation the magnitude allocations to modify for a single strategy * @param allocationEffectTimestamp the timestamp when the allocations will take effect - * @param deallocationCompletableTimestamp the timestamp when the deallocations will be completable + * @param deallocationEffectTimestamp the timestamp when the deallocations will be completable * @dev For each allocation, allocation.operatorSets MUST be ordered in ascending order according to the * encoding of the operatorSet. This is to prevent duplicate operatorSets being passed in. The easiest way to ensure * ordering is to sort allocated operatorSets by address first, and then sort for each avs by ascending operatorSetIds. @@ -302,7 +276,7 @@ contract AllocationManager is address operator, MagnitudeAllocation calldata allocation, uint32 allocationEffectTimestamp, - uint32 deallocationCompletableTimestamp + uint32 deallocationEffectTimestamp ) internal { require(allocation.operatorSets.length == allocation.magnitudes.length, InputArrayLengthMismatch()); @@ -313,101 +287,56 @@ contract AllocationManager is ); bytes32 operatorSetKey = _encodeOperatorSet(allocation.operatorSets[i]); - // prep magnitudeUpdates in storage - - // Check that there is at MOST `MAX_PENDING_UPDATES` combined allocations & deallocations for the operator, operatorSet, strategy - (uint256 numPendingAllocations, uint256 numPendingDeallocations) = - _getPendingAllocationsAndDeallocations(operator, allocation.strategy, operatorSetKey); + // Check that there are no pending allocations & deallocations for the operator, operatorSet, strategy + MagnitudeInfo memory opsetMagnitudeInfo = _operatorMagnitudeInfo[operator][allocation.strategy][operatorSetKey]; require( - numPendingAllocations + numPendingDeallocations < MAX_PENDING_UPDATES, + opsetMagnitudeInfo.effectTimestamp <= block.timestamp, PendingAllocationOrDeallocation() ); - Snapshots.History storage magnitudeUpdates = _magnitudeUpdate[operator][allocation.strategy][operatorSetKey]; - - // Read current magnitude allocation including its respective array index and length. - // We'll use these values later to check the number of pending allocations/deallocations. - (uint224 currentMagnitude,,) = - magnitudeUpdates.upperLookupRecentWithPos(uint32(block.timestamp)); + // Set the current magnitude to the pending magnitude if the effectTimestamp is in the past + uint64 currentMagnitude = opsetMagnitudeInfo.currentMagnitude; + if (opsetMagnitudeInfo.effectTimestamp <= block.timestamp) { + if (opsetMagnitudeInfo.pendingMagnitudeDiff >= 0) { + currentMagnitude = opsetMagnitudeInfo.currentMagnitude + uint64(opsetMagnitudeInfo.pendingMagnitudeDiff); + } else { + currentMagnitude = opsetMagnitudeInfo.currentMagnitude - uint64(-opsetMagnitudeInfo.pendingMagnitudeDiff); + } + } + require(currentMagnitude != allocation.magnitudes[i], SameMagnitude()); - - if (allocation.magnitudes[i] < uint64(currentMagnitude)) { - // Newly configured magnitude is less than current value. - // Therefore we handle this as a deallocation - - // Note: MAX_PENDING_UPDATES == 1, so we do not have to decrement any allocations + + // The timestamp at which the pending allocation/deallocation will take effect + uint32 effectTimestamp; + if (allocation.magnitudes[i] < currentMagnitude) { + // This is a deallocation // 1. push PendingFreeMagnitude and respective array index into (op,opSet,Strategy) queued deallocations - uint64 magnitudeToDeallocate = uint64(currentMagnitude) - allocation.magnitudes[i]; - _queuedDeallocationIndices[operator][allocation.strategy][operatorSetKey].push( - _pendingFreeMagnitude[operator][allocation.strategy].length - ); - _pendingFreeMagnitude[operator][allocation.strategy].push( - PendingFreeMagnitude({ - magnitudeDiff: magnitudeToDeallocate, - completableTimestamp: deallocationCompletableTimestamp - }) - ); - - // 2. decrement allocated magnitude - magnitudeUpdates.decrementAtAndFutureSnapshots({ - key: uint32(block.timestamp), - decrementValue: magnitudeToDeallocate - }); - } else if (allocation.magnitudes[i] > uint64(currentMagnitude)) { - // Newly configured magnitude is greater than current value. - // Therefore we handle this as an allocation + _pendingDeallocationOperatorSets[operator][allocation.strategy].push(operatorSetKey); + + // 2. Update the effect timestamp for the deallocation + effectTimestamp = deallocationEffectTimestamp; + } else if (allocation.magnitudes[i] > currentMagnitude) { + // This is an allocation // 1. decrement free magnitude by incremented amount - uint64 magnitudeToAllocate = allocation.magnitudes[i] - uint64(currentMagnitude); - OperatorMagnitudeInfo storage info = operatorMagnitudeInfo[operator][allocation.strategy]; - require(info.freeMagnitude >= magnitudeToAllocate, InsufficientAllocatableMagnitude()); - info.freeMagnitude -= magnitudeToAllocate; + uint64 magnitudeToAllocate = allocation.magnitudes[i] - currentMagnitude; + FreeMagnitudeInfo storage freeInfo = operatorFreeMagnitudeInfo[operator][allocation.strategy]; + require(freeInfo.freeMagnitude >= magnitudeToAllocate, InsufficientAllocatableMagnitude()); + freeInfo.freeMagnitude -= magnitudeToAllocate; - // 2. allocate magnitude which will take effect in the future 21 days from now - magnitudeUpdates.push({key: allocationEffectTimestamp, value: allocation.magnitudes[i]}); + // 2. Update the effectTimestamp for the allocation + effectTimestamp = allocationEffectTimestamp; } - } - } - /** - * @notice Get the number of queued allocation/deallocations for the given (operator, strategy, operatorSetKey) tuple - * @param operator address to get queued allocation/deallocations for - * @param strategy the strategy to get queued allocation/deallocations for - * @param operatorSetKey the encoded operatorSet to get queued allocation/deallocations for - * @dev Does not make an assumption on the number of pending allocations or deallocations at a time - */ - function _getPendingAllocationsAndDeallocations( - address operator, - IStrategy strategy, - bytes32 operatorSetKey - ) internal view returns (uint256 numPendingAllocations, uint256 numPendingDeallocations) { - // Get pending allocations - Snapshots.History storage magnitudeUpdates = _magnitudeUpdate[operator][strategy][operatorSetKey]; - - // Read current magnitude's respective array index and length. - (,uint256 latestAllocPos, uint256 allocLength) = - magnitudeUpdates.upperLookupRecentWithPos(uint32(block.timestamp)); - - if (latestAllocPos < allocLength - 1) { - numPendingAllocations = allocLength - 1 - latestAllocPos; - } - // Else, latestAllocPos >= allocLength - 1; - // latestAllocPos cannot be greater than length - 1, thus when pos == length - 1 there are no pending allocations - - // Get pending deallocations - uint256 deallocationsLength = _queuedDeallocationIndices[operator][strategy][operatorSetKey].length; - for (uint256 i = deallocationsLength; i > 0; --i) { - // index of pendingFreeMagnitude/deallocation to check for slashing - uint256 index = _queuedDeallocationIndices[operator][strategy][operatorSetKey][i - 1]; - - // If completableTimestamp is greater than completeUntilTimestamp, break - if (block.timestamp < _pendingFreeMagnitude[operator][strategy][index].completableTimestamp) { - ++numPendingDeallocations; - } else { - break; - } + // Allocate magnitude which will take effect at the `effectTimestamp` + + _operatorMagnitudeInfo[operator][allocation.strategy][operatorSetKey] = MagnitudeInfo({ + currentMagnitude: currentMagnitude, + pendingMagnitudeDiff: int64(allocation.magnitudes[i]) - int64(currentMagnitude), + effectTimestamp: effectTimestamp + }); } } @@ -417,7 +346,7 @@ contract AllocationManager is if (!exists) { totalMagnitude = WAD; _totalMagnitudeUpdate[operator][strategy].push({key: uint32(block.timestamp), value: totalMagnitude}); - operatorMagnitudeInfo[operator][strategy].freeMagnitude = WAD; + operatorFreeMagnitudeInfo[operator][strategy].freeMagnitude = WAD; } return uint64(totalMagnitude); @@ -430,19 +359,26 @@ contract AllocationManager is IStrategy strategy, uint16 numToComplete, uint192 nextIndex - ) internal view returns (uint64 freeMagnitudeToAdd, uint192 completed) { - uint256 pendingFreeMagnitudeLength = _pendingFreeMagnitude[operator][strategy].length; + ) internal returns (uint64 freeMagnitudeToAdd, uint192 completed) { + uint256 numDeallocations = _pendingDeallocationOperatorSets[operator][strategy].length; freeMagnitudeToAdd = 0; - while (nextIndex < pendingFreeMagnitudeLength && completed < numToComplete) { - PendingFreeMagnitude memory pendingFreeMagnitude = _pendingFreeMagnitude[operator][strategy][nextIndex]; - // pendingFreeMagnitude is ordered by completableTimestamp. If we reach one that is not completable yet, then break + while (nextIndex < numDeallocations && completed < numToComplete) { + bytes32 opsetKey = _pendingDeallocationOperatorSets[operator][strategy][nextIndex]; + MagnitudeInfo memory opsetMagnitudeInfo = _operatorMagnitudeInfo[operator][strategy][opsetKey]; + // _pendingDeallocationOperatorSets is ordered by `effectTimestamp`. If we reach one that is not completable yet, then break // loop until completableTimestamp is < block.timestamp - if (block.timestamp < pendingFreeMagnitude.completableTimestamp) { + if (block.timestamp < opsetMagnitudeInfo.effectTimestamp) { break; } // pending free magnitude can be added to freeMagnitude - freeMagnitudeToAdd += pendingFreeMagnitude.magnitudeDiff; + freeMagnitudeToAdd += uint64(-opsetMagnitudeInfo.pendingMagnitudeDiff); + _operatorMagnitudeInfo[operator][strategy][opsetKey] = MagnitudeInfo({ + currentMagnitude: opsetMagnitudeInfo.currentMagnitude - uint64(-opsetMagnitudeInfo.pendingMagnitudeDiff), + pendingMagnitudeDiff: 0, + effectTimestamp: 0 + }); + ++nextIndex; ++completed; } @@ -480,11 +416,16 @@ contract AllocationManager is for (uint256 i = 0; i < strategies.length; ++i) { slashableMagnitudes[i] = new uint64[](operatorSets.length); for (uint256 j = 0; j < operatorSets.length; ++j) { - slashableMagnitudes[i][j] = uint64( - _magnitudeUpdate[operator][strategies[i]][_encodeOperatorSet(operatorSets[j])].upperLookupLinear( - uint32(block.timestamp) - ) - ); + MagnitudeInfo memory opsetMagnitudeInfo = _operatorMagnitudeInfo[operator][strategies[i]][_encodeOperatorSet(operatorSets[j])]; + if (block.timestamp < opsetMagnitudeInfo.effectTimestamp) { + slashableMagnitudes[i][j] = opsetMagnitudeInfo.currentMagnitude; + } else { + if (opsetMagnitudeInfo.pendingMagnitudeDiff >= 0) { + slashableMagnitudes[i][j] = opsetMagnitudeInfo.currentMagnitude + uint64(opsetMagnitudeInfo.pendingMagnitudeDiff); + } else { + slashableMagnitudes[i][j] = opsetMagnitudeInfo.currentMagnitude - uint64(-opsetMagnitudeInfo.pendingMagnitudeDiff); + } + } } } return (operatorSets, slashableMagnitudes); @@ -497,13 +438,17 @@ contract AllocationManager is * @param strategy the strategy to get the allocatable magnitude for */ function getAllocatableMagnitude(address operator, IStrategy strategy) external view returns (uint64) { - OperatorMagnitudeInfo storage info = operatorMagnitudeInfo[operator][strategy]; - (uint64 freeMagnitudeToAdd,) = _getPendingFreeMagnitude({ - operator: operator, - strategy: strategy, - numToComplete: type(uint16).max, - nextIndex: info.nextPendingFreeMagnitudeIndex - }); + FreeMagnitudeInfo memory info = operatorFreeMagnitudeInfo[operator][strategy]; + uint256 numDeallocations = _pendingDeallocationOperatorSets[operator][strategy].length; + uint64 freeMagnitudeToAdd = 0; + for (uint192 i = info.nextPendingIndex; i < numDeallocations; ++i) { + bytes32 opsetKey = _pendingDeallocationOperatorSets[operator][strategy][i]; + MagnitudeInfo memory opsetMagnitudeInfo = _operatorMagnitudeInfo[operator][strategy][opsetKey]; + if (block.timestamp < opsetMagnitudeInfo.effectTimestamp) { + break; + } + freeMagnitudeToAdd += uint64(-opsetMagnitudeInfo.pendingMagnitudeDiff); + } return info.freeMagnitude + freeMagnitudeToAdd; } @@ -579,7 +524,6 @@ contract AllocationManager is } else { totalMagnitude = uint64(value); } - return totalMagnitude; } @@ -598,23 +542,20 @@ contract AllocationManager is IStrategy strategy, OperatorSet[] calldata operatorSets ) external view returns (uint64[] memory, uint32[] memory) { - uint64[] memory pendingMagnitude = new uint64[](operatorSets.length); + uint64[] memory pendingMagnitudes = new uint64[](operatorSets.length); uint32[] memory timestamps = new uint32[](operatorSets.length); for (uint256 i = 0; i < operatorSets.length; ++i) { - // We use latestSnapshot to get the latest pending allocation for an operatorSet. - (bool exists, uint32 key, uint224 value) = - _magnitudeUpdate[operator][strategy][_encodeOperatorSet(operatorSets[i])].latestSnapshot(); - if (exists) { - if (key > block.timestamp) { - pendingMagnitude[i] = uint64(value); - timestamps[i] = key; - } else { - pendingMagnitude[i] = 0; - timestamps[i] = 0; - } + MagnitudeInfo memory opsetMagnitudeInfo = _operatorMagnitudeInfo[operator][strategy][_encodeOperatorSet(operatorSets[i])]; + + if (opsetMagnitudeInfo.effectTimestamp < block.timestamp && opsetMagnitudeInfo.pendingMagnitudeDiff > 0) { + pendingMagnitudes[i] = opsetMagnitudeInfo.currentMagnitude + uint64(opsetMagnitudeInfo.pendingMagnitudeDiff); + timestamps[i] = opsetMagnitudeInfo.effectTimestamp; + } else { + pendingMagnitudes[i] = 0; + timestamps[i] = 0; } } - return (pendingMagnitude, timestamps); + return (pendingMagnitudes, timestamps); } /** @@ -624,28 +565,29 @@ contract AllocationManager is * @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) { - PendingFreeMagnitude[] memory pendingMagnitudes = new PendingFreeMagnitude[](operatorSets.length); + ) external view returns (uint64[] memory, uint32[] memory) { + uint64[] memory pendingMagnitudeDiffs = new uint64[](operatorSets.length); + uint32[] memory timestamps = new uint32[](operatorSets.length); + for (uint256 i = 0; i < operatorSets.length; ++i) { - uint256[] storage deallocationIndices = - _queuedDeallocationIndices[operator][strategy][_encodeOperatorSet(operatorSets[i])]; - - if (deallocationIndices.length > 0) { - uint256 deallocationIndex = deallocationIndices[deallocationIndices.length - 1]; - PendingFreeMagnitude storage latestPendingMagnitude = - _pendingFreeMagnitude[operator][strategy][deallocationIndex]; - if (latestPendingMagnitude.completableTimestamp > block.timestamp) { - pendingMagnitudes[i] = latestPendingMagnitude; - } + MagnitudeInfo memory opsetMagnitudeInfo = _operatorMagnitudeInfo[operator][strategy][_encodeOperatorSet(operatorSets[i])]; + + if (opsetMagnitudeInfo.effectTimestamp < block.timestamp && opsetMagnitudeInfo.pendingMagnitudeDiff < 0) { + pendingMagnitudeDiffs[i] = uint64(-opsetMagnitudeInfo.pendingMagnitudeDiff); + timestamps[i] = opsetMagnitudeInfo.effectTimestamp; + } else { + pendingMagnitudeDiffs[i] = 0; + timestamps[i] = 0; } } - return pendingMagnitudes; + return (pendingMagnitudeDiffs, timestamps); } /// @dev Verify operator's signature and spend salt diff --git a/src/contracts/core/AllocationManagerStorage.sol b/src/contracts/core/AllocationManagerStorage.sol index 8abe6a3a1..df3b24c9b 100644 --- a/src/contracts/core/AllocationManagerStorage.sol +++ b/src/contracts/core/AllocationManagerStorage.sol @@ -45,17 +45,17 @@ 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 => operatorSet (encoded) => MagnitudeInfo + mapping(address => mapping(IStrategy => mapping(bytes32 => MagnitudeInfo))) internal _operatorMagnitudeInfo; - /// @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) to keep track of pending free magnitude for operatorSet from deallocations + mapping(address => mapping(IStrategy => bytes32[])) internal _pendingDeallocationOperatorSets; /// @notice Mapping: operator => strategy => operatorSet (encoded) => list of queuedDeallocation indices - mapping(address => mapping(IStrategy => mapping(bytes32 => uint256[]))) internal _queuedDeallocationIndices; + // mapping(address => mapping(IStrategy => mapping(bytes32 => uint256[]))) internal _queuedDeallocationIndices; /// @notice Mapping: operator => allocation delay (in seconds) for the operator. /// This determines how long it takes for allocations to take effect in the future. diff --git a/src/contracts/interfaces/IAllocationManager.sol b/src/contracts/interfaces/IAllocationManager.sol index 7b967ae20..f7ea8542e 100644 --- a/src/contracts/interfaces/IAllocationManager.sol +++ b/src/contracts/interfaces/IAllocationManager.sol @@ -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 { + uint64 currentMagnitude; + int64 pendingMagnitudeDiff; + 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; } @@ -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