Skip to content
Open
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 @@ -52,16 +52,19 @@ contract CompoundingStakingSSVStrategy is
/// @param _rewardTokenAddresses Not used so empty array
/// @param _assets Not used so empty array
/// @param _pTokens Not used so empty array
/// @param _initialDepositAmountWei The amount of ETH required for the first deposit to a new validator.
function initialize(
address[] memory _rewardTokenAddresses,
address[] memory _assets,
address[] memory _pTokens
address[] memory _pTokens,
uint256 _initialDepositAmountWei
) external onlyGovernor initializer {
InitializableAbstractStrategy._initialize(
_rewardTokenAddresses,
_assets,
_pTokens
);
_setInitialDepositAmountWei(_initialDepositAmountWei);
}

/// @notice Unlike other strategies, this does not deposit assets into the underlying platform.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ import { IBeaconProofs } from "../../interfaces/IBeaconProofs.sol";
abstract contract CompoundingValidatorManager is Governable, Pausable {
using SafeERC20 for IERC20;

/// @dev The amount of ETH in wei that is required for a deposit to a new validator.
uint256 internal constant DEPOSIT_AMOUNT_WEI = 1 ether;
/// @dev Validator balances over this amount will eventually become active on the beacon chain.
/// Due to hysteresis, if the effective balance is 31 ETH, the actual balance
/// must rise to 32.25 ETH to trigger an effective balance update to 32 ETH.
Expand Down Expand Up @@ -124,7 +122,7 @@ abstract contract CompoundingValidatorManager is Governable, Pausable {
REGISTERED, // validator is registered on the SSV network
STAKED, // validator has funds staked
VERIFIED, // validator has been verified to exist on the beacon chain
ACTIVE, // The validator balance is at least 32 ETH. The validator may not yet be active on the beacon chain.
ACTIVE, // The validator balance is at least 32.25 ETH. The validator may not yet be active on the beacon chain.
EXITING, // The validator has been requested to exit
EXITED, // The validator has been verified to have a zero balance
REMOVED, // validator has funds withdrawn to this strategy contract and is removed from the SSV
Expand Down Expand Up @@ -168,11 +166,14 @@ abstract contract CompoundingValidatorManager is Governable, Pausable {
/// withdrawal of the validators. It is strictly concerned with WETH that has been deposited and is waiting to
/// be staked.
uint256 public depositedWethAccountedFor;
/// @notice The amount of ETH in wei that is required for the first deposit to a new validator.
uint256 public initialDepositAmountWei;

// For future use
uint256[41] private __gap;
uint256[40] private __gap;

event RegistratorChanged(address indexed newAddress);
event InitialDepositAmountChanged(uint256 amountWei);
event FirstDepositReset();
event SSVValidatorRegistered(
bytes32 indexed pubKeyHash,
Expand Down Expand Up @@ -262,6 +263,14 @@ abstract contract CompoundingValidatorManager is Governable, Pausable {
emit RegistratorChanged(_address);
}

/// @notice Set the amount of ETH required for the first deposit to a new validator.
function setInitialDepositAmount(uint256 _initialDepositAmountWei)
external
onlyGovernor
{
_setInitialDepositAmountWei(_initialDepositAmountWei);
}

/// @notice Reset the `firstDeposit` flag to false so deposits to unverified validators can be made again.
function resetFirstDeposit() external onlyGovernor {
require(firstDeposit, "No first deposit");
Expand Down Expand Up @@ -328,9 +337,9 @@ abstract contract CompoundingValidatorManager is Governable, Pausable {
}

/// @notice Stakes WETH in this strategy to a compounding validator.
/// The first deposit to a new validator, the amount must be 1 ETH.
/// Another deposit of at least 31 ETH is required for the validator to be activated.
/// This second deposit has to be done after the validator has been verified.
/// The first deposit to a new validator must be exactly `initialDepositAmountWei`.
/// Once verified on the beacon chain, rewards can push the validator's balance above
/// the activation threshold so it can become active without requiring a second deposit.
/// Does not convert any ETH sitting in this strategy to WETH.
/// There can not be two deposits to the same validator in the same block for the same amount.
/// Function is pausable so in case a run-away Registrator can be prevented from continuing
Expand Down Expand Up @@ -378,7 +387,7 @@ abstract contract CompoundingValidatorManager is Governable, Pausable {
require(!firstDeposit, "Existing first deposit");
// Limits the amount of ETH that can be at risk from a front-running deposit attack.
require(
depositAmountWei == DEPOSIT_AMOUNT_WEI,
depositAmountWei == initialDepositAmountWei,
"Invalid first deposit amount"
);
// Limits the number of validator balance proofs to verifyBalances
Expand Down Expand Up @@ -1202,6 +1211,19 @@ abstract contract CompoundingValidatorManager is Governable, Pausable {
}
}

function _setInitialDepositAmountWei(uint256 _initialDepositAmountWei)
internal
{
require(_initialDepositAmountWei >= 1 ether, "Deposit too small");
require(
_initialDepositAmountWei <= MIN_ACTIVATION_BALANCE_GWEI * 1e9,
"Deposit too large"
);

initialDepositAmountWei = _initialDepositAmountWei;
emit InitialDepositAmountChanged(_initialDepositAmountWei);
}

/// @notice Hash a validator public key using the Beacon Chain's format
function _hashPubKey(bytes memory pubKey) internal pure returns (bytes32) {
require(pubKey.length == 48, "Invalid public key");
Expand Down
3 changes: 2 additions & 1 deletion contracts/deploy/deployActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -458,14 +458,15 @@ const deployCompoundingStakingSSVStrategy = async () => {

log("Deploy encode initialize function of the strategy contract");
const initData = cStrategyImpl.interface.encodeFunctionData(
"initialize(address[],address[],address[])",
"initialize(address[],address[],address[],uint256)",
[
[], // reward token addresses
/* no need to specify WETH as an asset, since we have that overridden in the "supportsAsset"
* function on the strategy
*/
[], // asset token addresses
[], // platform tokens addresses
ethers.utils.parseEther("1"), // initial validator deposit amount
]
);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const addresses = require("../../utils/addresses");
const { beaconChainGenesisTimeMainnet } = require("../../utils/constants");
const { deploymentWithGovernanceProposal } = require("../../utils/deploy");

module.exports = deploymentWithGovernanceProposal(
{
deployName: "196_upgrade_compounding_staking_initial_deposit",
forceDeploy: false,
reduceQueueTime: true,
deployerIsProposer: false,
},
async ({ deployWithConfirmation, ethers }) => {
const cOETHVaultProxy = await ethers.getContract("OETHVaultProxy");
const cCompoundingStakingStrategyProxy = await ethers.getContract(
"CompoundingStakingSSVStrategyProxy"
);
const cCompoundingStakingSSVStrategy = await ethers.getContractAt(
"CompoundingStakingSSVStrategy",
cCompoundingStakingStrategyProxy.address
);
const cBeaconProofs = await ethers.getContract("BeaconProofs");

console.log("Deploy CompoundingStakingSSVStrategy");
const dCompoundingStakingStrategy = await deployWithConfirmation(
"CompoundingStakingSSVStrategy",
[
[addresses.zero, cOETHVaultProxy.address], //_baseConfig
addresses.mainnet.WETH, // wethAddress
addresses.mainnet.SSVNetwork, // ssvNetwork
addresses.mainnet.beaconChainDepositContract, // beaconChainDepositContract
cBeaconProofs.address, // beaconProofs
beaconChainGenesisTimeMainnet,
]
);

return {
name: "Upgrade the compounding staking strategy initial deposit to 32.25 ETH",
actions: [
{
contract: cCompoundingStakingStrategyProxy,
signature: "upgradeTo(address)",
args: [dCompoundingStakingStrategy.address],
},
{
contract: cCompoundingStakingSSVStrategy,
signature: "setInitialDepositAmount(uint256)",
args: [ethers.utils.parseEther("32.25")],
},
],
};
}
);
Binary file modified contracts/docs/plantuml/oethProcesses.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion contracts/docs/plantuml/oethProcesses.puml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ return ETH
compStrat -> dep : deposit(\npubkey,\nwithdrawal_credentials,\nsignature,\ndeposit root)
activate dep
note left
32 ETH from Staking Strategy is sent to Beacon Deposit.
1 ETH from Staking Strategy is sent to Beacon Deposit.
Withdrawal credential is the Staking Strategy.
end note
return
Expand Down
10 changes: 8 additions & 2 deletions contracts/tasks/validatorCompound.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,16 @@ async function stakeValidator({
withdrawalCredentials = calcWithdrawalCredential("0x02", strategy.address);
}

if (amount == 1) {
const amountWei = parseUnits(amount.toString(), 18);
const initialDepositAmountWei = await strategy.initialDepositAmountWei();

if (amountWei.eq(initialDepositAmountWei)) {
if (!sig) {
throw new Error(
"The signature is required for the first deposit of 1 ETH"
`The signature is required for the first deposit of ${formatUnits(
initialDepositAmountWei,
18
)} ETH`
);
}
await verifyDepositSignatureAndMessageRoot({
Expand Down
Loading
Loading