Skip to content

Commit

Permalink
chore: fix comments
Browse files Browse the repository at this point in the history
  • Loading branch information
tamtamchik committed Feb 26, 2025
1 parent d4f3a62 commit 081444b
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 59 deletions.
2 changes: 1 addition & 1 deletion contracts/0.8.25/vaults/Dashboard.sol
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ contract Dashboard is Permissions {
* @param _pubkeys Concatenated validator public keys (48 bytes each).
* @param _amounts Withdrawal amounts in wei for each validator key and must match _pubkeys length.
* Set amount to 0 for a full validator exit.
* For partial withdrawals, amounts will be capped to maintain the minimum stake of 32 ETH on the validator.
* For partial withdrawals, amounts will be trimmed to keep MIN_ACTIVATION_BALANCE on the validator to avoid deactivation
* @param _refundRecipient Address to receive any fee refunds, if zero, refunds go to msg.sender.
* @dev A withdrawal fee must be paid via msg.value.
* Use `StakingVault.calculateValidatorWithdrawalFee()` to determine the required fee for the current block.
Expand Down
6 changes: 2 additions & 4 deletions contracts/0.8.25/vaults/Permissions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -223,17 +223,15 @@ abstract contract Permissions is AccessControlConfirmable {

/**
* @dev Checks the REQUEST_VALIDATOR_EXIT_ROLE and requests validator exit on the StakingVault.
* @param _pubkeys The public keys of the validators to request exit for.
* @dev The zero check for _pubkeys is performed in the StakingVault contract.
*/
function _requestValidatorExit(bytes calldata _pubkeys) internal onlyRole(REQUEST_VALIDATOR_EXIT_ROLE) {
stakingVault().requestValidatorExit(_pubkeys);
}

/**
* @dev Checks the TRIGGER_VALIDATOR_WITHDRAWAL_ROLE and triggers validator withdrawal on the StakingVault using EIP-7002 triggerable exit.
* @param _pubkeys The public keys of the validators to trigger withdrawal for.
* @param _amounts The amounts of ether to trigger withdrawal for.
* @param _refundRecipient The address to refund the excess ether to.
* @dev The zero checks for parameters are performed in the StakingVault contract.
*/
function _triggerValidatorWithdrawal(bytes calldata _pubkeys, uint64[] calldata _amounts, address _refundRecipient) internal onlyRole(TRIGGER_VALIDATOR_WITHDRAWAL_ROLE) {
stakingVault().triggerValidatorWithdrawal{value: msg.value}(_pubkeys, _amounts, _refundRecipient);
Expand Down
73 changes: 29 additions & 44 deletions contracts/0.8.25/vaults/StakingVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,19 @@ import {IStakingVault} from "./interfaces/IStakingVault.sol";
* StakingVault is a private staking pool that enables staking with a designated node operator.
* Each StakingVault includes an accounting system that tracks its valuation via reports.
*
* The StakingVault can be used as a backing for minting new stETH if the StakingVault is connected to the VaultHub.
* When minting stETH backed by the StakingVault, the VaultHub locks a portion of the StakingVault's valuation,
* which cannot be withdrawn by the owner. If the locked amount exceeds the StakingVault's valuation,
* the StakingVault enters the unhealthy state.
* In this state, the VaultHub can force-rebalance the StakingVault by withdrawing a portion of the locked amount
* and writing off the locked amount to restore the healthy state.
* The owner can voluntarily rebalance the StakingVault in any state or by simply
* supplying more ether to increase the valuation.
* The StakingVault can be used as a backing for minting new stETH through integration with the VaultHub.
* When minting stETH backed by the StakingVault, the VaultHub designates a portion of the StakingVault's
* valuation as locked, which cannot be withdrawn by the owner. This locked portion represents the
* backing for the minted stETH.
*
* If the locked amount exceeds the StakingVault's current valuation, the VaultHub has the ability to
* rebalance the StakingVault. This rebalancing process involves withdrawing a portion of the staked amount
* and adjusting the locked amount to align with the current valuation.
*
* The owner may proactively maintain the vault's backing ratio by either:
* - Voluntarily rebalancing the StakingVault at any time
* - Adding more ether to increase the valuation
* - Triggering validator withdrawals to increase the valuation
*
* Access
* - Owner:
Expand Down Expand Up @@ -141,16 +146,14 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {
}

/**
* @notice Returns the highest version that has been initialized
* @return Highest initialized version number as uint64
* @notice Returns the highest version that has been initialized as uint64
*/
function getInitializedVersion() external view returns (uint64) {
return _getInitializedVersion();
}

/**
* @notice Returns the version of the contract
* @return Version number as uint64
* @notice Returns the version of the contract as uint64
*/
function version() external pure returns (uint64) {
return _VERSION;
Expand All @@ -162,15 +165,13 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {

/**
* @notice Returns the address of `VaultHub`
* @return Address of `VaultHub`
*/
function vaultHub() external view returns (address) {
return address(VAULT_HUB);
}

/**
* @notice Returns the total valuation of `StakingVault`
* @return Total valuation in ether
* @notice Returns the total valuation of `StakingVault` in ether
* @dev Valuation = latestReport.valuation + (current inOutDelta - latestReport.inOutDelta)
*/
function valuation() public view returns (uint256) {
Expand All @@ -179,8 +180,7 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {
}

/**
* @notice Returns the amount of ether locked in `StakingVault`.
* @return Amount of locked ether
* @notice Returns the amount of ether locked in `StakingVault` in ether
* @dev Locked amount is updated by `VaultHub` with reports
* and can also be increased by `VaultHub` outside of reports
*/
Expand All @@ -189,8 +189,7 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {
}

/**
* @notice Returns the unlocked amount, which is the valuation minus the locked amount
* @return Amount of unlocked ether
* @notice Returns the unlocked amount of ether, which is the valuation minus the locked ether amount
* @dev Unlocked amount is the total amount that can be withdrawn from `StakingVault`,
* including ether currently being staked on validators
*/
Expand All @@ -205,7 +204,6 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {

/**
* @notice Returns the net difference between funded and withdrawn ether.
* @return Delta between funded and withdrawn ether
* @dev This counter is only updated via:
* - `fund()`,
* - `withdraw()`,
Expand All @@ -220,8 +218,7 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {
}

/**
* @notice Returns the latest report data for the vault
* @return Report struct containing valuation and inOutDelta from last report
* @notice Returns the latest report data for the vault (valuation and inOutDelta)
*/
function latestReport() external view returns (IStakingVault.Report memory) {
return _getStorage().report;
Expand All @@ -233,7 +230,6 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {
* In the context of this contract, the node operator performs deposits to the beacon chain
* and processes validator exit requests submitted by `owner` through `requestValidatorExit()`.
* Node operator address is set in the initialization and can never be changed.
* @return Address of the node operator
*/
function nodeOperator() external view returns (address) {
return _getStorage().nodeOperator;
Expand Down Expand Up @@ -265,9 +261,8 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {
* @param _recipient Address to receive the withdrawn ether.
* @param _ether Amount of ether to withdraw.
* @dev Cannot withdraw more than the unlocked amount or the balance of the contract, whichever is less.
* @dev Updates inOutDelta to track the net difference between funded and withdrawn ether
* @dev Checks that valuation remains greater than locked amount after withdrawal to maintain
* `StakingVault` health and prevent reentrancy attacks.
* @dev Updates inOutDelta to track the net difference between funded and withdrawn ether.
* @dev Checks that valuation remains greater or equal than locked amount and prevents reentrancy attacks.
*/
function withdraw(address _recipient, uint256 _ether) external onlyOwner {
if (_recipient == address(0)) revert ZeroArgument("_recipient");
Expand Down Expand Up @@ -305,7 +300,7 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {

/**
* @notice Rebalances StakingVault by withdrawing ether to VaultHub
* @dev Can only be called by VaultHub if StakingVault is unhealthy, or by owner at any moment
* @dev Can only be called by VaultHub if StakingVault valuation is less than locked amount
* @param _ether Amount of ether to rebalance
*/
function rebalance(uint256 _ether) external {
Expand Down Expand Up @@ -348,15 +343,13 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {
/**
* @notice Returns the 0x02-type withdrawal credentials for the validators deposited from this `StakingVault`
* All consensus layer rewards are sent to this contract. Only 0x02-type withdrawal credentials are supported
* @return Withdrawal credentials as bytes32
*/
function withdrawalCredentials() public view returns (bytes32) {
return bytes32(WC_0X02_PREFIX | uint160(address(this)));
}

/**
* @notice Returns whether deposits are paused
* @return True if deposits are paused
*/
function beaconChainDepositsPaused() external view returns (bool) {
return _getStorage().beaconChainDepositsPaused;
Expand Down Expand Up @@ -408,11 +401,12 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {

uint256 totalAmount = 0;
uint256 numberOfDeposits = _deposits.length;
bytes memory withdrawalCredentials_ = bytes.concat(withdrawalCredentials());
for (uint256 i = 0; i < numberOfDeposits; i++) {
IStakingVault.Deposit calldata deposit = _deposits[i];
DEPOSIT_CONTRACT.deposit{value: deposit.amount}(
deposit.pubkey,
bytes.concat(withdrawalCredentials()),
withdrawalCredentials_,
deposit.signature,
deposit.depositDataRoot
);
Expand Down Expand Up @@ -448,7 +442,7 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {
uint256 keysCount = _pubkeys.length / PUBLIC_KEY_LENGTH;
for (uint256 i = 0; i < keysCount; i++) {
bytes memory pubkey = _pubkeys[i * PUBLIC_KEY_LENGTH : (i + 1) * PUBLIC_KEY_LENGTH];
emit ValidatorExitRequested(msg.sender, pubkey, pubkey);
emit ValidatorExitRequested(msg.sender, /* indexed */ pubkey, pubkey);
}
}

Expand All @@ -460,9 +454,7 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {
* @dev The caller must provide sufficient fee via msg.value to cover the withdrawal request costs
*/
function triggerValidatorWithdrawal(bytes calldata _pubkeys, uint64[] calldata _amounts, address _refundRecipient) external payable {
uint256 value = msg.value;

if (value == 0) revert ZeroArgument("msg.value");
if (msg.value == 0) revert ZeroArgument("msg.value");
if (_pubkeys.length == 0) revert ZeroArgument("_pubkeys");
if (_amounts.length == 0) revert ZeroArgument("_amounts");
if (_pubkeys.length % PUBLIC_KEY_LENGTH != 0) revert InvalidPubkeysLength();
Expand Down Expand Up @@ -493,11 +485,11 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {

uint256 feePerRequest = TriggerableWithdrawals.getWithdrawalRequestFee();
uint256 totalFee = feePerRequest * keysCount;
if (value < totalFee) revert InsufficientValidatorWithdrawalFee(value, totalFee);
if (msg.value < totalFee) revert InsufficientValidatorWithdrawalFee(msg.value, totalFee);

TriggerableWithdrawals.addWithdrawalRequests(_pubkeys, _amounts, feePerRequest);

uint256 excess = value - totalFee;
uint256 excess = msg.value - totalFee;
if (excess > 0) {
(bool success,) = _refundRecipient.call{value: excess}("");
if (!success) revert WithdrawalFeeRefundFailed(_refundRecipient, excess);
Expand Down Expand Up @@ -637,13 +629,6 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {
*/
event ValidatorWithdrawalTriggered(address indexed _sender, bytes _pubkeys, uint64[] _amounts, address _refundRecipient, uint256 _excess);

/**
* @notice Emitted when an excess fee is refunded back to the sender.
* @param _sender Address that received the refund.
* @param _amount Amount of ether refunded.
*/
event ValidatorWithdrawalFeeRefunded(address indexed _sender, uint256 _amount);

/**
* @notice Thrown when an invalid zero value is passed
* @param name Name of the argument that was zero
Expand Down Expand Up @@ -747,7 +732,7 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {
error WithdrawalFeeRefundFailed(address _sender, uint256 _amount);

/**
* @notice Thrown when partial withdrawals are not allowed on an unbalanced vault
* @notice Thrown when partial withdrawals are not allowed when valuation is below locked
*/
error PartialWithdrawalNotAllowed();
}
12 changes: 5 additions & 7 deletions contracts/0.8.25/vaults/VaultHub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ abstract contract VaultHub is PausableUntilWithRoles {
IStETH public immutable STETH;

/// @param _stETH Lido stETH contract
/// @param _connectedVaultsLimit Maximum number of vaults that can be connected
/// @param _connectedVaultsLimit Maximum number of vaults that can be connected simultaneously
/// @param _relativeShareLimitBP Maximum share limit relative to TVL in basis points
constructor(IStETH _stETH, uint256 _connectedVaultsLimit, uint256 _relativeShareLimitBP) {
if (_connectedVaultsLimit == 0) revert ZeroArgument("_connectedVaultsLimit");
Expand Down Expand Up @@ -136,9 +136,7 @@ abstract contract VaultHub is PausableUntilWithRoles {
}

/// @notice checks if the vault is healthy by comparing its valuation against minted shares
/// @dev A vault is considered healthy if it has no shares minted, or if its valuation minus required reserves
/// is sufficient to cover the current value of minted shares. The required reserves are determined by
/// the reserve ratio threshold.
/// @dev A vault is considered healthy when its valuation is sufficient to cover the current value of minted shares
/// @param _vault vault address
/// @return true if vault is healthy, false otherwise
function isVaultHealthy(address _vault) public view returns (bool) {
Expand Down Expand Up @@ -354,11 +352,11 @@ abstract contract VaultHub is PausableUntilWithRoles {
emit VaultRebalanced(msg.sender, sharesToBurn);
}

/// @notice Forces validator exit from the beacon chain when vault health ratio is below 100%
/// @notice Forces validator exit from the beacon chain when vault is unhealthy
/// @param _vault The address of the vault to exit validators from
/// @param _pubkeys The public keys of the validators to exit
/// @param _refundRecepient The address that will receive the refund for transaction costs
/// @dev When a vault's health ratio drops below 100%, anyone can force its validators to exit the beacon chain
/// @dev When the vault becomes unhealthy, anyone can force its validators to exit the beacon chain
/// This returns the vault's deposited ETH back to vault's balance and allows to rebalance the vault
function forceValidatorExit(
address _vault,
Expand Down Expand Up @@ -532,7 +530,7 @@ abstract contract VaultHub is PausableUntilWithRoles {
}
}

/// @dev check if the share limit is within the upper bound set by relativeShareLimitBP
/// @dev check if the share limit is within the upper bound set by RELATIVE_SHARE_LIMIT_BP
function _checkShareLimitUpperBound(address _vault, uint256 _shareLimit) internal view {
uint256 relativeMaxShareLimitPerVault = (STETH.getTotalShares() * RELATIVE_SHARE_LIMIT_BP) / TOTAL_BASIS_POINTS;
if (_shareLimit > relativeMaxShareLimitPerVault) {
Expand Down
6 changes: 3 additions & 3 deletions test/0.8.25/vaults/staking-vault/stakingVault.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ describe("StakingVault.sol", () => {
});

it("makes multiple deposits to the beacon chain and emits the `DepositedToBeaconChain` event", async () => {
const numberOfKeys = 2; // number because of Array.from
const numberOfKeys = 300; // number because of Array.from
const totalAmount = ether("32") * BigInt(numberOfKeys);
const withdrawalCredentials = await stakingVault.withdrawalCredentials();

Expand All @@ -612,7 +612,7 @@ describe("StakingVault.sol", () => {

await expect(stakingVault.connect(operator).depositToBeaconChain(deposits))
.to.emit(stakingVault, "DepositedToBeaconChain")
.withArgs(operator, 2, totalAmount);
.withArgs(operator, numberOfKeys, totalAmount);
});
});

Expand Down Expand Up @@ -857,7 +857,7 @@ describe("StakingVault.sol", () => {
});

it("requests a multiple validator withdrawals", async () => {
const numberOfKeys = 2;
const numberOfKeys = 300;
const pubkeys = getPubkeys(numberOfKeys);
const value = baseFee * BigInt(numberOfKeys);
const amounts = Array(numberOfKeys)
Expand Down

0 comments on commit 081444b

Please sign in to comment.