diff --git a/contracts/contract/minipool/RocketMinipoolLinkedQueue.sol b/contracts/contract/minipool/RocketMinipoolLinkedQueue.sol deleted file mode 100644 index efb76316..00000000 --- a/contracts/contract/minipool/RocketMinipoolLinkedQueue.sol +++ /dev/null @@ -1,245 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity 0.7.6; - -import "@openzeppelin/contracts/math/SafeMath.sol"; -import "@openzeppelin/contracts/math/SignedSafeMath.sol"; -import "@openzeppelin/contracts/utils/SafeCast.sol"; - -import "../RocketBase.sol"; -import "../../interface/minipool/RocketMinipoolInterface.sol"; -import "../../interface/minipool/RocketMinipoolLinkedQueueInterface.sol"; -import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsMinipoolInterface.sol"; -import "../../interface/util/AddressLinkedQueueStorageInterface.sol"; -import "../../types/MinipoolDeposit.sol"; - -/// @notice Minipool queueing for deposit assignment -contract RocketMinipoolLinkedQueue is RocketBase, RocketMinipoolLinkedQueueInterface { - - // Libs - using SafeMath for uint; - using SignedSafeMath for int; - - // Constants - bytes32 private constant queueKeyFull = keccak256("linked.minipools.available.full"); - bytes32 private constant queueKeyHalf = keccak256("linked.minipools.available.half"); - bytes32 private constant queueKeyVariable = keccak256("linked.minipools.available.variable"); - - // Events - event MinipoolEnqueued(address indexed minipool, bytes32 indexed queueId, uint256 time); - event MinipoolDequeued(address indexed minipool, bytes32 indexed queueId, uint256 time); - event MinipoolRemoved(address indexed minipool, bytes32 indexed queueId, uint256 time); - - constructor(RocketStorageInterface _rocketStorageAddress) RocketBase(_rocketStorageAddress) { - version = 1; - } - - /// @notice Get the total combined length of the queues - function getTotalLength() override external view returns (uint256) { - return ( - getLengthLegacy(queueKeyFull) - ).add( - getLengthLegacy(queueKeyHalf) - ).add( - getLength() - ); - } - - /// @notice Returns true if there are any legacy minipools in the queue - function getContainsLegacy() override external view returns (bool) { - return getLengthLegacy(queueKeyFull).add(getLengthLegacy(queueKeyHalf)) > 0; - } - - /// @notice Get the length of a given queue. Returns 0 for invalid queues - /// @param _depositType Which queue to query the length of - function getLengthLegacy(MinipoolDeposit _depositType) override external view returns (uint256) { - if (_depositType == MinipoolDeposit.Full) { return getLengthLegacy(queueKeyFull); } - if (_depositType == MinipoolDeposit.Half) { return getLengthLegacy(queueKeyHalf); } - return 0; - } - - /// @dev Returns a queue length by internal key representation - /// @param _key The internal key representation of the queue to query the length of - function getLengthLegacy(bytes32 _key) private view returns (uint256) { - AddressLinkedQueueStorageInterface addressLinkedQueueStorage = AddressLinkedQueueStorageInterface(getContractAddress("addressLinkedQueueStorage")); - return addressLinkedQueueStorage.getLength(_key); - } - - /// @notice Gets the length of the variable (global) queue - function getLength() override public view returns (uint256) { - AddressLinkedQueueStorageInterface addressLinkedQueueStorage = AddressLinkedQueueStorageInterface(getContractAddress("addressLinkedQueueStorage")); - return addressLinkedQueueStorage.getLength(queueKeyVariable); - } - - /// @notice Get the total combined capacity of the queues - function getTotalCapacity() override external view returns (uint256) { - RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool")); - return ( - getLengthLegacy(queueKeyFull).mul(rocketDAOProtocolSettingsMinipool.getFullDepositUserAmount()) - ).add( - getLengthLegacy(queueKeyHalf).mul(rocketDAOProtocolSettingsMinipool.getHalfDepositUserAmount()) - ).add( - getVariableCapacity() - ); - } - - /// @notice Get the total effective capacity of the queues (used in node demand calculation) - function getEffectiveCapacity() override external view returns (uint256) { - RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool")); - return ( - getLengthLegacy(queueKeyFull).mul(rocketDAOProtocolSettingsMinipool.getFullDepositUserAmount()) - ).add( - getLengthLegacy(queueKeyHalf).mul(rocketDAOProtocolSettingsMinipool.getHalfDepositUserAmount()) - ).add( - getVariableCapacity() - ); - } - - /// @dev Get the ETH capacity of the variable queue - function getVariableCapacity() internal view returns (uint256) { - RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool")); - return getLength().mul(rocketDAOProtocolSettingsMinipool.getVariableDepositAmount()); - } - - /// @notice Get the capacity of the next available minipool. Returns 0 if no minipools are available - function getNextCapacityLegacy() override external view returns (uint256) { - RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool")); - if (getLengthLegacy(queueKeyHalf) > 0) { return rocketDAOProtocolSettingsMinipool.getHalfDepositUserAmount(); } - if (getLengthLegacy(queueKeyFull) > 0) { return rocketDAOProtocolSettingsMinipool.getFullDepositUserAmount(); } - return 0; - } - - /// @notice Get the deposit type of the next available minipool and the number of deposits in that queue. - /// Returns None if no minipools are available - function getNextDepositLegacy() override external view returns (MinipoolDeposit, uint256) { - uint256 length = getLengthLegacy(queueKeyHalf); - if (length > 0) { return (MinipoolDeposit.Half, length); } - length = getLengthLegacy(queueKeyFull); - if (length > 0) { return (MinipoolDeposit.Full, length); } - return (MinipoolDeposit.None, 0); - } - - /// @dev Add a minipool to the end of the appropriate queue. Only accepts calls from the RocketMinipoolManager contract - /// @param _minipool Address of the minipool to add to the queue - function enqueueMinipool(address _minipool) override external onlyLatestContract("rocketMinipoolQueue", address(this)) onlyLatestContract("rocketNodeDeposit", msg.sender) { - // Enqueue - AddressLinkedQueueStorageInterface addressLinkedQueueStorage = AddressLinkedQueueStorageInterface(getContractAddress("addressLinkedQueueStorage")); - addressLinkedQueueStorage.enqueueItem(queueKeyVariable, _minipool); - // Emit enqueued event - emit MinipoolEnqueued(_minipool, queueKeyVariable, block.timestamp); - } - - /// @dev Dequeues a minipool from a legacy queue - /// @param _depositType The queue to dequeue a minipool from - function dequeueMinipoolByDepositLegacy(MinipoolDeposit _depositType) override external onlyLatestContract("rocketMinipoolQueue", address(this)) onlyLatestContract("rocketDepositPool", msg.sender) returns (address minipoolAddress) { - if (_depositType == MinipoolDeposit.Half) { return dequeueMinipool(queueKeyHalf); } - if (_depositType == MinipoolDeposit.Full) { return dequeueMinipool(queueKeyFull); } - require(false, "No minipools are available"); - } - - /// @dev Dequeues multiple minipools from the variable queue and returns them all - /// @param _maxToDequeue The maximum number of items to dequeue - function dequeueMinipools(uint256 _maxToDequeue) override external onlyLatestContract("rocketMinipoolQueue", address(this)) onlyLatestContract("rocketDepositPool", msg.sender) returns (address[] memory minipoolAddress) { - uint256 queueLength = getLength(); - uint256 count = _maxToDequeue; - if (count > queueLength) { - count = queueLength; - } - address[] memory minipoolAddresses = new address[](count); - for (uint256 i = 0; i < count; i++) { - RocketMinipoolInterface minipool = RocketMinipoolInterface(dequeueMinipool(queueKeyVariable)); - minipoolAddresses[i] = address(minipool); - } - return minipoolAddresses; - } - - /// @dev Dequeues a minipool from a queue given an internal key - /// @param _key The internal key representation of the queue from which to dequeue a minipool from - function dequeueMinipool(bytes32 _key) private returns (address) { - // Dequeue - AddressLinkedQueueStorageInterface addressLinkedQueueStorage = AddressLinkedQueueStorageInterface(getContractAddress("addressLinkedQueueStorage")); - address minipool = addressLinkedQueueStorage.dequeueItem(_key); - // Emit dequeued event - emit MinipoolDequeued(minipool, _key, block.timestamp); - // Return - return minipool; - } - - /// @dev Remove a minipool from a queue. Only accepts calls from registered minipools - function removeMinipool(MinipoolDeposit _depositType) override external onlyLatestContract("rocketMinipoolQueue", address(this)) onlyRegisteredMinipool(msg.sender) { - // Remove minipool from queue - if (_depositType == MinipoolDeposit.Half) { return removeMinipool(queueKeyHalf, msg.sender); } - if (_depositType == MinipoolDeposit.Full) { return removeMinipool(queueKeyFull, msg.sender); } - if (_depositType == MinipoolDeposit.Variable) { return removeMinipool(queueKeyVariable, msg.sender); } - require(false, "Invalid minipool deposit type"); - } - - /// @dev Removes a minipool from a queue given an internal key - /// @param _key The internal key representation of the queue from which to remove a minipool from - /// @param _minipool The address of a minipool to remove from the specified queue - function removeMinipool(bytes32 _key, address _minipool) private { - // Remove - AddressLinkedQueueStorageInterface addressLinkedQueueStorage = AddressLinkedQueueStorageInterface(getContractAddress("addressLinkedQueueStorage")); - addressLinkedQueueStorage.removeItem(_key, _minipool); - // Emit removed event - emit MinipoolRemoved(_minipool, _key, block.timestamp); - } - - /// @notice Returns the minipool address of the minipool in the global queue at a given index - /// @param _index The index into the queue to retrieve - function getMinipoolAt(uint256 _index) override external view returns(address) { - AddressLinkedQueueStorageInterface addressLinkedQueueStorage = AddressLinkedQueueStorageInterface(getContractAddress("addressLinkedQueueStorage")); - - // Check if index is in the half queue - uint256 halfLength = addressLinkedQueueStorage.getLength(queueKeyHalf); - if (_index < halfLength) { - return addressLinkedQueueStorage.getItem(queueKeyHalf, _index); - } - _index = _index.sub(halfLength); - - // Check if index is in the full queue - uint256 fullLength = addressLinkedQueueStorage.getLength(queueKeyFull); - if (_index < fullLength) { - return addressLinkedQueueStorage.getItem(queueKeyFull, _index); - } - _index = _index.sub(fullLength); - - // Check if index is in the full queue - uint256 variableLength = addressLinkedQueueStorage.getLength(queueKeyVariable); - if (_index < variableLength) { - return addressLinkedQueueStorage.getItem(queueKeyVariable, _index); - } - - // Index is out of bounds - return address(0); - } - - /// @notice Returns the position a given minipool is in the queue - /// @param _minipool The minipool to query the position of - function getMinipoolPosition(address _minipool) override external view returns (int256) { - AddressLinkedQueueStorageInterface addressLinkedQueueStorage = AddressLinkedQueueStorageInterface(getContractAddress("addressLinkedQueueStorage")); - int256 position; - - // Check in half queue - position = addressLinkedQueueStorage.getIndexOf(queueKeyHalf, _minipool); - if (position != -1) { - return position; - } - int256 offset = SafeCast.toInt256(addressLinkedQueueStorage.getLength(queueKeyHalf)); - - // Check in full queue - position = addressLinkedQueueStorage.getIndexOf(queueKeyFull, _minipool); - if (position != -1) { - return offset.add(position); - } - offset = offset.add(SafeCast.toInt256(addressLinkedQueueStorage.getLength(queueKeyFull))); - - // Check in variable queue - position = addressLinkedQueueStorage.getIndexOf(queueKeyVariable, _minipool); - if (position != -1) { - return offset.add(position); - } - - // Isn't in the queue - return -1; - } -} diff --git a/contracts/contract/util/AddressLinkedQueueStorage.sol b/contracts/contract/util/AddressLinkedQueueStorage.sol index 4a5e6c2a..1244b11f 100644 --- a/contracts/contract/util/AddressLinkedQueueStorage.sol +++ b/contracts/contract/util/AddressLinkedQueueStorage.sol @@ -1,138 +1,182 @@ pragma solidity 0.8.18; +pragma abicoder v2; // SPDX-License-Identifier: GPL-3.0-only import "../RocketBase.sol"; import "../../interface/util/AddressLinkedQueueStorageInterface.sol"; -// Address linked queue storage helper for RocketStorage data (linked list implementation) +/// @notice Address linked queue storage helper for RocketStorage data (linked list implementation) contract AddressLinkedQueueStorage is RocketBase, AddressLinkedQueueStorageInterface { + // Constants for packing queue metadata into a single uint256 + uint256 constant internal startOffset = 256 - 64; + uint256 constant internal endOffset = 256 - 128; + uint256 constant internal lengthOffset = 256 - 192; + + // Constants for packing a deposit queue struct into a single uint256 + uint256 constant internal receiverOffset = 256 - 160; + uint256 constant internal indexOffset = 256 - 160 - 32; + uint256 constant internal suppliedOffset = 256 - 160 - 32 - 32; + // Construct constructor(RocketStorageInterface _rocketStorageAddress) RocketBase(_rocketStorageAddress) { version = 1; } - // The number of items in the list - function getLength(bytes32 _key) override public view returns (uint) { - return getUint(keccak256(abi.encodePacked(_key, ".length"))); + /// @notice The number of items in the queue + /// @param _namespace defines the queue to be used + function getLength(bytes32 _namespace) override public view returns (uint) { + return getUint(keccak256(abi.encodePacked(_namespace, ".data"))) >> lengthOffset; } - // The item in a queue by index - function getItem(bytes32 _key, uint _index) override external view returns (address) { - uint index = getUint(keccak256(abi.encodePacked(_key, ".start"))) + _index; - return getAddress(keccak256(abi.encodePacked(_key, ".item", index))); + /// @notice The item in a queue by index + /// @param _namespace defines the queue to be used + /// @param _index the item index + function getItem(bytes32 _namespace, uint _index) override external view returns (DepositQueueValue memory) { + uint index = getUint(keccak256(abi.encodePacked(_namespace, ".data"))) >> startOffset + _index; + uint packedValue = getUint(keccak256(abi.encodePacked(_namespace, ".item", index))); + return unpackDepositQueueValue(packedValue); } - // The index of an item in a queue - // Returns -1 if the value is not found - function getIndexOf(bytes32 _key, address _value) override external view returns (int) { - uint index = getUint(keccak256(abi.encodePacked(_key, ".index", _value))); + /// @notice The index of an item in a queue. Returns -1 if the value is not found + /// @param _namespace defines the queue to be used + /// @param _value the deposit queue value + function getIndexOf(bytes32 _namespace, DepositQueueValue memory _value) override external view returns (int) { + uint index = getUint(keccak256(abi.encodePacked(_namespace, ".index", _value.receiver, _value.validatorIndex))); if (index > 0) { return int(index); } return -1; } - // Finds an item index in a queue and returns the previous item - // Returns 0 if the value is not found - function getPreviousItem(bytes32 _key, address _value) external view returns (address) { - uint index = getUint(keccak256(abi.encodePacked(_key, ".index", _value))); + /// @notice Finds an item index in a queue and returns the previous item + /// @param _namespace defines the queue to be used + /// @param _value the deposit queue value + function getPreviousItem(bytes32 _namespace, DepositQueueValue memory _value) external view returns (DepositQueueValue memory previousItem) { + uint index = getUint(keccak256(abi.encodePacked(_namespace, ".index", _value.receiver, _value.validatorIndex))); if (index > 0) { - uint previousIndex = getUint(keccak256(abi.encodePacked(_key, ".prev", index))); - return getAddress(keccak256(abi.encodePacked(_key, ".item", previousIndex))); + uint previousIndex = getUint(keccak256(abi.encodePacked(_namespace, ".prev", index))); + previousItem = unpackDepositQueueValue(getUint(keccak256(abi.encodePacked(_namespace, ".item", previousIndex)))); } - return address(0); } - // Finds an item index in a queue and returns the previous item - // Returns 0 if the value is not found - function getNextItem(bytes32 _key, address _value) external view returns (address) { - uint index = getUint(keccak256(abi.encodePacked(_key, ".index", _value))); + /// @notice Finds an item index in a queue and returns the next item + /// @param _namespace defines the queue to be used + /// @param _value the deposit queue value + function getNextItem(bytes32 _namespace, DepositQueueValue memory _value) external view returns (DepositQueueValue memory nextItem) { + uint index = getUint(keccak256(abi.encodePacked(_namespace, ".index", _value.receiver, _value.validatorIndex))); if (index > 0) { - uint nextIndex = getUint(keccak256(abi.encodePacked(_key, ".next", index))); - return getAddress(keccak256(abi.encodePacked(_key, ".item", nextIndex))); + uint nextIndex = getUint(keccak256(abi.encodePacked(_namespace, ".next", index))); + nextItem = unpackDepositQueueValue(getUint(keccak256(abi.encodePacked(_namespace, ".item", nextIndex)))); } - return address(0); } - // Add an item to the end of the list - // Requires that the item does not exist in the list - function enqueueItem(bytes32 _key, address _value) virtual override external { + /// @notice Add an item to the end of the list. Requires that the item does not exist in the list + /// @param _namespace defines the queue to be used + /// @param _value the deposit queue value + function enqueueItem(bytes32 _namespace, DepositQueueValue memory _value) virtual override external { // onlyLatestContract("addressLinkedListStorage", address(this)) onlyLatestNetworkContract { - require(getUint(keccak256(abi.encodePacked(_key, ".index", _value))) == 0, "Item already exists in queue"); - uint endIndex = getUint(keccak256(abi.encodePacked(_key, ".end"))); + require(getUint(keccak256(abi.encodePacked(_namespace, ".index", _value.receiver, _value.validatorIndex))) == 0, "Item already exists in queue"); + uint data = getUint(keccak256(abi.encodePacked(_namespace, ".data"))); + uint endIndex = data >> endOffset; uint newIndex = endIndex + 1; if (endIndex > 0) { - setUint(keccak256(abi.encodePacked(_key, ".next", endIndex)), newIndex); - setUint(keccak256(abi.encodePacked(_key, ".prev", newIndex)), endIndex); + setUint(keccak256(abi.encodePacked(_namespace, ".next", endIndex)), newIndex); + setUint(keccak256(abi.encodePacked(_namespace, ".prev", newIndex)), endIndex); } else { - setUint(keccak256(abi.encodePacked(_key, ".start")), newIndex); + data |= newIndex << startOffset; } - setAddress(keccak256(abi.encodePacked(_key, ".item", newIndex)), _value); - setUint(keccak256(abi.encodePacked(_key, ".index", _value)), newIndex); - setUint(keccak256(abi.encodePacked(_key, ".end")), newIndex); + setUint(keccak256(abi.encodePacked(_namespace, ".item", newIndex)), packDepositQueueValue(_value)); + setUint(keccak256(abi.encodePacked(_namespace, ".index", _value.receiver, _value.validatorIndex)), newIndex); + data |= newIndex << endOffset; // Update the length of the queue - setUint(keccak256(abi.encodePacked(_key, ".length")), getLength(_key) + 1); + uint currentLength = data >> lengthOffset; + data |= (currentLength + 1) << lengthOffset; + setUint(keccak256(abi.encodePacked(_namespace, ".data")), data); } - // Remove an item from the start of a queue and return it - // Requires that the queue is not empty - function dequeueItem(bytes32 _key) public virtual override onlyLatestContract("addressLinkedListStorage", address(this)) onlyLatestNetworkContract returns (address) { - require(getLength(_key) > 0, "Queue is empty"); - uint start = getUint(keccak256(abi.encodePacked(_key, ".start"))); - address item = getAddress(keccak256(abi.encodePacked(_key, ".item", start))); + /// @notice Remove an item from the start of a queue and return it. Requires that the queue is not empty + /// @param _namespace defines the queue to be used + function dequeueItem(bytes32 _namespace) public virtual override onlyLatestContract("addressLinkedListStorage", address(this)) onlyLatestNetworkContract returns (address) { + require(getLength(_namespace) > 0, "Queue is empty"); + uint data = getUint(keccak256(abi.encodePacked(_namespace, ".data"))); + uint start = data >> startOffset; + address item = getAddress(keccak256(abi.encodePacked(_namespace, ".item", start))); - uint nextItem = getUint(keccak256(abi.encodePacked(_key, ".next", item))); - setUint(keccak256(abi.encodePacked(_key, ".start")), nextItem); - setUint(keccak256(abi.encodePacked(_key, ".index", item)), 0); + uint nextItem = getUint(keccak256(abi.encodePacked(_namespace, ".next", item))); + data |= nextItem << startOffset; + setUint(keccak256(abi.encodePacked(_namespace, ".index", item)), 0); if (nextItem > 0) { - setUint(keccak256(abi.encodePacked(_key, ".prev", nextItem)), 0); + setUint(keccak256(abi.encodePacked(_namespace, ".prev", nextItem)), 0); } else { - setUint(keccak256(abi.encodePacked(_key, ".end")), 0); + data |= 0 << endOffset; } // Update the length of the queue - setUint(keccak256(abi.encodePacked(_key, ".length")), getLength(_key) - 1); + uint currentLength = data >> lengthOffset; + data |= (currentLength + 1) << lengthOffset; + setUint(keccak256(abi.encodePacked(_namespace, ".data")), data); return item; } - // Removes an item from a queue - // Requires that the item exists in the queue - function removeItem(bytes32 _key, address _value) public virtual override onlyLatestContract("addressLinkedListStorage", address(this)) onlyLatestNetworkContract { - uint index = getUint(keccak256(abi.encodePacked(_key, ".index", _value))); + /// @notice Removes an item from a queue. Requires that the item exists in the queue + /// @param _namespace defines the queue to be used + function removeItem(bytes32 _namespace, DepositQueueValue memory _value) public virtual override onlyLatestContract("addressLinkedListStorage", address(this)) onlyLatestNetworkContract { + uint index = getUint(keccak256(abi.encodePacked(_namespace, ".index", _value.receiver, _value.validatorIndex))); + uint data = getUint(keccak256(abi.encodePacked(_namespace, ".data"))); require(index > 0, "Item does not exist in queue"); - uint prevIndex = getUint(keccak256(abi.encodePacked(_key, ".prev", index))); - uint nextIndex = getUint(keccak256(abi.encodePacked(_key, ".next", index))); + uint prevIndex = getUint(keccak256(abi.encodePacked(_namespace, ".prev", index))); + uint nextIndex = getUint(keccak256(abi.encodePacked(_namespace, ".next", index))); if (prevIndex > 0) { // Not the first item - setUint(keccak256(abi.encodePacked(_key, ".next", prevIndex)), nextIndex); + setUint(keccak256(abi.encodePacked(_namespace, ".next", prevIndex)), nextIndex); } else { // First item - setUint(keccak256(abi.encodePacked(_key, ".start")), nextIndex); - setUint(keccak256(abi.encodePacked(_key, ".prev", nextIndex)), 0); + data |= nextIndex << startOffset; + setUint(keccak256(abi.encodePacked(_namespace, ".prev", nextIndex)), 0); } if (nextIndex > 0) { // Not the last item - setUint(keccak256(abi.encodePacked(_key, ".prev", nextIndex)), prevIndex); + setUint(keccak256(abi.encodePacked(_namespace, ".prev", nextIndex)), prevIndex); } else { // Last item - setUint(keccak256(abi.encodePacked(_key, ".end")), prevIndex); + data |= prevIndex << endOffset; } - setUint(keccak256(abi.encodePacked(_key, ".index", _value)), 0); - setUint(keccak256(abi.encodePacked(_key, ".next", index)), 0); - setUint(keccak256(abi.encodePacked(_key, ".prev", index)), 0); + setUint(keccak256(abi.encodePacked(_namespace, ".index", _value.receiver, _value.validatorIndex)), 0); + setUint(keccak256(abi.encodePacked(_namespace, ".next", index)), 0); + setUint(keccak256(abi.encodePacked(_namespace, ".prev", index)), 0); // Update the length of the queue - setUint(keccak256(abi.encodePacked(_key, ".length")), getLength(_key) - 1); + uint currentLength = data >> lengthOffset; + data |= (currentLength + 1) << lengthOffset; + setUint(keccak256(abi.encodePacked(_namespace, ".data")), data); + } + + /// @notice packs a deposit queue value into a single uint256 + /// @param _struct the deposit queue value to be packed + function packDepositQueueValue(DepositQueueValue memory _struct) internal pure returns (uint256 packed) { + packed |= uint256(uint160(_struct.receiver)) << receiverOffset; + packed |= uint256(_struct.validatorIndex) << indexOffset; + packed |= uint256(_struct.suppliedValue) << suppliedOffset; + packed |= uint256(_struct.requestedValue); + } + + /// @notice unpacks an uint256 value into a deposit queue struct + /// @param _packedValue the packed deposit queue value + function unpackDepositQueueValue(uint256 _packedValue) internal pure returns (DepositQueueValue memory value) { + value.receiver = address(uint160(_packedValue >> receiverOffset)); + value.validatorIndex = uint32(_packedValue >> indexOffset); + value.suppliedValue = uint32(_packedValue >> suppliedOffset); + value.requestedValue = uint32(_packedValue); } } \ No newline at end of file diff --git a/contracts/interface/minipool/RocketMinipoolLinkedQueueInterface.sol b/contracts/interface/minipool/RocketMinipoolLinkedQueueInterface.sol deleted file mode 100644 index 0e8c9d05..00000000 --- a/contracts/interface/minipool/RocketMinipoolLinkedQueueInterface.sol +++ /dev/null @@ -1,22 +0,0 @@ -pragma solidity >0.5.0 <0.9.0; - -// SPDX-License-Identifier: GPL-3.0-only - -import "../../types/MinipoolDeposit.sol"; - -interface RocketMinipoolLinkedQueueInterface { - function getTotalLength() external view returns (uint256); - function getContainsLegacy() external view returns (bool); - function getLengthLegacy(MinipoolDeposit _depositType) external view returns (uint256); - function getLength() external view returns (uint256); - function getTotalCapacity() external view returns (uint256); - function getEffectiveCapacity() external view returns (uint256); - function getNextCapacityLegacy() external view returns (uint256); - function getNextDepositLegacy() external view returns (MinipoolDeposit, uint256); - function enqueueMinipool(address _minipool) external; - function dequeueMinipoolByDepositLegacy(MinipoolDeposit _depositType) external returns (address minipoolAddress); - function dequeueMinipools(uint256 _maxToDequeue) external returns (address[] memory minipoolAddress); - function removeMinipool(MinipoolDeposit _depositType) external; - function getMinipoolAt(uint256 _index) external view returns(address); - function getMinipoolPosition(address _minipool) external view returns (int256); -} \ No newline at end of file diff --git a/contracts/interface/util/AddressLinkedQueueStorageInterface.sol b/contracts/interface/util/AddressLinkedQueueStorageInterface.sol index 0b775115..1b60763b 100644 --- a/contracts/interface/util/AddressLinkedQueueStorageInterface.sol +++ b/contracts/interface/util/AddressLinkedQueueStorageInterface.sol @@ -1,12 +1,20 @@ pragma solidity >0.5.0 <0.9.0; +pragma abicoder v2; // SPDX-License-Identifier: GPL-3.0-only +struct DepositQueueValue { + address receiver; + uint32 validatorIndex; + uint32 suppliedValue; // in milliether + uint32 requestedValue; // in milliether +} + interface AddressLinkedQueueStorageInterface { function getLength(bytes32 _key) external view returns (uint); - function getItem(bytes32 _key, uint _index) external view returns (address); - function getIndexOf(bytes32 _key, address _value) external view returns (int); - function enqueueItem(bytes32 _key, address _value) external; + function getItem(bytes32 _key, uint _index) external view returns (DepositQueueValue memory); + function getIndexOf(bytes32 _key, DepositQueueValue memory _value) external view returns (int); + function enqueueItem(bytes32 _key, DepositQueueValue memory _value) external; function dequeueItem(bytes32 _key) external returns (address); - function removeItem(bytes32 _key, address _value) external; + function removeItem(bytes32 _key, DepositQueueValue memory _value) external; }