Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
fb5a9df
clusters::registration:eth storage added
venimir-ssv Dec 2, 2025
9635060
clusters::registration:refactored
venimir-ssv Dec 2, 2025
84e7816
clusters::remove:refactored
venimir-ssv Dec 2, 2025
0c9bc2f
clusters::liquidate:refactored, liquidateSSV added
venimir-ssv Dec 2, 2025
aa01b8c
clusters::reactivate:refactored for eth migration
venimir-ssv Dec 2, 2025
334414f
clusters::deposit:refactored for eth migration
venimir-ssv Dec 2, 2025
a6269b0
clusters::withdraw:refactored for eth migration
venimir-ssv Dec 2, 2025
800f6ac
operators::library:refactored for eth migration
venimir-ssv Dec 3, 2025
925f11f
operators::registerOperator:refactored for eth migration
venimir-ssv Dec 3, 2025
e71b395
operators::removeOperator:refactored for eth migration remove operato…
venimir-ssv Dec 3, 2025
63cda69
operators::declareOperatorFee:refactored for eth migration
venimir-ssv Dec 3, 2025
a0a87ff
operators::reduceOperatorFee:refactored for eth migration
venimir-ssv Dec 3, 2025
ab8d658
operators::withdraw:refactored for eth migration
venimir-ssv Dec 3, 2025
9db14fd
SSVDAO:refactored for eth migration
venimir-ssv Dec 3, 2025
8377c83
reentrancy guard added for eth payments
venimir-ssv Dec 3, 2025
b6c5d93
migrate to eth operator added
venimir-ssv Dec 3, 2025
7109d98
migrateClusterToETH added wip
venimir-ssv Dec 3, 2025
91285a4
ensureETHDefaults added
venimir-ssv Dec 3, 2025
cf2ee52
obsolate code removed
venimir-ssv Dec 3, 2025
2c3e531
compilation errors fixed
venimir-ssv Dec 3, 2025
fe08665
updateClusterOperatorsSSV added
venimir-ssv Dec 4, 2025
eeaa2c4
ClusterMigratedToETH event added
venimir-ssv Dec 4, 2025
fb31267
removeValidator nonReentrant modifier removed
venimir-ssv Dec 4, 2025
092fd52
ssv dao update during migration added
venimir-ssv Dec 4, 2025
aaf3422
withdrawAllVersionOperatorEarnings added
venimir-ssv Dec 4, 2025
fdac245
ensureETHDefaults refactored
venimir-ssv Dec 4, 2025
464273c
Add legacy SSV views, dual withdraw helpers, and bump version to v1.3.0
venimir-ssv Dec 4, 2025
a30d73c
Wire SSVNetworkViews to new SSV/ETH view helpers
venimir-ssv Dec 4, 2025
c37a58b
migrateOperator to ETH refactored
venimir-ssv Dec 4, 2025
caf13d1
reentracy changed to upgradable
venimir-ssv Dec 4, 2025
eb1092b
Initialize reentrancy guard in proxy for delegatecall modules
venimir-ssv Dec 5, 2025
914b277
Unify reentrancy guard at proxy and fix ETH/SSV accounting mismatches
venimir-ssv Dec 5, 2025
4400829
feat: persist ssv/eth balance checks
yurii-ssv Dec 5, 2025
8bd71f0
fix: ssv/eth natspec inconsistency
yurii-ssv Dec 5, 2025
09e783a
fix: add ethSnapshot check in `checkOwner`
yurii-ssv Dec 5, 2025
fa8aa07
chore: fix typos
yurii-ssv Dec 5, 2025
4437102
settle SSV snapshot before migrate ETHDefaults, msg.value fixed
venimir-ssv Dec 5, 2025
2df7bcf
update SSV before ensureETHDefaults
venimir-ssv Dec 5, 2025
e20df4e
update snapshor on registration removed
venimir-ssv Dec 5, 2025
d912a16
increase check added
venimir-ssv Dec 5, 2025
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
2 changes: 1 addition & 1 deletion .solhint.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"ordering": "warn",
"mark-callable-contracts": "off",
"max-line-length": [
"error",
"warn",
120
],
"compiler-version": "off",
Expand Down
536 changes: 536 additions & 0 deletions ETH_MIGRATION_CHANGELOG.md

Large diffs are not rendered by default.

65 changes: 54 additions & 11 deletions contracts/SSVNetwork.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ import {SSVModules} from "./libraries/SSVStorage.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";

contract SSVNetwork is
UUPSUpgradeable,
Ownable2StepUpgradeable,
ReentrancyGuardUpgradeable,
ISSVNetwork,
ISSVOperators,
ISSVOperatorsWhitelist,
Expand Down Expand Up @@ -55,6 +57,7 @@ contract SSVNetwork is
) external override initializer onlyProxy {
__UUPSUpgradeable_init();
__Ownable_init_unchained();
__ReentrancyGuard_init();
__SSVNetwork_init_unchained(
token_,
ssvOperators_,
Expand Down Expand Up @@ -129,7 +132,11 @@ contract SSVNetwork is
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_OPERATORS]);
}

function removeOperator(uint64 operatorId) external override {
function removeOperator(uint64 operatorId) external override nonReentrant {
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_OPERATORS]);
}

function migrateOperatorToETH(uint64 operatorId) external override {
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_OPERATORS]);
}

Expand Down Expand Up @@ -158,7 +165,7 @@ contract SSVNetwork is
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_OPERATORS]);
}

function setOperatorsPublicUnchecked(uint64[] calldata operatorIds) external {
function setOperatorsPublicUnchecked(uint64[] calldata operatorIds) external override {
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_OPERATORS]);
}

Expand All @@ -182,11 +189,23 @@ contract SSVNetwork is
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_OPERATORS]);
}

function withdrawOperatorEarnings(uint64 operatorId, uint256 amount) external override {
function withdrawOperatorEarnings(uint64 operatorId, uint256 amount) external override nonReentrant {
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_OPERATORS]);
}

function withdrawAllOperatorEarnings(uint64 operatorId) external override nonReentrant {
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_OPERATORS]);
}

function withdrawAllVersionOperatorEarnings(uint64 operatorId) external override nonReentrant {
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_OPERATORS]);
}

function withdrawOperatorEarningsSSV(uint64 operatorId, uint256 amount) external override nonReentrant {
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_OPERATORS]);
}

function withdrawAllOperatorEarnings(uint64 operatorId) external override {
function withdrawAllOperatorEarningsSSV(uint64 operatorId) external override nonReentrant {
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_OPERATORS]);
}

Expand All @@ -208,7 +227,7 @@ contract SSVNetwork is
bytes calldata sharesData,
uint256 amount,
ISSVNetworkCore.Cluster memory cluster
) external override {
) external payable override {
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_CLUSTERS]);
}

Expand All @@ -218,7 +237,7 @@ contract SSVNetwork is
bytes[] calldata sharesData,
uint256 amount,
ISSVNetworkCore.Cluster memory cluster
) external override {
) external payable override {
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_CLUSTERS]);
}

Expand All @@ -242,15 +261,23 @@ contract SSVNetwork is
address clusterOwner,
uint64[] calldata operatorIds,
ISSVNetworkCore.Cluster memory cluster
) external {
) external override nonReentrant {
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_CLUSTERS]);
}

function liquidateSSV(
address clusterOwner,
uint64[] calldata operatorIds,
ISSVNetworkCore.Cluster memory cluster
) external override nonReentrant {
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_CLUSTERS]);
}

function reactivate(
uint64[] calldata operatorIds,
uint256 amount,
ISSVNetworkCore.Cluster memory cluster
) external override {
) external payable override {
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_CLUSTERS]);
}

Expand All @@ -259,15 +286,23 @@ contract SSVNetwork is
uint64[] calldata operatorIds,
uint256 amount,
ISSVNetworkCore.Cluster memory cluster
) external override {
) external payable override {
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_CLUSTERS]);
}

function withdraw(
uint64[] calldata operatorIds,
uint256 amount,
ISSVNetworkCore.Cluster memory cluster
) external override {
) external override nonReentrant {
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_CLUSTERS]);
}

function migrateClusterToETH(uint64[] calldata operatorIds, ISSVNetworkCore.Cluster memory cluster)
external
payable
override
{
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_CLUSTERS]);
}

Expand All @@ -283,7 +318,15 @@ contract SSVNetwork is
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_DAO]);
}

function withdrawNetworkEarnings(uint256 amount) external override onlyOwner {
function updateNetworkFeeSSV(uint256 fee) external override onlyOwner {
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_DAO]);
}

function withdrawNetworkEarnings(uint256 amount) external override onlyOwner nonReentrant {
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_DAO]);
}

function withdrawNetworkSSVEarnings(uint256 amount) external override onlyOwner nonReentrant {
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_DAO]);
}

Expand Down
52 changes: 51 additions & 1 deletion contracts/SSVNetworkViews.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ contract SSVNetworkViews is UUPSUpgradeable, Ownable2StepUpgradeable, ISSVViews
return ssvNetwork.getOperatorFee(operatorId);
}

function getOperatorFeeSSV(uint64 operatorId) external view override returns (uint256) {
return ssvNetwork.getOperatorFeeSSV(operatorId);
}

function getOperatorDeclaredFee(uint64 operatorId) external view override returns (bool, uint256, uint64, uint64) {
return ssvNetwork.getOperatorDeclaredFee(operatorId);
}
Expand All @@ -61,6 +65,12 @@ contract SSVNetworkViews is UUPSUpgradeable, Ownable2StepUpgradeable, ISSVViews
return ssvNetwork.getOperatorById(operatorId);
}

function getOperatorByIdSSV(
uint64 operatorId
) external view override returns (address, uint256, uint32, address, bool, bool) {
return ssvNetwork.getOperatorByIdSSV(operatorId);
}

function getWhitelistedOperators(
uint64[] calldata operatorIds,
address whitelistedAddress
Expand Down Expand Up @@ -92,6 +102,14 @@ contract SSVNetworkViews is UUPSUpgradeable, Ownable2StepUpgradeable, ISSVViews
return ssvNetwork.isLiquidatable(clusterOwner, operatorIds, cluster);
}

function isLiquidatableSSV(
address clusterOwner,
uint64[] calldata operatorIds,
Cluster memory cluster
) external view override returns (bool) {
return ssvNetwork.isLiquidatableSSV(clusterOwner, operatorIds, cluster);
}

function isLiquidated(
address clusterOwner,
uint64[] calldata operatorIds,
Expand All @@ -104,10 +122,18 @@ contract SSVNetworkViews is UUPSUpgradeable, Ownable2StepUpgradeable, ISSVViews
address clusterOwner,
uint64[] calldata operatorIds,
Cluster memory cluster
) external view returns (uint256) {
) external view override returns (uint256) {
return ssvNetwork.getBurnRate(clusterOwner, operatorIds, cluster);
}

function getBurnRateSSV(
address clusterOwner,
uint64[] calldata operatorIds,
Cluster memory cluster
) external view override returns (uint256) {
return ssvNetwork.getBurnRateSSV(clusterOwner, operatorIds, cluster);
}

/***********************************/
/* Balance External View Functions */
/***********************************/
Expand All @@ -116,6 +142,10 @@ contract SSVNetworkViews is UUPSUpgradeable, Ownable2StepUpgradeable, ISSVViews
return ssvNetwork.getOperatorEarnings(id);
}

function getOperatorEarningsSSV(uint64 id) external view override returns (uint256) {
return ssvNetwork.getOperatorEarningsSSV(id);
}

function getBalance(
address clusterOwner,
uint64[] calldata operatorIds,
Expand All @@ -124,6 +154,14 @@ contract SSVNetworkViews is UUPSUpgradeable, Ownable2StepUpgradeable, ISSVViews
return ssvNetwork.getBalance(clusterOwner, operatorIds, cluster);
}

function getBalanceSSV(
address clusterOwner,
uint64[] calldata operatorIds,
Cluster memory cluster
) external view override returns (uint256) {
return ssvNetwork.getBalanceSSV(clusterOwner, operatorIds, cluster);
}

/*******************************/
/* DAO External View Functions */
/*******************************/
Expand All @@ -136,6 +174,14 @@ contract SSVNetworkViews is UUPSUpgradeable, Ownable2StepUpgradeable, ISSVViews
return ssvNetwork.getNetworkEarnings();
}

function getNetworkFeeSSV() external view override returns (uint256) {
return ssvNetwork.getNetworkFeeSSV();
}

function getNetworkEarningsSSV() external view override returns (uint256) {
return ssvNetwork.getNetworkEarningsSSV();
}

function getOperatorFeeIncreaseLimit() external view override returns (uint64) {
return ssvNetwork.getOperatorFeeIncreaseLimit();
}
Expand Down Expand Up @@ -164,6 +210,10 @@ contract SSVNetworkViews is UUPSUpgradeable, Ownable2StepUpgradeable, ISSVViews
return ssvNetwork.getNetworkValidatorsCount();
}

function getClusterVersion(address owner, uint64[] calldata operatorIds) external view override returns (uint8) {
return ssvNetwork.getClusterVersion(owner, operatorIds);
}

function getVersion() external view override returns (string memory) {
return ssvNetwork.getVersion();
}
Expand Down
40 changes: 36 additions & 4 deletions contracts/interfaces/ISSVClusters.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ interface ISSVClusters is ISSVNetworkCore {
bytes calldata sharesData,
uint256 amount,
Cluster memory cluster
) external;
) external payable;

/// @notice Registers new validators on the SSV Network
/// @param publicKeys The public keys of the new validators
Expand All @@ -30,7 +30,7 @@ interface ISSVClusters is ISSVNetworkCore {
bytes[] calldata sharesData,
uint256 amount,
Cluster memory cluster
) external;
) external payable;

/// @notice Removes an existing validator from the SSV Network
/// @param publicKey The public key of the validator to be removed
Expand All @@ -49,6 +49,11 @@ interface ISSVClusters is ISSVNetworkCore {
Cluster memory cluster
) external;

/// @notice Migrates an SSV cluster to ETH, returning any SSV balance and accepting ETH top-up
/// @param operatorIds Array of operator IDs in the cluster
/// @param cluster Cluster data to migrate
function migrateClusterToETH(uint64[] calldata operatorIds, Cluster memory cluster) external payable;

/**************************/
/* Cluster External Functions */
/**************************/
Expand All @@ -59,11 +64,17 @@ interface ISSVClusters is ISSVNetworkCore {
/// @param cluster Cluster to be liquidated
function liquidate(address owner, uint64[] memory operatorIds, Cluster memory cluster) external;

/// @notice Liquidates a cluster
/// @param owner The owner of the cluster
/// @param operatorIds Array of IDs of operators managing the cluster
/// @param cluster Cluster to be liquidated
function liquidateSSV(address owner, uint64[] memory operatorIds, Cluster memory cluster) external;

/// @notice Reactivates a cluster
/// @param operatorIds Array of IDs of operators managing the cluster
/// @param amount Amount of SSV tokens to be deposited for reactivation
/// @param cluster Cluster to be reactivated
function reactivate(uint64[] memory operatorIds, uint256 amount, Cluster memory cluster) external;
function reactivate(uint64[] memory operatorIds, uint256 amount, Cluster memory cluster) external payable;

/******************************/
/* Balance External Functions */
Expand All @@ -74,7 +85,12 @@ interface ISSVClusters is ISSVNetworkCore {
/// @param operatorIds Array of IDs of operators managing the cluster
/// @param amount Amount of SSV tokens to be deposited
/// @param cluster Cluster where the deposit will be made
function deposit(address owner, uint64[] memory operatorIds, uint256 amount, Cluster memory cluster) external;
function deposit(
address owner,
uint64[] memory operatorIds,
uint256 amount,
Cluster memory cluster
) external payable;

/// @notice Withdraws tokens from a cluster
/// @param operatorIds Array of IDs of operators managing the cluster
Expand Down Expand Up @@ -125,6 +141,22 @@ interface ISSVClusters is ISSVNetworkCore {
*/
event ClusterReactivated(address indexed owner, uint64[] operatorIds, Cluster cluster);

/**
* @dev Emitted when a legacy SSV cluster is migrated to ETH.
* @param owner The owner of the migrated cluster.
* @param operatorIds The operator IDs managing the cluster.
* @param ethDeposited The amount of ETH supplied during migration.
* @param ssvRefunded The amount of SSV tokens refunded to the owner.
* @param cluster The migrated cluster data (ETH version).
*/
event ClusterMigratedToETH(
address indexed owner,
uint64[] operatorIds,
uint256 ethDeposited,
uint256 ssvRefunded,
Cluster cluster
);

/**
* @dev Emitted when tokens are withdrawn from a cluster.
* @param owner The owner of the cluster.
Expand Down
16 changes: 12 additions & 4 deletions contracts/interfaces/ISSVDAO.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,22 @@ pragma solidity ^0.8.20;
import {ISSVNetworkCore} from "./ISSVNetworkCore.sol";

interface ISSVDAO is ISSVNetworkCore {
/// @notice Updates the network fee
/// @param fee The new network fee (SSV) to be set
/// @notice Updates the network fee (ETH post-migration)
/// @param fee The new network fee (ETH) to be set
function updateNetworkFee(uint256 fee) external;

/// @notice Withdraws network earnings
/// @param amount The amount (SSV) to be withdrawn
/// @notice Updates the legacy network fee (SSV pre-migration)
/// @param fee The new network fee (SSV) to be set
function updateNetworkFeeSSV(uint256 fee) external;

/// @notice Withdraws network earnings (ETH post-migration)
/// @param amount The amount (ETH) to be withdrawn
function withdrawNetworkEarnings(uint256 amount) external;

/// @notice Withdraws legacy network earnings (SSV pre-migration)
/// @param amount The amount (SSV) to be withdrawn
function withdrawNetworkSSVEarnings(uint256 amount) external;

/// @notice Updates the limit on the percentage increase in operator fees
/// @param percentage The new percentage limit
function updateOperatorFeeIncreaseLimit(uint64 percentage) external;
Expand Down
Loading
Loading