diff --git a/script/deploy/Vault.s.sol b/script/deploy/Vault.s.sol index 0b20f84..b5fc1a4 100644 --- a/script/deploy/Vault.s.sol +++ b/script/deploy/Vault.s.sol @@ -10,6 +10,8 @@ import {IBaseDelegator} from "../../src/interfaces/delegator/IBaseDelegator.sol" import {INetworkRestakeDelegator} from "../../src/interfaces/delegator/INetworkRestakeDelegator.sol"; import {IFullRestakeDelegator} from "../../src/interfaces/delegator/IFullRestakeDelegator.sol"; import {IOperatorSpecificDelegator} from "../../src/interfaces/delegator/IOperatorSpecificDelegator.sol"; +import {IBaseSlasher} from "../../src/interfaces/slasher/IBaseSlasher.sol"; +import {ISlasher} from "../../src/interfaces/slasher/ISlasher.sol"; import {IVetoSlasher} from "../../src/interfaces/slasher/IVetoSlasher.sol"; contract VaultScript is Script { @@ -74,8 +76,18 @@ contract VaultScript is Script { } bytes memory slasherParams; - if (slasherIndex == 1) { - slasherParams = abi.encode(IVetoSlasher.InitParams({vetoDuration: vetoDuration, resolverSetEpochsDelay: 3})); + if (slasherIndex == 0) { + slasherParams = abi.encode( + abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + ); + } else if (slasherIndex == 1) { + slasherParams = abi.encode( + IVetoSlasher.InitParams({ + baseParams: IBaseSlasher.BaseParams({isBurnerHook: false}), + vetoDuration: vetoDuration, + resolverSetEpochsDelay: 3 + }) + ); } (address vault_, address delegator_, address slasher_) = IVaultConfigurator(vaultConfigurator).create( diff --git a/src/contracts/delegator/BaseDelegator.sol b/src/contracts/delegator/BaseDelegator.sol index 2cd3672..556d2f2 100644 --- a/src/contracts/delegator/BaseDelegator.sol +++ b/src/contracts/delegator/BaseDelegator.sol @@ -219,7 +219,7 @@ abstract contract BaseDelegator is vault = vault_; - IBaseDelegator.BaseParams memory baseParams = __initialize(vault_, data_); + BaseParams memory baseParams = __initialize(vault_, data_); hook = baseParams.hook; @@ -242,8 +242,5 @@ abstract contract BaseDelegator is function _setMaxNetworkLimit(bytes32 subnetwork, uint256 amount) internal virtual {} - function __initialize( - address vault_, - bytes memory data - ) internal virtual returns (IBaseDelegator.BaseParams memory) {} + function __initialize(address vault_, bytes memory data) internal virtual returns (BaseParams memory) {} } diff --git a/src/contracts/slasher/BaseSlasher.sol b/src/contracts/slasher/BaseSlasher.sol index 43e0e3f..7ef61e9 100644 --- a/src/contracts/slasher/BaseSlasher.sol +++ b/src/contracts/slasher/BaseSlasher.sol @@ -6,6 +6,7 @@ import {StaticDelegateCallable} from "../common/StaticDelegateCallable.sol"; import {IBaseDelegator} from "../../interfaces/delegator/IBaseDelegator.sol"; import {IBaseSlasher} from "../../interfaces/slasher/IBaseSlasher.sol"; +import {IBurner} from "../../interfaces/slasher/IBurner.sol"; import {INetworkMiddlewareService} from "../../interfaces/service/INetworkMiddlewareService.sol"; import {IRegistry} from "../../interfaces/common/IRegistry.sol"; import {IVault} from "../../interfaces/vault/IVault.sol"; @@ -21,6 +22,16 @@ abstract contract BaseSlasher is Entity, StaticDelegateCallable, ReentrancyGuard using Checkpoints for Checkpoints.Trace256; using Subnetwork for bytes32; + /** + * @inheritdoc IBaseSlasher + */ + uint256 public constant BURNER_GAS_LIMIT = 150_000; + + /** + * @inheritdoc IBaseSlasher + */ + uint256 public constant BURNER_RESERVE = 20_000; + /** * @inheritdoc IBaseSlasher */ @@ -36,6 +47,11 @@ abstract contract BaseSlasher is Entity, StaticDelegateCallable, ReentrancyGuard */ address public vault; + /** + * @inheritdoc IBaseSlasher + */ + bool public isBurnerHook; + /** * @inheritdoc IBaseSlasher */ @@ -163,6 +179,21 @@ abstract contract BaseSlasher is Entity, StaticDelegateCallable, ReentrancyGuard IVault(vault).onSlash(amount, captureTimestamp); } + function _burnerOnSlash(bytes32 subnetwork, address operator, uint256 amount, uint48 captureTimestamp) internal { + if (isBurnerHook) { + address burner = IVault(vault).burner(); + bytes memory calldata_ = abi.encodeCall(IBurner.onSlash, (subnetwork, operator, amount, captureTimestamp)); + + if (gasleft() < BURNER_RESERVE + BURNER_GAS_LIMIT * 64 / 63) { + revert InsufficientBurnerGas(); + } + + assembly ("memory-safe") { + pop(call(BURNER_GAS_LIMIT, burner, 0, add(calldata_, 0x20), mload(calldata_), 0, 0)) + } + } + } + function _initialize( bytes calldata data ) internal override { @@ -176,8 +207,14 @@ abstract contract BaseSlasher is Entity, StaticDelegateCallable, ReentrancyGuard vault = vault_; - __initialize(vault_, data_); + BaseParams memory baseParams = __initialize(vault_, data_); + + if (IVault(vault_).burner() == address(0) && baseParams.isBurnerHook) { + revert NoBurner(); + } + + isBurnerHook = baseParams.isBurnerHook; } - function __initialize(address vault_, bytes memory data) internal virtual {} + function __initialize(address vault_, bytes memory data) internal virtual returns (BaseParams memory) {} } diff --git a/src/contracts/slasher/Slasher.sol b/src/contracts/slasher/Slasher.sol index e85c5c8..3321710 100644 --- a/src/contracts/slasher/Slasher.sol +++ b/src/contracts/slasher/Slasher.sol @@ -59,6 +59,14 @@ contract Slasher is BaseSlasher, ISlasher { _vaultOnSlash(slashedAmount, captureTimestamp); + _burnerOnSlash(subnetwork, operator, slashedAmount, captureTimestamp); + emit Slash(subnetwork, operator, slashedAmount, captureTimestamp); } + + function __initialize(address, /* vault_ */ bytes memory data) internal override returns (BaseParams memory) { + InitParams memory params = abi.decode(data, (InitParams)); + + return params.baseParams; + } } diff --git a/src/contracts/slasher/VetoSlasher.sol b/src/contracts/slasher/VetoSlasher.sol index 44ce0ae..b5c017a 100644 --- a/src/contracts/slasher/VetoSlasher.sol +++ b/src/contracts/slasher/VetoSlasher.sol @@ -188,6 +188,8 @@ contract VetoSlasher is BaseSlasher, IVetoSlasher { _vaultOnSlash(slashedAmount, request.captureTimestamp); + _burnerOnSlash(request.subnetwork, request.operator, slashedAmount, request.captureTimestamp); + emit ExecuteSlash(slashIndex, slashedAmount); } @@ -262,7 +264,7 @@ contract VetoSlasher is BaseSlasher, IVetoSlasher { emit SetResolver(subnetwork, resolver_); } - function __initialize(address vault_, bytes memory data) internal override { + function __initialize(address vault_, bytes memory data) internal override returns (BaseParams memory) { (InitParams memory params) = abi.decode(data, (InitParams)); uint48 epochDuration = IVault(vault_).epochDuration(); @@ -277,5 +279,7 @@ contract VetoSlasher is BaseSlasher, IVetoSlasher { vetoDuration = params.vetoDuration; resolverSetEpochsDelay = params.resolverSetEpochsDelay; + + return params.baseParams; } } diff --git a/src/interfaces/slasher/IBaseSlasher.sol b/src/interfaces/slasher/IBaseSlasher.sol index 4ece907..fdf61e9 100644 --- a/src/interfaces/slasher/IBaseSlasher.sol +++ b/src/interfaces/slasher/IBaseSlasher.sol @@ -4,9 +4,19 @@ pragma solidity ^0.8.0; import {IEntity} from "../common/IEntity.sol"; interface IBaseSlasher is IEntity { + error NoBurner(); + error InsufficientBurnerGas(); error NotNetworkMiddleware(); error NotVault(); + /** + * @notice Base parameters needed for slashers' deployment. + * @param isBurnerHook if the burner is needed to be called on a slashing + */ + struct BaseParams { + bool isBurnerHook; + } + /** * @notice Hints for a slashable stake. * @param stakeHints hints for the stake checkpoints @@ -27,6 +37,18 @@ interface IBaseSlasher is IEntity { bytes data; } + /** + * @notice Get a gas limit for the burner. + * @return value of the burner gas limit + */ + function BURNER_GAS_LIMIT() external view returns (uint256); + + /** + * @notice Get a reserve gas between the gas limit check and the burner's execution. + * @return value of the reserve gas + */ + function BURNER_RESERVE() external view returns (uint256); + /** * @notice Get the vault factory's address. * @return address of the vault factory @@ -45,6 +67,12 @@ interface IBaseSlasher is IEntity { */ function vault() external view returns (address); + /** + * @notice Get if the burner is needed to be called on a slashing. + * @return if the burner is a hook + */ + function isBurnerHook() external view returns (bool); + /** * @notice Get the latest capture timestamp that was slashed on a subnetwork. * @param subnetwork full identifier of the subnetwork (address of the network concatenated with the uint96 identifier) diff --git a/src/interfaces/slasher/IBurner.sol b/src/interfaces/slasher/IBurner.sol new file mode 100644 index 0000000..1e72815 --- /dev/null +++ b/src/interfaces/slasher/IBurner.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IBurner { + /** + * @notice Called when a slash happens. + * @param subnetwork full identifier of the subnetwork (address of the network concatenated with the uint96 identifier) + * @param operator address of the operator + * @param amount virtual amount of the collateral slashed + * @param captureTimestamp time point when the stake was captured + */ + function onSlash(bytes32 subnetwork, address operator, uint256 amount, uint48 captureTimestamp) external; +} diff --git a/src/interfaces/slasher/ISlasher.sol b/src/interfaces/slasher/ISlasher.sol index 0b60cc6..f610252 100644 --- a/src/interfaces/slasher/ISlasher.sol +++ b/src/interfaces/slasher/ISlasher.sol @@ -1,10 +1,20 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -interface ISlasher { +import {IBaseSlasher} from "./IBaseSlasher.sol"; + +interface ISlasher is IBaseSlasher { error InsufficientSlash(); error InvalidCaptureTimestamp(); + /** + * @notice Initial parameters needed for a slasher deployment. + * @param baseParams base parameters for slashers' deployment + */ + struct InitParams { + IBaseSlasher.BaseParams baseParams; + } + /** * @notice Hints for a slash. * @param slashableStakeHints hints for the slashable stake checkpoints diff --git a/src/interfaces/slasher/IVetoSlasher.sol b/src/interfaces/slasher/IVetoSlasher.sol index 2a5ad05..cc6680e 100644 --- a/src/interfaces/slasher/IVetoSlasher.sol +++ b/src/interfaces/slasher/IVetoSlasher.sol @@ -1,7 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -interface IVetoSlasher { +import {IBaseSlasher} from "./IBaseSlasher.sol"; + +interface IVetoSlasher is IBaseSlasher { error InsufficientSlash(); error InvalidCaptureTimestamp(); error InvalidResolverSetEpochsDelay(); @@ -17,10 +19,12 @@ interface IVetoSlasher { /** * @notice Initial parameters needed for a slasher deployment. + * @param baseParams base parameters for slashers' deployment * @param vetoDuration duration of the veto period for a slash request * @param resolverSetEpochsDelay delay in epochs for a network to update a resolver */ struct InitParams { + IBaseSlasher.BaseParams baseParams; uint48 vetoDuration; uint256 resolverSetEpochsDelay; } diff --git a/test/DelegatorFactory.t.sol b/test/DelegatorFactory.t.sol index 263934c..7bcfc9f 100644 --- a/test/DelegatorFactory.t.sol +++ b/test/DelegatorFactory.t.sol @@ -27,6 +27,8 @@ import {IVaultConfigurator} from "../src/interfaces/IVaultConfigurator.sol"; import {INetworkRestakeDelegator} from "../src/interfaces/delegator/INetworkRestakeDelegator.sol"; import {IFullRestakeDelegator} from "../src/interfaces/delegator/IFullRestakeDelegator.sol"; import {IBaseDelegator} from "../src/interfaces/delegator/IBaseDelegator.sol"; +import {IBaseSlasher} from "../src/interfaces/slasher/IBaseSlasher.sol"; +import {ISlasher} from "../src/interfaces/slasher/ISlasher.sol"; contract DelegatorFactoryTest is Test { address owner; @@ -173,7 +175,7 @@ contract DelegatorFactoryTest is Test { ), withSlasher: false, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); diff --git a/test/POCBase.t.sol b/test/POCBase.t.sol index af53146..47f3a53 100644 --- a/test/POCBase.t.sol +++ b/test/POCBase.t.sol @@ -213,7 +213,7 @@ contract POCBaseTest is Test { ), withSlasher: false, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -260,7 +260,7 @@ contract POCBaseTest is Test { ), withSlasher: true, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -307,7 +307,7 @@ contract POCBaseTest is Test { ), withSlasher: true, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -355,7 +355,13 @@ contract POCBaseTest is Test { ), withSlasher: true, slasherIndex: 1, - slasherParams: abi.encode(IVetoSlasher.InitParams({vetoDuration: vetoDuration, resolverSetEpochsDelay: 3})) + slasherParams: abi.encode( + IVetoSlasher.InitParams({ + baseParams: IBaseSlasher.BaseParams({isBurnerHook: false}), + vetoDuration: vetoDuration, + resolverSetEpochsDelay: 3 + }) + ) }) ); @@ -403,7 +409,13 @@ contract POCBaseTest is Test { ), withSlasher: true, slasherIndex: 1, - slasherParams: abi.encode(IVetoSlasher.InitParams({vetoDuration: vetoDuration, resolverSetEpochsDelay: 3})) + slasherParams: abi.encode( + IVetoSlasher.InitParams({ + baseParams: IBaseSlasher.BaseParams({isBurnerHook: false}), + vetoDuration: vetoDuration, + resolverSetEpochsDelay: 3 + }) + ) }) ); diff --git a/test/SlasherFactory.t.sol b/test/SlasherFactory.t.sol index 44cb809..6df6f6a 100644 --- a/test/SlasherFactory.t.sol +++ b/test/SlasherFactory.t.sol @@ -28,6 +28,8 @@ import {INetworkRestakeDelegator} from "../src/interfaces/delegator/INetworkRest import {IFullRestakeDelegator} from "../src/interfaces/delegator/IFullRestakeDelegator.sol"; import {IBaseDelegator} from "../src/interfaces/delegator/IBaseDelegator.sol"; import {IVetoSlasher} from "../src/interfaces/slasher/IVetoSlasher.sol"; +import {IBaseSlasher} from "../src/interfaces/slasher/IBaseSlasher.sol"; +import {ISlasher} from "../src/interfaces/slasher/ISlasher.sol"; contract SlasherFactoryTest is Test { address owner; @@ -174,16 +176,31 @@ contract SlasherFactoryTest is Test { ), withSlasher: false, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); - address slasher = slasherFactory.create(0, abi.encode(vault_, "")); + address slasher = slasherFactory.create( + 0, + abi.encode( + vault_, abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + ) + ); assertEq(Slasher(slasher).FACTORY(), address(slasherFactory)); assertEq(slasherFactory.isEntity(slasher), true); address vetoSlasher = slasherFactory.create( - 1, abi.encode(vault_, abi.encode(IVetoSlasher.InitParams({vetoDuration: 0, resolverSetEpochsDelay: 3}))) + 1, + abi.encode( + vault_, + abi.encode( + IVetoSlasher.InitParams({ + baseParams: IBaseSlasher.BaseParams({isBurnerHook: false}), + vetoDuration: 0, + resolverSetEpochsDelay: 3 + }) + ) + ) ); assertEq(VetoSlasher(vetoSlasher).FACTORY(), address(slasherFactory)); diff --git a/test/VaultConfigurator.t.sol b/test/VaultConfigurator.t.sol index f851c9a..d38f20f 100644 --- a/test/VaultConfigurator.t.sol +++ b/test/VaultConfigurator.t.sol @@ -27,6 +27,8 @@ import {IVaultConfigurator} from "../src/interfaces/IVaultConfigurator.sol"; import {INetworkRestakeDelegator} from "../src/interfaces/delegator/INetworkRestakeDelegator.sol"; import {IFullRestakeDelegator} from "../src/interfaces/delegator/IFullRestakeDelegator.sol"; import {IBaseDelegator} from "../src/interfaces/delegator/IBaseDelegator.sol"; +import {ISlasher} from "../src/interfaces/slasher/ISlasher.sol"; +import {IBaseSlasher} from "../src/interfaces/slasher/IBaseSlasher.sol"; contract VaultConfiguratorTest is Test { address owner; @@ -189,7 +191,7 @@ contract VaultConfiguratorTest is Test { ), withSlasher: withSlasher, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); diff --git a/test/VaultFactory.t.sol b/test/VaultFactory.t.sol index fec050c..8f6636b 100644 --- a/test/VaultFactory.t.sol +++ b/test/VaultFactory.t.sol @@ -27,6 +27,8 @@ import {IVaultConfigurator} from "../src/interfaces/IVaultConfigurator.sol"; import {INetworkRestakeDelegator} from "../src/interfaces/delegator/INetworkRestakeDelegator.sol"; import {IFullRestakeDelegator} from "../src/interfaces/delegator/IFullRestakeDelegator.sol"; import {IBaseDelegator} from "../src/interfaces/delegator/IBaseDelegator.sol"; +import {ISlasher} from "../src/interfaces/slasher/ISlasher.sol"; +import {IBaseSlasher} from "../src/interfaces/slasher/IBaseSlasher.sol"; contract VaultFactoryTest is Test { address owner; @@ -173,7 +175,7 @@ contract VaultFactoryTest is Test { ), withSlasher: false, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); diff --git a/test/delegator/FullRestakeDelegator.t.sol b/test/delegator/FullRestakeDelegator.t.sol index 909cbae..cec6a69 100644 --- a/test/delegator/FullRestakeDelegator.t.sol +++ b/test/delegator/FullRestakeDelegator.t.sol @@ -28,6 +28,7 @@ import {INetworkRestakeDelegator} from "../../src/interfaces/delegator/INetworkR import {IFullRestakeDelegator} from "../../src/interfaces/delegator/IFullRestakeDelegator.sol"; import {IBaseDelegator} from "../../src/interfaces/delegator/IBaseDelegator.sol"; import {ISlasher} from "../../src/interfaces/slasher/ISlasher.sol"; +import {IBaseSlasher} from "../../src/interfaces/slasher/IBaseSlasher.sol"; import {IVaultStorage} from "../../src/interfaces/vault/IVaultStorage.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; @@ -1031,7 +1032,7 @@ contract FullRestakeDelegatorTest is Test { ), withSlasher: true, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -1145,7 +1146,7 @@ contract FullRestakeDelegatorTest is Test { ), withSlasher: true, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -1889,7 +1890,7 @@ contract FullRestakeDelegatorTest is Test { ), withSlasher: false, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -1936,7 +1937,7 @@ contract FullRestakeDelegatorTest is Test { ), withSlasher: true, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -1946,7 +1947,15 @@ contract FullRestakeDelegatorTest is Test { function _getSlasher( address vault_ ) internal returns (Slasher) { - return Slasher(slasherFactory.create(0, abi.encode(address(vault_), ""))); + return Slasher( + slasherFactory.create( + 0, + abi.encode( + address(vault_), + abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + ) + ) + ); } function _registerOperator( diff --git a/test/delegator/NetworkRestakeDelegator.t.sol b/test/delegator/NetworkRestakeDelegator.t.sol index b912826..b5ce38c 100644 --- a/test/delegator/NetworkRestakeDelegator.t.sol +++ b/test/delegator/NetworkRestakeDelegator.t.sol @@ -29,6 +29,7 @@ import {IFullRestakeDelegator} from "../../src/interfaces/delegator/IFullRestake import {IBaseDelegator} from "../../src/interfaces/delegator/IBaseDelegator.sol"; import {IBaseSlasher} from "../../src/interfaces/slasher/IBaseSlasher.sol"; import {ISlasher} from "../../src/interfaces/slasher/ISlasher.sol"; +import {IBaseSlasher} from "../../src/interfaces/slasher/IBaseSlasher.sol"; import {IVaultStorage} from "../../src/interfaces/vault/IVaultStorage.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; @@ -1238,7 +1239,7 @@ contract NetworkRestakeDelegatorTest is Test { ), withSlasher: true, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -1379,7 +1380,7 @@ contract NetworkRestakeDelegatorTest is Test { ), withSlasher: true, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -2185,7 +2186,7 @@ contract NetworkRestakeDelegatorTest is Test { ), withSlasher: false, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -2232,7 +2233,7 @@ contract NetworkRestakeDelegatorTest is Test { ), withSlasher: true, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -2242,7 +2243,15 @@ contract NetworkRestakeDelegatorTest is Test { function _getSlasher( address vault_ ) internal returns (Slasher) { - return Slasher(slasherFactory.create(0, abi.encode(address(vault_), ""))); + return Slasher( + slasherFactory.create( + 0, + abi.encode( + address(vault_), + abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + ) + ) + ); } function _registerOperator( diff --git a/test/delegator/OperatorSpecificDelegator.t.sol b/test/delegator/OperatorSpecificDelegator.t.sol index 1fc9d79..864d101 100644 --- a/test/delegator/OperatorSpecificDelegator.t.sol +++ b/test/delegator/OperatorSpecificDelegator.t.sol @@ -28,6 +28,7 @@ import {IOperatorSpecificDelegator} from "../../src/interfaces/delegator/IOperat import {IFullRestakeDelegator} from "../../src/interfaces/delegator/IFullRestakeDelegator.sol"; import {IBaseDelegator} from "../../src/interfaces/delegator/IBaseDelegator.sol"; import {ISlasher} from "../../src/interfaces/slasher/ISlasher.sol"; +import {IBaseSlasher} from "../../src/interfaces/slasher/IBaseSlasher.sol"; import {IVaultStorage} from "../../src/interfaces/vault/IVaultStorage.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; @@ -751,7 +752,7 @@ contract OperatorSpecificDelegatorTest is Test { ), withSlasher: true, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -842,7 +843,7 @@ contract OperatorSpecificDelegatorTest is Test { ), withSlasher: true, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -1496,7 +1497,7 @@ contract OperatorSpecificDelegatorTest is Test { ), withSlasher: false, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -1543,7 +1544,7 @@ contract OperatorSpecificDelegatorTest is Test { ), withSlasher: true, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -1553,7 +1554,15 @@ contract OperatorSpecificDelegatorTest is Test { function _getSlasher( address vault_ ) internal returns (Slasher) { - return Slasher(slasherFactory.create(0, abi.encode(address(vault_), ""))); + return Slasher( + slasherFactory.create( + 0, + abi.encode( + address(vault_), + abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + ) + ) + ); } function _registerOperator( diff --git a/test/mocks/SimpleBurner.sol b/test/mocks/SimpleBurner.sol new file mode 100644 index 0000000..9f32af5 --- /dev/null +++ b/test/mocks/SimpleBurner.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.25; + +import {IBurner} from "../../src/interfaces/slasher/IBurner.sol"; + +import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +contract SimpleBurner is IBurner { + using SafeERC20 for IERC20; + + address public immutable COLLATERAL; + + constructor( + address collateral + ) { + COLLATERAL = collateral; + } + + uint256 public counter1; + uint256 public counter2; + uint256 public counter3; + + function onSlash(bytes32 subnetwork, address operator, uint256, uint48) external { + ++counter1; + ++counter2; + ++counter3; + } + + function distribute() external { + IERC20(COLLATERAL).safeTransfer(msg.sender, IERC20(COLLATERAL).balanceOf(address(this))); + } +} diff --git a/test/slasher/Slasher.t.sol b/test/slasher/Slasher.t.sol index 02a88c5..d105934 100644 --- a/test/slasher/Slasher.t.sol +++ b/test/slasher/Slasher.t.sol @@ -39,6 +39,8 @@ import {OptInServiceHints} from "../../src/contracts/hints/OptInServiceHints.sol import {VaultHints} from "../../src/contracts/hints/VaultHints.sol"; import {Subnetwork} from "../../src/contracts/libraries/Subnetwork.sol"; +import {SimpleBurner} from "../mocks/SimpleBurner.sol"; + contract SlasherTest is Test { using Subnetwork for bytes32; using Subnetwork for address; @@ -179,6 +181,65 @@ contract SlasherTest is Test { assertEq(slasher.slashableStake(alice.subnetwork(0), alice, 0, ""), 0); } + function test_CreateRevertNoBurner( + uint48 epochDuration + ) public { + epochDuration = uint48(bound(epochDuration, 1, 50 weeks)); + + address[] memory networkLimitSetRoleHolders = new address[](1); + networkLimitSetRoleHolders[0] = alice; + address[] memory operatorNetworkLimitSetRoleHolders = new address[](1); + operatorNetworkLimitSetRoleHolders[0] = alice; + (address vault_, address delegator_,) = vaultConfigurator.create( + IVaultConfigurator.InitParams({ + version: vaultFactory.lastVersion(), + owner: alice, + vaultParams: abi.encode( + IVault.InitParams({ + collateral: address(collateral), + burner: address(0), + epochDuration: epochDuration, + depositWhitelist: false, + isDepositLimit: false, + depositLimit: 0, + defaultAdminRoleHolder: alice, + depositWhitelistSetRoleHolder: alice, + depositorWhitelistRoleHolder: alice, + isDepositLimitSetRoleHolder: alice, + depositLimitSetRoleHolder: alice + }) + ), + delegatorIndex: 1, + delegatorParams: abi.encode( + IFullRestakeDelegator.InitParams({ + baseParams: IBaseDelegator.BaseParams({ + defaultAdminRoleHolder: alice, + hook: address(0), + hookSetRoleHolder: alice + }), + networkLimitSetRoleHolders: networkLimitSetRoleHolders, + operatorNetworkLimitSetRoleHolders: operatorNetworkLimitSetRoleHolders + }) + ), + withSlasher: false, + slasherIndex: 0, + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + }) + ); + + vault = Vault(vault_); + delegator = FullRestakeDelegator(delegator_); + + vm.expectRevert(IBaseSlasher.NoBurner.selector); + slasherFactory.create( + 0, + abi.encode( + address(vault), + abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: true})})) + ) + ); + } + function test_CreateRevertNotVault( uint48 epochDuration ) public { @@ -187,7 +248,13 @@ contract SlasherTest is Test { (vault,) = _getVaultAndDelegator(epochDuration); vm.expectRevert(IBaseSlasher.NotVault.selector); - slasherFactory.create(0, abi.encode(address(1), "")); + slasherFactory.create( + 0, + abi.encode( + address(1), + abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + ) + ); } function test_Slash( @@ -810,6 +877,300 @@ contract SlasherTest is Test { _slash(alice, network, alice, slashAmount1, uint48(blockTimestamp - captureAgo), ""); } + function test_SlashWithBurner( + // uint48 epochDuration, + uint256 depositAmount, + // uint256 networkLimit, + uint256 operatorNetworkLimit1, + uint256 slashAmount1, + uint256 slashAmount2 + ) public { + // epochDuration = uint48(bound(epochDuration, 1, 10 days)); + depositAmount = bound(depositAmount, 1, 100 * 10 ** 18); + // networkLimit = bound(networkLimit, 1, type(uint256).max); + operatorNetworkLimit1 = bound(operatorNetworkLimit1, 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, operatorNetworkLimit1))); + + uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + blockTimestamp = blockTimestamp + 1_720_700_948; + vm.warp(blockTimestamp); + + address burner = address(new SimpleBurner(address(collateral))); + 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: burner, + epochDuration: 7 days, + depositWhitelist: false, + isDepositLimit: false, + depositLimit: 0, + defaultAdminRoleHolder: alice, + depositWhitelistSetRoleHolder: alice, + depositorWhitelistRoleHolder: alice, + isDepositLimitSetRoleHolder: alice, + depositLimitSetRoleHolder: alice + }) + ), + delegatorIndex: 1, + delegatorParams: abi.encode( + IFullRestakeDelegator.InitParams({ + baseParams: IBaseDelegator.BaseParams({ + defaultAdminRoleHolder: alice, + hook: address(0), + hookSetRoleHolder: address(0) + }), + networkLimitSetRoleHolders: networkLimitSetRoleHolders, + operatorNetworkLimitSetRoleHolders: operatorNetworkLimitSetRoleHolders + }) + ), + withSlasher: true, + slasherIndex: 0, + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: true})})) + }) + ); + + vault = Vault(vault_); + delegator = FullRestakeDelegator(delegator_); + slasher = Slasher(slasher_); + + address network = alice; + _registerNetwork(network, alice); + _setMaxNetworkLimit(network, 0, type(uint256).max); + + _registerOperator(alice); + + _optInOperatorVault(alice); + + _optInOperatorNetwork(alice, address(network)); + + _deposit(alice, depositAmount); + + _setNetworkLimit(alice, network, type(uint256).max); + + _setOperatorNetworkLimit(alice, network, alice, operatorNetworkLimit1); + + assertEq(delegator.networkLimit(network.subnetwork(0)), type(uint256).max); + assertEq(delegator.operatorNetworkLimit(network.subnetwork(0), alice), operatorNetworkLimit1); + + blockTimestamp = blockTimestamp + 1; + vm.warp(blockTimestamp); + + _slash(alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(SimpleBurner(burner).counter1(), 1); + } + + function test_SlashWithBurnerDisabled( + // uint48 epochDuration, + uint256 depositAmount, + // uint256 networkLimit, + uint256 operatorNetworkLimit1, + uint256 slashAmount1, + uint256 slashAmount2 + ) public { + // epochDuration = uint48(bound(epochDuration, 1, 10 days)); + depositAmount = bound(depositAmount, 1, 100 * 10 ** 18); + // networkLimit = bound(networkLimit, 1, type(uint256).max); + operatorNetworkLimit1 = bound(operatorNetworkLimit1, 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, operatorNetworkLimit1))); + + uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + blockTimestamp = blockTimestamp + 1_720_700_948; + vm.warp(blockTimestamp); + + address burner = address(new SimpleBurner(address(collateral))); + 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: burner, + epochDuration: 7 days, + depositWhitelist: false, + isDepositLimit: false, + depositLimit: 0, + defaultAdminRoleHolder: alice, + depositWhitelistSetRoleHolder: alice, + depositorWhitelistRoleHolder: alice, + isDepositLimitSetRoleHolder: alice, + depositLimitSetRoleHolder: alice + }) + ), + delegatorIndex: 1, + delegatorParams: abi.encode( + IFullRestakeDelegator.InitParams({ + baseParams: IBaseDelegator.BaseParams({ + defaultAdminRoleHolder: alice, + hook: address(0), + hookSetRoleHolder: address(0) + }), + networkLimitSetRoleHolders: networkLimitSetRoleHolders, + operatorNetworkLimitSetRoleHolders: operatorNetworkLimitSetRoleHolders + }) + ), + withSlasher: true, + slasherIndex: 0, + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + }) + ); + + vault = Vault(vault_); + delegator = FullRestakeDelegator(delegator_); + slasher = Slasher(slasher_); + + address network = alice; + _registerNetwork(network, alice); + _setMaxNetworkLimit(network, 0, type(uint256).max); + + _registerOperator(alice); + + _optInOperatorVault(alice); + + _optInOperatorNetwork(alice, address(network)); + + _deposit(alice, depositAmount); + + _setNetworkLimit(alice, network, type(uint256).max); + + _setOperatorNetworkLimit(alice, network, alice, operatorNetworkLimit1); + + assertEq(delegator.networkLimit(network.subnetwork(0)), type(uint256).max); + assertEq(delegator.operatorNetworkLimit(network.subnetwork(0), alice), operatorNetworkLimit1); + + blockTimestamp = blockTimestamp + 1; + vm.warp(blockTimestamp); + + _slash(alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + assertEq(SimpleBurner(burner).counter1(), 0); + } + + function test_SlashWithBurnerGas( + // uint48 epochDuration, + uint256 depositAmount, + // uint256 networkLimit, + uint256 operatorNetworkLimit1, + uint256 slashAmount1, + uint256 totalGas + ) public { + // epochDuration = uint48(bound(epochDuration, 1, 10 days)); + depositAmount = bound(depositAmount, 1, 100 * 10 ** 18); + // networkLimit = bound(networkLimit, 1, type(uint256).max); + operatorNetworkLimit1 = bound(operatorNetworkLimit1, 1, type(uint256).max / 2); + slashAmount1 = bound(slashAmount1, 1, type(uint256).max); + totalGas = bound(totalGas, 1, 20_000_000); + vm.assume(slashAmount1 < Math.min(depositAmount, Math.min(type(uint256).max, operatorNetworkLimit1))); + + uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + blockTimestamp = blockTimestamp + 1_720_700_948; + vm.warp(blockTimestamp); + + address burner = address(new SimpleBurner(address(collateral))); + 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: burner, + epochDuration: 7 days, + depositWhitelist: false, + isDepositLimit: false, + depositLimit: 0, + defaultAdminRoleHolder: alice, + depositWhitelistSetRoleHolder: alice, + depositorWhitelistRoleHolder: alice, + isDepositLimitSetRoleHolder: alice, + depositLimitSetRoleHolder: alice + }) + ), + delegatorIndex: 1, + delegatorParams: abi.encode( + IFullRestakeDelegator.InitParams({ + baseParams: IBaseDelegator.BaseParams({ + defaultAdminRoleHolder: alice, + hook: address(0), + hookSetRoleHolder: address(0) + }), + networkLimitSetRoleHolders: networkLimitSetRoleHolders, + operatorNetworkLimitSetRoleHolders: operatorNetworkLimitSetRoleHolders + }) + ), + withSlasher: true, + slasherIndex: 0, + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: true})})) + }) + ); + + vault = Vault(vault_); + delegator = FullRestakeDelegator(delegator_); + slasher = Slasher(slasher_); + + address network = alice; + _registerNetwork(network, alice); + _setMaxNetworkLimit(network, 0, type(uint256).max); + + _registerOperator(alice); + + _optInOperatorVault(alice); + + _optInOperatorNetwork(alice, address(network)); + + _deposit(alice, depositAmount); + + _setNetworkLimit(alice, network, type(uint256).max); + + _setOperatorNetworkLimit(alice, network, alice, operatorNetworkLimit1); + + assertEq(delegator.networkLimit(network.subnetwork(0)), type(uint256).max); + assertEq(delegator.operatorNetworkLimit(network.subnetwork(0), alice), operatorNetworkLimit1); + + blockTimestamp = blockTimestamp + 1; + vm.warp(blockTimestamp); + + _slash(alice, network, alice, slashAmount1, uint48(blockTimestamp - 1), ""); + + vm.startPrank(alice); + uint256 HOOK_GAS_LIMIT = delegator.HOOK_GAS_LIMIT(); + uint256 BURNER_GAS_LIMIT = slasher.BURNER_GAS_LIMIT(); + vm.expectRevert(IBaseSlasher.InsufficientBurnerGas.selector); + slasher.slash{gas: HOOK_GAS_LIMIT}(network.subnetwork(0), alice, slashAmount1, uint48(blockTimestamp - 1), ""); + vm.stopPrank(); + + vm.startPrank(alice); + (bool success,) = address(slasher).call{gas: totalGas}( + abi.encodeCall(ISlasher.slash, (network.subnetwork(0), alice, slashAmount1, uint48(blockTimestamp - 1), "")) + ); + vm.stopPrank(); + + if (success) { + assertEq(SimpleBurner(burner).counter1(), 2); + } + } + // struct GasStruct { // uint256 gasSpent1; // uint256 gasSpent2; @@ -1363,7 +1724,7 @@ contract SlasherTest is Test { ), withSlasher: false, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -1410,7 +1771,7 @@ contract SlasherTest is Test { ), withSlasher: true, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -1420,7 +1781,15 @@ contract SlasherTest is Test { function _getSlasher( address vault_ ) internal returns (Slasher) { - return Slasher(slasherFactory.create(0, abi.encode(address(vault_), ""))); + return Slasher( + slasherFactory.create( + 0, + abi.encode( + address(vault_), + abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + ) + ) + ); } function _registerOperator( diff --git a/test/slasher/VetoSlasher.t.sol b/test/slasher/VetoSlasher.t.sol index 3261110..241101a 100644 --- a/test/slasher/VetoSlasher.t.sol +++ b/test/slasher/VetoSlasher.t.sol @@ -29,6 +29,7 @@ import {IFullRestakeDelegator} from "../../src/interfaces/delegator/IFullRestake import {IBaseDelegator} from "../../src/interfaces/delegator/IBaseDelegator.sol"; import {IMigratableEntityProxy} from "../../src/interfaces/common/IMigratableEntityProxy.sol"; import {IMigratableEntity} from "../../src/interfaces/common/IMigratableEntity.sol"; +import {ISlasher} from "../../src/interfaces/slasher/ISlasher.sol"; import {IVaultStorage} from "../../src/interfaces/vault/IVaultStorage.sol"; import {IVetoSlasher} from "../../src/interfaces/slasher/IVetoSlasher.sol"; @@ -201,7 +202,11 @@ contract VetoSlasherTest is Test { abi.encode( address(1), abi.encode( - IVetoSlasher.InitParams({vetoDuration: vetoDuration, resolverSetEpochsDelay: resolverSetEpochsDelay}) + IVetoSlasher.InitParams({ + baseParams: IBaseSlasher.BaseParams({isBurnerHook: false}), + vetoDuration: vetoDuration, + resolverSetEpochsDelay: resolverSetEpochsDelay + }) ) ) ); @@ -225,7 +230,11 @@ contract VetoSlasherTest is Test { abi.encode( address(vault), abi.encode( - IVetoSlasher.InitParams({vetoDuration: vetoDuration, resolverSetEpochsDelay: resolverSetEpochsDelay}) + IVetoSlasher.InitParams({ + baseParams: IBaseSlasher.BaseParams({isBurnerHook: false}), + vetoDuration: vetoDuration, + resolverSetEpochsDelay: resolverSetEpochsDelay + }) ) ) ); @@ -249,7 +258,11 @@ contract VetoSlasherTest is Test { abi.encode( address(vault), abi.encode( - IVetoSlasher.InitParams({vetoDuration: vetoDuration, resolverSetEpochsDelay: resolverSetEpochsDelay}) + IVetoSlasher.InitParams({ + baseParams: IBaseSlasher.BaseParams({isBurnerHook: false}), + vetoDuration: vetoDuration, + resolverSetEpochsDelay: resolverSetEpochsDelay + }) ) ) ); @@ -2350,7 +2363,7 @@ contract VetoSlasherTest is Test { ), withSlasher: false, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -2398,7 +2411,13 @@ contract VetoSlasherTest is Test { ), withSlasher: true, slasherIndex: 1, - slasherParams: abi.encode(IVetoSlasher.InitParams({vetoDuration: vetoDuration, resolverSetEpochsDelay: 3})) + slasherParams: abi.encode( + IVetoSlasher.InitParams({ + baseParams: IBaseSlasher.BaseParams({isBurnerHook: false}), + vetoDuration: vetoDuration, + resolverSetEpochsDelay: 3 + }) + ) }) ); @@ -2410,7 +2429,14 @@ contract VetoSlasherTest is Test { slasherFactory.create( 1, abi.encode( - vault_, abi.encode(IVetoSlasher.InitParams({vetoDuration: vetoDuration, resolverSetEpochsDelay: 3})) + vault_, + abi.encode( + IVetoSlasher.InitParams({ + baseParams: IBaseSlasher.BaseParams({isBurnerHook: false}), + vetoDuration: vetoDuration, + resolverSetEpochsDelay: 3 + }) + ) ) ) ); diff --git a/test/vault/Vault.t.sol b/test/vault/Vault.t.sol index de7f17b..b94dd86 100644 --- a/test/vault/Vault.t.sol +++ b/test/vault/Vault.t.sol @@ -28,6 +28,8 @@ import {IVaultConfigurator} from "../../src/interfaces/IVaultConfigurator.sol"; import {INetworkRestakeDelegator} from "../../src/interfaces/delegator/INetworkRestakeDelegator.sol"; import {IFullRestakeDelegator} from "../../src/interfaces/delegator/IFullRestakeDelegator.sol"; import {IBaseDelegator} from "../../src/interfaces/delegator/IBaseDelegator.sol"; +import {ISlasher} from "../../src/interfaces/slasher/ISlasher.sol"; +import {IBaseSlasher} from "../../src/interfaces/slasher/IBaseSlasher.sol"; import {IVaultStorage} from "../../src/interfaces/vault/IVaultStorage.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; @@ -202,7 +204,7 @@ contract VaultTest is Test { ), withSlasher: false, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -325,7 +327,7 @@ contract VaultTest is Test { ), withSlasher: false, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); } @@ -374,7 +376,7 @@ contract VaultTest is Test { ), withSlasher: false, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); } @@ -778,7 +780,15 @@ contract VaultTest is Test { assertEq(vault.isSlasherInitialized(), false); - slasher = Slasher(slasherFactory.create(0, abi.encode(address(vault), ""))); + slasher = Slasher( + slasherFactory.create( + 0, + abi.encode( + address(vault), + abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + ) + ) + ); vault.setSlasher(address(slasher)); @@ -812,7 +822,15 @@ contract VaultTest is Test { ) ); - slasher = Slasher(slasherFactory.create(0, abi.encode(address(vault), ""))); + slasher = Slasher( + slasherFactory.create( + 0, + abi.encode( + address(vault), + abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + ) + ) + ); vault.setSlasher(address(slasher)); @@ -845,7 +863,15 @@ contract VaultTest is Test { ) ); - slasher = Slasher(slasherFactory.create(0, abi.encode(address(vault), ""))); + slasher = Slasher( + slasherFactory.create( + 0, + abi.encode( + address(vault), + abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + ) + ) + ); vm.expectRevert(IVault.NotSlasher.selector); vault.setSlasher(address(1)); @@ -898,7 +924,15 @@ contract VaultTest is Test { ) ); - slasher = Slasher(slasherFactory.create(0, abi.encode(address(vault2), ""))); + slasher = Slasher( + slasherFactory.create( + 0, + abi.encode( + address(vault2), + abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + ) + ) + ); vm.expectRevert(IVault.InvalidSlasher.selector); vault.setSlasher(address(slasher)); @@ -2687,7 +2721,7 @@ contract VaultTest is Test { ), withSlasher: false, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -2734,7 +2768,7 @@ contract VaultTest is Test { ), withSlasher: true, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); diff --git a/test/vault/VaultTokenized.t.sol b/test/vault/VaultTokenized.t.sol index eb6b7fd..65297c5 100644 --- a/test/vault/VaultTokenized.t.sol +++ b/test/vault/VaultTokenized.t.sol @@ -29,6 +29,8 @@ import {IVaultConfigurator} from "../../src/interfaces/IVaultConfigurator.sol"; import {INetworkRestakeDelegator} from "../../src/interfaces/delegator/INetworkRestakeDelegator.sol"; import {IFullRestakeDelegator} from "../../src/interfaces/delegator/IFullRestakeDelegator.sol"; import {IBaseDelegator} from "../../src/interfaces/delegator/IBaseDelegator.sol"; +import {ISlasher} from "../../src/interfaces/slasher/ISlasher.sol"; +import {IBaseSlasher} from "../../src/interfaces/slasher/IBaseSlasher.sol"; import {IVaultStorage} from "../../src/interfaces/vault/IVaultStorage.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; @@ -207,7 +209,7 @@ contract VaultTokenizedTest is Test { ), withSlasher: false, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -341,7 +343,7 @@ contract VaultTokenizedTest is Test { ), withSlasher: false, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); } @@ -394,7 +396,7 @@ contract VaultTokenizedTest is Test { ), withSlasher: false, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); } @@ -842,7 +844,15 @@ contract VaultTokenizedTest is Test { assertEq(vault.isSlasherInitialized(), false); - slasher = Slasher(slasherFactory.create(0, abi.encode(address(vault), ""))); + slasher = Slasher( + slasherFactory.create( + 0, + abi.encode( + address(vault), + abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + ) + ) + ); vault.setSlasher(address(slasher)); @@ -880,7 +890,15 @@ contract VaultTokenizedTest is Test { ) ); - slasher = Slasher(slasherFactory.create(0, abi.encode(address(vault), ""))); + slasher = Slasher( + slasherFactory.create( + 0, + abi.encode( + address(vault), + abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + ) + ) + ); vault.setSlasher(address(slasher)); @@ -917,7 +935,15 @@ contract VaultTokenizedTest is Test { ) ); - slasher = Slasher(slasherFactory.create(0, abi.encode(address(vault), ""))); + slasher = Slasher( + slasherFactory.create( + 0, + abi.encode( + address(vault), + abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + ) + ) + ); vm.expectRevert(IVault.NotSlasher.selector); vault.setSlasher(address(1)); @@ -978,7 +1004,15 @@ contract VaultTokenizedTest is Test { ) ); - slasher = Slasher(slasherFactory.create(0, abi.encode(address(vault2), ""))); + slasher = Slasher( + slasherFactory.create( + 0, + abi.encode( + address(vault2), + abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) + ) + ) + ); vm.expectRevert(IVault.InvalidSlasher.selector); vault.setSlasher(address(slasher)); @@ -2854,7 +2888,7 @@ contract VaultTokenizedTest is Test { ), withSlasher: false, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) ); @@ -2905,7 +2939,7 @@ contract VaultTokenizedTest is Test { ), withSlasher: true, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})})) }) );