From d591af63670aeb14ea8a14c930670165faab064f Mon Sep 17 00:00:00 2001 From: Kresh Date: Wed, 16 Oct 2024 22:35:32 +0400 Subject: [PATCH 1/9] refactor: optimize with synced core --- lib/core | 2 +- src/contracts/NetworkRestakeFairHook.sol | 42 +++++++++++------ .../NetworkRestakeRedistributionHook.sol | 45 ++++++++++--------- 3 files changed, 55 insertions(+), 34 deletions(-) diff --git a/lib/core b/lib/core index fda1655..a611789 160000 --- a/lib/core +++ b/lib/core @@ -1 +1 @@ -Subproject commit fda1655c3694b9d1265e103ba1ecaa1b5e0c5ae5 +Subproject commit a61178929b09bac67d0346340e0df89f6aeb8e0c diff --git a/src/contracts/NetworkRestakeFairHook.sol b/src/contracts/NetworkRestakeFairHook.sol index 69c8f78..4c7db9b 100644 --- a/src/contracts/NetworkRestakeFairHook.sol +++ b/src/contracts/NetworkRestakeFairHook.sol @@ -6,7 +6,9 @@ import {INetworkRestakeFairHook} from "../interfaces/INetworkRestakeFairHook.sol import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; import {IEntity} from "@symbioticfi/core/src/interfaces/common/IEntity.sol"; import {INetworkRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/INetworkRestakeDelegator.sol"; -import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol"; +import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol"; +import {ISlasher} from "@symbioticfi/core/src/interfaces/slasher/ISlasher.sol"; +import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlasher.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; @@ -31,24 +33,38 @@ contract NetworkRestakeFairHook is INetworkRestakeFairHook { return; } - address slasher = IVault(INetworkRestakeDelegator(msg.sender).vault()).slasher(); + IBaseSlasher.GeneralDelegatorData memory generalData = abi.decode(data, (IBaseSlasher.GeneralDelegatorData)); + uint256 stakeAt; + if (generalData.slasherType == 0) { + ISlasher.DelegatorData memory delegatorData = abi.decode(generalData.data, (ISlasher.DelegatorData)); + stakeAt = delegatorData.stakeAt; + } else if (generalData.slasherType == 1) { + IVetoSlasher.DelegatorData memory delegatorData = abi.decode(generalData.data, (IVetoSlasher.DelegatorData)); + stakeAt = delegatorData.stakeAt; + } else { + stakeAt = INetworkRestakeDelegator(msg.sender).stakeAt(subnetwork, operator, captureTimestamp, new bytes(0)); + } uint256 networkLimit = INetworkRestakeDelegator(msg.sender).networkLimit(subnetwork); - INetworkRestakeDelegator(msg.sender).setNetworkLimit( - subnetwork, networkLimit - Math.min(slashedAmount, networkLimit) - ); + if (networkLimit != 0) { + INetworkRestakeDelegator(msg.sender).setNetworkLimit( + subnetwork, networkLimit - Math.min(slashedAmount, networkLimit) + ); + } uint256 operatorNetworkSharesAt = INetworkRestakeDelegator(msg.sender).operatorNetworkSharesAt( subnetwork, operator, captureTimestamp, new bytes(0) ); uint256 operatorNetworkShares = INetworkRestakeDelegator(msg.sender).operatorNetworkShares(subnetwork, operator); - uint256 operatorSlashedShares = slashedAmount.mulDiv( - operatorNetworkSharesAt, - INetworkRestakeDelegator(msg.sender).stakeAt(subnetwork, operator, captureTimestamp, new bytes(0)), - Math.Rounding.Ceil - ); - INetworkRestakeDelegator(msg.sender).setOperatorNetworkShares( - subnetwork, operator, operatorNetworkShares - Math.min(operatorSlashedShares, operatorNetworkShares) - ); + if (operatorNetworkShares != 0) { + INetworkRestakeDelegator(msg.sender).setOperatorNetworkShares( + subnetwork, + operator, + operatorNetworkShares + - Math.min( + slashedAmount.mulDiv(operatorNetworkSharesAt, stakeAt, Math.Rounding.Ceil), operatorNetworkShares + ) + ); + } } } diff --git a/src/contracts/NetworkRestakeRedistributionHook.sol b/src/contracts/NetworkRestakeRedistributionHook.sol index d529af6..ec788cb 100644 --- a/src/contracts/NetworkRestakeRedistributionHook.sol +++ b/src/contracts/NetworkRestakeRedistributionHook.sol @@ -8,6 +8,9 @@ import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelega import {IEntity} from "@symbioticfi/core/src/interfaces/common/IEntity.sol"; import {INetworkRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/INetworkRestakeDelegator.sol"; import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol"; +import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol"; +import {ISlasher} from "@symbioticfi/core/src/interfaces/slasher/ISlasher.sol"; +import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlasher.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; @@ -32,28 +35,30 @@ contract NetworkRestakeRedistributionHook is INetworkRestakeRedistributionHook { return; } - address vault = INetworkRestakeDelegator(msg.sender).vault(); - address slasher = IVault(vault).slasher(); - - uint256 prevSlashableStake = Math.min( - IVault(vault).activeStakeAt(captureTimestamp, new bytes(0)) - - ( - (IBaseSlasher(slasher).globalCumulativeSlash() - slashedAmount) - - IBaseSlasher(slasher).globalCumulativeSlashAt(captureTimestamp, new bytes(0)) - ), - INetworkRestakeDelegator(msg.sender).stakeAt(subnetwork, operator, captureTimestamp, new bytes(0)) + IBaseSlasher.GeneralDelegatorData memory generalData = abi.decode(data, (IBaseSlasher.GeneralDelegatorData)); + uint256 slashableStake; + if (generalData.slasherType == 0) { + ISlasher.DelegatorData memory delegatorData = abi.decode(generalData.data, (ISlasher.DelegatorData)); + slashableStake = delegatorData.slashableStake; + } else if (generalData.slasherType == 1) { + IVetoSlasher.DelegatorData memory delegatorData = abi.decode(generalData.data, (IVetoSlasher.DelegatorData)); + slashableStake = delegatorData.slashableStake; + } else { + address slasher = IVault(INetworkRestakeDelegator(msg.sender).vault()).slasher(); + slashableStake = INetworkRestakeDelegator(msg.sender).stakeAt( + subnetwork, operator, captureTimestamp, new bytes(0) + ) - ( (IBaseSlasher(slasher).cumulativeSlash(subnetwork, operator) - slashedAmount) - IBaseSlasher(slasher).cumulativeSlashAt(subnetwork, operator, captureTimestamp, new bytes(0)) - ) - ); - - INetworkRestakeDelegator(msg.sender).setOperatorNetworkShares( - subnetwork, - operator, - (prevSlashableStake - slashedAmount).mulDiv( - INetworkRestakeDelegator(msg.sender).operatorNetworkShares(subnetwork, operator), prevSlashableStake - ) - ); + ); + } + + uint256 operatorNetworkShares = INetworkRestakeDelegator(msg.sender).operatorNetworkShares(subnetwork, operator); + if (operatorNetworkShares != 0) { + INetworkRestakeDelegator(msg.sender).setOperatorNetworkShares( + subnetwork, operator, (slashableStake - slashedAmount).mulDiv(operatorNetworkShares, slashableStake) + ); + } } } From df9851cb38f0b3b380f1d98fc33a9802d4abba69 Mon Sep 17 00:00:00 2001 From: Kresh Date: Wed, 16 Oct 2024 22:37:00 +0400 Subject: [PATCH 2/9] chore: flexible versions for interfaces --- src/interfaces/INetworkRestakeFairHook.sol | 2 +- src/interfaces/INetworkRestakeRedistributionHook.sol | 2 +- src/interfaces/INetworkRestakeResetHook.sol | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/interfaces/INetworkRestakeFairHook.sol b/src/interfaces/INetworkRestakeFairHook.sol index 7b9e8ba..1a8c22c 100644 --- a/src/interfaces/INetworkRestakeFairHook.sol +++ b/src/interfaces/INetworkRestakeFairHook.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.25; +pragma solidity ^0.8.0; import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; diff --git a/src/interfaces/INetworkRestakeRedistributionHook.sol b/src/interfaces/INetworkRestakeRedistributionHook.sol index bd72a6a..a072c1d 100644 --- a/src/interfaces/INetworkRestakeRedistributionHook.sol +++ b/src/interfaces/INetworkRestakeRedistributionHook.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.25; +pragma solidity ^0.8.0; import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; diff --git a/src/interfaces/INetworkRestakeResetHook.sol b/src/interfaces/INetworkRestakeResetHook.sol index 1d035ac..a6cbe01 100644 --- a/src/interfaces/INetworkRestakeResetHook.sol +++ b/src/interfaces/INetworkRestakeResetHook.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.25; +pragma solidity ^0.8.0; import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; From 0477fb6ac4c6dd25b3f6c5cfe198bffd75013ede Mon Sep 17 00:00:00 2001 From: Kresh Date: Thu, 17 Oct 2024 11:08:48 +0400 Subject: [PATCH 3/9] chore: sync core --- lib/core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core b/lib/core index a611789..bdbb05e 160000 --- a/lib/core +++ b/lib/core @@ -1 +1 @@ -Subproject commit a61178929b09bac67d0346340e0df89f6aeb8e0c +Subproject commit bdbb05ebd9ea6d96c671b672562ae23afcb2123b From 9a282bcd18d5e193d4e75c809383d8c683d86699 Mon Sep 17 00:00:00 2001 From: Kresh Date: Wed, 23 Oct 2024 01:31:52 +0400 Subject: [PATCH 4/9] refactor: add folder for NetworkRestakeDelegator --- .../{ => networkRestakeDelegator}/NetworkRestakeFairHook.sol | 2 +- .../NetworkRestakeRedistributionHook.sol | 3 ++- .../{ => networkRestakeDelegator}/NetworkRestakeResetHook.sol | 4 ++-- .../{ => networkRestakeDelegator}/INetworkRestakeFairHook.sol | 0 .../INetworkRestakeRedistributionHook.sol | 0 .../INetworkRestakeResetHook.sol | 0 .../NetworkRestakeFairHook.t.sol | 3 +-- .../NetworkRestakeRedistributionHook.t copy.sol | 4 ++-- .../NetworkRestakeResetHook.t.sol | 3 +-- 9 files changed, 9 insertions(+), 10 deletions(-) rename src/contracts/{ => networkRestakeDelegator}/NetworkRestakeFairHook.sol (96%) rename src/contracts/{ => networkRestakeDelegator}/NetworkRestakeRedistributionHook.sol (95%) rename src/contracts/{ => networkRestakeDelegator}/NetworkRestakeResetHook.sol (91%) rename src/interfaces/{ => networkRestakeDelegator}/INetworkRestakeFairHook.sol (100%) rename src/interfaces/{ => networkRestakeDelegator}/INetworkRestakeRedistributionHook.sol (100%) rename src/interfaces/{ => networkRestakeDelegator}/INetworkRestakeResetHook.sol (100%) rename test/{ => networkRestakeDelegator}/NetworkRestakeFairHook.t.sol (96%) rename test/{ => networkRestakeDelegator}/NetworkRestakeRedistributionHook.t copy.sol (94%) rename test/{ => networkRestakeDelegator}/NetworkRestakeResetHook.t.sol (96%) diff --git a/src/contracts/NetworkRestakeFairHook.sol b/src/contracts/networkRestakeDelegator/NetworkRestakeFairHook.sol similarity index 96% rename from src/contracts/NetworkRestakeFairHook.sol rename to src/contracts/networkRestakeDelegator/NetworkRestakeFairHook.sol index 4c7db9b..c819044 100644 --- a/src/contracts/NetworkRestakeFairHook.sol +++ b/src/contracts/networkRestakeDelegator/NetworkRestakeFairHook.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import {INetworkRestakeFairHook} from "../interfaces/INetworkRestakeFairHook.sol"; +import {INetworkRestakeFairHook} from "../../interfaces/networkRestakeDelegator/INetworkRestakeFairHook.sol"; import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; import {IEntity} from "@symbioticfi/core/src/interfaces/common/IEntity.sol"; diff --git a/src/contracts/NetworkRestakeRedistributionHook.sol b/src/contracts/networkRestakeDelegator/NetworkRestakeRedistributionHook.sol similarity index 95% rename from src/contracts/NetworkRestakeRedistributionHook.sol rename to src/contracts/networkRestakeDelegator/NetworkRestakeRedistributionHook.sol index ec788cb..0e7ed8b 100644 --- a/src/contracts/NetworkRestakeRedistributionHook.sol +++ b/src/contracts/networkRestakeDelegator/NetworkRestakeRedistributionHook.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import {INetworkRestakeRedistributionHook} from "../interfaces/INetworkRestakeRedistributionHook.sol"; +import {INetworkRestakeRedistributionHook} from + "../../interfaces/networkRestakeDelegator/INetworkRestakeRedistributionHook.sol"; import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol"; import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; diff --git a/src/contracts/NetworkRestakeResetHook.sol b/src/contracts/networkRestakeDelegator/NetworkRestakeResetHook.sol similarity index 91% rename from src/contracts/NetworkRestakeResetHook.sol rename to src/contracts/networkRestakeDelegator/NetworkRestakeResetHook.sol index e46ab28..703c0fb 100644 --- a/src/contracts/NetworkRestakeResetHook.sol +++ b/src/contracts/networkRestakeDelegator/NetworkRestakeResetHook.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import {CircularBuffer} from "./libraries/CircularBuffer.sol"; +import {CircularBuffer} from "../libraries/CircularBuffer.sol"; -import {INetworkRestakeResetHook} from "../interfaces/INetworkRestakeResetHook.sol"; +import {INetworkRestakeResetHook} from "../../interfaces/networkRestakeDelegator/INetworkRestakeResetHook.sol"; import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; import {IEntity} from "@symbioticfi/core/src/interfaces/common/IEntity.sol"; diff --git a/src/interfaces/INetworkRestakeFairHook.sol b/src/interfaces/networkRestakeDelegator/INetworkRestakeFairHook.sol similarity index 100% rename from src/interfaces/INetworkRestakeFairHook.sol rename to src/interfaces/networkRestakeDelegator/INetworkRestakeFairHook.sol diff --git a/src/interfaces/INetworkRestakeRedistributionHook.sol b/src/interfaces/networkRestakeDelegator/INetworkRestakeRedistributionHook.sol similarity index 100% rename from src/interfaces/INetworkRestakeRedistributionHook.sol rename to src/interfaces/networkRestakeDelegator/INetworkRestakeRedistributionHook.sol diff --git a/src/interfaces/INetworkRestakeResetHook.sol b/src/interfaces/networkRestakeDelegator/INetworkRestakeResetHook.sol similarity index 100% rename from src/interfaces/INetworkRestakeResetHook.sol rename to src/interfaces/networkRestakeDelegator/INetworkRestakeResetHook.sol diff --git a/test/NetworkRestakeFairHook.t.sol b/test/networkRestakeDelegator/NetworkRestakeFairHook.t.sol similarity index 96% rename from test/NetworkRestakeFairHook.t.sol rename to test/networkRestakeDelegator/NetworkRestakeFairHook.t.sol index c1aa9c5..a4e7258 100644 --- a/test/NetworkRestakeFairHook.t.sol +++ b/test/networkRestakeDelegator/NetworkRestakeFairHook.t.sol @@ -7,8 +7,7 @@ import {POCBaseTest} from "@symbioticfi/core/test/POCBase.t.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol"; -import {NetworkRestakeFairHook} from "../src/contracts/NetworkRestakeFairHook.sol"; -import {INetworkRestakeFairHook} from "../src/interfaces/INetworkRestakeFairHook.sol"; +import {NetworkRestakeFairHook} from "../../src/contracts/networkRestakeDelegator/NetworkRestakeFairHook.sol"; contract NetworkRestakeFairHookTest is POCBaseTest { using Math for uint256; diff --git a/test/NetworkRestakeRedistributionHook.t copy.sol b/test/networkRestakeDelegator/NetworkRestakeRedistributionHook.t copy.sol similarity index 94% rename from test/NetworkRestakeRedistributionHook.t copy.sol rename to test/networkRestakeDelegator/NetworkRestakeRedistributionHook.t copy.sol index ec1ef94..2dd44bc 100644 --- a/test/NetworkRestakeRedistributionHook.t copy.sol +++ b/test/networkRestakeDelegator/NetworkRestakeRedistributionHook.t copy.sol @@ -7,8 +7,8 @@ import {POCBaseTest} from "@symbioticfi/core/test/POCBase.t.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol"; -import {NetworkRestakeRedistributionHook} from "../src/contracts/NetworkRestakeRedistributionHook.sol"; -import {INetworkRestakeRedistributionHook} from "../src/interfaces/INetworkRestakeRedistributionHook.sol"; +import {NetworkRestakeRedistributionHook} from + "../../src/contracts/networkRestakeDelegator/NetworkRestakeRedistributionHook.sol"; contract NetworkRestakeRedistributionHookTest is POCBaseTest { using Math for uint256; diff --git a/test/NetworkRestakeResetHook.t.sol b/test/networkRestakeDelegator/NetworkRestakeResetHook.t.sol similarity index 96% rename from test/NetworkRestakeResetHook.t.sol rename to test/networkRestakeDelegator/NetworkRestakeResetHook.t.sol index d20a330..bf90957 100644 --- a/test/NetworkRestakeResetHook.t.sol +++ b/test/networkRestakeDelegator/NetworkRestakeResetHook.t.sol @@ -7,8 +7,7 @@ import {POCBaseTest} from "@symbioticfi/core/test/POCBase.t.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol"; -import {NetworkRestakeResetHook} from "../src/contracts/NetworkRestakeResetHook.sol"; -import {INetworkRestakeResetHook} from "../src/interfaces/INetworkRestakeResetHook.sol"; +import {NetworkRestakeResetHook} from "../../src/contracts/networkRestakeDelegator/NetworkRestakeResetHook.sol"; contract NetworkRestakeResetHookTest is POCBaseTest { using Math for uint256; From c246ddec683cd1230cc5ec583962308d4bbdf783 Mon Sep 17 00:00:00 2001 From: Kresh Date: Wed, 23 Oct 2024 01:35:29 +0400 Subject: [PATCH 5/9] chore: update openzeppelin/openzeppelin-contracts --- lib/openzeppelin-contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts index dbb6104..3291252 160000 --- a/lib/openzeppelin-contracts +++ b/lib/openzeppelin-contracts @@ -1 +1 @@ -Subproject commit dbb6104ce834628e473d2173bbc9d47f81a9eec3 +Subproject commit 3291252c866ad698f6a55ec660259e49a67eb3d0 From 39f8ca8cfd11e79fe14f76d5c0bb13fa1c10f97e Mon Sep 17 00:00:00 2001 From: Kresh Date: Wed, 23 Oct 2024 01:53:04 +0400 Subject: [PATCH 6/9] refactor: use CircularBuffer from original library --- src/contracts/libraries/CircularBuffer.sol | 119 ------------------ .../NetworkRestakeResetHook.sol | 3 +- 2 files changed, 1 insertion(+), 121 deletions(-) delete mode 100644 src/contracts/libraries/CircularBuffer.sol diff --git a/src/contracts/libraries/CircularBuffer.sol b/src/contracts/libraries/CircularBuffer.sol deleted file mode 100644 index af5a5b0..0000000 --- a/src/contracts/libraries/CircularBuffer.sol +++ /dev/null @@ -1,119 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; -import {Arrays} from "@openzeppelin/contracts/utils/Arrays.sol"; - -/// @notice A fixed-size buffer for keeping `bytes32` items in storage. -/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/structs/CircularBuffer.sol) -library CircularBuffer { - error ArrayOutOfBounds(); - - /** - * @dev Error emitted when trying to setup a buffer with a size of 0. - */ - error InvalidBufferSize(); - - /** - * @dev Counts the number of items that have been pushed to the buffer. The residuo modulo _data.length indicates - * where the next value should be stored. - * - * Struct members have an underscore prefix indicating that they are "private" and should not be read or written to - * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and - * lead to unexpected behavior. - * - * In a full buffer: - * - The most recently pushed item (last) is at data[(index - 1) % data.length] - * - The oldest item (first) is at data[index % data.length] - */ - struct Bytes32CircularBuffer { - uint256 _count; - bytes32[] _data; - } - - /** - * @dev Initialize a new CircularBuffer of given size. - * - * If the CircularBuffer was already setup and used, calling that function again will reset it to a blank state. - * - * NOTE: The size of the buffer will affect the execution of {includes} function, as it has a complexity of O(N). - * Consider a large buffer size may render the function unusable. - */ - function setup(Bytes32CircularBuffer storage self, uint256 size) internal { - if (size == 0) revert InvalidBufferSize(); - clear(self); - bytes32[] storage array = self._data; - assembly ("memory-safe") { - sstore(array.slot, size) - } - } - - /** - * @dev Clear all data in the buffer without resetting memory, keeping the existing size. - */ - function clear( - Bytes32CircularBuffer storage self - ) internal { - self._count = 0; - } - - /** - * @dev Push a new value to the buffer. If the buffer is already full, the new value replaces the oldest value in - * the buffer. - */ - function push(Bytes32CircularBuffer storage self, bytes32 value) internal { - uint256 index = self._count++; - uint256 modulus = self._data.length; - Arrays.unsafeAccess(self._data, index % modulus).value = value; - } - - /** - * @dev Number of values currently in the buffer. This value is 0 for an empty buffer, and cannot exceed the size of - * the buffer. - */ - function count( - Bytes32CircularBuffer storage self - ) internal view returns (uint256) { - return Math.min(self._count, self._data.length); - } - - /** - * @dev Length of the buffer. This is the maximum number of elements kept in the buffer. - */ - function length( - Bytes32CircularBuffer storage self - ) internal view returns (uint256) { - return self._data.length; - } - - /** - * @dev Getter for the i-th value in the buffer, from the end. - * - * Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if trying to access an element that was not pushed, or that was - * dropped to make room for newer elements. - */ - function last(Bytes32CircularBuffer storage self, uint256 i) internal view returns (bytes32) { - uint256 index = self._count; - uint256 modulus = self._data.length; - uint256 total = Math.min(index, modulus); // count(self) - if (i >= total) { - revert ArrayOutOfBounds(); - } - return Arrays.unsafeAccess(self._data, (index - i - 1) % modulus).value; - } - - /** - * @dev Check if a given value is in the buffer. - */ - function includes(Bytes32CircularBuffer storage self, bytes32 value) internal view returns (bool) { - uint256 index = self._count; - uint256 modulus = self._data.length; - uint256 total = Math.min(index, modulus); // count(self) - for (uint256 i = 0; i < total; ++i) { - if (Arrays.unsafeAccess(self._data, (index - i - 1) % modulus).value == value) { - return true; - } - } - return false; - } -} diff --git a/src/contracts/networkRestakeDelegator/NetworkRestakeResetHook.sol b/src/contracts/networkRestakeDelegator/NetworkRestakeResetHook.sol index 703c0fb..a08f50a 100644 --- a/src/contracts/networkRestakeDelegator/NetworkRestakeResetHook.sol +++ b/src/contracts/networkRestakeDelegator/NetworkRestakeResetHook.sol @@ -1,14 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import {CircularBuffer} from "../libraries/CircularBuffer.sol"; - import {INetworkRestakeResetHook} from "../../interfaces/networkRestakeDelegator/INetworkRestakeResetHook.sol"; import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; import {IEntity} from "@symbioticfi/core/src/interfaces/common/IEntity.sol"; import {INetworkRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/INetworkRestakeDelegator.sol"; +import {CircularBuffer} from "@openzeppelin/contracts/utils/structs/CircularBuffer.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {Time} from "@openzeppelin/contracts/utils/types/Time.sol"; From f6a7809fe42143f2d413aaa58982efa8dc0c9698 Mon Sep 17 00:00:00 2001 From: Kresh Date: Wed, 23 Oct 2024 16:20:00 +0400 Subject: [PATCH 7/9] feat: add hooks for all delegators --- .../FullRestakeFairHook.sol | 47 +++ .../FullRestakeResetHook.sol | 77 ++++ .../NetworkRestakeResetHook.sol | 36 +- .../OperatorSpecificFairHook.sol | 40 ++ .../OperatorSpecificResetHook.sol | 76 ++++ .../IFullRestakeFairHook.sol | 8 + .../IFullRestakeResetHook.sol | 22 ++ .../INetworkRestakeResetHook.sol | 13 + .../IOperatorSpecificFairHook.sol | 8 + .../IOperatorSpecificResetHook.sol | 22 ++ .../FullRestakeFairHook.t.sol | 231 +++++++++++ .../FullRestakeResetHook.t.sol | 285 ++++++++++++++ test/mocks/FakeDelegator.sol | 27 ++ .../NetworkRestakeFairHook.t.sol | 132 +++++++ ...etworkRestakeRedistributionHook.t copy.sol | 87 ----- .../NetworkRestakeRedistributionHook.t.sol | 202 ++++++++++ .../NetworkRestakeResetHook.t.sol | 180 +++++++++ .../OperatorSpecificFairHook.t.sol | 257 +++++++++++++ .../OperatorSpecificResetHook.t.sol | 360 ++++++++++++++++++ 19 files changed, 2012 insertions(+), 98 deletions(-) create mode 100644 src/contracts/fullRestakeDelegator/FullRestakeFairHook.sol create mode 100644 src/contracts/fullRestakeDelegator/FullRestakeResetHook.sol create mode 100644 src/contracts/operatorSpecificDelegator/OperatorSpecificFairHook.sol create mode 100644 src/contracts/operatorSpecificDelegator/OperatorSpecificResetHook.sol create mode 100644 src/interfaces/fullRestakeDelegator/IFullRestakeFairHook.sol create mode 100644 src/interfaces/fullRestakeDelegator/IFullRestakeResetHook.sol create mode 100644 src/interfaces/operatorSpecificDelegator/IOperatorSpecificFairHook.sol create mode 100644 src/interfaces/operatorSpecificDelegator/IOperatorSpecificResetHook.sol create mode 100644 test/fullRestakeDelegator/FullRestakeFairHook.t.sol create mode 100644 test/fullRestakeDelegator/FullRestakeResetHook.t.sol create mode 100644 test/mocks/FakeDelegator.sol delete mode 100644 test/networkRestakeDelegator/NetworkRestakeRedistributionHook.t copy.sol create mode 100644 test/networkRestakeDelegator/NetworkRestakeRedistributionHook.t.sol create mode 100644 test/operatorSpecificDelegator/OperatorSpecificFairHook.t.sol create mode 100644 test/operatorSpecificDelegator/OperatorSpecificResetHook.t.sol diff --git a/src/contracts/fullRestakeDelegator/FullRestakeFairHook.sol b/src/contracts/fullRestakeDelegator/FullRestakeFairHook.sol new file mode 100644 index 0000000..58885db --- /dev/null +++ b/src/contracts/fullRestakeDelegator/FullRestakeFairHook.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.25; + +import {IFullRestakeFairHook} from "../../interfaces/fullRestakeDelegator/IFullRestakeFairHook.sol"; + +import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; +import {IEntity} from "@symbioticfi/core/src/interfaces/common/IEntity.sol"; +import {IFullRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/IFullRestakeDelegator.sol"; + +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; + +contract FullRestakeFairHook is IFullRestakeFairHook { + using Math for uint256; + + /** + * @inheritdoc IDelegatorHook + */ + function onSlash( + bytes32 subnetwork, + address operator, + uint256 slashedAmount, + uint48, /* captureTimestamp */ + bytes calldata /* data */ + ) external { + if (IEntity(msg.sender).TYPE() != 1) { + revert NotFullRestakeDelegator(); + } + + if (slashedAmount == 0) { + return; + } + + uint256 networkLimit = IFullRestakeDelegator(msg.sender).networkLimit(subnetwork); + if (networkLimit != 0) { + IFullRestakeDelegator(msg.sender).setNetworkLimit( + subnetwork, networkLimit - Math.min(slashedAmount, networkLimit) + ); + } + + uint256 operatorNetworkLimit = IFullRestakeDelegator(msg.sender).operatorNetworkLimit(subnetwork, operator); + if (operatorNetworkLimit != 0) { + IFullRestakeDelegator(msg.sender).setOperatorNetworkLimit( + subnetwork, operator, operatorNetworkLimit - Math.min(slashedAmount, operatorNetworkLimit) + ); + } + } +} diff --git a/src/contracts/fullRestakeDelegator/FullRestakeResetHook.sol b/src/contracts/fullRestakeDelegator/FullRestakeResetHook.sol new file mode 100644 index 0000000..6747173 --- /dev/null +++ b/src/contracts/fullRestakeDelegator/FullRestakeResetHook.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.25; + +import {IFullRestakeResetHook} from "../../interfaces/fullRestakeDelegator/IFullRestakeResetHook.sol"; + +import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; +import {IEntity} from "@symbioticfi/core/src/interfaces/common/IEntity.sol"; +import {IFullRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/IFullRestakeDelegator.sol"; +import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol"; + +import {CircularBuffer} from "@openzeppelin/contracts/utils/structs/CircularBuffer.sol"; +import {Time} from "@openzeppelin/contracts/utils/types/Time.sol"; + +contract FullRestakeResetHook is IFullRestakeResetHook { + using CircularBuffer for CircularBuffer.Bytes32CircularBuffer; + + /** + * @inheritdoc IFullRestakeResetHook + */ + uint48 public immutable PERIOD; + + /** + * @inheritdoc IFullRestakeResetHook + */ + uint256 public immutable SLASH_COUNT; + + mapping(address vault => mapping(address operator => CircularBuffer.Bytes32CircularBuffer buffer)) private + _slashings; + + constructor(uint48 period_, uint256 slashCount_) { + if (slashCount_ == 0) { + revert InvalidSlashCount(); + } + + PERIOD = period_; + SLASH_COUNT = slashCount_; + } + + /** + * @inheritdoc IDelegatorHook + */ + function onSlash( + bytes32 subnetwork, + address operator, + uint256, /* slashedAmount */ + uint48, /* captureTimestamp */ + bytes calldata /* data */ + ) external { + if (IEntity(msg.sender).TYPE() != 1) { + revert NotFullRestakeDelegator(); + } + + address vault = IFullRestakeDelegator(msg.sender).vault(); + + if (IVault(vault).delegator() != msg.sender) { + revert NotVaultDelegator(); + } + + uint256 slashCount_ = SLASH_COUNT; + if (_slashings[vault][operator].count() == 0) { + _slashings[vault][operator].setup(slashCount_); + } + + if (IFullRestakeDelegator(msg.sender).operatorNetworkLimit(subnetwork, operator) == 0) { + return; + } + + _slashings[vault][operator].push(bytes32(uint256(Time.timestamp()))); + + if ( + _slashings[vault][operator].count() == slashCount_ + && Time.timestamp() - uint256(_slashings[vault][operator].last(slashCount_ - 1)) <= PERIOD + ) { + IFullRestakeDelegator(msg.sender).setOperatorNetworkLimit(subnetwork, operator, 0); + } + } +} diff --git a/src/contracts/networkRestakeDelegator/NetworkRestakeResetHook.sol b/src/contracts/networkRestakeDelegator/NetworkRestakeResetHook.sol index a08f50a..1057aeb 100644 --- a/src/contracts/networkRestakeDelegator/NetworkRestakeResetHook.sol +++ b/src/contracts/networkRestakeDelegator/NetworkRestakeResetHook.sol @@ -6,17 +6,23 @@ import {INetworkRestakeResetHook} from "../../interfaces/networkRestakeDelegator import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; import {IEntity} from "@symbioticfi/core/src/interfaces/common/IEntity.sol"; import {INetworkRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/INetworkRestakeDelegator.sol"; +import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol"; import {CircularBuffer} from "@openzeppelin/contracts/utils/structs/CircularBuffer.sol"; -import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {Time} from "@openzeppelin/contracts/utils/types/Time.sol"; contract NetworkRestakeResetHook is INetworkRestakeResetHook { - using Math for uint256; using CircularBuffer for CircularBuffer.Bytes32CircularBuffer; - uint48 public period; - uint256 public slashCount; + /** + * @inheritdoc INetworkRestakeResetHook + */ + uint48 public immutable PERIOD; + + /** + * @inheritdoc INetworkRestakeResetHook + */ + uint256 public immutable SLASH_COUNT; mapping(address vault => mapping(address operator => CircularBuffer.Bytes32CircularBuffer buffer)) private _slashings; @@ -26,8 +32,8 @@ contract NetworkRestakeResetHook is INetworkRestakeResetHook { revert InvalidSlashCount(); } - period = period_; - slashCount = slashCount_; + PERIOD = period_; + SLASH_COUNT = slashCount_; } /** @@ -36,9 +42,9 @@ contract NetworkRestakeResetHook is INetworkRestakeResetHook { function onSlash( bytes32 subnetwork, address operator, - uint256 slashedAmount, - uint48 captureTimestamp, - bytes calldata data + uint256, /* slashedAmount */ + uint48, /* captureTimestamp */ + bytes calldata /* data */ ) external { if (IEntity(msg.sender).TYPE() != 0) { revert NotNetworkRestakeDelegator(); @@ -46,16 +52,24 @@ contract NetworkRestakeResetHook is INetworkRestakeResetHook { address vault = INetworkRestakeDelegator(msg.sender).vault(); - uint256 slashCount_ = slashCount; + if (IVault(vault).delegator() != msg.sender) { + revert NotVaultDelegator(); + } + + uint256 slashCount_ = SLASH_COUNT; if (_slashings[vault][operator].count() == 0) { _slashings[vault][operator].setup(slashCount_); } + if (INetworkRestakeDelegator(msg.sender).operatorNetworkShares(subnetwork, operator) == 0) { + return; + } + _slashings[vault][operator].push(bytes32(uint256(Time.timestamp()))); if ( _slashings[vault][operator].count() == slashCount_ - && Time.timestamp() - uint256(_slashings[vault][operator].last(slashCount_ - 1)) <= period + && Time.timestamp() - uint256(_slashings[vault][operator].last(slashCount_ - 1)) <= PERIOD ) { INetworkRestakeDelegator(msg.sender).setOperatorNetworkShares(subnetwork, operator, 0); } diff --git a/src/contracts/operatorSpecificDelegator/OperatorSpecificFairHook.sol b/src/contracts/operatorSpecificDelegator/OperatorSpecificFairHook.sol new file mode 100644 index 0000000..014589a --- /dev/null +++ b/src/contracts/operatorSpecificDelegator/OperatorSpecificFairHook.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.25; + +import {IOperatorSpecificFairHook} from "../../interfaces/operatorSpecificDelegator/IOperatorSpecificFairHook.sol"; + +import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; +import {IEntity} from "@symbioticfi/core/src/interfaces/common/IEntity.sol"; +import {IOperatorSpecificDelegator} from "@symbioticfi/core/src/interfaces/delegator/IOperatorSpecificDelegator.sol"; + +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; + +contract OperatorSpecificFairHook is IOperatorSpecificFairHook { + using Math for uint256; + + /** + * @inheritdoc IDelegatorHook + */ + function onSlash( + bytes32 subnetwork, + address, /* operator */ + uint256 slashedAmount, + uint48, /* captureTimestamp */ + bytes calldata /* data */ + ) external { + if (IEntity(msg.sender).TYPE() != 2) { + revert NotOperatorSpecificDelegator(); + } + + if (slashedAmount == 0) { + return; + } + + uint256 networkLimit = IOperatorSpecificDelegator(msg.sender).networkLimit(subnetwork); + if (networkLimit != 0) { + IOperatorSpecificDelegator(msg.sender).setNetworkLimit( + subnetwork, networkLimit - Math.min(slashedAmount, networkLimit) + ); + } + } +} diff --git a/src/contracts/operatorSpecificDelegator/OperatorSpecificResetHook.sol b/src/contracts/operatorSpecificDelegator/OperatorSpecificResetHook.sol new file mode 100644 index 0000000..25118f8 --- /dev/null +++ b/src/contracts/operatorSpecificDelegator/OperatorSpecificResetHook.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.25; + +import {IOperatorSpecificResetHook} from "../../interfaces/operatorSpecificDelegator/IOperatorSpecificResetHook.sol"; + +import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; +import {IEntity} from "@symbioticfi/core/src/interfaces/common/IEntity.sol"; +import {IOperatorSpecificDelegator} from "@symbioticfi/core/src/interfaces/delegator/IOperatorSpecificDelegator.sol"; +import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol"; + +import {CircularBuffer} from "@openzeppelin/contracts/utils/structs/CircularBuffer.sol"; +import {Time} from "@openzeppelin/contracts/utils/types/Time.sol"; + +contract OperatorSpecificResetHook is IOperatorSpecificResetHook { + using CircularBuffer for CircularBuffer.Bytes32CircularBuffer; + + /** + * @inheritdoc IOperatorSpecificResetHook + */ + uint48 public immutable PERIOD; + + /** + * @inheritdoc IOperatorSpecificResetHook + */ + uint256 public immutable SLASH_COUNT; + + mapping(address vault => CircularBuffer.Bytes32CircularBuffer buffer) private _slashings; + + constructor(uint48 period_, uint256 slashCount_) { + if (slashCount_ == 0) { + revert InvalidSlashCount(); + } + + PERIOD = period_; + SLASH_COUNT = slashCount_; + } + + /** + * @inheritdoc IDelegatorHook + */ + function onSlash( + bytes32 subnetwork, + address, /* operator */ + uint256, /* slashedAmount */ + uint48, /* captureTimestamp */ + bytes calldata /* data */ + ) external { + if (IEntity(msg.sender).TYPE() != 2) { + revert NotOperatorSpecificDelegator(); + } + + address vault = IOperatorSpecificDelegator(msg.sender).vault(); + + if (IVault(vault).delegator() != msg.sender) { + revert NotVaultDelegator(); + } + + uint256 slashCount_ = SLASH_COUNT; + if (_slashings[vault].count() == 0) { + _slashings[vault].setup(slashCount_); + } + + if (IOperatorSpecificDelegator(msg.sender).networkLimit(subnetwork) == 0) { + return; + } + + _slashings[vault].push(bytes32(uint256(Time.timestamp()))); + + if ( + _slashings[vault].count() == slashCount_ + && Time.timestamp() - uint256(_slashings[vault].last(slashCount_ - 1)) <= PERIOD + ) { + IOperatorSpecificDelegator(msg.sender).setNetworkLimit(subnetwork, 0); + } + } +} diff --git a/src/interfaces/fullRestakeDelegator/IFullRestakeFairHook.sol b/src/interfaces/fullRestakeDelegator/IFullRestakeFairHook.sol new file mode 100644 index 0000000..8ae8444 --- /dev/null +++ b/src/interfaces/fullRestakeDelegator/IFullRestakeFairHook.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; + +interface IFullRestakeFairHook is IDelegatorHook { + error NotFullRestakeDelegator(); +} diff --git a/src/interfaces/fullRestakeDelegator/IFullRestakeResetHook.sol b/src/interfaces/fullRestakeDelegator/IFullRestakeResetHook.sol new file mode 100644 index 0000000..45961cd --- /dev/null +++ b/src/interfaces/fullRestakeDelegator/IFullRestakeResetHook.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; + +interface IFullRestakeResetHook is IDelegatorHook { + error InvalidSlashCount(); + error NotFullRestakeDelegator(); + error NotVaultDelegator(); + + /** + * @notice Get a period during which the slashing should occur to reset the operator's stake. + * @return threshold period + */ + function PERIOD() external view returns (uint48); + + /** + * @notice Get a number of slashes that should occur during the PERIOD to reset the operator's stake. + * @return threshold count + */ + function SLASH_COUNT() external view returns (uint256); +} diff --git a/src/interfaces/networkRestakeDelegator/INetworkRestakeResetHook.sol b/src/interfaces/networkRestakeDelegator/INetworkRestakeResetHook.sol index a6cbe01..64e7aee 100644 --- a/src/interfaces/networkRestakeDelegator/INetworkRestakeResetHook.sol +++ b/src/interfaces/networkRestakeDelegator/INetworkRestakeResetHook.sol @@ -6,4 +6,17 @@ import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelega interface INetworkRestakeResetHook is IDelegatorHook { error InvalidSlashCount(); error NotNetworkRestakeDelegator(); + error NotVaultDelegator(); + + /** + * @notice Get a period during which the slashing should occur to reset the operator's stake. + * @return threshold period + */ + function PERIOD() external view returns (uint48); + + /** + * @notice Get a number of slashes that should occur during the PERIOD to reset the operator's stake. + * @return threshold count + */ + function SLASH_COUNT() external view returns (uint256); } diff --git a/src/interfaces/operatorSpecificDelegator/IOperatorSpecificFairHook.sol b/src/interfaces/operatorSpecificDelegator/IOperatorSpecificFairHook.sol new file mode 100644 index 0000000..e142c62 --- /dev/null +++ b/src/interfaces/operatorSpecificDelegator/IOperatorSpecificFairHook.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; + +interface IOperatorSpecificFairHook is IDelegatorHook { + error NotOperatorSpecificDelegator(); +} diff --git a/src/interfaces/operatorSpecificDelegator/IOperatorSpecificResetHook.sol b/src/interfaces/operatorSpecificDelegator/IOperatorSpecificResetHook.sol new file mode 100644 index 0000000..97b3f7d --- /dev/null +++ b/src/interfaces/operatorSpecificDelegator/IOperatorSpecificResetHook.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; + +interface IOperatorSpecificResetHook is IDelegatorHook { + error InvalidSlashCount(); + error NotOperatorSpecificDelegator(); + error NotVaultDelegator(); + + /** + * @notice Get a period during which the slashing should occur to reset the operator's stake. + * @return threshold period + */ + function PERIOD() external view returns (uint48); + + /** + * @notice Get a number of slashes that should occur during the PERIOD to reset the operator's stake. + * @return threshold count + */ + function SLASH_COUNT() external view returns (uint256); +} diff --git a/test/fullRestakeDelegator/FullRestakeFairHook.t.sol b/test/fullRestakeDelegator/FullRestakeFairHook.t.sol new file mode 100644 index 0000000..2c2b1fa --- /dev/null +++ b/test/fullRestakeDelegator/FullRestakeFairHook.t.sol @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.25; + +import {POCBaseTest} from "@symbioticfi/core/test/POCBase.t.sol"; +import {Vault} from "@symbioticfi/core/src/contracts/vault/Vault.sol"; +import {FullRestakeDelegator} from "@symbioticfi/core/src/contracts/delegator/FullRestakeDelegator.sol"; +import {Slasher} from "@symbioticfi/core/src/contracts/slasher/Slasher.sol"; +import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol"; +import {ISlasher} from "@symbioticfi/core/src/interfaces/slasher/ISlasher.sol"; +import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol"; +import {IFullRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/IFullRestakeDelegator.sol"; +import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol"; +import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigurator.sol"; + +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol"; + +import {FullRestakeFairHook} from "../../src/contracts/fullRestakeDelegator/FullRestakeFairHook.sol"; + +contract FullRestakeFairHookTest is POCBaseTest { + using Math for uint256; + using Subnetwork for bytes32; + using Subnetwork for address; + + Vault public vault0; + FullRestakeDelegator public delegator0; + Slasher public slasher0; + + function setUp() public override { + super.setUp(); + } + + function test_SlashWithHook( + uint256 depositAmount, + uint256 operatorNetworkLimit1, + uint256 operatorNetworkLimit2, + uint256 slashAmount1, + uint256 slashAmount2, + uint256 networkLimit + ) public { + depositAmount = bound(depositAmount, 100, 100 * 10 ** 18); + operatorNetworkLimit1 = bound(operatorNetworkLimit1, 1, type(uint256).max / 2); + operatorNetworkLimit2 = bound(operatorNetworkLimit2, 1, type(uint256).max / 2); + slashAmount1 = bound(slashAmount1, 1, type(uint256).max); + slashAmount2 = bound(slashAmount2, 1, type(uint256).max); + networkLimit = bound(networkLimit, 1, depositAmount); + + uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + blockTimestamp = blockTimestamp + 1_720_700_948; + vm.warp(blockTimestamp); + + address hook = address(new FullRestakeFairHook()); + + vm.startPrank(alice); + delegator2.setHook(hook); + delegator2.grantRole(delegator2.NETWORK_LIMIT_SET_ROLE(), hook); + delegator2.grantRole(delegator2.OPERATOR_NETWORK_LIMIT_SET_ROLE(), hook); + vm.stopPrank(); + + address network = alice; + _registerNetwork(network, alice); + _setMaxNetworkLimit(address(delegator2), network, 0, type(uint256).max); + + _registerOperator(alice); + _registerOperator(bob); + + _optInOperatorVault(vault2, alice); + + _optInOperatorNetwork(alice, address(network)); + + _optInOperatorVault(vault2, bob); + + _optInOperatorNetwork(bob, address(network)); + + _deposit(vault2, alice, depositAmount); + + _setNetworkLimitFull(delegator2, alice, network, networkLimit); + + _setOperatorNetworkLimit(delegator2, alice, network, alice, operatorNetworkLimit1); + _setOperatorNetworkLimit(delegator2, alice, network, bob, operatorNetworkLimit2); + + assertEq(delegator2.networkLimit(network.subnetwork(0)), networkLimit); + assertEq(delegator2.operatorNetworkLimit(network.subnetwork(0), alice), operatorNetworkLimit1); + assertEq(delegator2.operatorNetworkLimit(network.subnetwork(0), bob), operatorNetworkLimit2); + + blockTimestamp = blockTimestamp + 1; + vm.warp(blockTimestamp); + + uint256 stakeAtAlice = delegator2.stakeAt(network.subnetwork(0), alice, uint48(blockTimestamp - 1), ""); + + vm.assume(stakeAtAlice > slashAmount1); + uint256 slashedAmount1 = _slash(slasher2, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + uint256 slashedOperatorLimit1 = slashedAmount1; + + assertEq(delegator2.networkLimit(network.subnetwork(0)), networkLimit - slashedAmount1); + assertEq( + delegator2.operatorNetworkLimit(network.subnetwork(0), alice), operatorNetworkLimit1 - slashedOperatorLimit1 + ); + assertEq(delegator2.operatorNetworkLimit(network.subnetwork(0), bob), operatorNetworkLimit2); + + uint256 slashedAmount2 = _slash(slasher2, alice, network, alice, slashAmount2, uint48(blockTimestamp - 1), ""); + + uint256 slashedOperatorLimit2 = slashedAmount2; + + assertEq(delegator2.networkLimit(network.subnetwork(0)), networkLimit - slashedAmount1 - slashedAmount2); + assertApproxEqAbs( + delegator2.operatorNetworkLimit(network.subnetwork(0), alice), + operatorNetworkLimit1 - slashedOperatorLimit1 + - Math.min(operatorNetworkLimit1 - slashedOperatorLimit1, slashedOperatorLimit2), + 1 + ); + assertEq(delegator2.operatorNetworkLimit(network.subnetwork(0), bob), operatorNetworkLimit2); + } + + function test_SlashWithHookRevertNotFullRestakeDelegator( + uint256 depositAmount, + uint256 operatorNetworkLimit1, + uint256 operatorNetworkLimit2, + uint256 slashAmount1, + uint256 slashAmount2, + uint256 networkLimit + ) public { + depositAmount = bound(depositAmount, 100, 100 * 10 ** 18); + operatorNetworkLimit1 = bound(operatorNetworkLimit1, 1, type(uint256).max / 2); + operatorNetworkLimit2 = bound(operatorNetworkLimit2, 1, type(uint256).max / 2); + slashAmount1 = bound(slashAmount1, 1, type(uint256).max); + networkLimit = bound(networkLimit, 1, depositAmount); + + uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + blockTimestamp = blockTimestamp + 1_720_700_948; + vm.warp(blockTimestamp); + + address hook = address(new FullRestakeFairHook()); + + address fullRestakeDelegatorImpl = address( + new FullRestakeDelegator( + address(networkRegistry), + address(vaultFactory), + address(operatorVaultOptInService), + address(operatorNetworkOptInService), + address(delegatorFactory), + delegatorFactory.totalTypes() + ) + ); + delegatorFactory.whitelist(fullRestakeDelegatorImpl); + + address[] memory networkLimitSetRoleHolders = new address[](1); + networkLimitSetRoleHolders[0] = alice; + address[] memory operatorNetworkLimitSetRoleHolders = new address[](1); + operatorNetworkLimitSetRoleHolders[0] = alice; + (address vault_, address delegator_, address slasher_) = vaultConfigurator.create( + IVaultConfigurator.InitParams({ + version: vaultFactory.lastVersion(), + owner: alice, + vaultParams: abi.encode( + IVault.InitParams({ + collateral: address(collateral), + burner: address(0xdEaD), + epochDuration: 7 days, + depositWhitelist: false, + isDepositLimit: false, + depositLimit: 0, + defaultAdminRoleHolder: alice, + depositWhitelistSetRoleHolder: alice, + depositorWhitelistRoleHolder: alice, + isDepositLimitSetRoleHolder: alice, + depositLimitSetRoleHolder: alice + }) + ), + delegatorIndex: 3, + delegatorParams: abi.encode( + IFullRestakeDelegator.InitParams({ + baseParams: IBaseDelegator.BaseParams({ + defaultAdminRoleHolder: alice, + hook: address(0), + hookSetRoleHolder: alice + }), + networkLimitSetRoleHolders: networkLimitSetRoleHolders, + operatorNetworkLimitSetRoleHolders: operatorNetworkLimitSetRoleHolders + }) + ), + withSlasher: true, + slasherIndex: 0, + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + }) + ); + + (vault0, delegator0, slasher0) = (Vault(vault_), FullRestakeDelegator(delegator_), Slasher(slasher_)); + + vm.startPrank(alice); + delegator0.setHook(hook); + delegator0.grantRole(delegator0.NETWORK_LIMIT_SET_ROLE(), hook); + delegator0.grantRole(delegator0.OPERATOR_NETWORK_LIMIT_SET_ROLE(), hook); + vm.stopPrank(); + + address network = alice; + _registerNetwork(network, alice); + _setMaxNetworkLimit(address(delegator0), network, 0, type(uint256).max); + + _registerOperator(alice); + _registerOperator(bob); + + _optInOperatorVault(vault0, alice); + + _optInOperatorNetwork(alice, address(network)); + + _optInOperatorVault(vault0, bob); + + _optInOperatorNetwork(bob, address(network)); + + _deposit(vault0, alice, depositAmount); + + _setNetworkLimitFull(delegator0, alice, network, networkLimit); + + _setOperatorNetworkLimit(delegator0, alice, network, alice, operatorNetworkLimit1); + _setOperatorNetworkLimit(delegator0, alice, network, bob, operatorNetworkLimit2); + + blockTimestamp = blockTimestamp + 1; + vm.warp(blockTimestamp); + + uint256 stakeAtAlice = delegator0.stakeAt(network.subnetwork(0), alice, uint48(blockTimestamp - 1), ""); + vm.assume(stakeAtAlice > slashAmount1); + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator0.networkLimit(network.subnetwork(0)), networkLimit); + assertEq(delegator0.operatorNetworkLimit(network.subnetwork(0), alice), operatorNetworkLimit1); + assertEq(delegator0.operatorNetworkLimit(network.subnetwork(0), bob), operatorNetworkLimit2); + } +} diff --git a/test/fullRestakeDelegator/FullRestakeResetHook.t.sol b/test/fullRestakeDelegator/FullRestakeResetHook.t.sol new file mode 100644 index 0000000..8e53ee6 --- /dev/null +++ b/test/fullRestakeDelegator/FullRestakeResetHook.t.sol @@ -0,0 +1,285 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.25; + +import {POCBaseTest} from "@symbioticfi/core/test/POCBase.t.sol"; +import {Vault} from "@symbioticfi/core/src/contracts/vault/Vault.sol"; +import {FullRestakeDelegator} from "@symbioticfi/core/src/contracts/delegator/FullRestakeDelegator.sol"; +import {Slasher} from "@symbioticfi/core/src/contracts/slasher/Slasher.sol"; +import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol"; +import {ISlasher} from "@symbioticfi/core/src/interfaces/slasher/ISlasher.sol"; +import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol"; +import {IFullRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/IFullRestakeDelegator.sol"; +import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol"; +import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigurator.sol"; + +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol"; + +import {FullRestakeResetHook} from "../../src/contracts/fullRestakeDelegator/FullRestakeResetHook.sol"; +import {IFullRestakeResetHook} from "../../src/interfaces/fullRestakeDelegator/IFullRestakeResetHook.sol"; +import {FakeDelegator} from "../mocks/FakeDelegator.sol"; + +contract FullRestakeResetHookTest is POCBaseTest { + using Math for uint256; + using Subnetwork for bytes32; + using Subnetwork for address; + + Vault public vault0; + FullRestakeDelegator public delegator0; + Slasher public slasher0; + + function setUp() public override { + super.setUp(); + } + + function test_SlashWithHook( + uint256 operatorNetworkLimit1 + ) public { + uint256 depositAmount = 1e18; + uint256 slashAmount1 = 100; + operatorNetworkLimit1 = bound(operatorNetworkLimit1, 1, type(uint256).max / 2); + + uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + blockTimestamp = blockTimestamp + 1_720_700_948; + vm.warp(blockTimestamp); + + address hook = address(new FullRestakeResetHook(7 days, 3)); + + vm.startPrank(alice); + delegator2.setHook(hook); + delegator2.grantRole(delegator2.OPERATOR_NETWORK_LIMIT_SET_ROLE(), hook); + vm.stopPrank(); + + address network = alice; + _registerNetwork(network, alice); + _setMaxNetworkLimit(address(delegator2), network, 0, type(uint256).max); + + _registerOperator(alice); + + _optInOperatorVault(vault2, alice); + + _optInOperatorNetwork(alice, address(network)); + + _deposit(vault2, alice, depositAmount); + + _setNetworkLimitFull(delegator2, alice, network, type(uint256).max); + + _setOperatorNetworkLimit(delegator2, alice, network, alice, operatorNetworkLimit1); + + assertEq(delegator2.networkLimit(network.subnetwork(0)), type(uint256).max); + assertEq(delegator2.operatorNetworkLimit(network.subnetwork(0), alice), operatorNetworkLimit1); + + blockTimestamp = blockTimestamp + 1; + vm.warp(blockTimestamp); + + _slash(slasher2, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator2.networkLimit(network.subnetwork(0)), type(uint256).max); + assertEq(delegator2.operatorNetworkLimit(network.subnetwork(0), alice), operatorNetworkLimit1); + + blockTimestamp = blockTimestamp + 7 days; + vm.warp(blockTimestamp); + + _slash(slasher2, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator2.networkLimit(network.subnetwork(0)), type(uint256).max); + assertEq(delegator2.operatorNetworkLimit(network.subnetwork(0), alice), operatorNetworkLimit1); + + blockTimestamp = blockTimestamp + 3 days; + vm.warp(blockTimestamp); + + _slash(slasher2, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator2.networkLimit(network.subnetwork(0)), type(uint256).max); + assertEq(delegator2.operatorNetworkLimit(network.subnetwork(0), alice), operatorNetworkLimit1); + + blockTimestamp = blockTimestamp + 5 days; + vm.warp(blockTimestamp); + + _slash(slasher2, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator2.networkLimit(network.subnetwork(0)), type(uint256).max); + assertEq(delegator2.operatorNetworkLimit(network.subnetwork(0), alice), operatorNetworkLimit1); + + blockTimestamp = blockTimestamp + 3 days; + vm.warp(blockTimestamp); + + _slash(slasher2, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator2.networkLimit(network.subnetwork(0)), type(uint256).max); + assertEq(delegator2.operatorNetworkLimit(network.subnetwork(0), alice), operatorNetworkLimit1); + + blockTimestamp = blockTimestamp + 3 days; + vm.warp(blockTimestamp); + + _slash(slasher2, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator2.networkLimit(network.subnetwork(0)), type(uint256).max); + assertEq(delegator2.operatorNetworkLimit(network.subnetwork(0), alice), 0); + } + + function test_SlashWithHookRevertNotFullRestakeDelegator( + uint256 operatorNetworkLimit1 + ) public { + uint256 depositAmount = 1e18; + uint256 slashAmount1 = 100; + operatorNetworkLimit1 = bound(operatorNetworkLimit1, 1, type(uint256).max / 2); + + uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + blockTimestamp = blockTimestamp + 1_720_700_948; + vm.warp(blockTimestamp); + + address hook = address(new FullRestakeResetHook(7 days, 3)); + + address fullRestakeDelegatorImpl = address( + new FullRestakeDelegator( + address(networkRegistry), + address(vaultFactory), + address(operatorVaultOptInService), + address(operatorNetworkOptInService), + address(delegatorFactory), + delegatorFactory.totalTypes() + ) + ); + delegatorFactory.whitelist(fullRestakeDelegatorImpl); + + address[] memory networkLimitSetRoleHolders = new address[](1); + networkLimitSetRoleHolders[0] = alice; + address[] memory operatorNetworkLimitSetRoleHolders = new address[](1); + operatorNetworkLimitSetRoleHolders[0] = alice; + (address vault_, address delegator_, address slasher_) = vaultConfigurator.create( + IVaultConfigurator.InitParams({ + version: vaultFactory.lastVersion(), + owner: alice, + vaultParams: abi.encode( + IVault.InitParams({ + collateral: address(collateral), + burner: address(0xdEaD), + epochDuration: 7 days, + depositWhitelist: false, + isDepositLimit: false, + depositLimit: 0, + defaultAdminRoleHolder: alice, + depositWhitelistSetRoleHolder: alice, + depositorWhitelistRoleHolder: alice, + isDepositLimitSetRoleHolder: alice, + depositLimitSetRoleHolder: alice + }) + ), + delegatorIndex: 3, + delegatorParams: abi.encode( + IFullRestakeDelegator.InitParams({ + baseParams: IBaseDelegator.BaseParams({ + defaultAdminRoleHolder: alice, + hook: address(0), + hookSetRoleHolder: alice + }), + networkLimitSetRoleHolders: networkLimitSetRoleHolders, + operatorNetworkLimitSetRoleHolders: operatorNetworkLimitSetRoleHolders + }) + ), + withSlasher: true, + slasherIndex: 0, + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + }) + ); + + (vault0, delegator0, slasher0) = (Vault(vault_), FullRestakeDelegator(delegator_), Slasher(slasher_)); + + vm.startPrank(alice); + delegator0.setHook(hook); + vm.stopPrank(); + + address network = alice; + _registerNetwork(network, alice); + _setMaxNetworkLimit(address(delegator0), network, 0, type(uint256).max); + + _registerOperator(alice); + + _optInOperatorVault(vault0, alice); + + _optInOperatorNetwork(alice, address(network)); + + _deposit(vault0, alice, depositAmount); + + _setNetworkLimitFull(delegator0, alice, network, type(uint256).max); + + _setOperatorNetworkLimit(delegator0, alice, network, alice, operatorNetworkLimit1); + + blockTimestamp = blockTimestamp + 1; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + blockTimestamp = blockTimestamp + 7 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + blockTimestamp = blockTimestamp + 3 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + blockTimestamp = blockTimestamp + 5 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + blockTimestamp = blockTimestamp + 3 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + blockTimestamp = blockTimestamp + 3 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator0.networkLimit(network.subnetwork(0)), type(uint256).max); + assertEq(delegator0.operatorNetworkLimit(network.subnetwork(0), alice), operatorNetworkLimit1); + } + + function test_SlashWithHookRevertNotVaultDelegator( + uint256 operatorNetworkLimit1 + ) public { + uint256 depositAmount = 1e18; + uint256 slashAmount1 = 100; + operatorNetworkLimit1 = bound(operatorNetworkLimit1, 1, type(uint256).max / 2); + + uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + blockTimestamp = blockTimestamp + 1_720_700_948; + vm.warp(blockTimestamp); + + address hook = address(new FullRestakeResetHook(7 days, 3)); + + vm.startPrank(alice); + delegator2.setHook(hook); + delegator2.grantRole(delegator2.OPERATOR_NETWORK_LIMIT_SET_ROLE(), hook); + vm.stopPrank(); + + address network = alice; + _registerNetwork(network, alice); + _setMaxNetworkLimit(address(delegator2), network, 0, type(uint256).max); + + _registerOperator(alice); + + _optInOperatorVault(vault2, alice); + + _optInOperatorNetwork(alice, address(network)); + + _deposit(vault2, alice, depositAmount); + + _setNetworkLimitFull(delegator2, alice, network, type(uint256).max); + + _setOperatorNetworkLimit(delegator2, alice, network, alice, operatorNetworkLimit1); + + blockTimestamp = blockTimestamp + 1; + vm.warp(blockTimestamp); + + FakeDelegator fakeDelegator = new FakeDelegator(address(vault2), 1); + vm.expectRevert(IFullRestakeResetHook.NotVaultDelegator.selector); + fakeDelegator.onSlash(hook, network.subnetwork(0), alice, slashAmount1, uint48(blockTimestamp - 1), ""); + } +} diff --git a/test/mocks/FakeDelegator.sol b/test/mocks/FakeDelegator.sol new file mode 100644 index 0000000..f9c66c8 --- /dev/null +++ b/test/mocks/FakeDelegator.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.25; + +import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; + +contract FakeDelegator { + address public vault; + + uint64 public TYPE; + + constructor(address vault_, uint64 type_) { + vault = vault_; + + TYPE = type_; + } + + function onSlash( + address target, + bytes32 subnetwork, + address operator, + uint256 slashedAmount, + uint48 captureTimestamp, + bytes calldata data + ) external { + IDelegatorHook(target).onSlash(subnetwork, operator, slashedAmount, captureTimestamp, data); + } +} diff --git a/test/networkRestakeDelegator/NetworkRestakeFairHook.t.sol b/test/networkRestakeDelegator/NetworkRestakeFairHook.t.sol index a4e7258..fb257af 100644 --- a/test/networkRestakeDelegator/NetworkRestakeFairHook.t.sol +++ b/test/networkRestakeDelegator/NetworkRestakeFairHook.t.sol @@ -3,6 +3,15 @@ pragma solidity 0.8.25; import {POCBaseTest} from "@symbioticfi/core/test/POCBase.t.sol"; +import {Vault} from "@symbioticfi/core/src/contracts/vault/Vault.sol"; +import {NetworkRestakeDelegator} from "@symbioticfi/core/src/contracts/delegator/NetworkRestakeDelegator.sol"; +import {Slasher} from "@symbioticfi/core/src/contracts/slasher/Slasher.sol"; +import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol"; +import {ISlasher} from "@symbioticfi/core/src/interfaces/slasher/ISlasher.sol"; +import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol"; +import {INetworkRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/INetworkRestakeDelegator.sol"; +import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol"; +import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigurator.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol"; @@ -14,6 +23,10 @@ contract NetworkRestakeFairHookTest is POCBaseTest { using Subnetwork for bytes32; using Subnetwork for address; + Vault public vault0; + NetworkRestakeDelegator public delegator0; + Slasher public slasher0; + function setUp() public override { super.setUp(); } @@ -116,4 +129,123 @@ contract NetworkRestakeFairHookTest is POCBaseTest { assertEq(delegator1.operatorNetworkShares(network.subnetwork(0), bob), operatorNetworkShares2); assertLe(stakeAtBob, delegator1.stakeAt(network.subnetwork(0), bob, uint48(blockTimestamp), "")); } + + function test_SlashWithHookRevertNotNetworkRestakeDelegator( + uint256 depositAmount, + uint256 operatorNetworkShares1, + uint256 operatorNetworkShares2, + uint256 slashAmount1, + uint256 slashAmount2, + uint256 networkLimit + ) public { + depositAmount = bound(depositAmount, 100, 100 * 10 ** 18); + operatorNetworkShares1 = bound(operatorNetworkShares1, 1, type(uint256).max / 2); + operatorNetworkShares2 = bound(operatorNetworkShares2, 1, type(uint256).max / 2); + slashAmount1 = bound(slashAmount1, 1, type(uint256).max); + networkLimit = bound(networkLimit, 1, depositAmount); + + uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + blockTimestamp = blockTimestamp + 1_720_700_948; + vm.warp(blockTimestamp); + + address hook = address(new NetworkRestakeFairHook()); + + address networkRestakeDelegatorImpl = address( + new NetworkRestakeDelegator( + address(networkRegistry), + address(vaultFactory), + address(operatorVaultOptInService), + address(operatorNetworkOptInService), + address(delegatorFactory), + delegatorFactory.totalTypes() + ) + ); + delegatorFactory.whitelist(networkRestakeDelegatorImpl); + + address[] memory networkLimitSetRoleHolders = new address[](1); + networkLimitSetRoleHolders[0] = alice; + address[] memory operatorNetworkSharesSetRoleHolders = new address[](1); + operatorNetworkSharesSetRoleHolders[0] = alice; + (address vault_, address delegator_, address slasher_) = vaultConfigurator.create( + IVaultConfigurator.InitParams({ + version: vaultFactory.lastVersion(), + owner: alice, + vaultParams: abi.encode( + IVault.InitParams({ + collateral: address(collateral), + burner: address(0xdEaD), + epochDuration: 7 days, + depositWhitelist: false, + isDepositLimit: false, + depositLimit: 0, + defaultAdminRoleHolder: alice, + depositWhitelistSetRoleHolder: alice, + depositorWhitelistRoleHolder: alice, + isDepositLimitSetRoleHolder: alice, + depositLimitSetRoleHolder: alice + }) + ), + delegatorIndex: 3, + delegatorParams: abi.encode( + INetworkRestakeDelegator.InitParams({ + baseParams: IBaseDelegator.BaseParams({ + defaultAdminRoleHolder: alice, + hook: address(0), + hookSetRoleHolder: alice + }), + networkLimitSetRoleHolders: networkLimitSetRoleHolders, + operatorNetworkSharesSetRoleHolders: operatorNetworkSharesSetRoleHolders + }) + ), + withSlasher: true, + slasherIndex: 0, + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + }) + ); + + (vault0, delegator0, slasher0) = (Vault(vault_), NetworkRestakeDelegator(delegator_), Slasher(slasher_)); + + vm.startPrank(alice); + delegator0.setHook(hook); + delegator0.grantRole(delegator0.NETWORK_LIMIT_SET_ROLE(), hook); + delegator0.grantRole(delegator0.OPERATOR_NETWORK_SHARES_SET_ROLE(), hook); + vm.stopPrank(); + + address network = alice; + _registerNetwork(network, alice); + _setMaxNetworkLimit(address(delegator0), network, 0, type(uint256).max); + + _registerOperator(alice); + _registerOperator(bob); + + _optInOperatorVault(vault0, alice); + + _optInOperatorNetwork(alice, address(network)); + + _optInOperatorVault(vault0, bob); + + _optInOperatorNetwork(bob, address(network)); + + _deposit(vault0, alice, depositAmount); + + _setNetworkLimitNetwork(delegator0, alice, network, networkLimit); + + _setOperatorNetworkShares(delegator0, alice, network, alice, operatorNetworkShares1); + _setOperatorNetworkShares(delegator0, alice, network, bob, operatorNetworkShares2); + + blockTimestamp = blockTimestamp + 1; + vm.warp(blockTimestamp); + + uint256 stakeAtAlice = delegator0.stakeAt(network.subnetwork(0), alice, uint48(blockTimestamp - 1), ""); + vm.assume(stakeAtAlice > slashAmount1); + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator0.networkLimit(network.subnetwork(0)), networkLimit); + assertEq( + delegator0.totalOperatorNetworkShares(network.subnetwork(0)), + operatorNetworkShares1 + operatorNetworkShares2 + ); + assertEq(delegator0.operatorNetworkShares(network.subnetwork(0), alice), operatorNetworkShares1); + assertEq(delegator0.operatorNetworkShares(network.subnetwork(0), bob), operatorNetworkShares2); + } } diff --git a/test/networkRestakeDelegator/NetworkRestakeRedistributionHook.t copy.sol b/test/networkRestakeDelegator/NetworkRestakeRedistributionHook.t copy.sol deleted file mode 100644 index 2dd44bc..0000000 --- a/test/networkRestakeDelegator/NetworkRestakeRedistributionHook.t copy.sol +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity 0.8.25; - -import {POCBaseTest} from "@symbioticfi/core/test/POCBase.t.sol"; - -import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; -import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol"; - -import {NetworkRestakeRedistributionHook} from - "../../src/contracts/networkRestakeDelegator/NetworkRestakeRedistributionHook.sol"; - -contract NetworkRestakeRedistributionHookTest is POCBaseTest { - using Math for uint256; - using Subnetwork for bytes32; - using Subnetwork for address; - - function setUp() public override { - super.setUp(); - } - - function test_SlashWithHook( - uint256 depositAmount, - uint256 operatorNetworkShares1, - uint256 slashAmount1, - uint256 slashAmount2 - ) public { - depositAmount = bound(depositAmount, 1, 100 * 10 ** 18); - operatorNetworkShares1 = bound(operatorNetworkShares1, 1, type(uint256).max / 2); - slashAmount1 = bound(slashAmount1, 1, type(uint256).max); - slashAmount2 = bound(slashAmount2, 1, type(uint256).max); - vm.assume(slashAmount1 < Math.min(depositAmount, Math.min(type(uint256).max, operatorNetworkShares1))); - - uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; - blockTimestamp = blockTimestamp + 1_720_700_948; - vm.warp(blockTimestamp); - - address hook = address(new NetworkRestakeRedistributionHook()); - - vm.startPrank(alice); - delegator1.setHook(hook); - delegator1.grantRole(delegator1.OPERATOR_NETWORK_SHARES_SET_ROLE(), hook); - vm.stopPrank(); - - address network = alice; - _registerNetwork(network, alice); - _setMaxNetworkLimit(address(delegator1), network, 0, type(uint256).max); - - _registerOperator(alice); - - _optInOperatorVault(vault1, alice); - - _optInOperatorNetwork(alice, address(network)); - - _deposit(vault1, alice, depositAmount); - - _setNetworkLimitNetwork(delegator1, alice, network, type(uint256).max); - - _setOperatorNetworkShares(delegator1, alice, network, alice, operatorNetworkShares1); - - assertEq(delegator1.networkLimit(network.subnetwork(0)), type(uint256).max); - assertEq(delegator1.totalOperatorNetworkShares(network.subnetwork(0)), operatorNetworkShares1); - assertEq(delegator1.operatorNetworkShares(network.subnetwork(0), alice), operatorNetworkShares1); - - blockTimestamp = blockTimestamp + 1; - vm.warp(blockTimestamp); - - uint256 slashableStake = slasher1.slashableStake(network.subnetwork(0), alice, uint48(blockTimestamp - 1), ""); - uint256 slashedAmount = _slash(slasher1, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); - - uint256 operatorShares = - operatorNetworkShares1 - slashedAmount.mulDiv(operatorNetworkShares1, slashableStake, Math.Rounding.Ceil); - - assertEq(delegator1.networkLimit(network.subnetwork(0)), type(uint256).max); - assertEq(delegator1.totalOperatorNetworkShares(network.subnetwork(0)), operatorShares); - assertEq(delegator1.operatorNetworkShares(network.subnetwork(0), alice), operatorShares); - - slashableStake = slasher1.slashableStake(network.subnetwork(0), alice, uint48(blockTimestamp - 1), ""); - slashedAmount = _slash(slasher1, alice, network, alice, slashAmount2, uint48(blockTimestamp - 1), ""); - - operatorShares = operatorShares - slashedAmount.mulDiv(operatorShares, slashableStake, Math.Rounding.Ceil); - - assertEq(delegator1.networkLimit(network.subnetwork(0)), type(uint256).max); - assertEq(delegator1.totalOperatorNetworkShares(network.subnetwork(0)), operatorShares); - assertEq(delegator1.operatorNetworkShares(network.subnetwork(0), alice), operatorShares); - } -} diff --git a/test/networkRestakeDelegator/NetworkRestakeRedistributionHook.t.sol b/test/networkRestakeDelegator/NetworkRestakeRedistributionHook.t.sol new file mode 100644 index 0000000..9616033 --- /dev/null +++ b/test/networkRestakeDelegator/NetworkRestakeRedistributionHook.t.sol @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.25; + +import {POCBaseTest} from "@symbioticfi/core/test/POCBase.t.sol"; +import {Vault} from "@symbioticfi/core/src/contracts/vault/Vault.sol"; +import {NetworkRestakeDelegator} from "@symbioticfi/core/src/contracts/delegator/NetworkRestakeDelegator.sol"; +import {Slasher} from "@symbioticfi/core/src/contracts/slasher/Slasher.sol"; +import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol"; +import {ISlasher} from "@symbioticfi/core/src/interfaces/slasher/ISlasher.sol"; +import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol"; +import {INetworkRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/INetworkRestakeDelegator.sol"; +import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol"; +import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigurator.sol"; + +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol"; + +import {NetworkRestakeRedistributionHook} from + "../../src/contracts/networkRestakeDelegator/NetworkRestakeRedistributionHook.sol"; + +contract NetworkRestakeRedistributionHookTest is POCBaseTest { + using Math for uint256; + using Subnetwork for bytes32; + using Subnetwork for address; + + Vault public vault0; + NetworkRestakeDelegator public delegator0; + Slasher public slasher0; + + function setUp() public override { + super.setUp(); + } + + function test_SlashWithHook( + uint256 depositAmount, + uint256 operatorNetworkShares1, + uint256 slashAmount1, + uint256 slashAmount2 + ) public { + depositAmount = bound(depositAmount, 1, 100 * 10 ** 18); + operatorNetworkShares1 = bound(operatorNetworkShares1, 1, type(uint256).max / 2); + slashAmount1 = bound(slashAmount1, 1, type(uint256).max); + slashAmount2 = bound(slashAmount2, 1, type(uint256).max); + vm.assume(slashAmount1 < Math.min(depositAmount, Math.min(type(uint256).max, operatorNetworkShares1))); + + uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + blockTimestamp = blockTimestamp + 1_720_700_948; + vm.warp(blockTimestamp); + + address hook = address(new NetworkRestakeRedistributionHook()); + + vm.startPrank(alice); + delegator1.setHook(hook); + delegator1.grantRole(delegator1.OPERATOR_NETWORK_SHARES_SET_ROLE(), hook); + vm.stopPrank(); + + address network = alice; + _registerNetwork(network, alice); + _setMaxNetworkLimit(address(delegator1), network, 0, type(uint256).max); + + _registerOperator(alice); + + _optInOperatorVault(vault1, alice); + + _optInOperatorNetwork(alice, address(network)); + + _deposit(vault1, alice, depositAmount); + + _setNetworkLimitNetwork(delegator1, alice, network, type(uint256).max); + + _setOperatorNetworkShares(delegator1, alice, network, alice, operatorNetworkShares1); + + assertEq(delegator1.networkLimit(network.subnetwork(0)), type(uint256).max); + assertEq(delegator1.totalOperatorNetworkShares(network.subnetwork(0)), operatorNetworkShares1); + assertEq(delegator1.operatorNetworkShares(network.subnetwork(0), alice), operatorNetworkShares1); + + blockTimestamp = blockTimestamp + 1; + vm.warp(blockTimestamp); + + uint256 slashableStake = slasher1.slashableStake(network.subnetwork(0), alice, uint48(blockTimestamp - 1), ""); + uint256 slashedAmount = _slash(slasher1, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + uint256 operatorShares = + operatorNetworkShares1 - slashedAmount.mulDiv(operatorNetworkShares1, slashableStake, Math.Rounding.Ceil); + + assertEq(delegator1.networkLimit(network.subnetwork(0)), type(uint256).max); + assertEq(delegator1.totalOperatorNetworkShares(network.subnetwork(0)), operatorShares); + assertEq(delegator1.operatorNetworkShares(network.subnetwork(0), alice), operatorShares); + + slashableStake = slasher1.slashableStake(network.subnetwork(0), alice, uint48(blockTimestamp - 1), ""); + slashedAmount = _slash(slasher1, alice, network, alice, slashAmount2, uint48(blockTimestamp - 1), ""); + + operatorShares = operatorShares - slashedAmount.mulDiv(operatorShares, slashableStake, Math.Rounding.Ceil); + + assertEq(delegator1.networkLimit(network.subnetwork(0)), type(uint256).max); + assertEq(delegator1.totalOperatorNetworkShares(network.subnetwork(0)), operatorShares); + assertEq(delegator1.operatorNetworkShares(network.subnetwork(0), alice), operatorShares); + } + + function test_SlashWithHookRevertNotNetworkRestakeDelegator( + uint256 depositAmount, + uint256 operatorNetworkShares1, + uint256 slashAmount1, + uint256 slashAmount2 + ) public { + depositAmount = bound(depositAmount, 1, 100 * 10 ** 18); + operatorNetworkShares1 = bound(operatorNetworkShares1, 1, type(uint256).max / 2); + slashAmount1 = bound(slashAmount1, 1, type(uint256).max); + vm.assume(slashAmount1 < Math.min(depositAmount, Math.min(type(uint256).max, operatorNetworkShares1))); + + uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + blockTimestamp = blockTimestamp + 1_720_700_948; + vm.warp(blockTimestamp); + + address hook = address(new NetworkRestakeRedistributionHook()); + + address networkRestakeDelegatorImpl = address( + new NetworkRestakeDelegator( + address(networkRegistry), + address(vaultFactory), + address(operatorVaultOptInService), + address(operatorNetworkOptInService), + address(delegatorFactory), + delegatorFactory.totalTypes() + ) + ); + delegatorFactory.whitelist(networkRestakeDelegatorImpl); + + address[] memory networkLimitSetRoleHolders = new address[](1); + networkLimitSetRoleHolders[0] = alice; + address[] memory operatorNetworkSharesSetRoleHolders = new address[](1); + operatorNetworkSharesSetRoleHolders[0] = alice; + (address vault_, address delegator_, address slasher_) = vaultConfigurator.create( + IVaultConfigurator.InitParams({ + version: vaultFactory.lastVersion(), + owner: alice, + vaultParams: abi.encode( + IVault.InitParams({ + collateral: address(collateral), + burner: address(0xdEaD), + epochDuration: 7 days, + depositWhitelist: false, + isDepositLimit: false, + depositLimit: 0, + defaultAdminRoleHolder: alice, + depositWhitelistSetRoleHolder: alice, + depositorWhitelistRoleHolder: alice, + isDepositLimitSetRoleHolder: alice, + depositLimitSetRoleHolder: alice + }) + ), + delegatorIndex: 3, + delegatorParams: abi.encode( + INetworkRestakeDelegator.InitParams({ + baseParams: IBaseDelegator.BaseParams({ + defaultAdminRoleHolder: alice, + hook: address(0), + hookSetRoleHolder: alice + }), + networkLimitSetRoleHolders: networkLimitSetRoleHolders, + operatorNetworkSharesSetRoleHolders: operatorNetworkSharesSetRoleHolders + }) + ), + withSlasher: true, + slasherIndex: 0, + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + }) + ); + + (vault0, delegator0, slasher0) = (Vault(vault_), NetworkRestakeDelegator(delegator_), Slasher(slasher_)); + + vm.startPrank(alice); + delegator0.setHook(hook); + vm.stopPrank(); + + address network = alice; + _registerNetwork(network, alice); + _setMaxNetworkLimit(address(delegator0), network, 0, type(uint256).max); + + _registerOperator(alice); + + _optInOperatorVault(vault0, alice); + + _optInOperatorNetwork(alice, address(network)); + + _deposit(vault0, alice, depositAmount); + + _setNetworkLimitNetwork(delegator0, alice, network, type(uint256).max); + + _setOperatorNetworkShares(delegator0, alice, network, alice, operatorNetworkShares1); + + blockTimestamp = blockTimestamp + 1; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator0.networkLimit(network.subnetwork(0)), type(uint256).max); + assertEq(delegator0.totalOperatorNetworkShares(network.subnetwork(0)), operatorNetworkShares1); + assertEq(delegator0.operatorNetworkShares(network.subnetwork(0), alice), operatorNetworkShares1); + } +} diff --git a/test/networkRestakeDelegator/NetworkRestakeResetHook.t.sol b/test/networkRestakeDelegator/NetworkRestakeResetHook.t.sol index bf90957..e767ad0 100644 --- a/test/networkRestakeDelegator/NetworkRestakeResetHook.t.sol +++ b/test/networkRestakeDelegator/NetworkRestakeResetHook.t.sol @@ -3,17 +3,32 @@ pragma solidity 0.8.25; import {POCBaseTest} from "@symbioticfi/core/test/POCBase.t.sol"; +import {Vault} from "@symbioticfi/core/src/contracts/vault/Vault.sol"; +import {NetworkRestakeDelegator} from "@symbioticfi/core/src/contracts/delegator/NetworkRestakeDelegator.sol"; +import {Slasher} from "@symbioticfi/core/src/contracts/slasher/Slasher.sol"; +import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol"; +import {ISlasher} from "@symbioticfi/core/src/interfaces/slasher/ISlasher.sol"; +import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol"; +import {INetworkRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/INetworkRestakeDelegator.sol"; +import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol"; +import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigurator.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol"; import {NetworkRestakeResetHook} from "../../src/contracts/networkRestakeDelegator/NetworkRestakeResetHook.sol"; +import {INetworkRestakeResetHook} from "../../src/interfaces/networkRestakeDelegator/INetworkRestakeResetHook.sol"; +import {FakeDelegator} from "../mocks/FakeDelegator.sol"; contract NetworkRestakeResetHookTest is POCBaseTest { using Math for uint256; using Subnetwork for bytes32; using Subnetwork for address; + Vault public vault0; + NetworkRestakeDelegator public delegator0; + Slasher public slasher0; + function setUp() public override { super.setUp(); } @@ -110,4 +125,169 @@ contract NetworkRestakeResetHookTest is POCBaseTest { assertEq(delegator1.totalOperatorNetworkShares(network.subnetwork(0)), 0); assertEq(delegator1.operatorNetworkShares(network.subnetwork(0), alice), 0); } + + function test_SlashWithHookRevertNotNetworkRestakeDelegator( + uint256 operatorNetworkShares1 + ) public { + uint256 depositAmount = 1e18; + uint256 slashAmount1 = 100; + operatorNetworkShares1 = bound(operatorNetworkShares1, 1, type(uint256).max / 2); + + uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + blockTimestamp = blockTimestamp + 1_720_700_948; + vm.warp(blockTimestamp); + + address hook = address(new NetworkRestakeResetHook(7 days, 3)); + + address networkRestakeDelegatorImpl = address( + new NetworkRestakeDelegator( + address(networkRegistry), + address(vaultFactory), + address(operatorVaultOptInService), + address(operatorNetworkOptInService), + address(delegatorFactory), + delegatorFactory.totalTypes() + ) + ); + delegatorFactory.whitelist(networkRestakeDelegatorImpl); + + address[] memory networkLimitSetRoleHolders = new address[](1); + networkLimitSetRoleHolders[0] = alice; + address[] memory operatorNetworkSharesSetRoleHolders = new address[](1); + operatorNetworkSharesSetRoleHolders[0] = alice; + (address vault_, address delegator_, address slasher_) = vaultConfigurator.create( + IVaultConfigurator.InitParams({ + version: vaultFactory.lastVersion(), + owner: alice, + vaultParams: abi.encode( + IVault.InitParams({ + collateral: address(collateral), + burner: address(0xdEaD), + epochDuration: 7 days, + depositWhitelist: false, + isDepositLimit: false, + depositLimit: 0, + defaultAdminRoleHolder: alice, + depositWhitelistSetRoleHolder: alice, + depositorWhitelistRoleHolder: alice, + isDepositLimitSetRoleHolder: alice, + depositLimitSetRoleHolder: alice + }) + ), + delegatorIndex: 3, + delegatorParams: abi.encode( + INetworkRestakeDelegator.InitParams({ + baseParams: IBaseDelegator.BaseParams({ + defaultAdminRoleHolder: alice, + hook: address(0), + hookSetRoleHolder: alice + }), + networkLimitSetRoleHolders: networkLimitSetRoleHolders, + operatorNetworkSharesSetRoleHolders: operatorNetworkSharesSetRoleHolders + }) + ), + withSlasher: true, + slasherIndex: 0, + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + }) + ); + + (vault0, delegator0, slasher0) = (Vault(vault_), NetworkRestakeDelegator(delegator_), Slasher(slasher_)); + + vm.startPrank(alice); + delegator0.setHook(hook); + vm.stopPrank(); + + address network = alice; + _registerNetwork(network, alice); + _setMaxNetworkLimit(address(delegator0), network, 0, type(uint256).max); + + _registerOperator(alice); + + _optInOperatorVault(vault0, alice); + + _optInOperatorNetwork(alice, address(network)); + + _deposit(vault0, alice, depositAmount); + + _setNetworkLimitNetwork(delegator0, alice, network, type(uint256).max); + + _setOperatorNetworkShares(delegator0, alice, network, alice, operatorNetworkShares1); + + blockTimestamp = blockTimestamp + 1; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + blockTimestamp = blockTimestamp + 7 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + blockTimestamp = blockTimestamp + 3 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + blockTimestamp = blockTimestamp + 5 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + blockTimestamp = blockTimestamp + 3 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + blockTimestamp = blockTimestamp + 3 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator0.networkLimit(network.subnetwork(0)), type(uint256).max); + assertEq(delegator0.totalOperatorNetworkShares(network.subnetwork(0)), operatorNetworkShares1); + assertEq(delegator0.operatorNetworkShares(network.subnetwork(0), alice), operatorNetworkShares1); + } + + function test_SlashWithHookRevertNotVaultDelegator( + uint256 operatorNetworkShares1 + ) public { + uint256 depositAmount = 1e18; + uint256 slashAmount1 = 100; + operatorNetworkShares1 = bound(operatorNetworkShares1, 1, type(uint256).max / 2); + + uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + blockTimestamp = blockTimestamp + 1_720_700_948; + vm.warp(blockTimestamp); + + address hook = address(new NetworkRestakeResetHook(7 days, 3)); + + vm.startPrank(alice); + delegator1.setHook(hook); + delegator1.grantRole(delegator1.OPERATOR_NETWORK_SHARES_SET_ROLE(), hook); + vm.stopPrank(); + + address network = alice; + _registerNetwork(network, alice); + _setMaxNetworkLimit(address(delegator1), network, 0, type(uint256).max); + + _registerOperator(alice); + + _optInOperatorVault(vault1, alice); + + _optInOperatorNetwork(alice, address(network)); + + _deposit(vault1, alice, depositAmount); + + _setNetworkLimitNetwork(delegator1, alice, network, type(uint256).max); + + _setOperatorNetworkShares(delegator1, alice, network, alice, operatorNetworkShares1); + + blockTimestamp = blockTimestamp + 1; + vm.warp(blockTimestamp); + + FakeDelegator fakeDelegator = new FakeDelegator(address(vault1), 0); + vm.expectRevert(INetworkRestakeResetHook.NotVaultDelegator.selector); + fakeDelegator.onSlash(hook, network.subnetwork(0), alice, slashAmount1, uint48(blockTimestamp - 1), ""); + } } diff --git a/test/operatorSpecificDelegator/OperatorSpecificFairHook.t.sol b/test/operatorSpecificDelegator/OperatorSpecificFairHook.t.sol new file mode 100644 index 0000000..81f740f --- /dev/null +++ b/test/operatorSpecificDelegator/OperatorSpecificFairHook.t.sol @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.25; + +import {POCBaseTest} from "@symbioticfi/core/test/POCBase.t.sol"; +import {Vault} from "@symbioticfi/core/src/contracts/vault/Vault.sol"; +import {OperatorSpecificDelegator} from "@symbioticfi/core/src/contracts/delegator/OperatorSpecificDelegator.sol"; +import {Slasher} from "@symbioticfi/core/src/contracts/slasher/Slasher.sol"; +import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol"; +import {ISlasher} from "@symbioticfi/core/src/interfaces/slasher/ISlasher.sol"; +import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol"; +import {IOperatorSpecificDelegator} from "@symbioticfi/core/src/interfaces/delegator/IOperatorSpecificDelegator.sol"; +import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol"; +import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigurator.sol"; + +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol"; + +import {OperatorSpecificFairHook} from "../../src/contracts/operatorSpecificDelegator/OperatorSpecificFairHook.sol"; + +contract OperatorSpecificFairHookTest is POCBaseTest { + using Math for uint256; + using Subnetwork for bytes32; + using Subnetwork for address; + + Vault public vault0; + OperatorSpecificDelegator public delegator0; + Slasher public slasher0; + + function setUp() public override { + super.setUp(); + } + + function test_SlashWithHook( + uint256 depositAmount, + uint256 operatorNetworkShares1, + uint256 operatorNetworkShares2, + uint256 slashAmount1, + uint256 slashAmount2, + uint256 networkLimit + ) public { + depositAmount = bound(depositAmount, 100, 100 * 10 ** 18); + operatorNetworkShares1 = bound(operatorNetworkShares1, 1, type(uint256).max / 2); + operatorNetworkShares2 = bound(operatorNetworkShares2, 1, type(uint256).max / 2); + slashAmount1 = bound(slashAmount1, 1, type(uint256).max); + slashAmount2 = bound(slashAmount2, 1, type(uint256).max); + networkLimit = bound(networkLimit, 1, depositAmount); + + uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + blockTimestamp = blockTimestamp + 1_720_700_948; + vm.warp(blockTimestamp); + + address hook = address(new OperatorSpecificFairHook()); + + _registerOperator(alice); + address[] memory networkLimitSetRoleHolders = new address[](1); + networkLimitSetRoleHolders[0] = alice; + (address vault_, address delegator_, address slasher_) = vaultConfigurator.create( + IVaultConfigurator.InitParams({ + version: vaultFactory.lastVersion(), + owner: alice, + vaultParams: abi.encode( + IVault.InitParams({ + collateral: address(collateral), + burner: address(0xdEaD), + epochDuration: 7 days, + depositWhitelist: false, + isDepositLimit: false, + depositLimit: 0, + defaultAdminRoleHolder: alice, + depositWhitelistSetRoleHolder: alice, + depositorWhitelistRoleHolder: alice, + isDepositLimitSetRoleHolder: alice, + depositLimitSetRoleHolder: alice + }) + ), + delegatorIndex: 2, + delegatorParams: abi.encode( + IOperatorSpecificDelegator.InitParams({ + baseParams: IBaseDelegator.BaseParams({ + defaultAdminRoleHolder: alice, + hook: address(0), + hookSetRoleHolder: alice + }), + networkLimitSetRoleHolders: networkLimitSetRoleHolders, + operator: alice + }) + ), + withSlasher: true, + slasherIndex: 0, + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + }) + ); + + (vault0, delegator0, slasher0) = (Vault(vault_), OperatorSpecificDelegator(delegator_), Slasher(slasher_)); + + vm.startPrank(alice); + delegator0.setHook(hook); + delegator0.grantRole(delegator0.NETWORK_LIMIT_SET_ROLE(), hook); + vm.stopPrank(); + + address network = alice; + _registerNetwork(network, alice); + _setMaxNetworkLimit(address(delegator0), network, 0, type(uint256).max); + + _registerOperator(bob); + + _optInOperatorVault(vault0, alice); + + _optInOperatorNetwork(alice, address(network)); + + _optInOperatorVault(vault0, bob); + + _optInOperatorNetwork(bob, address(network)); + + _deposit(vault0, alice, depositAmount); + + _setNetworkLimitOperator(delegator0, alice, network, networkLimit); + + assertEq(delegator0.networkLimit(network.subnetwork(0)), networkLimit); + + blockTimestamp = blockTimestamp + 1; + vm.warp(blockTimestamp); + + uint256 stakeAtAlice = delegator0.stakeAt(network.subnetwork(0), alice, uint48(blockTimestamp - 1), ""); + uint256 stakeAtBob = delegator0.stakeAt(network.subnetwork(0), bob, uint48(blockTimestamp - 1), ""); + vm.assume(stakeAtAlice > slashAmount1); + uint256 slashedAmount1 = _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator0.networkLimit(network.subnetwork(0)), networkLimit - slashedAmount1); + assertLe(stakeAtBob, delegator0.stakeAt(network.subnetwork(0), bob, uint48(blockTimestamp), "")); + + uint256 slashedAmount2 = _slash(slasher0, alice, network, alice, slashAmount2, uint48(blockTimestamp - 1), ""); + + assertEq(delegator0.networkLimit(network.subnetwork(0)), networkLimit - slashedAmount1 - slashedAmount2); + assertLe(stakeAtBob, delegator0.stakeAt(network.subnetwork(0), bob, uint48(blockTimestamp), "")); + } + + function test_SlashWithHookRevertNotOperatorSpecificDelegator( + uint256 depositAmount, + uint256 operatorNetworkShares1, + uint256 operatorNetworkShares2, + uint256 slashAmount1, + uint256 slashAmount2, + uint256 networkLimit + ) public { + depositAmount = bound(depositAmount, 100, 100 * 10 ** 18); + operatorNetworkShares1 = bound(operatorNetworkShares1, 1, type(uint256).max / 2); + operatorNetworkShares2 = bound(operatorNetworkShares2, 1, type(uint256).max / 2); + slashAmount1 = bound(slashAmount1, 1, type(uint256).max); + networkLimit = bound(networkLimit, 1, depositAmount); + + uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + blockTimestamp = blockTimestamp + 1_720_700_948; + vm.warp(blockTimestamp); + + address hook = address(new OperatorSpecificFairHook()); + + address operatorSpecificDelegatorImpl = address( + new OperatorSpecificDelegator( + address(operatorRegistry), + address(networkRegistry), + address(vaultFactory), + address(operatorVaultOptInService), + address(operatorNetworkOptInService), + address(delegatorFactory), + delegatorFactory.totalTypes() + ) + ); + delegatorFactory.whitelist(operatorSpecificDelegatorImpl); + + _registerOperator(alice); + address[] memory networkLimitSetRoleHolders = new address[](1); + networkLimitSetRoleHolders[0] = alice; + (address vault_, address delegator_, address slasher_) = vaultConfigurator.create( + IVaultConfigurator.InitParams({ + version: vaultFactory.lastVersion(), + owner: alice, + vaultParams: abi.encode( + IVault.InitParams({ + collateral: address(collateral), + burner: address(0xdEaD), + epochDuration: 7 days, + depositWhitelist: false, + isDepositLimit: false, + depositLimit: 0, + defaultAdminRoleHolder: alice, + depositWhitelistSetRoleHolder: alice, + depositorWhitelistRoleHolder: alice, + isDepositLimitSetRoleHolder: alice, + depositLimitSetRoleHolder: alice + }) + ), + delegatorIndex: 3, + delegatorParams: abi.encode( + IOperatorSpecificDelegator.InitParams({ + baseParams: IBaseDelegator.BaseParams({ + defaultAdminRoleHolder: alice, + hook: address(0), + hookSetRoleHolder: alice + }), + networkLimitSetRoleHolders: networkLimitSetRoleHolders, + operator: alice + }) + ), + withSlasher: true, + slasherIndex: 0, + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + }) + ); + + (vault0, delegator0, slasher0) = (Vault(vault_), OperatorSpecificDelegator(delegator_), Slasher(slasher_)); + + vm.startPrank(alice); + delegator0.setHook(hook); + delegator0.grantRole(delegator0.NETWORK_LIMIT_SET_ROLE(), hook); + vm.stopPrank(); + + address network = alice; + _registerNetwork(network, alice); + _setMaxNetworkLimit(address(delegator0), network, 0, type(uint256).max); + + _registerOperator(bob); + + _optInOperatorVault(vault0, alice); + + _optInOperatorNetwork(alice, address(network)); + + _optInOperatorVault(vault0, bob); + + _optInOperatorNetwork(bob, address(network)); + + _deposit(vault0, alice, depositAmount); + + _setNetworkLimitOperator(delegator0, alice, network, networkLimit); + + blockTimestamp = blockTimestamp + 1; + vm.warp(blockTimestamp); + + uint256 stakeAtAlice = delegator0.stakeAt(network.subnetwork(0), alice, uint48(blockTimestamp - 1), ""); + vm.assume(stakeAtAlice > slashAmount1); + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator0.networkLimit(network.subnetwork(0)), networkLimit); + } + + function _setNetworkLimitOperator( + OperatorSpecificDelegator delegator, + address user, + address network, + uint256 amount + ) internal { + vm.startPrank(user); + delegator.setNetworkLimit(network.subnetwork(0), amount); + vm.stopPrank(); + } +} diff --git a/test/operatorSpecificDelegator/OperatorSpecificResetHook.t.sol b/test/operatorSpecificDelegator/OperatorSpecificResetHook.t.sol new file mode 100644 index 0000000..78f3985 --- /dev/null +++ b/test/operatorSpecificDelegator/OperatorSpecificResetHook.t.sol @@ -0,0 +1,360 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.25; + +import {POCBaseTest} from "@symbioticfi/core/test/POCBase.t.sol"; +import {Vault} from "@symbioticfi/core/src/contracts/vault/Vault.sol"; +import {OperatorSpecificDelegator} from "@symbioticfi/core/src/contracts/delegator/OperatorSpecificDelegator.sol"; +import {Slasher} from "@symbioticfi/core/src/contracts/slasher/Slasher.sol"; +import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol"; +import {ISlasher} from "@symbioticfi/core/src/interfaces/slasher/ISlasher.sol"; +import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol"; +import {IOperatorSpecificDelegator} from "@symbioticfi/core/src/interfaces/delegator/IOperatorSpecificDelegator.sol"; +import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol"; +import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigurator.sol"; + +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol"; + +import {OperatorSpecificResetHook} from "../../src/contracts/operatorSpecificDelegator/OperatorSpecificResetHook.sol"; +import {IOperatorSpecificResetHook} from "../../src/interfaces/operatorSpecificDelegator/IOperatorSpecificResetHook.sol"; +import {FakeDelegator} from "../mocks/FakeDelegator.sol"; + +contract OperatorSpecificResetHookTest is POCBaseTest { + using Math for uint256; + using Subnetwork for bytes32; + using Subnetwork for address; + + Vault public vault0; + OperatorSpecificDelegator public delegator0; + Slasher public slasher0; + + function setUp() public override { + super.setUp(); + } + + function test_SlashWithHook( + uint256 operatorNetworkShares1 + ) public { + uint256 depositAmount = 1e18; + uint256 slashAmount1 = 100; + operatorNetworkShares1 = bound(operatorNetworkShares1, 1, type(uint256).max / 2); + + uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + blockTimestamp = blockTimestamp + 1_720_700_948; + vm.warp(blockTimestamp); + + address hook = address(new OperatorSpecificResetHook(7 days, 3)); + + _registerOperator(alice); + address[] memory networkLimitSetRoleHolders = new address[](1); + networkLimitSetRoleHolders[0] = alice; + (address vault_, address delegator_, address slasher_) = vaultConfigurator.create( + IVaultConfigurator.InitParams({ + version: vaultFactory.lastVersion(), + owner: alice, + vaultParams: abi.encode( + IVault.InitParams({ + collateral: address(collateral), + burner: address(0xdEaD), + epochDuration: 7 days, + depositWhitelist: false, + isDepositLimit: false, + depositLimit: 0, + defaultAdminRoleHolder: alice, + depositWhitelistSetRoleHolder: alice, + depositorWhitelistRoleHolder: alice, + isDepositLimitSetRoleHolder: alice, + depositLimitSetRoleHolder: alice + }) + ), + delegatorIndex: 2, + delegatorParams: abi.encode( + IOperatorSpecificDelegator.InitParams({ + baseParams: IBaseDelegator.BaseParams({ + defaultAdminRoleHolder: alice, + hook: address(0), + hookSetRoleHolder: alice + }), + networkLimitSetRoleHolders: networkLimitSetRoleHolders, + operator: alice + }) + ), + withSlasher: true, + slasherIndex: 0, + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + }) + ); + + (vault0, delegator0, slasher0) = (Vault(vault_), OperatorSpecificDelegator(delegator_), Slasher(slasher_)); + + vm.startPrank(alice); + delegator0.setHook(hook); + delegator0.grantRole(delegator0.NETWORK_LIMIT_SET_ROLE(), hook); + vm.stopPrank(); + + address network = alice; + _registerNetwork(network, alice); + _setMaxNetworkLimit(address(delegator0), network, 0, type(uint256).max); + + _optInOperatorVault(vault0, alice); + + _optInOperatorNetwork(alice, address(network)); + + _deposit(vault0, alice, depositAmount); + + _setNetworkLimitOperator(delegator0, alice, network, type(uint256).max); + + assertEq(delegator0.networkLimit(network.subnetwork(0)), type(uint256).max); + + blockTimestamp = blockTimestamp + 1; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator0.networkLimit(network.subnetwork(0)), type(uint256).max); + + blockTimestamp = blockTimestamp + 7 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator0.networkLimit(network.subnetwork(0)), type(uint256).max); + + blockTimestamp = blockTimestamp + 3 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator0.networkLimit(network.subnetwork(0)), type(uint256).max); + + blockTimestamp = blockTimestamp + 5 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator0.networkLimit(network.subnetwork(0)), type(uint256).max); + + blockTimestamp = blockTimestamp + 3 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator0.networkLimit(network.subnetwork(0)), type(uint256).max); + + blockTimestamp = blockTimestamp + 3 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator0.networkLimit(network.subnetwork(0)), 0); + } + + function test_SlashWithHookRevertNotOperatorSpecificDelegator( + uint256 operatorNetworkShares1 + ) public { + uint256 depositAmount = 1e18; + uint256 slashAmount1 = 100; + operatorNetworkShares1 = bound(operatorNetworkShares1, 1, type(uint256).max / 2); + + uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + blockTimestamp = blockTimestamp + 1_720_700_948; + vm.warp(blockTimestamp); + + address hook = address(new OperatorSpecificResetHook(7 days, 3)); + + address operatorSpecificDelegatorImpl = address( + new OperatorSpecificDelegator( + address(operatorRegistry), + address(networkRegistry), + address(vaultFactory), + address(operatorVaultOptInService), + address(operatorNetworkOptInService), + address(delegatorFactory), + delegatorFactory.totalTypes() + ) + ); + delegatorFactory.whitelist(operatorSpecificDelegatorImpl); + + _registerOperator(alice); + address[] memory networkLimitSetRoleHolders = new address[](1); + networkLimitSetRoleHolders[0] = alice; + (address vault_, address delegator_, address slasher_) = vaultConfigurator.create( + IVaultConfigurator.InitParams({ + version: vaultFactory.lastVersion(), + owner: alice, + vaultParams: abi.encode( + IVault.InitParams({ + collateral: address(collateral), + burner: address(0xdEaD), + epochDuration: 7 days, + depositWhitelist: false, + isDepositLimit: false, + depositLimit: 0, + defaultAdminRoleHolder: alice, + depositWhitelistSetRoleHolder: alice, + depositorWhitelistRoleHolder: alice, + isDepositLimitSetRoleHolder: alice, + depositLimitSetRoleHolder: alice + }) + ), + delegatorIndex: 3, + delegatorParams: abi.encode( + IOperatorSpecificDelegator.InitParams({ + baseParams: IBaseDelegator.BaseParams({ + defaultAdminRoleHolder: alice, + hook: address(0), + hookSetRoleHolder: alice + }), + networkLimitSetRoleHolders: networkLimitSetRoleHolders, + operator: alice + }) + ), + withSlasher: true, + slasherIndex: 0, + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + }) + ); + + (vault0, delegator0, slasher0) = (Vault(vault_), OperatorSpecificDelegator(delegator_), Slasher(slasher_)); + + vm.startPrank(alice); + delegator0.setHook(hook); + vm.stopPrank(); + + address network = alice; + _registerNetwork(network, alice); + _setMaxNetworkLimit(address(delegator0), network, 0, type(uint256).max); + + _optInOperatorVault(vault0, alice); + + _optInOperatorNetwork(alice, address(network)); + + _deposit(vault0, alice, depositAmount); + + _setNetworkLimitOperator(delegator0, alice, network, type(uint256).max); + + blockTimestamp = blockTimestamp + 1; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + blockTimestamp = blockTimestamp + 7 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + blockTimestamp = blockTimestamp + 3 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + blockTimestamp = blockTimestamp + 5 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + blockTimestamp = blockTimestamp + 3 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + blockTimestamp = blockTimestamp + 3 days; + vm.warp(blockTimestamp); + + _slash(slasher0, alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(delegator0.networkLimit(network.subnetwork(0)), type(uint256).max); + } + + function test_SlashWithHookRevertNotVaultDelegator( + uint256 operatorNetworkShares1 + ) public { + uint256 depositAmount = 1e18; + uint256 slashAmount1 = 100; + operatorNetworkShares1 = bound(operatorNetworkShares1, 1, type(uint256).max / 2); + + uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + blockTimestamp = blockTimestamp + 1_720_700_948; + vm.warp(blockTimestamp); + + address hook = address(new OperatorSpecificResetHook(7 days, 3)); + + _registerOperator(alice); + address[] memory networkLimitSetRoleHolders = new address[](1); + networkLimitSetRoleHolders[0] = alice; + (address vault_, address delegator_, address slasher_) = vaultConfigurator.create( + IVaultConfigurator.InitParams({ + version: vaultFactory.lastVersion(), + owner: alice, + vaultParams: abi.encode( + IVault.InitParams({ + collateral: address(collateral), + burner: address(0xdEaD), + epochDuration: 7 days, + depositWhitelist: false, + isDepositLimit: false, + depositLimit: 0, + defaultAdminRoleHolder: alice, + depositWhitelistSetRoleHolder: alice, + depositorWhitelistRoleHolder: alice, + isDepositLimitSetRoleHolder: alice, + depositLimitSetRoleHolder: alice + }) + ), + delegatorIndex: 2, + delegatorParams: abi.encode( + IOperatorSpecificDelegator.InitParams({ + baseParams: IBaseDelegator.BaseParams({ + defaultAdminRoleHolder: alice, + hook: address(0), + hookSetRoleHolder: alice + }), + networkLimitSetRoleHolders: networkLimitSetRoleHolders, + operator: alice + }) + ), + withSlasher: true, + slasherIndex: 0, + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + }) + ); + + (vault0, delegator0, slasher0) = (Vault(vault_), OperatorSpecificDelegator(delegator_), Slasher(slasher_)); + + vm.startPrank(alice); + delegator0.setHook(hook); + delegator0.grantRole(delegator0.NETWORK_LIMIT_SET_ROLE(), hook); + vm.stopPrank(); + + address network = alice; + _registerNetwork(network, alice); + _setMaxNetworkLimit(address(delegator0), network, 0, type(uint256).max); + + _optInOperatorVault(vault0, alice); + + _optInOperatorNetwork(alice, address(network)); + + _deposit(vault0, alice, depositAmount); + + _setNetworkLimitOperator(delegator0, alice, network, type(uint256).max); + + blockTimestamp = blockTimestamp + 1; + vm.warp(blockTimestamp); + + FakeDelegator fakeDelegator = new FakeDelegator(address(vault0), 2); + vm.expectRevert(IOperatorSpecificResetHook.NotVaultDelegator.selector); + fakeDelegator.onSlash(hook, network.subnetwork(0), alice, slashAmount1, uint48(blockTimestamp - 1), ""); + } + + function _setNetworkLimitOperator( + OperatorSpecificDelegator delegator, + address user, + address network, + uint256 amount + ) internal { + vm.startPrank(user); + delegator.setNetworkLimit(network.subnetwork(0), amount); + vm.stopPrank(); + } +} From a47176f4ac88f2f562881cb1bdc38cc4a7af839b Mon Sep 17 00:00:00 2001 From: Kresh Date: Fri, 25 Oct 2024 15:00:28 +0400 Subject: [PATCH 8/9] refactor: fair -> decrease & distribution -> distribute --- specs/FullRestakeDelegatorHooks.md | 13 +++++++++++++ specs/NetworkRestakeDelegatorHooks.md | 19 +++++++++++++++++++ specs/OperatorSpecificDelegatorHooks.md | 13 +++++++++++++ specs/hooks.md | 19 ------------------- .../FullRestakeFairHook.sol | 4 ++-- .../NetworkRestakeFairHook.sol | 4 ++-- ...sol => NetworkRestakeRedistributeHook.sol} | 6 +++--- .../OperatorSpecificFairHook.sol | 4 ++-- .../IFullRestakeFairHook.sol | 2 +- .../INetworkRestakeFairHook.sol | 2 +- ...ol => INetworkRestakeRedistributeHook.sol} | 2 +- .../IOperatorSpecificFairHook.sol | 2 +- .../FullRestakeFairHook.t.sol | 8 ++++---- .../NetworkRestakeFairHook.t.sol | 8 ++++---- ...l => NetworkRestakeRedistributeHook.t.sol} | 10 +++++----- .../OperatorSpecificFairHook.t.sol | 8 ++++---- 16 files changed, 75 insertions(+), 49 deletions(-) create mode 100644 specs/FullRestakeDelegatorHooks.md create mode 100644 specs/NetworkRestakeDelegatorHooks.md create mode 100644 specs/OperatorSpecificDelegatorHooks.md delete mode 100644 specs/hooks.md rename src/contracts/networkRestakeDelegator/{NetworkRestakeRedistributionHook.sol => NetworkRestakeRedistributeHook.sol} (94%) rename src/interfaces/networkRestakeDelegator/{INetworkRestakeRedistributionHook.sol => INetworkRestakeRedistributeHook.sol} (75%) rename test/networkRestakeDelegator/{NetworkRestakeRedistributionHook.t.sol => NetworkRestakeRedistributeHook.t.sol} (97%) diff --git a/specs/FullRestakeDelegatorHooks.md b/specs/FullRestakeDelegatorHooks.md new file mode 100644 index 0000000..5fc7020 --- /dev/null +++ b/specs/FullRestakeDelegatorHooks.md @@ -0,0 +1,13 @@ +## Hooks + +### FullRestakeDecreaseHook + +FullRestakeDecreaseHook supports `onSlash()` calls only from `FullRestakeDelegator`. + +This hook decreases the network's limit by the slashed amount and decreases the operator's limit also by the slashed amount. It doesn't change stake amounts for other operators. + +### FullRestakeResetHook + +FullRestakeResetHook supports `onSlash()` calls only from `FullRestakeDelegator`. + +This hook resets the slashed operator's limit to zero in case it was slashed a configured number of times during a configured period of time. diff --git a/specs/NetworkRestakeDelegatorHooks.md b/specs/NetworkRestakeDelegatorHooks.md new file mode 100644 index 0000000..8fad3e8 --- /dev/null +++ b/specs/NetworkRestakeDelegatorHooks.md @@ -0,0 +1,19 @@ +## Hooks + +### NetworkRestakeDecreaseHook + +NetworkRestakeDecreaseHook supports `onSlash()` calls only from `NetworkRestakeDelegator`. + +This hook decreases the network's limit by the slashed amount and decreases the slashed operator's shares in such a way as to decrease his stake (which depends on the network's limit) by the slashed amount. It doesn't change stake amounts for other operators. + +### NetworkRestakeRedistributeHook + +NetworkRestakeRedistributeHook supports `onSlash()` calls only from `NetworkRestakeDelegator`. + +This hook decreases the slashed operator's shares by slashed percent from the given stake, redistributing the decreased stake to other operators. + +### NetworkRestakeResetHook + +NetworkRestakeResetHook supports `onSlash()` calls only from `NetworkRestakeDelegator`. + +This hook resets the slashed operator's shares to zero in case it was slashed a configured number of times during a configured period of time. diff --git a/specs/OperatorSpecificDelegatorHooks.md b/specs/OperatorSpecificDelegatorHooks.md new file mode 100644 index 0000000..d7fba95 --- /dev/null +++ b/specs/OperatorSpecificDelegatorHooks.md @@ -0,0 +1,13 @@ +## Hooks + +### OperatorSpecificDecreaseHook + +OperatorSpecificDecreaseHook supports `onSlash()` calls only from `OperatorSpecificDelegator`. + +This hook decreases the network's limit by the slashed amount. + +### OperatorSpecificResetHook + +OperatorSpecificResetHook supports `onSlash()` calls only from `OperatorSpecificDelegator`. + +This hook resets the slashing network's limit to zero in case it was slashed a configured number of times during a configured period of time. diff --git a/specs/hooks.md b/specs/hooks.md deleted file mode 100644 index bbec3d8..0000000 --- a/specs/hooks.md +++ /dev/null @@ -1,19 +0,0 @@ -## Hooks - -### NetworkRestakeFairHook - -NetworkRestakeFairHook supports `onSlash()` calls only from `NetworkRestakeDelegator`. - -This hook decreases the network limit by the slashed amount and decreases the slashed operator's shares in such a way as to decrease his stake (which depends on the network limit) by the slashed amount. It doesn't change stake amounts for other operators. - -### NetworkRestakeRedistributionHook - -NetworkRestakeRedistributionHook supports `onSlash()` calls only from `NetworkRestakeDelegator`. - -This hook decreases the slashed operator's shares by slashed percent from the given stake, redistributing the decreased stake to other operators. - -### NetworkRestakeResetHook - -NetworkRestakeResetHook supports `onSlash()` calls only from `NetworkRestakeDelegator`. - -This hook resets the slashed operator's shares to zero in case it was slashed a configured number of times during a configured period of time. diff --git a/src/contracts/fullRestakeDelegator/FullRestakeFairHook.sol b/src/contracts/fullRestakeDelegator/FullRestakeFairHook.sol index 58885db..ffe3f50 100644 --- a/src/contracts/fullRestakeDelegator/FullRestakeFairHook.sol +++ b/src/contracts/fullRestakeDelegator/FullRestakeFairHook.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import {IFullRestakeFairHook} from "../../interfaces/fullRestakeDelegator/IFullRestakeFairHook.sol"; +import {IFullRestakeDecreaseHook} from "../../interfaces/fullRestakeDelegator/IFullRestakeDecreaseHook.sol"; import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; import {IEntity} from "@symbioticfi/core/src/interfaces/common/IEntity.sol"; @@ -9,7 +9,7 @@ import {IFullRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/ import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; -contract FullRestakeFairHook is IFullRestakeFairHook { +contract FullRestakeDecreaseHook is IFullRestakeDecreaseHook { using Math for uint256; /** diff --git a/src/contracts/networkRestakeDelegator/NetworkRestakeFairHook.sol b/src/contracts/networkRestakeDelegator/NetworkRestakeFairHook.sol index c819044..16dbbef 100644 --- a/src/contracts/networkRestakeDelegator/NetworkRestakeFairHook.sol +++ b/src/contracts/networkRestakeDelegator/NetworkRestakeFairHook.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import {INetworkRestakeFairHook} from "../../interfaces/networkRestakeDelegator/INetworkRestakeFairHook.sol"; +import {INetworkRestakeDecreaseHook} from "../../interfaces/networkRestakeDelegator/INetworkRestakeDecreaseHook.sol"; import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; import {IEntity} from "@symbioticfi/core/src/interfaces/common/IEntity.sol"; @@ -12,7 +12,7 @@ import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlashe import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; -contract NetworkRestakeFairHook is INetworkRestakeFairHook { +contract NetworkRestakeDecreaseHook is INetworkRestakeDecreaseHook { using Math for uint256; /** diff --git a/src/contracts/networkRestakeDelegator/NetworkRestakeRedistributionHook.sol b/src/contracts/networkRestakeDelegator/NetworkRestakeRedistributeHook.sol similarity index 94% rename from src/contracts/networkRestakeDelegator/NetworkRestakeRedistributionHook.sol rename to src/contracts/networkRestakeDelegator/NetworkRestakeRedistributeHook.sol index 0e7ed8b..c36ef6a 100644 --- a/src/contracts/networkRestakeDelegator/NetworkRestakeRedistributionHook.sol +++ b/src/contracts/networkRestakeDelegator/NetworkRestakeRedistributeHook.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import {INetworkRestakeRedistributionHook} from - "../../interfaces/networkRestakeDelegator/INetworkRestakeRedistributionHook.sol"; +import {INetworkRestakeRedistributeHook} from + "../../interfaces/networkRestakeDelegator/INetworkRestakeRedistributeHook.sol"; import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol"; import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; @@ -15,7 +15,7 @@ import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlashe import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; -contract NetworkRestakeRedistributionHook is INetworkRestakeRedistributionHook { +contract NetworkRestakeRedistributeHook is INetworkRestakeRedistributeHook { using Math for uint256; /** diff --git a/src/contracts/operatorSpecificDelegator/OperatorSpecificFairHook.sol b/src/contracts/operatorSpecificDelegator/OperatorSpecificFairHook.sol index 014589a..f5985f5 100644 --- a/src/contracts/operatorSpecificDelegator/OperatorSpecificFairHook.sol +++ b/src/contracts/operatorSpecificDelegator/OperatorSpecificFairHook.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import {IOperatorSpecificFairHook} from "../../interfaces/operatorSpecificDelegator/IOperatorSpecificFairHook.sol"; +import {IOperatorSpecificDecreaseHook} from "../../interfaces/operatorSpecificDelegator/IOperatorSpecificDecreaseHook.sol"; import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; import {IEntity} from "@symbioticfi/core/src/interfaces/common/IEntity.sol"; @@ -9,7 +9,7 @@ import {IOperatorSpecificDelegator} from "@symbioticfi/core/src/interfaces/deleg import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; -contract OperatorSpecificFairHook is IOperatorSpecificFairHook { +contract OperatorSpecificDecreaseHook is IOperatorSpecificDecreaseHook { using Math for uint256; /** diff --git a/src/interfaces/fullRestakeDelegator/IFullRestakeFairHook.sol b/src/interfaces/fullRestakeDelegator/IFullRestakeFairHook.sol index 8ae8444..628363e 100644 --- a/src/interfaces/fullRestakeDelegator/IFullRestakeFairHook.sol +++ b/src/interfaces/fullRestakeDelegator/IFullRestakeFairHook.sol @@ -3,6 +3,6 @@ pragma solidity ^0.8.0; import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; -interface IFullRestakeFairHook is IDelegatorHook { +interface IFullRestakeDecreaseHook is IDelegatorHook { error NotFullRestakeDelegator(); } diff --git a/src/interfaces/networkRestakeDelegator/INetworkRestakeFairHook.sol b/src/interfaces/networkRestakeDelegator/INetworkRestakeFairHook.sol index 1a8c22c..4ef10e1 100644 --- a/src/interfaces/networkRestakeDelegator/INetworkRestakeFairHook.sol +++ b/src/interfaces/networkRestakeDelegator/INetworkRestakeFairHook.sol @@ -3,6 +3,6 @@ pragma solidity ^0.8.0; import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; -interface INetworkRestakeFairHook is IDelegatorHook { +interface INetworkRestakeDecreaseHook is IDelegatorHook { error NotNetworkRestakeDelegator(); } diff --git a/src/interfaces/networkRestakeDelegator/INetworkRestakeRedistributionHook.sol b/src/interfaces/networkRestakeDelegator/INetworkRestakeRedistributeHook.sol similarity index 75% rename from src/interfaces/networkRestakeDelegator/INetworkRestakeRedistributionHook.sol rename to src/interfaces/networkRestakeDelegator/INetworkRestakeRedistributeHook.sol index a072c1d..7628944 100644 --- a/src/interfaces/networkRestakeDelegator/INetworkRestakeRedistributionHook.sol +++ b/src/interfaces/networkRestakeDelegator/INetworkRestakeRedistributeHook.sol @@ -3,6 +3,6 @@ pragma solidity ^0.8.0; import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; -interface INetworkRestakeRedistributionHook is IDelegatorHook { +interface INetworkRestakeRedistributeHook is IDelegatorHook { error NotNetworkRestakeDelegator(); } diff --git a/src/interfaces/operatorSpecificDelegator/IOperatorSpecificFairHook.sol b/src/interfaces/operatorSpecificDelegator/IOperatorSpecificFairHook.sol index e142c62..be63103 100644 --- a/src/interfaces/operatorSpecificDelegator/IOperatorSpecificFairHook.sol +++ b/src/interfaces/operatorSpecificDelegator/IOperatorSpecificFairHook.sol @@ -3,6 +3,6 @@ pragma solidity ^0.8.0; import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; -interface IOperatorSpecificFairHook is IDelegatorHook { +interface IOperatorSpecificDecreaseHook is IDelegatorHook { error NotOperatorSpecificDelegator(); } diff --git a/test/fullRestakeDelegator/FullRestakeFairHook.t.sol b/test/fullRestakeDelegator/FullRestakeFairHook.t.sol index 2c2b1fa..65f4faa 100644 --- a/test/fullRestakeDelegator/FullRestakeFairHook.t.sol +++ b/test/fullRestakeDelegator/FullRestakeFairHook.t.sol @@ -16,9 +16,9 @@ import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigu import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol"; -import {FullRestakeFairHook} from "../../src/contracts/fullRestakeDelegator/FullRestakeFairHook.sol"; +import {FullRestakeDecreaseHook} from "../../src/contracts/fullRestakeDelegator/FullRestakeDecreaseHook.sol"; -contract FullRestakeFairHookTest is POCBaseTest { +contract FullRestakeDecreaseHookTest is POCBaseTest { using Math for uint256; using Subnetwork for bytes32; using Subnetwork for address; @@ -50,7 +50,7 @@ contract FullRestakeFairHookTest is POCBaseTest { blockTimestamp = blockTimestamp + 1_720_700_948; vm.warp(blockTimestamp); - address hook = address(new FullRestakeFairHook()); + address hook = address(new FullRestakeDecreaseHook()); vm.startPrank(alice); delegator2.setHook(hook); @@ -132,7 +132,7 @@ contract FullRestakeFairHookTest is POCBaseTest { blockTimestamp = blockTimestamp + 1_720_700_948; vm.warp(blockTimestamp); - address hook = address(new FullRestakeFairHook()); + address hook = address(new FullRestakeDecreaseHook()); address fullRestakeDelegatorImpl = address( new FullRestakeDelegator( diff --git a/test/networkRestakeDelegator/NetworkRestakeFairHook.t.sol b/test/networkRestakeDelegator/NetworkRestakeFairHook.t.sol index fb257af..eab91a7 100644 --- a/test/networkRestakeDelegator/NetworkRestakeFairHook.t.sol +++ b/test/networkRestakeDelegator/NetworkRestakeFairHook.t.sol @@ -16,9 +16,9 @@ import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigu import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol"; -import {NetworkRestakeFairHook} from "../../src/contracts/networkRestakeDelegator/NetworkRestakeFairHook.sol"; +import {NetworkRestakeDecreaseHook} from "../../src/contracts/networkRestakeDelegator/NetworkRestakeDecreaseHook.sol"; -contract NetworkRestakeFairHookTest is POCBaseTest { +contract NetworkRestakeDecreaseHookTest is POCBaseTest { using Math for uint256; using Subnetwork for bytes32; using Subnetwork for address; @@ -50,7 +50,7 @@ contract NetworkRestakeFairHookTest is POCBaseTest { blockTimestamp = blockTimestamp + 1_720_700_948; vm.warp(blockTimestamp); - address hook = address(new NetworkRestakeFairHook()); + address hook = address(new NetworkRestakeDecreaseHook()); vm.startPrank(alice); delegator1.setHook(hook); @@ -148,7 +148,7 @@ contract NetworkRestakeFairHookTest is POCBaseTest { blockTimestamp = blockTimestamp + 1_720_700_948; vm.warp(blockTimestamp); - address hook = address(new NetworkRestakeFairHook()); + address hook = address(new NetworkRestakeDecreaseHook()); address networkRestakeDelegatorImpl = address( new NetworkRestakeDelegator( diff --git a/test/networkRestakeDelegator/NetworkRestakeRedistributionHook.t.sol b/test/networkRestakeDelegator/NetworkRestakeRedistributeHook.t.sol similarity index 97% rename from test/networkRestakeDelegator/NetworkRestakeRedistributionHook.t.sol rename to test/networkRestakeDelegator/NetworkRestakeRedistributeHook.t.sol index 9616033..145fad3 100644 --- a/test/networkRestakeDelegator/NetworkRestakeRedistributionHook.t.sol +++ b/test/networkRestakeDelegator/NetworkRestakeRedistributeHook.t.sol @@ -16,10 +16,10 @@ import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigu import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol"; -import {NetworkRestakeRedistributionHook} from - "../../src/contracts/networkRestakeDelegator/NetworkRestakeRedistributionHook.sol"; +import {NetworkRestakeRedistributeHook} from + "../../src/contracts/networkRestakeDelegator/NetworkRestakeRedistributeHook.sol"; -contract NetworkRestakeRedistributionHookTest is POCBaseTest { +contract NetworkRestakeRedistributeHookTest is POCBaseTest { using Math for uint256; using Subnetwork for bytes32; using Subnetwork for address; @@ -48,7 +48,7 @@ contract NetworkRestakeRedistributionHookTest is POCBaseTest { blockTimestamp = blockTimestamp + 1_720_700_948; vm.warp(blockTimestamp); - address hook = address(new NetworkRestakeRedistributionHook()); + address hook = address(new NetworkRestakeRedistributeHook()); vm.startPrank(alice); delegator1.setHook(hook); @@ -113,7 +113,7 @@ contract NetworkRestakeRedistributionHookTest is POCBaseTest { blockTimestamp = blockTimestamp + 1_720_700_948; vm.warp(blockTimestamp); - address hook = address(new NetworkRestakeRedistributionHook()); + address hook = address(new NetworkRestakeRedistributeHook()); address networkRestakeDelegatorImpl = address( new NetworkRestakeDelegator( diff --git a/test/operatorSpecificDelegator/OperatorSpecificFairHook.t.sol b/test/operatorSpecificDelegator/OperatorSpecificFairHook.t.sol index 81f740f..420e100 100644 --- a/test/operatorSpecificDelegator/OperatorSpecificFairHook.t.sol +++ b/test/operatorSpecificDelegator/OperatorSpecificFairHook.t.sol @@ -16,9 +16,9 @@ import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigu import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol"; -import {OperatorSpecificFairHook} from "../../src/contracts/operatorSpecificDelegator/OperatorSpecificFairHook.sol"; +import {OperatorSpecificDecreaseHook} from "../../src/contracts/operatorSpecificDelegator/OperatorSpecificDecreaseHook.sol"; -contract OperatorSpecificFairHookTest is POCBaseTest { +contract OperatorSpecificDecreaseHookTest is POCBaseTest { using Math for uint256; using Subnetwork for bytes32; using Subnetwork for address; @@ -50,7 +50,7 @@ contract OperatorSpecificFairHookTest is POCBaseTest { blockTimestamp = blockTimestamp + 1_720_700_948; vm.warp(blockTimestamp); - address hook = address(new OperatorSpecificFairHook()); + address hook = address(new OperatorSpecificDecreaseHook()); _registerOperator(alice); address[] memory networkLimitSetRoleHolders = new address[](1); @@ -154,7 +154,7 @@ contract OperatorSpecificFairHookTest is POCBaseTest { blockTimestamp = blockTimestamp + 1_720_700_948; vm.warp(blockTimestamp); - address hook = address(new OperatorSpecificFairHook()); + address hook = address(new OperatorSpecificDecreaseHook()); address operatorSpecificDelegatorImpl = address( new OperatorSpecificDelegator( From 84e3c546c7e83d376f1d2b9d2e5bb061fade9276 Mon Sep 17 00:00:00 2001 From: Kresh Date: Fri, 25 Oct 2024 15:06:13 +0400 Subject: [PATCH 9/9] fix: finalize renamings --- .../{FullRestakeFairHook.sol => FullRestakeDecreaseHook.sol} | 0 ...tworkRestakeFairHook.sol => NetworkRestakeDecreaseHook.sol} | 0 ...orSpecificFairHook.sol => OperatorSpecificDecreaseHook.sol} | 3 ++- .../{IFullRestakeFairHook.sol => IFullRestakeDecreaseHook.sol} | 0 ...workRestakeFairHook.sol => INetworkRestakeDecreaseHook.sol} | 0 ...rSpecificFairHook.sol => IOperatorSpecificDecreaseHook.sol} | 0 ...FullRestakeFairHook.t.sol => FullRestakeDecreaseHook.t.sol} | 0 ...kRestakeFairHook.t.sol => NetworkRestakeDecreaseHook.t.sol} | 0 ...ecificFairHook.t.sol => OperatorSpecificDecreaseHook.t.sol} | 3 ++- 9 files changed, 4 insertions(+), 2 deletions(-) rename src/contracts/fullRestakeDelegator/{FullRestakeFairHook.sol => FullRestakeDecreaseHook.sol} (100%) rename src/contracts/networkRestakeDelegator/{NetworkRestakeFairHook.sol => NetworkRestakeDecreaseHook.sol} (100%) rename src/contracts/operatorSpecificDelegator/{OperatorSpecificFairHook.sol => OperatorSpecificDecreaseHook.sol} (90%) rename src/interfaces/fullRestakeDelegator/{IFullRestakeFairHook.sol => IFullRestakeDecreaseHook.sol} (100%) rename src/interfaces/networkRestakeDelegator/{INetworkRestakeFairHook.sol => INetworkRestakeDecreaseHook.sol} (100%) rename src/interfaces/operatorSpecificDelegator/{IOperatorSpecificFairHook.sol => IOperatorSpecificDecreaseHook.sol} (100%) rename test/fullRestakeDelegator/{FullRestakeFairHook.t.sol => FullRestakeDecreaseHook.t.sol} (100%) rename test/networkRestakeDelegator/{NetworkRestakeFairHook.t.sol => NetworkRestakeDecreaseHook.t.sol} (100%) rename test/operatorSpecificDelegator/{OperatorSpecificFairHook.t.sol => OperatorSpecificDecreaseHook.t.sol} (98%) diff --git a/src/contracts/fullRestakeDelegator/FullRestakeFairHook.sol b/src/contracts/fullRestakeDelegator/FullRestakeDecreaseHook.sol similarity index 100% rename from src/contracts/fullRestakeDelegator/FullRestakeFairHook.sol rename to src/contracts/fullRestakeDelegator/FullRestakeDecreaseHook.sol diff --git a/src/contracts/networkRestakeDelegator/NetworkRestakeFairHook.sol b/src/contracts/networkRestakeDelegator/NetworkRestakeDecreaseHook.sol similarity index 100% rename from src/contracts/networkRestakeDelegator/NetworkRestakeFairHook.sol rename to src/contracts/networkRestakeDelegator/NetworkRestakeDecreaseHook.sol diff --git a/src/contracts/operatorSpecificDelegator/OperatorSpecificFairHook.sol b/src/contracts/operatorSpecificDelegator/OperatorSpecificDecreaseHook.sol similarity index 90% rename from src/contracts/operatorSpecificDelegator/OperatorSpecificFairHook.sol rename to src/contracts/operatorSpecificDelegator/OperatorSpecificDecreaseHook.sol index f5985f5..82f81fa 100644 --- a/src/contracts/operatorSpecificDelegator/OperatorSpecificFairHook.sol +++ b/src/contracts/operatorSpecificDelegator/OperatorSpecificDecreaseHook.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import {IOperatorSpecificDecreaseHook} from "../../interfaces/operatorSpecificDelegator/IOperatorSpecificDecreaseHook.sol"; +import {IOperatorSpecificDecreaseHook} from + "../../interfaces/operatorSpecificDelegator/IOperatorSpecificDecreaseHook.sol"; import {IDelegatorHook} from "@symbioticfi/core/src/interfaces/delegator/IDelegatorHook.sol"; import {IEntity} from "@symbioticfi/core/src/interfaces/common/IEntity.sol"; diff --git a/src/interfaces/fullRestakeDelegator/IFullRestakeFairHook.sol b/src/interfaces/fullRestakeDelegator/IFullRestakeDecreaseHook.sol similarity index 100% rename from src/interfaces/fullRestakeDelegator/IFullRestakeFairHook.sol rename to src/interfaces/fullRestakeDelegator/IFullRestakeDecreaseHook.sol diff --git a/src/interfaces/networkRestakeDelegator/INetworkRestakeFairHook.sol b/src/interfaces/networkRestakeDelegator/INetworkRestakeDecreaseHook.sol similarity index 100% rename from src/interfaces/networkRestakeDelegator/INetworkRestakeFairHook.sol rename to src/interfaces/networkRestakeDelegator/INetworkRestakeDecreaseHook.sol diff --git a/src/interfaces/operatorSpecificDelegator/IOperatorSpecificFairHook.sol b/src/interfaces/operatorSpecificDelegator/IOperatorSpecificDecreaseHook.sol similarity index 100% rename from src/interfaces/operatorSpecificDelegator/IOperatorSpecificFairHook.sol rename to src/interfaces/operatorSpecificDelegator/IOperatorSpecificDecreaseHook.sol diff --git a/test/fullRestakeDelegator/FullRestakeFairHook.t.sol b/test/fullRestakeDelegator/FullRestakeDecreaseHook.t.sol similarity index 100% rename from test/fullRestakeDelegator/FullRestakeFairHook.t.sol rename to test/fullRestakeDelegator/FullRestakeDecreaseHook.t.sol diff --git a/test/networkRestakeDelegator/NetworkRestakeFairHook.t.sol b/test/networkRestakeDelegator/NetworkRestakeDecreaseHook.t.sol similarity index 100% rename from test/networkRestakeDelegator/NetworkRestakeFairHook.t.sol rename to test/networkRestakeDelegator/NetworkRestakeDecreaseHook.t.sol diff --git a/test/operatorSpecificDelegator/OperatorSpecificFairHook.t.sol b/test/operatorSpecificDelegator/OperatorSpecificDecreaseHook.t.sol similarity index 98% rename from test/operatorSpecificDelegator/OperatorSpecificFairHook.t.sol rename to test/operatorSpecificDelegator/OperatorSpecificDecreaseHook.t.sol index 420e100..826b80b 100644 --- a/test/operatorSpecificDelegator/OperatorSpecificFairHook.t.sol +++ b/test/operatorSpecificDelegator/OperatorSpecificDecreaseHook.t.sol @@ -16,7 +16,8 @@ import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigu import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol"; -import {OperatorSpecificDecreaseHook} from "../../src/contracts/operatorSpecificDelegator/OperatorSpecificDecreaseHook.sol"; +import {OperatorSpecificDecreaseHook} from + "../../src/contracts/operatorSpecificDelegator/OperatorSpecificDecreaseHook.sol"; contract OperatorSpecificDecreaseHookTest is POCBaseTest { using Math for uint256;