Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ abstract contract ValidatorRegistrator is Governable, Pausable {
/// @notice Amount of ETH that has been staked since the `stakingMonitor` last called `resetStakeETHTally`.
/// This can not go above `stakeETHThreshold`.
uint256 public stakeETHTally;

// For future use
uint256[47] private __gap;

Expand Down Expand Up @@ -231,6 +230,7 @@ abstract contract ValidatorRegistrator is Governable, Pausable {
/// @param sharesData The shares data for each validator
/// @param ssvAmount The amount of SSV tokens to be deposited to the SSV cluster
/// @param cluster The SSV cluster details including the validator count and SSV balance
// slither-disable-start reentrancy-no-eth
function registerSsvValidators(
bytes[] calldata publicKeys,
uint64[] calldata operatorIds,
Expand Down Expand Up @@ -267,86 +267,66 @@ abstract contract ValidatorRegistrator is Governable, Pausable {
);
}

/// @notice Exit validators from the Beacon chain.
// slither-disable-end reentrancy-no-eth

/// @notice Exit a validator from the Beacon chain.
/// The staked ETH will eventually swept to this native staking strategy.
/// Only the registrator can call this function.
/// @param publicKeys List of SSV validator public keys
/// @param publicKey The public key of the validator
/// @param operatorIds The operator IDs of the SSV Cluster
function exitSsvValidators(
bytes[] calldata publicKeys,
// slither-disable-start reentrancy-no-eth
function exitSsvValidator(
bytes calldata publicKey,
uint64[] calldata operatorIds
) external onlyRegistrator whenNotPaused nonReentrant {
ISSVNetwork(SSV_NETWORK).bulkExitValidator(publicKeys, operatorIds);

bytes32 pubKeyHash;
VALIDATOR_STATE currentState;
for (uint256 i = 0; i < publicKeys.length; ++i) {
pubKeyHash = keccak256(publicKeys[i]);
currentState = validatorsStates[pubKeyHash];
) external onlyRegistrator whenNotPaused {
bytes32 pubKeyHash = keccak256(publicKey);
VALIDATOR_STATE currentState = validatorsStates[pubKeyHash];
require(currentState == VALIDATOR_STATE.STAKED, "Validator not staked");

// Check each validator has not already been staked.
// This would normally be done before the external call but is after
// so only one for loop of the validators is needed.
require(
currentState == VALIDATOR_STATE.STAKED,
"Validator not staked"
);
ISSVNetwork(SSV_NETWORK).exitValidator(publicKey, operatorIds);

// Store the new validator state
validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXITING;
validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXITING;

emit SSVValidatorExitInitiated(
pubKeyHash,
publicKeys[i],
operatorIds
);
}
emit SSVValidatorExitInitiated(pubKeyHash, publicKey, operatorIds);
}

/// @notice Remove validators from the SSV Cluster.
// slither-disable-end reentrancy-no-eth

/// @notice Remove a validator from the SSV Cluster.
/// Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain.
/// If removed before the validator has exited the beacon chain will result in the validator being slashed.
/// Only the registrator can call this function.
/// @param publicKeys List of SSV validator public keys
/// @param publicKey The public key of the validator
/// @param operatorIds The operator IDs of the SSV Cluster
/// @param cluster The SSV cluster details including the validator count and SSV balance
function removeSsvValidators(
bytes[] calldata publicKeys,
// slither-disable-start reentrancy-no-eth
function removeSsvValidator(
bytes calldata publicKey,
uint64[] calldata operatorIds,
Cluster calldata cluster
) external onlyRegistrator whenNotPaused nonReentrant {
ISSVNetwork(SSV_NETWORK).bulkRemoveValidator(
publicKeys,
) external onlyRegistrator whenNotPaused {
bytes32 pubKeyHash = keccak256(publicKey);
VALIDATOR_STATE currentState = validatorsStates[pubKeyHash];
// Can remove SSV validators that were incorrectly registered and can not be deposited to.
require(
currentState == VALIDATOR_STATE.EXITING ||
currentState == VALIDATOR_STATE.REGISTERED,
"Validator not regd or exiting"
);

ISSVNetwork(SSV_NETWORK).removeValidator(
publicKey,
operatorIds,
cluster
);

bytes32 pubKeyHash;
VALIDATOR_STATE currentState;
for (uint256 i = 0; i < publicKeys.length; ++i) {
pubKeyHash = keccak256(publicKeys[i]);
currentState = validatorsStates[pubKeyHash];

// Check each validator is either registered or exited.
// This would normally be done before the external call but is after
// so only one for loop of the validators is needed.
require(
currentState == VALIDATOR_STATE.EXITING ||
currentState == VALIDATOR_STATE.REGISTERED,
"Validator not regd or exiting"
);

// Store the new validator state
validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXIT_COMPLETE;
validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXIT_COMPLETE;

emit SSVValidatorExitCompleted(
pubKeyHash,
publicKeys[i],
operatorIds
);
}
emit SSVValidatorExitCompleted(pubKeyHash, publicKey, operatorIds);
}

// slither-disable-end reentrancy-no-eth

/// @notice Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators.
/// @dev A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds.
/// uses "onlyStrategist" modifier so continuous front-running can't DOS our maintenance service
Expand Down
75 changes: 6 additions & 69 deletions contracts/deploy/mainnet/153_upgrade_native_staking.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module.exports = deploymentWithGovernanceProposal(
deployerIsProposer: false,
// proposalId: "",
},
async ({ deployWithConfirmation, ethers }) => {
async ({ ethers }) => {
// Current contracts
const cVaultProxy = await ethers.getContract("OETHVaultProxy");
const cVaultAdmin = await ethers.getContractAt(
Expand All @@ -21,91 +21,28 @@ module.exports = deploymentWithGovernanceProposal(
// Deployer Actions
// ----------------

// 1. Fetch the Native Strategy proxies
const cNativeStakingStrategyProxy_2 = await ethers.getContract(
"NativeStakingSSVStrategy2Proxy"
);
const cNativeStakingStrategyProxy_3 = await ethers.getContract(
"NativeStakingSSVStrategy3Proxy"
);

// 2. Fetch the Fee Accumulator proxies
const cFeeAccumulatorProxy_2 = await ethers.getContract(
"NativeStakingFeeAccumulator2Proxy"
);
const cFeeAccumulatorProxy_3 = await ethers.getContract(
"NativeStakingFeeAccumulator3Proxy"
);

// 3. Deploy the new Native Staking Strategy implementation
const dNativeStakingStrategyImpl_2 = await deployWithConfirmation(
"NativeStakingSSVStrategy",
[
[addresses.zero, cVaultProxy.address], //_baseConfig
addresses.mainnet.WETH, // wethAddress
addresses.mainnet.SSV, // ssvToken
addresses.mainnet.SSVNetwork, // ssvNetwork
500, // maxValidators
cFeeAccumulatorProxy_2.address, // feeAccumulator
addresses.mainnet.beaconChainDepositContract, // beacon chain deposit contract
]
);
console.log(
`Deployed 2nd NativeStakingSSVStrategy ${dNativeStakingStrategyImpl_2.address}`
);

const dNativeStakingStrategyImpl_3 = await deployWithConfirmation(
"NativeStakingSSVStrategy",
[
[addresses.zero, cVaultProxy.address], //_baseConfig
addresses.mainnet.WETH, // wethAddress
addresses.mainnet.SSV, // ssvToken
addresses.mainnet.SSVNetwork, // ssvNetwork
500, // maxValidators
cFeeAccumulatorProxy_3.address, // feeAccumulator
addresses.mainnet.beaconChainDepositContract, // beacon chain deposit contract
],
undefined,
true // skipUpgradeSafety
);
console.log(
`Deployed 3rd NativeStakingSSVStrategy ${dNativeStakingStrategyImpl_3.address}`
);

// 4. Deploy the new Compounding Staking Strategy contracts
// 1. Deploy the new Compounding Staking Strategy contracts
const cCompoundingStakingStrategy =
await deployCompoundingStakingSSVStrategy();

// Governance Actions
// ----------------
return {
name: `Upgrade the existing Native Staking Strategies and deploy new Compounding Staking Strategy`,
name: `Deploy new Compounding Staking Strategy that uses compounding validators`,
actions: [
// 1. Upgrade the second Native Staking Strategy
{
contract: cNativeStakingStrategyProxy_2,
signature: "upgradeTo(address)",
args: [dNativeStakingStrategyImpl_2.address],
},
// 2. Upgrade the third Native Staking Strategy
{
contract: cNativeStakingStrategyProxy_3,
signature: "upgradeTo(address)",
args: [dNativeStakingStrategyImpl_3.address],
},
// 3. Add new strategy to vault
// 1. Add new strategy to vault
{
contract: cVaultAdmin,
signature: "approveStrategy(address)",
args: [cCompoundingStakingStrategy.address],
},
// 4. set harvester to the Defender Relayer
// 2. set harvester to the Defender Relayer
{
contract: cCompoundingStakingStrategy,
signature: "setHarvesterAddress(address)",
args: [addresses.mainnet.validatorRegistrator],
},
// 5. set validator registrator to the Defender Relayer
// 3. set validator registrator to the Defender Relayer
{
contract: cCompoundingStakingStrategy,
signature: "setRegistrator(address)",
Expand Down
17 changes: 7 additions & 10 deletions contracts/tasks/ssv.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { parseUnits, formatUnits, hexlify } = require("ethers/lib/utils");
const { parseUnits, formatUnits } = require("ethers/lib/utils");

const addresses = require("../utils/addresses");
const { resolveContract } = require("../utils/resolvers");
Expand All @@ -10,11 +10,11 @@ const { resolveNativeStakingStrategyProxy } = require("./validator");

const log = require("../utils/logger")("task:ssv");

async function removeValidators({ index, pubkeys, operatorids }) {
async function removeValidator({ index, pubkey, operatorids }) {
const signer = await getSigner();

log(`Splitting operator IDs ${operatorids}`);
const operatorIds = await sortOperatorIds(operatorids);
const operatorIds = operatorids.split(",").map((id) => parseInt(id));

const strategy = await resolveNativeStakingStrategyProxy(index);

Expand All @@ -28,14 +28,11 @@ async function removeValidators({ index, pubkeys, operatorids }) {
ownerAddress: strategy.address,
});

log(`Splitting public keys ${pubkeys}`);
const pubKeys = pubkeys.split(",").map((pubkey) => hexlify(pubkey));

log(`About to remove validators: ${pubKeys}`);
log(`About to remove validator: ${pubkey}`);
const tx = await strategy
.connect(signer)
.removeSsvValidators(pubKeys, operatorIds, cluster);
await logTxDetails(tx, "removeSsvValidators");
.removeSsvValidator(pubkey, operatorIds, cluster);
await logTxDetails(tx, "removeSsvValidator");
}

const printClusterInfo = async (options) => {
Expand Down Expand Up @@ -121,5 +118,5 @@ module.exports = {
printClusterInfo,
depositSSV,
withdrawSSV,
removeValidators,
removeValidator,
};
Loading
Loading