Skip to content
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

[SI][Vaults] feat: Dashboard UX updates #915

Merged
merged 43 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
b6156ad
feat: dashboard token recovery
Jeday Dec 26, 2024
a11d6b6
feat: add locator, update burn/mint methods, fixes, tests
DiRaiks Jan 9, 2025
29ef4ad
tests: update Delegation constructor
DiRaiks Jan 9, 2025
b5c839f
tests: add tests for burnWstETHWithPermit
DiRaiks Jan 9, 2025
4b16505
fix: add nft recovery
Jeday Jan 10, 2025
41f6125
fix(docs): dashboard comment
Jeday Jan 10, 2025
ae59476
Merge branch 'feat/vaults' of github.com:lidofinance/core into feat/d…
Jeday Jan 10, 2025
de3d3b9
fix: update naming for burn/mint
Jeday Jan 10, 2025
3261a8c
fix(test): check allowance in dashboard
Jeday Jan 10, 2025
c228afd
fix(test): remove extra await
Jeday Jan 10, 2025
c6cc70f
fix(test): dashboard address reuse
Jeday Jan 10, 2025
739a60d
test: dashboard valuation and recieve
Jeday Jan 10, 2025
839b726
fix: happy path integration test and linters
tamtamchik Jan 10, 2025
99f7d9a
fix: tests
tamtamchik Jan 10, 2025
186e266
test: update tests for dashboard
tamtamchik Jan 10, 2025
0aea721
fix: reduce dashboard._burn gas
Jeday Jan 13, 2025
c4e7ceb
chore: simplify burnWstETH
tamtamchik Jan 13, 2025
62710b0
Merge branch 'feat/dashboard-ux-updates' of github.com:lidofinance/co…
Jeday Jan 14, 2025
95b11fb
fix: use eth address convention
Jeday Jan 14, 2025
b5ce3a4
fix: to lowercase address
Jeday Jan 14, 2025
fe87ca3
fix: revert to checksum
Jeday Jan 14, 2025
50259ec
Merge pull request #908 from lidofinance/feat/vaults-dashboard-recovery
tamtamchik Jan 14, 2025
fac1f9d
feat(vaults): mint/burn steth
Jeday Jan 15, 2025
710ccac
docs: burn shares permit comment
Jeday Jan 15, 2025
77d8739
fix: use round up
Jeday Jan 16, 2025
0903095
feat: fix burnWsteth
Jeday Jan 16, 2025
5300444
feat(test): mint wsteth wei tests
Jeday Jan 16, 2025
f24c48e
test: variable wei/shareRate burnWsteth test
Jeday Jan 17, 2025
90f64d4
fix: burner event order
Jeday Jan 17, 2025
5a907fc
docs: comment
Jeday Jan 17, 2025
b529f7b
Merge branch 'feat/vaults' of github.com:lidofinance/core into feat/d…
Jeday Jan 17, 2025
5215e35
docs: add notice
Jeday Jan 17, 2025
f78235c
Merge branch 'feat/vaults' of github.com:lidofinance/core into feat/d…
Jeday Jan 22, 2025
bea9a49
test: fix oz version
Jeday Jan 22, 2025
616a0f8
fix: use safeERC20
Jeday Jan 23, 2025
2b871fb
Merge branch 'feat/vaults' of github.com:lidofinance/core into feat/d…
Jeday Jan 23, 2025
c9c7f74
test: whitespace
Jeday Jan 23, 2025
e470a89
fix: fund/withdraw naming
Jeday Jan 23, 2025
4ff312b
Merge branch 'feat/vaults' of github.com:lidofinance/core into feat/d…
Jeday Jan 28, 2025
34d4519
fix: dashboard tests
Jeday Jan 28, 2025
b7e5536
fix: remove onlyRole
Jeday Jan 29, 2025
0c2c170
fix: unused imports & naming
Jeday Jan 29, 2025
067f38b
test: fix delegation test
Jeday Jan 29, 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: 2 additions & 0 deletions contracts/0.8.25/interfaces/ILido.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ interface ILido is IERC20, IERC20Permit {

function transferSharesFrom(address, address, uint256) external returns (uint256);

function transferShares(address, uint256) external returns (uint256);

function rebalanceExternalEtherToInternal() external payable;

function getTotalPooledEther() external view returns (uint256);
Expand Down
294 changes: 198 additions & 96 deletions contracts/0.8.25/vaults/Dashboard.sol
Copy link
Contributor

Choose a reason for hiding this comment

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

thresholdReserveRatio vs reserveRatioThreshold is a bit weird

Copy link
Contributor

Choose a reason for hiding this comment

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

folkyatina marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

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

Please update following comment:

/**
 * @title Dashboard
 * @notice This contract is meant to be used as the owner of `StakingVault`.
 * This contract improves the vault UX by bundling all functions from the vault and vault hub
 * in this single contract. It provides administrative functions for managing the staking vault,
 * including funding, withdrawing, depositing to the beacon chain, minting, burning, and rebalancing operations.
 * All these functions are only callable by the account with the DEFAULT_ADMIN_ROLE.
 * TODO: need to add recover methods for ERC20, probably in a separate contract
 */

Copy link
Contributor

Choose a reason for hiding this comment

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

fixed

Copy link
Contributor

Choose a reason for hiding this comment

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

votingCommittee -> multiConfirmationRoles

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

reserveRatio() -> reserveRatioBP() or at least comment that this is the BP convention

Copy link
Contributor

Choose a reason for hiding this comment

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

fixed

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 document whether already minted are included or not

function totalMintableShares() public view returns (uint256)

Copy link
Contributor

Choose a reason for hiding this comment

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

fixed

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions contracts/0.8.25/vaults/Delegation.sol
Copy link
Contributor

Choose a reason for hiding this comment

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

keccak256("Vault.Delegation.CuratorRole") ⇒ keccak256("vaults.Delegation.CuratorRole") and so on

Copy link
Contributor

Choose a reason for hiding this comment

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

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 remove msg.sender from initialization

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

vote -> multiConfirmationRole (everywhere)

Copy link
Contributor

Choose a reason for hiding this comment

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

Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,10 @@ contract Delegation is Dashboard {
/**
* @notice Constructs the contract.
* @dev Stores token addresses in the bytecode to reduce gas costs.
* @param _steth Address of the stETH token contract.
* @param _weth Address of the weth token contract.
* @param _wsteth Address of the wstETH token contract.
* @param _lidoLocator Address of the Lido locator contract.
*/
constructor(address _steth, address _weth, address _wsteth) Dashboard(_steth, _weth, _wsteth) {}
constructor(address _weth, address _lidoLocator) Dashboard(_weth, _lidoLocator) {}

/**
* @notice Initializes the contract:
Expand Down
4 changes: 2 additions & 2 deletions contracts/0.8.25/vaults/Permissions.sol
Copy link
Contributor

Choose a reason for hiding this comment

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

2025 copyright

Copy link
Contributor

Choose a reason for hiding this comment

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

fixed

Copy link
Contributor

Choose a reason for hiding this comment

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

maybe namespace should be 'vaults.Permissions.X'

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

REQUEST_VALIDATOR_EXIT_ROLE + FORCE_VALIDATOR_EXIT_ROLE

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

maybe move this to an internal func (nitpick)

        address addr;
        assembly {
            addr := mload(add(args, 32))
        }

Copy link
Contributor

Choose a reason for hiding this comment

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

maybe emit an event with an argument:

        emit Initialized(_defaultAdmin);

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Committee => MultiRoleConfirmation or smth

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

do we need _unsafeWithdraw at all? even if so, let's rename to _noAuthWithdraw

Copy link
Contributor

Choose a reason for hiding this comment

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

Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,11 @@ abstract contract Permissions is AccessControlVoteable {
_unsafeWithdraw(_recipient, _ether);
}

function _mint(address _recipient, uint256 _shares) internal onlyRole(MINT_ROLE) {
function _mintShares(address _recipient, uint256 _shares) internal onlyRole(MINT_ROLE) {
vaultHub.mintSharesBackedByVault(address(stakingVault()), _recipient, _shares);
}

function _burn(uint256 _shares) internal onlyRole(BURN_ROLE) {
function _burnShares(uint256 _shares) internal onlyRole(BURN_ROLE) {
vaultHub.burnSharesBackedByVault(address(stakingVault()), _shares);
}

Expand Down
8 changes: 4 additions & 4 deletions contracts/0.8.9/Burner.sol
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 move this one to 0.8.25 and take recovery lib from CSM

Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,9 @@ contract Burner is IBurner, AccessControlEnumerable {
if (_amount == 0) revert ZeroRecoveryAmount();
if (_token == address(LIDO)) revert StETHRecoveryWrongFunc();

emit ERC20Recovered(msg.sender, _token, _amount);

IERC20(_token).safeTransfer(LOCATOR.treasury(), _amount);

emit ERC20Recovered(msg.sender, _token, _amount);
}

/**
Expand All @@ -259,9 +259,9 @@ contract Burner is IBurner, AccessControlEnumerable {
function recoverERC721(address _token, uint256 _tokenId) external {
if (_token == address(LIDO)) revert StETHRecoveryWrongFunc();

emit ERC721Recovered(msg.sender, _token, _tokenId);

IERC721(_token).transferFrom(address(this), LOCATOR.treasury(), _tokenId);

emit ERC721Recovered(msg.sender, _token, _tokenId);
}

/**
Expand Down
6 changes: 2 additions & 4 deletions scripts/scratch/steps/0145-deploy-vaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ export async function main() {
const state = readNetworkState({ deployer });

const accountingAddress = state[Sk.accounting].proxy.address;
const lidoAddress = state[Sk.appLido].proxy.address;
const wstEthAddress = state[Sk.wstETH].address;
const locatorAddress = state[Sk.lidoLocator].proxy.address;

const depositContract = state.chainSpec.depositContract;
const wethContract = state.delegation.deployParameters.wethContract;
Expand All @@ -27,9 +26,8 @@ export async function main() {

// Deploy Delegation implementation contract
const delegation = await deployWithoutProxy(Sk.delegationImpl, "Delegation", deployer, [
lidoAddress,
wethContract,
wstEthAddress,
locatorAddress,
]);
const delegationAddress = await delegation.getAddress();

Expand Down
2 changes: 0 additions & 2 deletions test/0.8.25/vaults/contracts/WETH9__MockForVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

pragma solidity 0.4.24;
tamtamchik marked this conversation as resolved.
Show resolved Hide resolved

import {StETH} from "contracts/0.4.24/StETH.sol";

contract WETH9__MockForVault {
string public name = "Wrapped Ether";
string public symbol = "WETH";
Expand Down
14 changes: 14 additions & 0 deletions test/0.8.25/vaults/dashboard/contracts/ERC721_MockForDashboard.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: UNLICENSED
// for testing purposes only

pragma solidity 0.8.25;

import {ERC721} from "@openzeppelin/contracts-v5.2/token/ERC721/ERC721.sol";

contract ERC721_MockForDashboard is ERC721 {
constructor() ERC721("MockERC721", "M721") {}

function mint(address _recipient, uint256 _tokenId) external {
_mint(_recipient, _tokenId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,4 @@ contract StETHPermit__HarnessForDashboard is StETHPermit {
function mock__setTotalShares(uint256 _totalShares) external {
totalShares = _totalShares;
}

function mock__getTotalShares() external view returns (uint256) {
return _getTotalShares();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,18 @@ contract VaultFactory__MockForDashboard is UpgradeableBeacon {
bytes memory immutableArgs = abi.encode(vault);
dashboard = Dashboard(payable(Clones.cloneWithImmutableArgs(dashboardImpl, immutableArgs)));

dashboard.initialize(msg.sender);
dashboard.initialize(address(this));
dashboard.grantRole(dashboard.DEFAULT_ADMIN_ROLE(), msg.sender);
dashboard.grantRole(dashboard.FUND_ROLE(), msg.sender);
dashboard.grantRole(dashboard.WITHDRAW_ROLE(), msg.sender);
dashboard.grantRole(dashboard.MINT_ROLE(), msg.sender);
dashboard.grantRole(dashboard.BURN_ROLE(), msg.sender);
dashboard.grantRole(dashboard.REBALANCE_ROLE(), msg.sender);
dashboard.grantRole(dashboard.PAUSE_BEACON_CHAIN_DEPOSITS_ROLE(), msg.sender);
dashboard.grantRole(dashboard.RESUME_BEACON_CHAIN_DEPOSITS_ROLE(), msg.sender);
dashboard.grantRole(dashboard.REQUEST_VALIDATOR_EXIT_ROLE(), msg.sender);
dashboard.grantRole(dashboard.VOLUNTARY_DISCONNECT_ROLE(), msg.sender);

dashboard.revokeRole(dashboard.DEFAULT_ADMIN_ROLE(), address(this));

vault.initialize(address(dashboard), _operator, "");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,31 @@ contract VaultHub__MockForDashboard {
emit Mock__VaultDisconnected(vault);
}

function mintSharesBackedByVault(address /* vault */, address recipient, uint256 amount) external {
function mintSharesBackedByVault(address vault, address recipient, uint256 amount) external {
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 mintSharesBackedByVault(address vault, address recipient, uint256 amount) external {
function mintSharesBackedByVault(address _vault, address _recipient, uint256 _shares) external {

if (vault == address(0)) revert ZeroArgument("_vault");
if (recipient == address(0)) revert ZeroArgument("recipient");
if (amount == 0) revert ZeroArgument("amount");

steth.mintExternalShares(recipient, amount);
vaultSockets[vault].sharesMinted = uint96(vaultSockets[vault].sharesMinted + amount);
}

function burnSharesBackedByVault(address /* vault */, uint256 amount) external {
steth.burnExternalShares(amount);
function burnSharesBackedByVault(address _vault, uint256 _amountOfShares) external {
if (_vault == address(0)) revert ZeroArgument("_vault");
if (_amountOfShares == 0) revert ZeroArgument("_amountOfShares");
steth.burnExternalShares(_amountOfShares);
vaultSockets[_vault].sharesMinted = uint96(vaultSockets[_vault].sharesMinted - _amountOfShares);
}

function voluntaryDisconnect(address _vault) external {
emit Mock__VaultDisconnected(_vault);
}

function rebalance() external payable {
vaultSockets[msg.sender].sharesMinted = 0;

emit Mock__Rebalanced(msg.value);
}

error ZeroArgument(string argument);
}
Loading
Loading