Skip to content

Merkle oracle integration #977

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

Merged
merged 51 commits into from
Apr 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
037415e
feat: preparation for external vaults oracle
vp4242 Mar 10, 2025
f730492
feat: update related tests with updated report format
vp4242 Mar 10, 2025
5c3913f
fix: report field name in contract
vp4242 Mar 10, 2025
5de882f
feat: fix report params
vp4242 Mar 19, 2025
5afe756
fix: remove some vaults-related logic
vp4242 Mar 19, 2025
6011099
feat: add tree root and cid with vaults data
vp4242 Mar 19, 2025
1e40bbf
fix: related helpers and tests
vp4242 Mar 19, 2025
d0e0e78
feat: update vault data report and related tests
vp4242 Mar 19, 2025
9b007ca
fix: silence warn temp unused var
vp4242 Mar 19, 2025
d762e8d
feat: add proof checking and timestamp handling
vp4242 Mar 20, 2025
8e47303
feat: double keccak for leaf hashing
vp4242 Mar 21, 2025
5ac712f
feat: add mintedShares and remove locked
vp4242 Mar 24, 2025
28ffd1a
feat: add locked calc
vp4242 Mar 24, 2025
591734c
fix: rename internal functions
vp4242 Mar 24, 2025
075cce0
feat: new params for report
vp4242 Mar 24, 2025
ad56a1f
feat: update fees calc, introduce vaultsTotalDeficit
vp4242 Mar 24, 2025
fd306ab
feat: update vaults fee calculation
vp4242 Mar 26, 2025
606faa4
feat: better check for report freshness
vp4242 Mar 26, 2025
045e331
test: fix errors after rebase
vp4242 Mar 28, 2025
7bc953f
feat: comments and proper leaf calc
vp4242 Mar 31, 2025
1a2ac64
test: reporting for VaultHub first steps
vp4242 Mar 31, 2025
4f89b01
feat: add some tests for async reporting
vp4242 Apr 1, 2025
8add862
Merge branch 'feat/vaults' into feat/merkle-oracle-2
vp4242 Apr 1, 2025
24b65ed
feat: fix accounting params
vp4242 Apr 1, 2025
ba24e14
test: disable failed tests due to zero fees
vp4242 Apr 1, 2025
0750598
fix: remove cruft
vp4242 Apr 2, 2025
d5833db
test: treasury fees
vp4242 Apr 2, 2025
3117836
feat: rename vaultsTotalTreasuryFees -> vaultsTotalTreasuryFeesShares
vp4242 Apr 2, 2025
b7978a2
fix: rename lastFees -> feeSharesCharged
vp4242 Apr 2, 2025
57e7ea9
feat: change timestamp to uint64
vp4242 Apr 4, 2025
9df8be5
feat: address review
vp4242 Apr 4, 2025
0b62565
Merge branch 'feat/vaults' into feat/merkle-oracle-2
vp4242 Apr 4, 2025
8a51e90
Merge branch 'feat/vaults' into feat/merkle-oracle-2
vp4242 Apr 8, 2025
b767df9
feat: add merkle reporting
vp4242 Apr 9, 2025
d79b690
fix: proof reporting tests
vp4242 Apr 9, 2025
81679aa
test: reject rewards test
vp4242 Apr 9, 2025
757dcb1
Merge branch 'feat/vaults' into feat/merkle-oracle-2
vp4242 Apr 9, 2025
ef46740
feat: remove unused code
vp4242 Apr 10, 2025
178bec8
feat: report freshness
vp4242 Apr 10, 2025
a6041fa
feat: report freshness check in VaultHub
vp4242 Apr 10, 2025
f1bd8f9
fix: remove unused event
vp4242 Apr 10, 2025
27a067a
fix: address review comments
vp4242 Apr 11, 2025
8714237
Merge branch 'feat/vaults' into feat/merkle-oracle-2
vp4242 Apr 11, 2025
4c171d1
feat: allow full withdrawals without fresh report
vp4242 Apr 11, 2025
399785e
feat: improve withdrawal lock check
vp4242 Apr 11, 2025
6d29caf
feat: more comments, fix tests
vp4242 Apr 11, 2025
f994009
fix: tests
vp4242 Apr 11, 2025
082296e
Merge branch 'feat/vaults' into feat/merkle-oracle-2
vp4242 Apr 11, 2025
efa258f
feat: remove report as there is one on connect
vp4242 Apr 11, 2025
48224fc
feat: remove public function
vp4242 Apr 11, 2025
87873c5
feat: remove unnecessary check
vp4242 Apr 11, 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
35 changes: 8 additions & 27 deletions contracts/0.8.25/Accounting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,6 @@ contract Accounting {
uint256 postTotalShares;
/// @notice amount of ether under the protocol after the report is applied
uint256 postTotalPooledEther;
/// @notice amount of ether to be locked in the vaults
uint256[] vaultsLockedEther;
/// @notice amount of shares to be minted as vault fees to the treasury
uint256[] vaultsTreasuryFeeShares;
/// @notice total amount of shares to be minted as vault fees to the treasury
uint256 totalVaultsTreasuryFeeShares;
}

struct StakingRewardsDistribution {
Expand Down Expand Up @@ -219,19 +213,9 @@ contract Accounting {

update.postInternalShares = postInternalSharesBeforeFees + update.sharesToMintAsFees;

// Calculate the amount of ether locked in the vaults to back external balance of stETH
// and the amount of shares to mint as fees to the treasury for each vault
(update.vaultsLockedEther, update.vaultsTreasuryFeeShares, update.totalVaultsTreasuryFeeShares) =
_contracts.vaultHub.calculateVaultsRebase(
_report.vaultValues,
_pre.totalShares,
_pre.totalPooledEther,
update.postInternalShares,
update.postInternalEther,
update.sharesToMintAsFees
);
// Calculate the amount of shares to mint as fees to the treasury for vaults

uint256 externalShares = _pre.externalShares + update.totalVaultsTreasuryFeeShares;
uint256 externalShares = _pre.externalShares + _report.vaultsTotalTreasuryFeesShares;

update.postTotalShares = update.postInternalShares + externalShares;
update.postTotalPooledEther = update.postInternalEther + externalShares * update.postInternalEther / update.postInternalShares;
Expand Down Expand Up @@ -328,16 +312,13 @@ contract Accounting {
_update.etherToFinalizeWQ
);

// TODO: Remove this once decide on vaults reporting
_contracts.vaultHub.updateVaults(
_report.vaultValues,
_report.inOutDeltas,
_update.vaultsLockedEther,
_update.vaultsTreasuryFeeShares
_contracts.vaultHub.updateReportData(
uint64(_report.timestamp),
_report.vaultsDataTreeRoot,
_report.vaultsDataTreeCid
);

if (_update.totalVaultsTreasuryFeeShares > 0) {
_contracts.vaultHub.mintVaultsTreasuryFeeShares(_update.totalVaultsTreasuryFeeShares);
if (_report.vaultsTotalTreasuryFeesShares > 0) {
_contracts.vaultHub.mintVaultsTreasuryFeeShares(_report.vaultsTotalTreasuryFeesShares);
}

_notifyRebaseObserver(_contracts.postTokenRebaseReceiver, _report, _pre, _update);
Expand Down
45 changes: 39 additions & 6 deletions contracts/0.8.25/vaults/StakingVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,11 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {
(bool success, ) = _recipient.call{value: _ether}("");
if (!success) revert TransferFailed(_recipient, _ether);

if (valuation() < $.locked) revert ValuationBelowLockedAmount();
if (isReportFresh()) {
if (valuation() < $.locked) revert ValuationBelowLockedAmount();
} else {
if (address(this).balance < $.locked) revert ValuationBelowLockedAmount();
}

emit Withdrawn(msg.sender, _recipient, _ether);
}
Expand All @@ -427,7 +431,11 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {
function lock(uint256 _locked) external onlyOwner {
ERC7201Storage storage $ = _getStorage();
if (_locked <= $.locked) revert NewLockedNotGreaterThanCurrent();
if (_locked > valuation()) revert NewLockedExceedsValuation();
if (isReportFresh()) {
if (_locked > valuation()) revert NewLockedExceedsValuation();
} else {
if (_locked > address(this).balance) revert NewLockedExceedsValuation();
}

$.locked = uint128(_locked);

Expand Down Expand Up @@ -466,15 +474,19 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {
* @param _inOutDelta New net difference between funded and withdrawn ether
* @param _locked New amount of locked ether
*/
function report(uint256 _valuation, int256 _inOutDelta, uint256 _locked) external {
function report(uint64 _timestamp, uint256 _valuation, int256 _inOutDelta, uint256 _locked) external {
ERC7201Storage storage $ = _getStorage();
if (msg.sender != address(VAULT_HUB) || !$.vaultHubAuthorized) revert NotAuthorized("report", msg.sender);

uint64 currentTimestamp = $.report.timestamp;
if (currentTimestamp >= _timestamp) revert ReportTooOld(currentTimestamp, _timestamp);

$.report.timestamp = _timestamp;
$.report.valuation = uint128(_valuation);
$.report.inOutDelta = int128(_inOutDelta);
$.locked = uint128(_locked);

emit Reported(_valuation, _inOutDelta, _locked);
emit Reported(_timestamp, _valuation, _inOutDelta, _locked);
}

/**
Expand Down Expand Up @@ -612,7 +624,7 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {

ERC7201Storage storage $ = _getStorage();
bool isValuationBelowLocked = valuation() < $.locked;
if (isValuationBelowLocked) {
if (isValuationBelowLocked || !isReportFresh()) {
// Block partial withdrawals to prevent front-running force withdrawals
for (uint256 i = 0; i < _amounts.length; i++) {
if (_amounts[i] > 0) revert PartialWithdrawalNotAllowed();
Expand Down Expand Up @@ -642,6 +654,17 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {
emit ValidatorWithdrawalTriggered(msg.sender, _pubkeys, _amounts, _refundRecipient, excess);
}

function isReportFresh() public view returns (bool) {
ERC7201Storage storage $ = _getStorage();
if (!$.vaultHubAuthorized) return true;
return block.timestamp - $.report.timestamp < VAULT_HUB.REPORT_FRESHNESS_DELTA();
}

function _checkFreshnessAndGetValuation() internal view returns (uint256) {
if (!isReportFresh()) revert ReportStaled();
return valuation();
}

function _getStorage() private pure returns (ERC7201Storage storage $) {
assembly {
$.slot := ERC7201_STORAGE_LOCATION
Expand Down Expand Up @@ -689,7 +712,7 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {
* @param inOutDelta Net difference between ether funded and withdrawn from `StakingVault`
* @param locked Amount of ether locked in `StakingVault`
*/
event Reported(uint256 valuation, int256 inOutDelta, uint256 locked);
event Reported(uint64 indexed timestamp, uint256 valuation, int256 inOutDelta, uint256 locked);

/**
* @notice Emitted when deposits to beacon chain are paused
Expand Down Expand Up @@ -853,6 +876,16 @@ contract StakingVault is IStakingVault, OwnableUpgradeable {
*/
error VaultIsOssified();

/**
* @notice Thrown when a report is staled
*/
error ReportStaled();

/**
* @notice Thrown when a report is too old
*/
error ReportTooOld(uint64 currentTimestamp, uint64 newTimestamp);

/**
* @notice Thrown when the depositor is not the Lido Predeposit Guarantee
* @param depositor Address of the depositor
Expand Down
Loading
Loading