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 UX suggestions #893

Merged
merged 59 commits into from
Dec 24, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
8d6b255
feat: suggestions for additional methods to improve the UX of interac…
DiRaiks Dec 6, 2024
d4250c1
fix: weth call withdraw
DiRaiks Dec 6, 2024
3725cea
feat: add burn for wstETH (with permit)
DiRaiks Dec 6, 2024
8af0dc0
Update contracts/0.8.25/vaults/Dashboard.sol
DiRaiks Dec 6, 2024
e539ece
Update contracts/0.8.25/vaults/Dashboard.sol
DiRaiks Dec 6, 2024
1205e6e
feat: update interfaces, update methods for work with weth/wsteth
DiRaiks Dec 9, 2024
4d3b8ea
Merge branch 'feat/vaults-suggestions' of github.com:lidofinance/core…
DiRaiks Dec 9, 2024
b3a50f5
feat: delete vaultsByOwner from VaultHub
DiRaiks Dec 9, 2024
76ec271
featL add permit modifier, fix errors, update Delegation constructor
DiRaiks Dec 16, 2024
a4febe8
Merge branch 'feat-immutable-operator-in-vault' of github.com:lidofin…
DiRaiks Dec 16, 2024
31d419b
feat: update dashboard consts and methods, add tests
DiRaiks Dec 17, 2024
d4b170c
Merge branch 'feat-immutable-operator-in-vault' into feat/vaults-sugg…
tamtamchik Dec 17, 2024
0099af6
fix: dashboard naming & tests
Jeday Dec 18, 2024
7045ec3
test: add tests for mintWstETH, burnWstETH
DiRaiks Dec 18, 2024
705bb31
fix: burnWstETHWithPermit method
DiRaiks Dec 18, 2024
5ba2431
Merge branch 'feat/vaults-suggestions' of github.com:lidofinance/core…
DiRaiks Dec 18, 2024
f3b4ed9
fix: canMint lower bound
Jeday Dec 18, 2024
aaf6ee6
Merge branch 'feat/vaults-suggestions' of github.com:lidofinance/core…
Jeday Dec 18, 2024
7c8eb29
test: canMint bound by shareLimit
Jeday Dec 18, 2024
8e0e547
tests: fix burnWstETH
DiRaiks Dec 18, 2024
1eb5e62
fix: dashboard naming
Jeday Dec 18, 2024
776f3c5
Merge branch 'feat/vaults-suggestions' of github.com:lidofinance/core…
Jeday Dec 18, 2024
8669b43
fix: merge canMintShares
Jeday Dec 18, 2024
77fccb4
chore: fix pragma for test contracts
tamtamchik Dec 18, 2024
d1a3e7e
chore: fix scratch deploy
tamtamchik Dec 18, 2024
b8028c7
test(integration): stabilize vaults happy path
tamtamchik Dec 18, 2024
b4e1e35
test: fix tests
tamtamchik Dec 18, 2024
17669d6
test(integration): skip negative rebase tests for now
tamtamchik Dec 18, 2024
c89ac39
test: can withdraw test
Jeday Dec 19, 2024
6616579
chore: extract some vaults helpers to library
tamtamchik Dec 19, 2024
04100c0
chore: update StETH harness contract for dashboard tests
tamtamchik Dec 19, 2024
65ec051
tests: start burn permit tests
DiRaiks Dec 19, 2024
6065f91
chore: simplify constructor
tamtamchik Dec 19, 2024
00223f4
fix: constructor
tamtamchik Dec 19, 2024
7d6da64
tests: fix steth events
DiRaiks Dec 19, 2024
7b58f62
Merge branch 'feat/steth-permit' of github.com:lidofinance/core into …
DiRaiks Dec 19, 2024
85baf12
Merge pull request #903 from lidofinance/feat/steth-permit
tamtamchik Dec 19, 2024
dd9157e
Merge branch 'feat-immutable-operator-in-vault' into feat/vaults-sugg…
tamtamchik Dec 19, 2024
856e6ef
fix: comments and tests
tamtamchik Dec 19, 2024
14e6273
fix: integration tests
tamtamchik Dec 19, 2024
c56493e
Merge branch 'feat/vaults-suggestions' of github.com:lidofinance/core…
DiRaiks Dec 19, 2024
3d5fbb8
tests: add tests for burnWstETHWithPermit and burnWithPermit, fix bur…
DiRaiks Dec 19, 2024
dcc5203
Merge pull request #902 from lidofinance/feat/vaults-actions
Jeday Dec 20, 2024
e9e105d
fix: dashboard naming
Jeday Dec 20, 2024
02c78b9
Merge branch 'feat-immutable-operator-in-vault' of github.com:lidofin…
Jeday Dec 20, 2024
592f06f
fix: add ERC20 token to lido interface
Jeday Dec 20, 2024
fe033da
test: fix vault hub mock
Jeday Dec 20, 2024
777d6ce
fix: interfaces&imports
Jeday Dec 20, 2024
13a0464
fix: ILido
Jeday Dec 20, 2024
14fe2d8
test(integration): fix and update vaults happy path
tamtamchik Dec 20, 2024
0739501
Merge branch 'feat-immutable-operator-in-vault' into feat/vaults-sugg…
tamtamchik Dec 20, 2024
49ba3fd
Merge branch 'feat-immutable-operator-in-vault' into feat/vaults-sugg…
tamtamchik Dec 20, 2024
972b84c
fix: delegation tests
tamtamchik Dec 20, 2024
6d4bd11
Merge branch 'feat-immutable-operator-in-vault' into feat/vaults-sugg…
tamtamchik Dec 20, 2024
c808b26
chore: updates after review
tamtamchik Dec 20, 2024
10897a0
fix: contract compilation
tamtamchik Dec 20, 2024
e2c380f
chore: restore some formating
tamtamchik Dec 20, 2024
61163ae
tests: fix getMintableShares test
DiRaiks Dec 24, 2024
e4f8595
Merge branch 'feat-immutable-operator-in-vault' into feat/vaults-sugg…
tamtamchik Dec 24, 2024
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
129 changes: 126 additions & 3 deletions contracts/0.8.25/vaults/Dashboard.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ import {IERC20} from "@openzeppelin/contracts-v5.0.2/token/ERC20/IERC20.sol";
import {OwnableUpgradeable} from "contracts/openzeppelin/5.0.2/upgradeable/access/OwnableUpgradeable.sol";
import {VaultHub} from "./VaultHub.sol";

interface IWeth {
function withdraw(uint) external;
function deposit() external payable;
}

interface IWstETH {
function wrap(uint256) external returns (uint256);
function unwrap(uint256) external returns (uint256);
}

/**
* @title Dashboard
* @notice This contract is meant to be used as the owner of `StakingVault`.
Expand All @@ -35,15 +45,27 @@ contract Dashboard is AccessControlEnumerable {
/// @notice The `VaultHub` contract
VaultHub public vaultHub;

/// @notice The wrapped ether token contract
IWeth public weth;

/// @notice The wrapped staked ether token contract
IWstETH public wstETH;

/**
* @notice Constructor sets the stETH token address and the implementation contract address.
* @param _stETH Address of the stETH token contract.
* @param _weth Address of the weth token contract.
* @param _wstETH Address of the wstETH token contract.
*/
constructor(address _stETH) {
constructor(address _stETH, address _weth, address _wstETH) {
if (_stETH == address(0)) revert ZeroArgument("_stETH");
if (_weth == address(0)) revert ZeroArgument("_weth");
if (_wstETH == address(0)) revert ZeroArgument("_wstETH");

_SELF = address(this);
stETH = IERC20(_stETH);
weth = IWeth(_weth);
wstETH = IWstETH(_wstETH);
}

/**
Expand Down Expand Up @@ -126,6 +148,49 @@ contract Dashboard is AccessControlEnumerable {
return vaultSocket().treasuryFeeBP;
}

/**
* @notice Returns the maximum number of stETH shares that can be minted on the vault.
* @return The maximum number of stETH shares as a uint256.
*/
function maxMintableShares() external view returns (uint256) {
return vaultHub._maxMintableShares(address(stakingVault), vaultSocket().reserveRatio);
}

/**
* @notice Returns the maximum number of stETH shares that can be minted.
* @return The maximum number of stETH shares that can be minted.
*/
function canMint() external view returns (uint256) {

uint256 maxMintableShares = maxMintableShares();
uint256 sharesMinted = vaultSocket().sharesMinted;

return maxMintableShares - sharesMinted;
}

/**
* @notice Returns the maximum number of stETH that can be minted for deposited ether.
* @param _ether The amount of ether to check.
* @return the maximum number of stETH that can be minted by ether
*/
function canMintByEther(uint256 _ether) external view returns (uint256) {
if (_ether == 0) return 0;

uint256 maxMintableShares = maxMintableShares();
uint256 sharesMinted = vaultSocket().sharesMinted;
uint256 sharesToMint = stETH.getSharesByPooledEth(_ether);

return sharesMinted + sharesToMint > maxMintableShares ? maxMintableShares - sharesMinted : sharesToMint;
}

/**
* @notice Returns the amount of ether that can be withdrawn from the staking vault.
* @return The amount of ether that can be withdrawn.
*/
function canWithdraw() external view returns (uint256) {
return address(stakingVault).balance - stakingVault.locked();
}

// ==================== Vault Management Functions ====================

/**
Expand All @@ -150,6 +215,15 @@ contract Dashboard is AccessControlEnumerable {
_fund();
}

/**
* @notice Funds the staking vault with wrapped ether. Approvals for the passed amounts should be done before.
* @param _wethAmount Amount of wrapped ether to fund the staking vault with
*/
function fundByWeth(uint256 _wethAmount) external virtual onlyRole(DEFAULT_ADMIN_ROLE) {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
function fundByWeth(uint256 _wethAmount) external virtual onlyRole(DEFAULT_ADMIN_ROLE) {
function fundWeth(uint256 _wethAmount) external virtual onlyRole(DEFAULT_ADMIN_ROLE) {

IWeth(weth).withdraw(_wethAmount);
_fund();
}

/**
* @notice Withdraws ether from the staking vault to a recipient
* @param _recipient Address of the recipient
Expand All @@ -159,6 +233,15 @@ contract Dashboard is AccessControlEnumerable {
_withdraw(_recipient, _ether);
}

/**
* @notice Withdraws stETH tokens from the staking vault to wrapped ether. Approvals for the passed amounts should be done before.
Copy link
Member

Choose a reason for hiding this comment

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

Sorry, didn't get what it should do. RN, ether is still on the dashboard contract. Should it be transferred to msg.sender or some other recepient?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@folkyatina The idea is to send to the fundByWeth method the amount of WETH that needs to be "unwrap" to the ETH and then fund Vault
WETH withdraw method https://github.com/gnosis/canonical-weth/blob/master/contracts/WETH9.sol#L38

Now I understand that it seems that this code will not work correctly

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated

* @param _tokens Amount of tokens to withdraw
*/
function withdrawToWeth(uint256 _tokens) external virtual onlyRole(DEFAULT_ADMIN_ROLE) {
_withdraw(address(weth), _tokens);
IWeth(weth).deposit{value: _tokens}();
}

/**
* @notice Requests the exit of a validator from the staking vault
* @param _validatorPublicKey Public key of the validator to exit
Expand Down Expand Up @@ -194,13 +277,53 @@ contract Dashboard is AccessControlEnumerable {
}

/**
* @notice Burns stETH tokens from the sender backed by the vault
* @param _tokens Amount of tokens to burn
* @notice Mints wstETH tokens backed by the vault to a recipient. Approvals for the passed amounts should be done before.
* @param _recipient Address of the recipient
* @param _tokens Amount of tokens to mint
*/
function mintWstETH(address _recipient, uint256 _tokens) external payable virtual onlyRole(DEFAULT_ADMIN_ROLE) fundAndProceed {
_mint(_recipient, _tokens);
IWstETH(wstETH).wrap(_tokens);
}

/**
* @notice Burns stETH tokens from the sender backed by the vault. Approvals for the passed amounts should be done before.
* @param _tokens Amount of stETH tokens to burn
*/
function burn(uint256 _tokens) external virtual onlyRole(DEFAULT_ADMIN_ROLE) {
_burn(_tokens);
}

/**
* @notice Burns wstETH tokens from the sender backed by the vault. Approvals for the passed amounts should be done before.
* @param _tokens Amount of wstETH tokens to burn
*/
function burnWstETH(uint256 _tokens) external virtual onlyRole(DEFAULT_ADMIN_ROLE) {
IWstETH(wstETH).unwrap(_tokens);
_burn(_tokens);
}

/**
* @notice Burns stETH tokens from the sender backed by the vault using EIP-2612 Permit.
* @param _tokens Amount of stETH tokens to burn
* @param _permit data required for the stETH.permit() method to set the allowance
*/
function burnWithPermit(uint256 _tokens, PermitInput calldata _permit) external virtual onlyRole(DEFAULT_ADMIN_ROLE) {
stETH.permit(msg.sender, address(this), _permit.value, _permit.deadline, _permit.v, _permit.r, _permit.s);
_burn(_tokens);
}

/**
* @notice Burns wstETH tokens from the sender backed by the vault using EIP-2612 Permit.
* @param _tokens Amount of wstETH tokens to burn
* @param _permit data required for the stETH.permit() method to set the allowance
*/
function burnWstETHWithPermit(uint256 _tokens, PermitInput calldata _permit) external virtual onlyRole(DEFAULT_ADMIN_ROLE) {
stETH.permit(msg.sender, address(this), _permit.value, _permit.deadline, _permit.v, _permit.r, _permit.s);
IWstETH(wstETH).unwrap(_tokens);
_burn(_tokens);
}

/**
* @notice Rebalances the vault by transferring ether
* @param _ether Amount of ether to rebalance
Expand Down
29 changes: 29 additions & 0 deletions contracts/0.8.25/vaults/VaultHub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,35 @@ abstract contract VaultHub is AccessControlEnumerableUpgradeable {
return $.sockets[$.vaultIndex[IHubVault(_vault)]];
}

/// @notice Returns all vaults owned by a given address
/// @param _owner Address of the owner
/// @return An array of vaults owned by the given address
function vaultsByOwner(address _owner) external view returns (IHubVault[] memory) {
VaultHubStorage storage $ = _getVaultHubStorage();
uint256 count = 0;

// First, count how many vaults belong to the owner
for (uint256 i = 1; i < $.sockets.length; i++) {
if ($.sockets[i].vault.owner() == _owner) {
count++;
}
}

// Create an array to hold the owner's vaults
IHubVault[] memory ownerVaults = new IHubVault[](count);
uint256 index = 0;

// Populate the array with the owner's vaults
for (uint256 i = 1; i < $.sockets.length; i++) {
if ($.sockets[i].vault.owner() == _owner) {
ownerVaults[index] = $.sockets[i].vault;
index++;
}
}

return ownerVaults;
}

/// @notice connects a vault to the hub
/// @param _vault vault address
/// @param _shareLimit maximum number of stETH shares that can be minted by the vault
Expand Down
Loading