Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add call to burner #62

Merged
merged 3 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions script/deploy/Vault.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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(
Expand Down
7 changes: 2 additions & 5 deletions src/contracts/delegator/BaseDelegator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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) {}
}
41 changes: 39 additions & 2 deletions src/contracts/slasher/BaseSlasher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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
*/
Expand All @@ -36,6 +47,11 @@ abstract contract BaseSlasher is Entity, StaticDelegateCallable, ReentrancyGuard
*/
address public vault;

/**
* @inheritdoc IBaseSlasher
*/
bool public isBurnerHook;

/**
* @inheritdoc IBaseSlasher
*/
Expand Down Expand Up @@ -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 {
Expand All @@ -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) {}
}
8 changes: 8 additions & 0 deletions src/contracts/slasher/Slasher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
6 changes: 5 additions & 1 deletion src/contracts/slasher/VetoSlasher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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();
Expand All @@ -277,5 +279,7 @@ contract VetoSlasher is BaseSlasher, IVetoSlasher {
vetoDuration = params.vetoDuration;

resolverSetEpochsDelay = params.resolverSetEpochsDelay;

return params.baseParams;
}
}
28 changes: 28 additions & 0 deletions src/interfaces/slasher/IBaseSlasher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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)
Expand Down
13 changes: 13 additions & 0 deletions src/interfaces/slasher/IBurner.sol
Original file line number Diff line number Diff line change
@@ -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;
}
12 changes: 11 additions & 1 deletion src/interfaces/slasher/ISlasher.sol
Original file line number Diff line number Diff line change
@@ -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
Expand Down
6 changes: 5 additions & 1 deletion src/interfaces/slasher/IVetoSlasher.sol
Original file line number Diff line number Diff line change
@@ -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();
Expand All @@ -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;
}
Expand Down
4 changes: 3 additions & 1 deletion test/DelegatorFactory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -173,7 +175,7 @@ contract DelegatorFactoryTest is Test {
),
withSlasher: false,
slasherIndex: 0,
slasherParams: ""
slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})}))
})
);

Expand Down
22 changes: 17 additions & 5 deletions test/POCBase.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ contract POCBaseTest is Test {
),
withSlasher: false,
slasherIndex: 0,
slasherParams: ""
slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})}))
})
);

Expand Down Expand Up @@ -260,7 +260,7 @@ contract POCBaseTest is Test {
),
withSlasher: true,
slasherIndex: 0,
slasherParams: ""
slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})}))
})
);

Expand Down Expand Up @@ -307,7 +307,7 @@ contract POCBaseTest is Test {
),
withSlasher: true,
slasherIndex: 0,
slasherParams: ""
slasherParams: abi.encode(ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})}))
})
);

Expand Down Expand Up @@ -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
})
)
})
);

Expand Down Expand Up @@ -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
})
)
})
);

Expand Down
23 changes: 20 additions & 3 deletions test/SlasherFactory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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));
Expand Down
Loading
Loading