8000 [EPIC] stVaults by tamtamchik · Pull Request #874 · lidofinance/core · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

[EPIC] stVaults #874

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

Draft
wants to merge 2,267 commits into
base: feat/triggerable-exits
Choose a base branch
from
Draft

[EPIC] stVaults #874

wants to merge 2,267 commits into from

Conversation

tamtamchik
Copy link
Member
@tamtamchik tamtamchik commented Nov 17, 2024

❗ 🚧 Under construction 🚧 ❗

Staking Vaults

New way of isolated staking, through separate vaults, with optional stETH liquidity

  • Support minting external backed stETH in Lido contract
  • Extract protocol accounting to separate contract (two-step, better precision)
  • StakingVault + VaultHub
  • Dashboard
  • VaultFactory
  • OperatorGrid
  • PredepositGuarantee
  • LazyOracle

@folkyatina folkyatina changed the base branch from master to develop November 27, 2024 07:48
@folkyatina folkyatina changed the base branch from develop to master November 27, 2024 07:48
@TheDZhon TheDZhon self-requested a review November 27, 2024 08:05
Copy link
Contributor
@TheDZhon TheDZhon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👀

8000
Copy link
@github-advanced-security github-advanced-security bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slither found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

Copy link
github-actions bot commented Nov 27, 2024

badge

Hardhat Unit Tests Coverage Summary

Filename                                                                Stmts    Miss  Cover    Missing
--------------------------------------------------------------------  -------  ------  -------  --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
contracts/0.4.24/Lido.sol                                                 240      12  95.00%   769-787, 867-879, 1007-1008
contracts/0.4.24/StETH.sol                                                 82       0  100.00%
contracts/0.4.24/StETHPermit.sol                                           15       0  100.00%
contracts/0.4.24/lib/Packed64x4.sol                                         5       0  100.00%
contracts/0.4.24/lib/SigningKeys.sol                                       36       0  100.00%
contracts/0.4.24/lib/StakeLimitUtils.sol                                   37       0  100.00%
contracts/0.4.24/nos/NodeOperatorsRegistry.sol                            435       0  100.00%
contracts/0.4.24/utils/Pausable.sol                                         9       0  100.00%
contracts/0.4.24/utils/UnstructuredStorageUint128.sol                      14       1  92.86%   49
contracts/0.4.24/utils/Versioned.sol                                        5       0  100.00%
contracts/0.6.12/WstETH.sol                                                17       0  100.00%
contracts/0.8.25/ValidatorExitDelayVerifier.sol                            64       0  100.00%
contracts/0.8.25/utils/AccessControlConfirmable.sol                         2       0  100.00%
contracts/0.8.25/utils/Confirmable2Addresses.sol                            5       0  100.00%
contracts/0.8.25/utils/Confirmations.sol                                   37       0  100.00%
contracts/0.8.25/utils/PausableUntilWithRoles.sol                           3       0  100.00%
contracts/0.8.25/vaults/LazyOracle.sol                                     84      67  20.24%   144-145, 155-226, 262-360, 371-379, 389-393
contracts/0.8.25/vaults/OperatorGrid.sol                                  149       0  100.00%
contracts/0.8.25/vaults/PinnedBeaconProxy.sol                               5       0  100.00%
contracts/0.8.25/vaults/StakingVault.sol                                   98       0  100.00%
contracts/0.8.25/vaults/ValidatorConsolidationRequests.sol                 56       2  96.43%   100, 187
contracts/0.8.25/vaults/VaultFactory.sol                                   30       0  100.00%
contracts/0.8.25/vaults/VaultHub.sol                                      391     168  57.03%   231-232, 245-262, 274-308, 321-329, 416-479, 535-536, 573-670, 693-712, 749-758, 775-870, 893-944, 1015, 1089, 1118-1126, 1154, 1275, 1281-1282, 1402, 1410-1424, 1438-1442, 1473-1476, 1517, 1529
contracts/0.8.25/vaults/dashboard/Dashboard.sol                           120       0  100.00%
contracts/0.8.25/vaults/dashboard/NodeOperatorFee.sol                      70       0  100.00%
contracts/0.8.25/vaults/dashboard/Permissions.sol                          50       0  100.00%
contracts/0.8.25/vaults/interfaces/IPredepositGuarantee.sol                 0       0  100.00%
contracts/0.8.25/vaults/interfaces/IStakingVault.sol                        0       0  100.00%
contracts/0.8.25/vaults/lib/PinnedBeaconUtils.sol                           6       0  100.00%
contracts/0.8.25/vaults/lib/RefSlotCache.sol                               22      17  22.73%   31-42, 60-61, 77-97
contracts/0.8.25/vaults/predeposit_guarantee/CLProofVerifier.sol           16       1  93.75%   214
contracts/0.8.25/vaults/predeposit_guarantee/MeIfNobodyElse.sol             3       0  100.00%
contracts/0.8.25/vaults/predeposit_guarantee/PredepositGuarantee.sol      159       0  100.00%
contracts/0.8.9/Accounting.sol                                             83       2  97.59%   297-298
contracts/0.8.9/BeaconChainDepositor.sol                                   21       2  90.48%   48, 51
contracts/0.8.9/Burner.sol                                                 92       0  100.00%
contracts/0.8.9/DepositSecurityModule.sol                                 128       0  100.00%
contracts/0.8.9/EIP712StETH.sol                                            16       0  100.00%
contracts/0.8.9/LidoExecutionLayerRewardsVault.sol                         16       0  100.00%
contracts/0.8.9/LidoLocator.sol                                            26       0  100.00%
contracts/0.8.9/OracleDaemonConfig.sol                                     28       0  100.00%
contracts/0.8.9/StakingRouter.sol                                         305       0  100.00%
contracts/0.8.9/TriggerableWithdrawalsGateway.sol                          54       1  98.15%   274
contracts/0.8.9/WithdrawalQueue.sol                                        88       0  100.00%
contracts/0.8.9/WithdrawalQueueBase.sol                                   146       0  100.00%
contracts/0.8.9/WithdrawalQueueERC721.sol                                  89       0  100.00%
contracts/0.8.9/WithdrawalVault.sol                                        32       0  100.00%
contracts/0.8.9/WithdrawalVaultEIP7002.sol                                 21       0  100.00%
contracts/0.8.9/lib/ExitLimitUtils.sol                                     31       0  100.00%
contracts/0.8.9/lib/Math.sol                                                4       0  100.00%
contracts/0.8.9/lib/PositiveTokenRebaseLimiter.sol                         22       0  100.00%
contracts/0.8.9/lib/UnstructuredRefStorage.sol                              2       0  100.00%
contracts/0.8.9/oracle/AccountingOracle.sol                               173       2  98.84%   123-124
contracts/0.8.9/oracle/BaseOracle.sol                                      89       1  98.88%   397
contracts/0.8.9/oracle/HashConsensus.sol                                  263       1  99.62%   1005
contracts/0.8.9/oracle/ValidatorsExitBus.sol                              136      10  92.65%   440-453, 516
contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol                         53       1  98.11%   232
contracts/0.8.9/proxy/OssifiableProxy.sol                                  17       0  100.00%
contracts/0.8.9/proxy/WithdrawalsManagerProxy.sol                          60       0  100.00%
contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol               216       1  99.54%   860
contracts/0.8.9/utils/DummyEmptyContract.sol                                0       0  100.00%
contracts/0.8.9/utils/PausableUntil.sol                                    31       0  100.00%
contracts/0.8.9/utils/Versioned.sol                                        11       0  100.00%
contracts/0.8.9/utils/access/AccessControl.sol                             23       0  100.00%
contracts/0.8.9/utils/access/AccessControlEnumerable.sol                    9       0  100.00%
contracts/common/utils/PausableUntil.sol                                   29       0  100.00%
TOTAL                                                                    4579     289  93.69%

Diff against master

Filename                                                                Stmts    Miss  Cover
--------------------------------------------------------------------  -------  ------  --------
contracts/0.4.24/Lido.sol                                                 +28     +12  -5.00%
contracts/0.4.24/StETH.sol                                                +10       0  +100.00%
contracts/0.4.24/nos/NodeOperatorsRegistry.sol                            -77       0  +100.00%
contracts/0.4.24/utils/UnstructuredStorageUint128.sol                     +14      +1  +92.86%
contracts/0.8.25/ValidatorExitDelayVerifier.sol                           +64       0  +100.00%
contracts/0.8.25/utils/AccessControlConfirmable.sol                        +2       0  +100.00%
contracts/0.8.25/utils/Confirmable2Addresses.sol                           +5       0  +100.00%
contracts/0.8.25/utils/Confirmations.sol                                  +37       0  +100.00%
contracts/0.8.25/utils/PausableUntilWithRoles.sol                          +3       0  +100.00%
contracts/0.8.25/vaults/LazyOracle.sol                                    +84     +67  +20.24%
contracts/0.8.25/vaults/OperatorGrid.sol                                 +149       0  +100.00%
contracts/0.8.25/vaults/PinnedBeaconProxy.sol                              +5       0  +100.00%
contracts/0.8.25/vaults/StakingVault.sol                                  +98       0  +100.00%
contracts/0.8.25/vaults/ValidatorConsolidationRequests.sol                +56      +2  +96.43%
contracts/0.8.25/vaults/VaultFactory.sol                                  +30       0  +100.00%
contracts/0.8.25/vaults/VaultHub.sol                                     +391    +168  +57.03%
contracts/0.8.25/vaults/dashboard/Dashboard.sol                          +120       0  +100.00%
contracts/0.8.25/vaults/dashboard/NodeOperatorFee.sol                     +70       0  +100.00%
contracts/0.8.25/vaults/dashboard/Permissions.sol                         +50       0  +100.00%
contracts/0.8.25/vaults/interfaces/IPredepositGuarantee.sol                 0       0  +100.00%
contracts/0.8.25/vaults/interfaces/IStakingVault.sol                        0       0  +100.00%
contracts/0.8.25/vaults/lib/PinnedBeaconUtils.sol                          +6       0  +100.00%
contracts/0.8.25/vaults/lib/RefSlotCache.sol                              +22     +17  +22.73%
contracts/0.8.25/vaults/predeposit_guarantee/CLProofVerifier.sol          +16      +1  +93.75%
contracts/0.8.25/vaults/predeposit_guarantee/MeIfNobodyElse.sol            +3       0  +100.00%
contracts/0.8.25/vaults/predeposit_guarantee/PredepositGuarantee.sol     +159       0  +100.00%
contracts/0.8.9/Accounting.sol                                            +83      +2  +97.59%
contracts/0.8.9/Burner.sol                                                +21       0  +100.00%
contracts/0.8.9/LidoLocator.sol                                            +8       0  +100.00%
contracts/0.8.9/StakingRouter.sol                                         -11       0  +100.00%
contracts/0.8.9/TriggerableWithdrawalsGateway.sol                         +54      +1  +98.15%
contracts/0.8.9/WithdrawalVault.sol                                       +11       0  +100.00%
contracts/0.8.9/WithdrawalVaultEIP7002.sol                                +21       0  +100.00%
contracts/0.8.9/lib/ExitLimitUtils.sol                                    +31       0  +100.00%
contracts/0.8.9/oracle/AccountingOracle.sol                               -17       0  -0.11%
contracts/0.8.9/oracle/ValidatorsExitBus.sol                             +136     +10  +92.65%
contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol                        -38      -1  +0.31%
contracts/0.8.9/proxy/WithdrawalsManagerProxy.sol                         +60       0  +100.00%
contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol               -16      +1  -0.46%
contracts/common/utils/PausableUntil.sol                                  +29       0  +100.00%
TOTAL                                                                   +1717    +281  -5.35%

Results for commit: fb4f7e5

Minimum allowed coverage is 80%

♻️ This comment has been updated with latest results

Copy link
Contributor
@TheDZhon TheDZhon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👀

}

// Distribute protocol fee (treasury & node operators)
if (_update.sharesToMintAsFees > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this name might be misleading, should be named smth 'sharesToMintAsLidoV2ProtocolFees'

Copy link
Contributor
@TheDZhon TheDZhon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👀

import {AccessControlEnumerableUpgradeable} from "contracts/openzeppelin/5.0.2/upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol";
import {IHubVault} from "./interfaces/IHubVault.sol";
import {Math256} from "contracts/common/lib/Math256.sol";
import {ILido as StETH} from "contracts/0.8.25/interfaces/ILido.sol";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this iface not in common?

Copy link
Contributor

Choose a reason for hiding this c 67E6 omment

The reason will be displayed to describe this comment to others. Learn more.

should revise iface structure in the future


/// @notice disconnects a vault from the hub
/// @dev can be called by vaults only
function disconnectVault(address _vault) external {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's add emergency flow ⚠️

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's consider the following cases:

  • voluntary disconnect (this one)
  • stop new minting
  • eject and withdraw
  • disconnect forcibly

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • disconnect and dust issue

/// @param _reserveRatio minimum Reserve ratio in basis points
/// @param _reserveRatioThreshold reserve ratio that makes possible to force rebalance on the vault (in basis points)
/// @param _treasuryFeeBP treasury fee in basis points
function connectVault(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for permissionless addition:

  • there could be a scenario when we adding a vault under slashing

@tamtamchik tamtamchik changed the base branch from master to develop November 29, 2024 11:56
/// @notice force rebalance of the vault to have sufficient reserve ratio
/// @param _vault vault address
/// @dev can be used permissionlessly if the vault's min reserve ratio is broken
function forceRebalance(IHubVault _vault) external {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Embed auto-disconnect if resulting valuation is too small

Copy link
Contributor
@TheDZhon TheDZhon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👀


stETH.mintExternalShares(_recipient, sharesToMint);

emit MintedStETHOnVault(_vault, _tokens);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to disentangle events for each core operation later 🧠

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

backward compatibility is needed for Subgraph

< F438 summary role="button" data-target="details-collapsible.summaryElement details-toggle.summaryTarget" data-action="click:details-collapsible#toggle click:details-toggle#toggle" data-aria-label-closed="Expand comment" data-aria-label-open="Collapse comment" aria-expanded="false" aria-label="Collapse comment" data-view-component="true" class="js-toggle-outdated-comments py-2 px-3 rounded-2 color-bg-subtle">
contracts/0.8.25/vaults/VaultHub.sol Outdated Show resolved Hide resolved
Copy link
Contributor
@TheDZhon TheDZhon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👀 👀 👀

// Lido curated validators could earn if vault's ETH was staked in Lido
// itself and minted as stETH shares
//
// treasuryFeeShares = value * lidoGrossAPR * treasuryFeeRate / preShareRate
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// treasuryFeeShares = value * lidoGrossAPR * treasuryFeeRate / preShareRate
// treasuryFeeShares = chargeableValue * lidoGrossAPR * treasuryFeeRate / (_preTotalPooledEther / _preTotalShares)

}
}

function _calculateLidoFees(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// @dev impossible to invoke this method under negative rebase

//
// treasuryFeeShares = value * lidoGrossAPR * treasuryFeeRate / preShareRate
// lidoGrossAPR = postShareRateWithoutFees / preShareRate - 1
// = value * (postShareRateWithoutFees / preShareRate - 1) * treasuryFeeRate / preShareRate
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// = value * (postShareRateWithoutFees / preShareRate - 1) * treasuryFeeRate / preShareRate
// treasuryFeeShares = value * (postShareRateWithoutFees / preShareRate - 1) * treasuryFeeRate / preShareRate

chargeableValue);
uint256 treasuryFee = (potentialRewards * _socket.treasuryFeeBP) / BPS_BASE;

treasuryFeeShares = (treasuryFee * _preTotalShares) / _preTotalPooledEther;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be precision issues

if (msg.value == 0) revert ZeroArgument("msg.value");

VaultStorage storage $ = _getVaultStorage();
$.inOutDelta += SafeCast.toInt128(int256(msg.value));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:)

VaultStorage storage $ = _getVaultStorage();
$.inOutDelta -= SafeCast.toInt128(int256(_ether));

(bool success, ) = _recipient.call{value: _ether}("");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a bit scary

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe Address.sendValue

* @param _numberOfDeposits Number of 32 ETH deposits to make
* @param _pubkeys Validator public keys
* @param _signatures Validator signatures
* @dev Ensures vault is healthy and handles deposit logistics
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @dev Ensures vault is healthy and handles deposit logistics
* @dev Ensures vault is balanced and handles deposit logistics

* @param _validatorPublicKey Public key of validator to exit
*/
function requestValidatorExit(bytes calldata _validatorPublicKey) external onlyOwner {
emit ValidatorsExitRequest(msg.sender, _validatorPublicKey);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe make it compatible with ValidatorsExitBus and an ejector service

VaultStorage storage $ = _getVaultStorage();
$.inOutDelta -= SafeCast.toInt128(int256(_ether));

emit Withdrawn(msg.sender, msg.sender, _ether);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
emit Withdrawn(msg.sender, msg.sender, _ether);
emit Withdrawn(msg.sender, VAULT_HUB, _ether);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or maybe 'Rebalanced'

Copy link
Contributor
@TheDZhon TheDZhon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚛

return address(VAULT_HUB);
}

receive() external payable {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Here we have an attack scenario

This func accepts ether without updating valuation (and inOutDelta) and it's not possible to withdraw it back.
The more important thing is that while calling rebalance() it gets used to reduce inOutDelta allowing to underflow valuation()

$.locked = SafeCast.toUint128(_locked);

try IReportReceiver(owner()).onReport(_valuation, _inOutDelta, _locked) {} catch (bytes memory reason) {
emit OnReportFailed(address(this), reason);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe rename this event


event Funded(address indexed sender, uint256 amount);
event Withdrawn(address indexed sender, address indexed recipient, uint256 amount);
event DepositedToBeaconChain(address indexed sender, uint256 deposits, uint256 amount);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe should target pectra (array of amounts)

Comment on lines 357 to 359
event Locked(uint256 locked);
event Reported(address indexed vault, uint256 valuation, int256 inOutDelta, uint256 locked);
event OnReportFailed(address vault, bytes reason);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here have three different approaches:

  • do not include the emitter contract (and it's fine indeed)
  • include the address but indexed
  • include non-indexed addr

let's use the first approach 🧠

/**
* @dev Modifier to fund the staking vault if msg.value > 0
*/
modifier fundAndProceed() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
modifier fundAndProceed() {
modifier prefundable() {

17AE
* @dev Transfers ownership of the staking vault to a new owner
* @param _newOwner Address of the new owner
*/
function _transferStVaultOwnership(address _newOwner) internal {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see the rename proposal above

* @dev Requests the exit of a validator from the staking vault
* @param _validatorPublicKey Public key of the validator to exit
*/
function _requestValidatorExit(bytes calldata _validatorPublicKey) internal {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe plural for keys


// ==================== Errors ====================

/// @notice Error for zero address arguments
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// @notice Error for zero address arguments
/// @notice Error for zero value arguments

/// @notice Error when the withdrawable amount is insufficient.
/// @param withdrawable The amount that is withdrawable
/// @param requested The amount requested to withdraw
error InsufficientWithdrawableAmount(uint256 withdrawable, uint256 requested);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should have a view func to show withdrawable amount
for rebalance we also need a view to show what would happen

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this error should be moved to Delegation not being used here at all (it seems)

Copy link
Contributor
@TheDZhon TheDZhon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚛 🚛 🚛

// ==================== Constants ====================

uint256 private constant BP_BASE = 10000; // Basis points base (100%)
uint256 private constant MAX_FEE = BP_BASE; // Maximum fee in basis points (100%)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TOTAL_BASIS_POINTS

Comment on lines 43 to 44
* - vote on ownership transfer
* - vote on performance fee changes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe veto instead of approval (ET dynamics)
later

* @notice Role for the Lido DAO.
* This can be the Lido DAO agent, EasyTrack or any other DAO decision-making system.
* Lido DAO can:
* - set the operator role
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure

* Lido DAO can:
* - set the operator role
* - vote on ownership transfer
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about VaultHub.connect?

10000
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another issue: vault should express a WILL to connect (two-step)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧠 🧠 🧠 LDO staking

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these comments might be not relevant to Delegation

* Key master can:
* - deposit validators to the beacon chain
*/
bytes32 public constant KEY_MASTER_ROLE = keccak256("Vault.Delegation.KeyMasterRole");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BEACON_CHAIN_DEPOSITOR_ROLE?

function onReport(uint256 _valuation, int256 _inOutDelta, uint256 _locked) external {
if (msg.sender != address(stakingVault)) revert OnlyStVaultCanCallOnReportHook();

managementDue += (_valuation * managementFee) / 365 / BP_BASE;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ there is no timeElapsed (in case of missing reports e.g.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and 365.25

Comment on lines 387 to 388
int256 unlocked = int256(stakingVault.valuation()) - int256(stakingVault.locked());
uint256 unreserved = unlocked >= 0 ? uint256(unlocked) : 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can query stakingVault.unlocked() instead

modifier onlyIfVotedBy(bytes32[] memory _committee, uint256 _votingPeriod) {
bytes32 callId = keccak256(msg.data);
uint256 committeeSize = _committee.length;
uint256 votingStart = block.timestamp - _votingPeriod;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
uint256 votingStart = block.timestamp - _votingPeriod;
uint256 votesVaildSince = block.timestamp - _votingPeriod;

// ==================== Events ====================

/// @notice Emitted when a role member votes on a function requiring committee approval.
event RoleMemberVoted(address member, bytes32 role, uint256 timestamp, bytes data);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indexed fields?

/// @notice Emitted when a role member votes on a function requiring committee approval.
event RoleMemberVoted(address member, bytes32 role, uint256 timestamp, bytes data);

// ==================== Errors ====================
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fees not covered with event changes

@tamtamchik tamtamchik added solidity Smart contract code changes next upgrade Things to pickup for the next protocol upgrade vaults Lido stVaults related changes labels Dec 12, 2024
Copy link
Contributor
@TheDZhon TheDZhon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First lap finished 👍

Comment on lines 14 to 15
uint256 managementFee;
uint256 performanceFee;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
uint256 managementFee;
uint256 performanceFee;
uint256 managementFeeBP;
uint256 performanceFeeBP;


pragma solidity 0.8.25;

interface IDelegation {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why we don't import this interface though?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's add the comment that it's intended (to hook up the particular interface strictly)

}

contract VaultFactory is UpgradeableBeacon {
address public immutable delegationImpl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
address public immutable delegationImpl;
address public immutable DELEGATION_IMPL;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why it's immutable?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should think about disentangling the beacon and factory (from Azat)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@loga4 (the problem is that it's impossible to upgrade the delegation for the factory)

delegation.grantRole(delegation.LIDO_DAO_ROLE(), _lidoAgent);
delegation.grantRole(delegation.MANAGER_ROLE(), _initializationParams.manager);
delegation.grantRole(delegation.OPERATOR_ROLE(), _initializationParams.operator);
delegation.grantRole(delegation.DEFAULT_ADMIN_ROLE(), msg.sender);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scary though, let's add a comment that those roles above have their admins

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ let's not rely on msg.sender and use input parameters instead to make the deployments automated without pain (suggested defaultAdmin above to replace msg.sender)


delegation.initialize(address(this), address(vault));

delegation.grantRole(delegation.LIDO_DAO_ROLE(), _lidoAgent);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe LIDO_AGENT should be immutable for the factory

/// @notice Creates a new StakingVault and Delegation contracts
/// @param _stakingVaultParams The params of vault initialization
/// @param _initializationParams The params of vault initialization
function createVault(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
function createVault(
function createVaultWithDelegation(

* @notice The term "fee" is used to express the fee percentage as basis points, e.g. 5%,
* while "due" is the actual amount of the fee, e.g. 1 ether
*/
contract Delegation is Dashboard, IReportReceiver {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
contract Delegation is Dashboard, IReportReceiver {
contract Delegation is Dashboard, IReportReceiver, AssetRecoverer {


emit VaultCreated(address(delegation), address(vault));
emit DelegationCreated(msg.sender, address(delegation));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧠 role setup has dependencies on the Delegation internals which is not perfect

Comment on lines +240 to +268
function _calculateLidoProtocolFeeShares(
ReportValues calldata _report,
CalculatedValues memory _update,
uint256 _internalSharesBeforeFees,
uint256 _internalEther
) internal pure returns (uint256 sharesToMintAsFees) {
// we are calculating the share rate equal to the post-rebase share rate
// but with fees taken as ether deduction instead of minting shares
// to learn the amount of shares we need to mint to compensate for this fee

uint256 unifiedClBalance = _report.clBalance + _update.withdrawals;
// Don't mint/distribute any protocol fee on the non-profitable Lido oracle report
// (when consensus layer balance delta is zero or negative).
// See LIP-12 for details:
// https://research.lido.fi/t/lip-12-on-chain-part-of-the-rewards-distribution-after-the-merge/1625
if (unifiedClBalance > _update.principalClBalance) {
uint256 totalRewards = unifiedClBalance - _update.principalClBalance + _update.elRewards;
uint256 totalFee = _update.rewardDistribution.totalFee;
uint256 precision = _update.rewardDistribution.precisionPoints;
// amount of fees in ether
uint256 feeEther = (totalRewards * totalFee) / precision;
// but we won't pay fees in ether, so we need to calculate how many shares we need to mint as fees
// using the share rate that takes fees into account
// the share rate is the same as the post-rebase share rate
// but with fees taken as ether deduction instead of minting shares
// to learn the amount of shares we need to mint to compensate for this fee
sharesToMintAsFees = (feeEther * _internalSharesBeforeFees) / (_internalEther - feeEther);
}
}
) internal {
_checkAccountingOracleReport(_contracts, _report, _pre, _update);

uint256 lastWithdrawalRequestToFinalize;

Check warning

Code scanning / Slither

Uninitialized local variables Medium

10000
@TheDZhon TheDZhon changed the base branch from develop to feat/triggerable-exits June 17, 2025 08:34
arwer13 and others added 23 commits June 17, 2025 11:51
# Conflicts:
#	test/0.8.25/vaults/vaulthub/contracts/VaultFactory__MockForVaultHub.sol
tests: restore unit tests for vaults
# Conflicts:
#	test/0.8.25/vaults/vaultFactory.test.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
solidity Smart contract code changes tests When it comes to testing the code vaults Lido stVaults related changes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

0