Skip to content

Commit 3d55079

Browse files
authored
Merge pull request #1490 from lidofinance/feat/view-vault-info
2 parents d50d465 + cc7ef3d commit 3d55079

File tree

9 files changed

+129
-44
lines changed

9 files changed

+129
-44
lines changed

contracts/0.8.25/vaults/LazyOracle.sol

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -226,29 +226,40 @@ contract LazyOracle is ILazyOracle, AccessControlEnumerableUpgradeable {
226226
VaultInfo[] memory batch = new VaultInfo[](batchSize);
227227
for (uint256 i = 0; i < batchSize; i++) {
228228
address vaultAddress = vaultHub.vaultByIndex(_offset + i + 1);
229-
IStakingVault vault = IStakingVault(vaultAddress);
230-
VaultHub.VaultConnection memory connection = vaultHub.vaultConnection(vaultAddress);
231-
VaultHub.VaultRecord memory record = vaultHub.vaultRecord(vaultAddress);
232-
batch[i] = VaultInfo(
233-
vaultAddress,
234-
vault.availableBalance() + vault.stagedBalance(),
235-
record.inOutDelta.currentValue(),
236-
vault.withdrawalCredentials(),
237-
record.liabilityShares,
238-
record.maxLiabilityShares,
239-
_mintableStETH(vaultAddress),
240-
connection.shareLimit,
241-
connection.reserveRatioBP,
242-
connection.forcedRebalanceThresholdBP,
243-
connection.infraFeeBP,
244-
connection.liquidityFeeBP,
245-
connection.reservationFeeBP,
246-
vaultHub.isPendingDisconnect(vaultAddress)
247-
);
229+
batch[i] = _vaultInfo(vaultAddress, vaultHub);
248230
}
249231
return batch;
250232
}
251233

234+
/// @notice returns the vault data info
235+
/// @param _vault the address of the vault
236+
/// @return the vault data info
237+
function vaultInfo(address _vault) external view returns (VaultInfo memory) {
238+
return _vaultInfo(_vault, _vaultHub());
239+
}
240+
241+
function _vaultInfo(address _vault, VaultHub _vaultHub) internal view returns (VaultInfo memory) {
242+
IStakingVault vault = IStakingVault(_vault);
243+
VaultHub.VaultConnection memory connection = _vaultHub.vaultConnection(_vault);
244+
VaultHub.VaultRecord memory record = _vaultHub.vaultRecord(_vault);
245+
return VaultInfo(
246+
_vault,
247+
vault.availableBalance() + vault.stagedBalance(),
248+
record.inOutDelta.currentValue(),
249+
vault.withdrawalCredentials(),
250+
record.liabilityShares,
251+
record.maxLiabilityShares,
252+
_mintableStETH(_vault),
253+
connection.shareLimit,
254+
connection.reserveRatioBP,
255+
connection.forcedRebalanceThresholdBP,
256+
connection.infraFeeBP,
257+
connection.liquidityFeeBP,
258+
connection.reservationFeeBP,
259+
_vaultHub.isPendingDisconnect(_vault)
260+
);
261+
}
262+
252263
/**
253264
* @notice batch method to mass check the validator stages in PredepositGuarantee contract
254265
* @param _pubkeys the array of validator's pubkeys to check

contracts/0.8.25/vaults/OperatorGrid.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,7 @@ contract OperatorGrid is AccessControlEnumerableUpgradeable, Confirmable2Address
674674
emit VaultJailStatusUpdated(_vault, _isInJail);
675675
}
676676

677-
/// @notice Get vault limits
677+
/// @notice Get vault's tier limits
678678
/// @param _vault address of the vault
679679
/// @return nodeOperator node operator of the vault
680680
/// @return tierId tier id of the vault
@@ -684,7 +684,7 @@ contract OperatorGrid is AccessControlEnumerableUpgradeable, Confirmable2Address
684684
/// @return infraFeeBP infra fee of the vault
685685
/// @return liquidityFeeBP liquidity fee of the vault
686686
/// @return reservationFeeBP reservation fee of the vault
687-
function vaultInfo(address _vault)
687+
function vaultTierInfo(address _vault)
688688
external
689689
view
690690
returns (

contracts/0.8.25/vaults/VaultHub.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ contract VaultHub is PausableUntilWithRoles {
367367
uint256 infraFeeBP,
368368
uint256 liquidityFeeBP,
369369
uint256 reservationFeeBP
370-
) = _operatorGrid().vaultInfo(_vault);
370+
) = _operatorGrid().vaultTierInfo(_vault);
371371

372372
_connectVault(_vault,
373373
shareLimit,

test/0.8.25/vaults/lazyOracle/contracts/VaultHub__MockForLazyOracle.sol

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ contract VaultHub__MockForLazyOracle {
8787
return false;
8888
}
8989

90+
function isVaultConnected(address _vault) external view returns (bool) {
91+
return mock__vaultConnections[_vault].vaultIndex != 0;
92+
}
93+
9094
function totalMintingCapacityShares(address _vault, int256 _deltaValue) external view returns (uint256) {
9195
uint256 base = mock__vaultRecords[_vault].report.totalValue;
9296
uint256 maxLockableValue = _deltaValue >= 0 ? base + uint256(_deltaValue) : base - uint256(-_deltaValue);

test/0.8.25/vaults/lazyOracle/lazyOracle.test.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,76 @@ describe("LazyOracle.sol", () => {
227227
});
228228
});
229229

230+
context("vaultInfo", () => {
231+
it("returns the vault info for a single vault", async () => {
232+
const vault1 = await createVault();
233+
await vaultHub.mock__addVault(vault1);
234+
235+
await vaultHub.mock__setVaultConnection(vault1, {
236+
owner: randomAddress(),
237+
shareLimit: 2000n,
238+
vaultIndex: 1,
239+
disconnectInitiatedTs: DISCONNECT_NOT_INITIATED,
240+
reserveRatioBP: 5000,
241+
forcedRebalanceThresholdBP: 8000,
242+
infraFeeBP: 1500,
243+
liquidityFeeBP: 2500,
244+
reservationFeeBP: 3500,
245+
isBeaconDepositsManuallyPaused: false,
246+
});
247+
248+
await vaultHub.mock__setVaultRecord(vault1, {
249+
report: {
250+
totalValue: 0n, // Set to 0 to make mintableStETH calculation return 0
251+
inOutDelta: 3000000000000000000n,
252+
timestamp: 2000000000n,
253+
},
254+
maxLiabilityShares: 8n,
255+
liabilityShares: 6n,
256+
inOutDelta: [
257+
{
258+
value: 10n,
259+
valueOnRefSlot: 12n,
260+
refSlot: 9n,
261+
},
262+
{
263+
value: 0n,
264+
valueOnRefSlot: 0n,
265+
refSlot: 0n,
266+
},
267+
],
268+
minimalReserve: 0n,
269+
redemptionShares: 0n,
270+
cumulativeLidoFees: 0n,
271+
settledLidoFees: 0n,
272+
});
273+
274+
const vaultInfo = await lazyOracle.vaultInfo(vault1);
275+
276+
expect(vaultInfo.vault).to.equal(vault1);
277+
expect(vaultInfo.aggregatedBalance).to.equal(0n);
278+
expect(vaultInfo.inOutDelta).to.equal(10n);
279+
expect(vaultInfo.withdrawalCredentials).to.equal(ZERO_BYTES32);
280+
expect(vaultInfo.liabilityShares).to.equal(6n);
281+
expect(vaultInfo.maxLiabilityShares).to.equal(8n);
282+
expect(vaultInfo.mintableStETH).to.equal(0n);
283+
expect(vaultInfo.shareLimit).to.equal(2000n);
284+
expect(vaultInfo.reserveRatioBP).to.equal(5000);
285+
expect(vaultInfo.forcedRebalanceThresholdBP).to.equal(8000);
286+
expect(vaultInfo.infraFeeBP).to.equal(1500);
287+
expect(vaultInfo.liquidityFeeBP).to.equal(2500);
288+
expect(vaultInfo.reservationFeeBP).to.equal(3500);
289+
expect(vaultInfo.pendingDisconnect).to.equal(false);
290+
});
291+
292+
it("reverts with VaultNotConnected for non-existent vault", async () => {
293+
const nonExistentVault = randomAddress();
294+
295+
// The contract will revert with VaultNotConnected error for non-connected vaults
296+
await expect(lazyOracle.vaultInfo(nonExistentVault)).to.be.reverted;
297+
});
298+
});
299+
230300
context("getter functions", () => {
231301
it("return latest report data", async () => {
232302
const reportData = await lazyOracle.latestReportData();

test/0.8.25/vaults/operatorGrid/operatorGrid.test.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,7 +1078,7 @@ describe("OperatorGrid.sol", () => {
10781078

10791079
const group = await operatorGrid.group(nodeOperator1);
10801080

1081-
const vaultTier = await operatorGrid.vaultInfo(vault_NO1_V1);
1081+
const vaultTier = await operatorGrid.vaultTierInfo(vault_NO1_V1);
10821082
const tier = await operatorGrid.tier(vaultTier.tierId);
10831083

10841084
expect(group.liabilityShares).to.equal(tierShareLimit);
@@ -1216,8 +1216,8 @@ describe("OperatorGrid.sol", () => {
12161216
const group = await operatorGrid.group(nodeOperator1);
12171217
const group2 = await operatorGrid.group(nodeOperator2);
12181218

1219-
const vaultTier = await operatorGrid.vaultInfo(vault_NO1_V1);
1220-
const vaultTier2 = await operatorGrid.vaultInfo(vault_NO2_V2);
1219+
const vaultTier = await operatorGrid.vaultTierInfo(vault_NO1_V1);
1220+
const vaultTier2 = await operatorGrid.vaultTierInfo(vault_NO2_V2);
12211221

12221222
const tier = await operatorGrid.tier(vaultTier.tierId);
12231223
const tier2 = await operatorGrid.tier(vaultTier2.tierId);
@@ -1729,8 +1729,8 @@ describe("OperatorGrid.sol", () => {
17291729

17301730
const group = await operatorGrid.group(nodeOperator1);
17311731

1732-
const vaultTier = await operatorGrid.vaultInfo(vault_NO1_V1);
1733-
const vaultTier2 = await operatorGrid.vaultInfo(vault_NO1_V2);
1732+
const vaultTier = await operatorGrid.vaultTierInfo(vault_NO1_V1);
1733+
const vaultTier2 = await operatorGrid.vaultTierInfo(vault_NO1_V2);
17341734

17351735
const tier = await operatorGrid.tier(vaultTier.tierId);
17361736
const tier2 = await operatorGrid.tier(vaultTier2.tierId);
@@ -1800,7 +1800,7 @@ describe("OperatorGrid.sol", () => {
18001800
retInfraFee,
18011801
retLiquidityFee,
18021802
retReservationFee,
1803-
] = await operatorGrid.vaultInfo(vault_NO1_V1);
1803+
] = await operatorGrid.vaultTierInfo(vault_NO1_V1);
18041804

18051805
expect(retGroupOperator).to.equal(nodeOperator1);
18061806
expect(retTierIndex).to.equal(tier_NO1_Id1);
@@ -1821,12 +1821,12 @@ describe("OperatorGrid.sol", () => {
18211821
});
18221822

18231823
it("does nothing if vault is already in default tier", async () => {
1824-
const vaultTierBefore = await operatorGrid.vaultInfo(vault_NO1_V1);
1824+
const vaultTierBefore = await operatorGrid.vaultTierInfo(vault_NO1_V1);
18251825
expect(vaultTierBefore.tierId).to.equal(await operatorGrid.DEFAULT_TIER_ID());
18261826

18271827
await operatorGrid.connect(vaultHubAsSigner).resetVaultTier(vault_NO1_V1);
18281828

1829-
const vaultTierAfter = await operatorGrid.vaultInfo(vault_NO1_V1);
1829+
const vaultTierAfter = await operatorGrid.vaultTierInfo(vault_NO1_V1);
18301830
expect(vaultTierAfter.tierId).to.equal(await operatorGrid.DEFAULT_TIER_ID());
18311831
});
18321832

@@ -1847,14 +1847,14 @@ describe("OperatorGrid.sol", () => {
18471847
await operatorGrid.connect(vaultOwner).changeTier(vault_NO1_V1, 1, shareLimit);
18481848
await operatorGrid.connect(nodeOperator1).changeTier(vault_NO1_V1, 1, shareLimit);
18491849

1850-
const vaultTierBefore = await operatorGrid.vaultInfo(vault_NO1_V1);
1850+
const vaultTierBefore = await operatorGrid.vaultTierInfo(vault_NO1_V1);
18511851
expect(vaultTierBefore.tierId).to.equal(1);
18521852

18531853
// Reset tier
18541854
await operatorGrid.connect(vaultHubAsSigner).resetVaultTier(vault_NO1_V1);
18551855

18561856
// Check final state
1857-
const vaultTierAfter = await operatorGrid.vaultInfo(vault_NO1_V1);
1857+
const vaultTierAfter = await operatorGrid.vaultTierInfo(vault_NO1_V1);
18581858
expect(vaultTierAfter.tierId).to.equal(await operatorGrid.DEFAULT_TIER_ID());
18591859
});
18601860
});

test/0.8.25/vaults/vaulthub/contracts/OperatorGrid__MockForVaultHub.sol

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,13 @@ contract OperatorGrid__MockForVaultHub {
3636
tierParams.reservationFeeBP = uint16(_tierParams.reservationFeeBP);
3737
}
3838

39-
function vaultInfo(
39+
function vaultTierInfo(
4040
address _vault
4141
)
4242
external
4343
view
4444
returns (
45-
uint256 groupId,
45+
address nodeOperator,
4646
uint256 tierId,
4747
uint256 shareLimit,
4848
uint256 reserveRatioBP,
@@ -54,8 +54,8 @@ contract OperatorGrid__MockForVaultHub {
5454
{
5555
Tier memory tierParams = tiers[vaultTier[_vault]];
5656

57-
groupId = 0;
58-
tierId = 0;
57+
nodeOperator = tierParams.operator;
58+
tierId = vaultTier[_vault];
5959
shareLimit = tierParams.shareLimit;
6060
reserveRatioBP = tierParams.reserveRatioBP;
6161
forcedRebalanceThresholdBP = tierParams.forcedRebalanceThresholdBP;

test/integration/vaults/operator.grid.integration.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ describe("Integration: OperatorGrid", () => {
9595
]);
9696

9797
// Initially vault is in default tier (0)
98-
const beforeInfo = await operatorGrid.vaultInfo(stakingVault);
98+
const beforeInfo = await operatorGrid.vaultTierInfo(stakingVault);
9999
expect(beforeInfo.tierId).to.equal(0n);
100100

101101
const requestedTierId = 1n;
@@ -110,7 +110,7 @@ describe("Integration: OperatorGrid", () => {
110110
operatorGrid.connect(nodeOperator).changeTier(stakingVault, requestedTierId, requestedShareLimit),
111111
).to.emit(vaultHub, "VaultConnectionUpdated");
112112

113-
const afterInfo = await operatorGrid.vaultInfo(stakingVault);
113+
const afterInfo = await operatorGrid.vaultTierInfo(stakingVault);
114114
expect(afterInfo.tierId).to.equal(requestedTierId);
115115

116116
const connection = await vaultHub.vaultConnection(stakingVault);
@@ -258,7 +258,7 @@ describe("Integration: OperatorGrid", () => {
258258

259259
it("reverts when requested share limit exceeds tier limit", async () => {
260260
// Default tier case
261-
const info = await operatorGrid.vaultInfo(stakingVault);
261+
const info = await operatorGrid.vaultTierInfo(stakingVault);
262262
const over = info.shareLimit + 1n;
263263
await expect(dashboard.updateShareLimit(over)).to.be.revertedWithCustomError(
264264
operatorGrid,
@@ -330,15 +330,15 @@ describe("Integration: OperatorGrid", () => {
330330
await expect(dashboard.mintShares(owner, 100n)).to.be.revertedWithCustomError(operatorGrid, "VaultInJail");
331331

332332
// Get initial tier
333-
const initialVaultInfo = await operatorGrid.vaultInfo(stakingVault);
333+
const initialVaultInfo = await operatorGrid.vaultTierInfo(stakingVault);
334334
expect(initialVaultInfo.tierId).to.equal(0); // Should be default tier
335335

336336
// Change tier from default (0) to tier 1
337337
await operatorGrid.connect(nodeOperator).changeTier(stakingVault, 1, ether("1000"));
338338
await dashboard.connect(owner).changeTier(1, ether("1000"));
339339

340340
// Verify tier changed
341-
const updatedVaultInfo = await operatorGrid.vaultInfo(stakingVault);
341+
const updatedVaultInfo = await operatorGrid.vaultTierInfo(stakingVault);
342342
expect(updatedVaultInfo.tierId).to.equal(1);
343343

344344
// Verify jail status is preserved after tier change

test/integration/vaults/vaulthub.disconnect.integration.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ describe("Integration: VaultHub", () => {
6565
.to.emit(vaultHub, "VaultDisconnectInitiated")
6666
.withArgs(stakingVault);
6767

68-
expect((await operatorGrid.vaultInfo(stakingVault)).tierId).to.be.equal(tierId);
68+
expect((await operatorGrid.vaultTierInfo(stakingVault)).tierId).to.be.equal(tierId);
6969
expect(await vaultHub.isPendingDisconnect(stakingVault)).to.be.true;
7070
expect(await vaultHub.isVaultConnected(stakingVault)).to.be.true;
7171
expect(await vaultHub.locked(stakingVault)).to.be.equal(ether("1"));
@@ -120,7 +120,7 @@ describe("Integration: VaultHub", () => {
120120
.to.emit(vaultHub, "VaultDisconnectCompleted")
121121
.withArgs(stakingVault);
122122

123-
expect((await operatorGrid.vaultInfo(stakingVault)).tierId).to.be.equal(0n);
123+
expect((await operatorGrid.vaultTierInfo(stakingVault)).tierId).to.be.equal(0n);
124124
expect(await vaultHub.isPendingDisconnect(stakingVault)).to.be.false;
125125
expect(await vaultHub.isVaultConnected(stakingVault)).to.be.false;
126126
expect(await vaultHub.locked(stakingVault)).to.be.equal(0n);
@@ -154,7 +154,7 @@ describe("Integration: VaultHub", () => {
154154
.to.emit(vaultHub, "VaultDisconnectAborted")
155155
.withArgs(stakingVault, ether("1"));
156156

157-
expect((await operatorGrid.vaultInfo(stakingVault)).tierId).to.be.equal(tierId);
157+
expect((await operatorGrid.vaultTierInfo(stakingVault)).tierId).to.be.equal(tierId);
158158
expect(await vaultHub.isPendingDisconnect(stakingVault)).to.be.false;
159159
expect(await vaultHub.isVaultConnected(stakingVault)).to.be.true;
160160
expect(await vaultHub.locked(stakingVault)).to.be.equal(ether("1"));

0 commit comments

Comments
 (0)