-
Notifications
You must be signed in to change notification settings - Fork 195
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
feat: Vaults #874
base: develop
Are you sure you want to change the base?
feat: Vaults #874
Changes from 1 commit
75fa209
007794d
852d82c
b4955c5
9652868
aa3efdd
34b654a
5973c00
fae1537
c83edc3
c8d19e6
4c2ae7c
94f1d18
c7bbf23
9cfe04e
c384a2c
8206704
7987794
58e5b83
0757a90
97f330b
b6e4f82
c26f793
8e0c17f
ba2c2aa
20770b3
c0bd5c2
e85791b
ab52647
eb9195f
97612ee
7943917
1eafcbe
599806a
6f8c01c
528dae7
ce34c54
1e57a1b
803199c
d56c26f
bf83fcd
d376ee3
f560380
6286561
e14f443
f9ca4a4
043b26e
1102123
29cde40
137ced5
ae0f7f1
06b3c39
038e2bd
b2b413e
41ed2c7
9b59268
fa8e84c
728d828
481979d
ce82205
d2c8008
7166610
a0ed62c
ebbad1a
c376856
b2ef4fe
a4b15fd
2a0233d
f5cadef
d607895
41bbc8e
b75c742
1cc1ded
a8f95a9
dd485cd
fc5b704
580a703
847c9ab
a18c2f0
6d8426f
f0d14ce
417d433
d534778
fe2b426
eb9c29e
e7b546e
5de258b
e83f05f
7e7edee
2de4da5
733740a
0aadf9f
d9f1f14
28fedbd
2e1c3c0
2e20710
aee1294
1bcd4fd
6a88a0e
9f4ddcc
fa53eb4
fb2aa93
9030b5c
03a84a8
681c122
1395555
751c77e
17b88bf
a50851f
91d432e
e88a7de
0cdfaf8
8d6b255
d4250c1
3725cea
8af0dc0
e539ece
94509bc
212ec13
50b04f6
1205e6e
4d3b8ea
b3a50f5
bca1ddc
9faf18a
1b7ca1e
d040e12
06340ca
6f14ec7
20d7db8
2c31ba1
e94cd96
1fad723
ef39ef1
1a843a9
7a7e622
953f5e6
4875492
e137105
a4e4ad1
8b023e5
7ca3cdc
f229b7a
5c40f69
cfc013b
2427c02
11c74e7
2114611
5185b04
ca89ffc
446c36d
76ec271
a4febe8
2963755
31d419b
204260e
7d3047d
4daff2d
168d025
cb6ed42
ce7ccb8
496e6f2
d4b170c
79653dd
bb43b2e
afcb7d3
1463ad3
611ce3a
0099af6
7045ec3
705bb31
5ba2431
f3b4ed9
aaf6ee6
7c8eb29
8e0e547
1eb5e62
776f3c5
39c155f
8669b43
77fccb4
d1a3e7e
b8028c7
b4e1e35
17669d6
c89ac39
732dbf4
6256c16
6616579
04100c0
65ec051
6065f91
00223f4
7d6da64
7b58f62
85baf12
dd9157e
856e6ef
14e6273
c56493e
3d5fbb8
34261a9
bc86331
21425d0
7899756
8d7a6af
2f0ec60
d9888f0
dcc5203
e9e105d
02c78b9
592f06f
fe033da
777d6ce
13a0464
14fe2d8
c34ebe1
0739501
4897271
49ba3fd
d0b1d4c
f7086b5
972b84c
887fec3
6d4bd11
c808b26
10897a0
e2c380f
0408978
61163ae
9099c27
b3e53b5
dbabb36
a936b19
b2cc291
e4f8595
2168c79
b9ffdf6
a9154a7
5ae82dd
01a41e4
9f2d151
7c2d498
1659803
3cb1d76
901c0e1
ab1db80
eafd3bc
978ff1e
df8400f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- deposit-logistics-lib
- (#910)
- feat/factory-upgrade
- (#901)
- feat/fix-accounting-tests-vaults
- (#912)
- feat/hub-viewer
- (#905)
- feat/steth-oss
- feat/vaults
- (#874)
- feat/vaults-dashboard-recovery
- (#908)
- feat/vaults-hub-role
- p-less-vaults-dsm
- (#911)
- pausable-vault-hub
- (#914)
- precision-loss-2
- (#913)
- test/staking-vault
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,11 +6,11 @@ pragma solidity 0.8.25; | |
|
||
import {OwnableUpgradeable} from "contracts/openzeppelin/5.0.2/upgradeable/access/OwnableUpgradeable.sol"; | ||
import {VaultBeaconChainDepositor} from "./VaultBeaconChainDepositor.sol"; | ||
import {IHub} from "./interfaces/IHub.sol"; | ||
import {IVaultHub} from "./interfaces/IVaultHub.sol"; | ||
import {IReportValuationReceiver} from "./interfaces/IReportValuationReceiver.sol"; | ||
import {SafeCast} from "@openzeppelin/contracts-v5.0.2/utils/math/SafeCast.sol"; | ||
|
||
contract Vault is VaultBeaconChainDepositor, OwnableUpgradeable { | ||
contract StakingVault is VaultBeaconChainDepositor, OwnableUpgradeable { | ||
event Funded(address indexed sender, uint256 amount); | ||
event Withdrawn(address indexed sender, address indexed recipient, uint256 amount); | ||
event DepositedToBeaconChain(address indexed sender, uint256 numberOfDeposits, uint256 amount); | ||
|
@@ -33,7 +33,7 @@ contract Vault is VaultBeaconChainDepositor, OwnableUpgradeable { | |
|
||
uint256 private constant MAX_FEE = 100_00; | ||
|
||
IHub public immutable hub; | ||
IVaultHub public immutable vaultHub; | ||
Report public latestReport; | ||
uint256 public locked; | ||
int256 public inOutDelta; | ||
|
@@ -46,7 +46,7 @@ contract Vault is VaultBeaconChainDepositor, OwnableUpgradeable { | |
if (_owner == address(0)) revert ZeroArgument("_owner"); | ||
if (_hub == address(0)) revert ZeroArgument("_hub"); | ||
|
||
hub = IHub(_hub); | ||
vaultHub = IVaultHub(_hub); | ||
_transferOwnership(_owner); | ||
} | ||
|
||
|
@@ -122,7 +122,7 @@ contract Vault is VaultBeaconChainDepositor, OwnableUpgradeable { | |
if (_recipient == address(0)) revert ZeroArgument("_recipient"); | ||
if (_tokens == 0) revert ZeroArgument("_tokens"); | ||
|
||
uint256 newlyLocked = hub.mintStethBackedByVault(_recipient, _tokens); | ||
uint256 newlyLocked = vaultHub.mintStethBackedByVault(_recipient, _tokens); | ||
|
||
if (newlyLocked > locked) { | ||
locked = newlyLocked; | ||
|
@@ -134,28 +134,28 @@ contract Vault is VaultBeaconChainDepositor, OwnableUpgradeable { | |
function burn(uint256 _tokens) external onlyOwner { | ||
if (_tokens == 0) revert ZeroArgument("_tokens"); | ||
|
||
hub.burnStethBackedByVault(_tokens); | ||
vaultHub.burnStethBackedByVault(_tokens); | ||
} | ||
|
||
function rebalance(uint256 _ether) external payable { | ||
if (_ether == 0) revert ZeroArgument("_ether"); | ||
if (_ether > address(this).balance) revert InsufficientBalance(address(this).balance); | ||
|
||
if (owner() == msg.sender || (!isHealthy() && msg.sender == address(hub))) { | ||
if (owner() == msg.sender || (!isHealthy() && msg.sender == address(vaultHub))) { | ||
// force rebalance | ||
// TODO: check rounding here | ||
// mint some stETH in Lido v2 and burn it on the vault | ||
inOutDelta -= int256(_ether); | ||
emit Withdrawn(msg.sender, msg.sender, _ether); | ||
|
||
hub.rebalance{value: _ether}(); | ||
vaultHub.rebalance{value: _ether}(); | ||
} else { | ||
revert NotAuthorized("rebalance", msg.sender); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe we should have two different revert options based on the branching above |
||
} | ||
} | ||
|
||
function report(uint256 _valuation, int256 _inOutDelta, uint256 _locked) external { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. naive mitigation approach: pre-report hook to withdraw rewards and put them on the vault address |
||
if (msg.sender != address(hub)) revert NotAuthorized("update", msg.sender); | ||
if (msg.sender != address(vaultHub)) revert NotAuthorized("update", msg.sender); | ||
|
||
latestReport = Report(SafeCast.toUint128(_valuation), SafeCast.toInt128(_inOutDelta)); | ||
locked = _locked; | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -5,7 +5,7 @@ | |||||
pragma solidity 0.8.25; | ||||||
|
||||||
import {AccessControlEnumerableUpgradeable} from "contracts/openzeppelin/5.0.2/upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol"; | ||||||
import {IVault} from "./interfaces/IVault.sol"; | ||||||
import {IStakingVault} from "./interfaces/IStakingVault.sol"; | ||||||
|
||||||
interface StETH { | ||||||
function mintExternalShares(address, uint256) external; | ||||||
|
@@ -43,7 +43,7 @@ abstract contract VaultHub is AccessControlEnumerableUpgradeable { | |||||
|
||||||
struct VaultSocket { | ||||||
/// @notice vault address | ||||||
IVault vault; | ||||||
IStakingVault vault; | ||||||
/// @notice maximum number of stETH shares that can be minted by vault owner | ||||||
uint96 capShares; | ||||||
/// @notice total number of stETH shares minted by the vault | ||||||
|
@@ -58,13 +58,13 @@ abstract contract VaultHub is AccessControlEnumerableUpgradeable { | |||||
VaultSocket[] private sockets; | ||||||
/// @notice mapping from vault address to its socket | ||||||
/// @dev if vault is not connected to the hub, it's index is zero | ||||||
mapping(IVault => uint256) private vaultIndex; | ||||||
mapping(IStakingVault => uint256) private vaultIndex; | ||||||
|
||||||
constructor(address _admin, address _stETH, address _treasury) { | ||||||
STETH = StETH(_stETH); | ||||||
treasury = _treasury; | ||||||
|
||||||
sockets.push(VaultSocket(IVault(address(0)), 0, 0, 0, 0)); // stone in the elevator | ||||||
sockets.push(VaultSocket(IStakingVault(address(0)), 0, 0, 0, 0)); // stone in the elevator | ||||||
|
||||||
_grantRole(DEFAULT_ADMIN_ROLE, _admin); | ||||||
} | ||||||
|
@@ -74,15 +74,15 @@ abstract contract VaultHub is AccessControlEnumerableUpgradeable { | |||||
return sockets.length - 1; | ||||||
} | ||||||
|
||||||
function vault(uint256 _index) public view returns (IVault) { | ||||||
function vault(uint256 _index) public view returns (IStakingVault) { | ||||||
return sockets[_index + 1].vault; | ||||||
} | ||||||
|
||||||
function vaultSocket(uint256 _index) external view returns (VaultSocket memory) { | ||||||
return sockets[_index + 1]; | ||||||
} | ||||||
|
||||||
function vaultSocket(IVault _vault) public view returns (VaultSocket memory) { | ||||||
function vaultSocket(IStakingVault _vault) public view returns (VaultSocket memory) { | ||||||
return sockets[vaultIndex[_vault]]; | ||||||
} | ||||||
|
||||||
|
@@ -91,7 +91,7 @@ abstract contract VaultHub is AccessControlEnumerableUpgradeable { | |||||
/// @param _capShares maximum number of stETH shares that can be minted by the vault | ||||||
/// @param _minBondRateBP minimum bond rate in basis points | ||||||
function connectVault( | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for permissionless addition:
|
||||||
IVault _vault, | ||||||
IStakingVault _vault, | ||||||
uint256 _capShares, | ||||||
uint256 _minBondRateBP, | ||||||
uint256 _treasuryFeeBP | ||||||
|
@@ -110,7 +110,7 @@ abstract contract VaultHub is AccessControlEnumerableUpgradeable { | |||||
if (_treasuryFeeBP > BPS_BASE) revert TreasuryFeeTooHigh(address(_vault), _treasuryFeeBP, BPS_BASE); | ||||||
|
||||||
VaultSocket memory vr = VaultSocket( | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
IVault(_vault), | ||||||
IStakingVault(_vault), | ||||||
uint96(_capShares), | ||||||
0, | ||||||
uint16(_minBondRateBP), | ||||||
|
@@ -124,8 +124,8 @@ abstract contract VaultHub is AccessControlEnumerableUpgradeable { | |||||
|
||||||
/// @notice disconnects a vault from the hub | ||||||
/// @param _vault vault address | ||||||
function disconnectVault(IVault _vault) external onlyRole(VAULT_MASTER_ROLE) { | ||||||
if (_vault == IVault(address(0))) revert ZeroArgument("vault"); | ||||||
function disconnectVault(IStakingVault _vault) external onlyRole(VAULT_MASTER_ROLE) { | ||||||
if (_vault == IStakingVault(address(0))) revert ZeroArgument("vault"); | ||||||
|
||||||
uint256 index = vaultIndex[_vault]; | ||||||
if (index == 0) revert NotConnectedToHub(address(_vault)); | ||||||
|
@@ -164,7 +164,7 @@ abstract contract VaultHub is AccessControlEnumerableUpgradeable { | |||||
if (_amountOfTokens == 0) revert ZeroArgument("amountOfTokens"); | ||||||
if (_receiver == address(0)) revert ZeroArgument("receivers"); | ||||||
|
||||||
IVault vault_ = IVault(msg.sender); | ||||||
IStakingVault vault_ = IStakingVault(msg.sender); | ||||||
uint256 index = vaultIndex[vault_]; | ||||||
if (index == 0) revert NotConnectedToHub(msg.sender); | ||||||
VaultSocket memory socket = sockets[index]; | ||||||
|
@@ -190,7 +190,7 @@ abstract contract VaultHub is AccessControlEnumerableUpgradeable { | |||||
function burnStethBackedByVault(uint256 _amountOfTokens) external { | ||||||
if (_amountOfTokens == 0) revert ZeroArgument("amountOfTokens"); | ||||||
|
||||||
uint256 index = vaultIndex[IVault(msg.sender)]; | ||||||
uint256 index = vaultIndex[IStakingVault(msg.sender)]; | ||||||
if (index == 0) revert NotConnectedToHub(msg.sender); | ||||||
VaultSocket memory socket = sockets[index]; | ||||||
|
||||||
|
@@ -203,7 +203,7 @@ abstract contract VaultHub is AccessControlEnumerableUpgradeable { | |||||
emit BurnedStETHOnVault(msg.sender, _amountOfTokens); | ||||||
} | ||||||
|
||||||
function forceRebalance(IVault _vault) external { | ||||||
function forceRebalance(IStakingVault _vault) external { | ||||||
uint256 index = vaultIndex[_vault]; | ||||||
if (index == 0) revert NotConnectedToHub(msg.sender); | ||||||
VaultSocket memory socket = sockets[index]; | ||||||
|
@@ -231,7 +231,7 @@ abstract contract VaultHub is AccessControlEnumerableUpgradeable { | |||||
function rebalance() external payable { | ||||||
if (msg.value == 0) revert ZeroArgument("msg.value"); | ||||||
|
||||||
uint256 index = vaultIndex[IVault(msg.sender)]; | ||||||
uint256 index = vaultIndex[IStakingVault(msg.sender)]; | ||||||
if (index == 0) revert NotConnectedToHub(msg.sender); | ||||||
VaultSocket memory socket = sockets[index]; | ||||||
|
||||||
|
@@ -303,7 +303,7 @@ abstract contract VaultHub is AccessControlEnumerableUpgradeable { | |||||
uint256 preTotalShares, | ||||||
uint256 preTotalPooledEther | ||||||
) internal view returns (uint256 treasuryFeeShares) { | ||||||
IVault vault_ = _socket.vault; | ||||||
IStakingVault vault_ = _socket.vault; | ||||||
|
||||||
uint256 chargeableValue = _min(vault_.valuation(), (_socket.capShares * preTotalPooledEther) / preTotalShares); | ||||||
|
||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or maybe 'Rebalanced'