Skip to content

Commit 8b10f03

Browse files
committed
feat: add 'statistic-by-reports-full' command
1 parent fdaf426 commit 8b10f03

File tree

2 files changed

+188
-7
lines changed

2 files changed

+188
-7
lines changed

docs/cli/commands/metrics.md

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,14 @@ For a detailed explanation of how each metric is calculated, see [Metrics Calcul
3030

3131
### Read
3232

33-
| Command | Description |
34-
| ------------------------------ | ------------------------------------------ |
35-
| statistic | get statistic data for last report |
36-
| statistic-by-reports \<count\> | get statistic data for N last reports |
37-
| report-data \<count\> | get report data for Vault from N reports |
38-
| charts-apr \<count\> | get APR charts data for N last reports |
39-
| charts-rewards \<count\> | get rewards charts data for N last reports |
33+
| Command | Description |
34+
| ----------------------------------- | ---------------------------------------------------- |
35+
| statistic | get statistic data for last report |
36+
| statistic-by-reports \<count\> | get statistic data for N last reports |
37+
| statistic-by-reports-full \<count\> | get statistic data for N last reports with full data |
38+
| report-data \<count\> | get report data for Vault from N reports |
39+
| charts-apr \<count\> | get APR charts data for N last reports |
40+
| charts-rewards \<count\> | get rewards charts data for N last reports |
4041

4142
### Write
4243

@@ -108,6 +109,20 @@ Analyzes multiple historical vault reports and calculates comprehensive performa
108109

109110
**Use Case:** Compare performance metrics across multiple reporting periods and identify trends over time.
110111

112+
### statistic-by-reports-full
113+
114+
Analyzes multiple historical vault reports and calculates comprehensive performance metrics for N last reports with full data.
115+
116+
**Arguments:**
117+
118+
- `<count>`: Number of historical reports to analyze
119+
120+
**Options:**
121+
122+
- `-v, --vault <string>`: Vault address
123+
- `-g, --gateway`: IPFS gateway URL for report data retrieval
124+
- `--no-utc`: format timestamps in local time instead of UTC
125+
111126
### report-data
112127

113128
Retrieves raw report data for the vault from N last reports.

programs/use-cases/metrics/read.ts

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
prepareBottomLine,
2929
prepareDailyLidoFees,
3030
formatTimestamp,
31+
formatBP,
3132
} from 'utils';
3233
import {
3334
checkQuarantine,
@@ -212,6 +213,171 @@ metricsRead
212213
});
213214
});
214215

216+
metricsRead
217+
.command('statistic-by-reports-full')
218+
.description('get statistic data for N last reports with full data')
219+
.argument('<count>', 'count of reports', stringToNumber)
220+
.option('-v, --vault <string>', 'vault address')
221+
.option('-g, --gateway', 'ipfs gateway url')
222+
.option('--no-utc', 'do not use UTC time zone')
223+
.action(async (count: number, { vault, gateway, utc }) => {
224+
const { contract: dashboardContract, vault: vaultAddress } =
225+
await chooseVaultAndGetDashboard({ vault });
226+
227+
await checkQuarantine(vaultAddress);
228+
229+
const lazyOracleContract = await getLazyOracleContract();
230+
const [
231+
_vaultsDataTimestamp,
232+
_vaultsDataRefSlot,
233+
_vaultsDataTreeRoot,
234+
vaultsDataReportCid,
235+
] = await callReadMethod({
236+
contract: lazyOracleContract,
237+
methodName: 'latestReportData',
238+
payload: [],
239+
});
240+
241+
const { cacheUse, csv } = program.opts();
242+
const history = await getVaultReportHistory(
243+
{
244+
vault: vaultAddress,
245+
cid: vaultsDataReportCid,
246+
limit: count,
247+
direction: 'asc',
248+
gateway,
249+
},
250+
cacheUse,
251+
);
252+
253+
const blockNumbers = history.map((r) => r.blockNumber);
254+
const noFeeSnapshots = await getNOFeeSnapshotsByBlockNumbers(
255+
vaultAddress,
256+
blockNumbers,
257+
dashboardContract,
258+
history,
259+
);
260+
261+
const [
262+
grossStakingRewards,
263+
nodeOperatorRewards,
264+
netStakingRewards,
265+
grossStakingAPR,
266+
netStakingAPR,
267+
carrySpread,
268+
bottomLine,
269+
dailyLidoFees,
270+
] = await Promise.all([
271+
prepareGrossStakingRewards(history),
272+
prepareNodeOperatorRewards(history, noFeeSnapshots),
273+
prepareNetStakingRewards(history, noFeeSnapshots),
274+
prepareGrossStakingAPR(history),
275+
prepareNetStakingAPR(history, noFeeSnapshots),
276+
prepareCarrySpread(history, noFeeSnapshots, vaultAddress),
277+
prepareBottomLine(history, noFeeSnapshots, vaultAddress),
278+
prepareDailyLidoFees(history),
279+
]);
280+
281+
const historyCutted = history.slice(1); // cut first report to align with metrics which calculated from 2 reports
282+
const noFeeSnapshotsCutted = noFeeSnapshots.slice(1); // cut first report to align with metrics which calculated from 2 reports
283+
284+
logResult({
285+
data: [
286+
['Vault Address', vaultAddress],
287+
[
288+
'Node Operator Accrued Fee, ETH',
289+
...noFeeSnapshotsCutted.map((r) => formatEther(BigInt(r.accruedFee))),
290+
],
291+
[
292+
'Node Operator Fee Rate, %',
293+
...noFeeSnapshotsCutted.map((r) => formatBP(r.feeRate)),
294+
],
295+
[
296+
'Node Operator Settled Growth, ETH',
297+
...noFeeSnapshotsCutted.map((r) =>
298+
formatEther(BigInt(r.settledGrowth)),
299+
),
300+
],
301+
[
302+
'Total Value, ETH',
303+
...historyCutted.map((r) =>
304+
formatEther(BigInt(r.data.totalValueWei)),
305+
),
306+
],
307+
[
308+
'Fee, ETH',
309+
...historyCutted.map((r) => formatEther(BigInt(r.data.fee))),
310+
],
311+
[
312+
'Liability Shares, ETH',
313+
...historyCutted.map((r) =>
314+
formatEther(BigInt(r.data.liabilityShares)),
315+
),
316+
],
317+
[
318+
'Slashing Reserve, ETH',
319+
...historyCutted.map((r) =>
320+
formatEther(BigInt(r.data.slashingReserve)),
321+
),
322+
],
323+
[
324+
'In/Out Delta, ETH',
325+
...historyCutted.map((r) =>
326+
formatEther(BigInt(r.extraData.inOutDelta)),
327+
),
328+
],
329+
[
330+
'Prev Fee, ETH',
331+
...historyCutted.map((r) => formatEther(BigInt(r.extraData.prevFee))),
332+
],
333+
[
334+
'Infra Fee, ETH',
335+
...historyCutted.map((r) =>
336+
formatEther(BigInt(r.extraData.infraFee)),
337+
),
338+
],
339+
[
340+
'Liquidity Fee, ETH',
341+
...historyCutted.map((r) =>
342+
formatEther(BigInt(r.extraData.liquidityFee)),
343+
),
344+
],
345+
[
346+
'Reservation Fee, ETH',
347+
...historyCutted.map((r) =>
348+
formatEther(BigInt(r.extraData.reservationFee)),
349+
),
350+
],
351+
['Timestamp', ...historyCutted.map((r) => r.timestamp)],
352+
['CID', ...historyCutted.map((r) => r.cid)],
353+
[
354+
'Report date',
355+
...historyCutted.map((r) =>
356+
formatTimestamp(r.timestamp, 'dd.mm hh:mm', utc ? 'UTC' : 'local'),
357+
),
358+
],
359+
['Gross Staking Rewards, ETH', ...grossStakingRewards.values],
360+
['Node Operator Rewards, ETH', ...nodeOperatorRewards.values],
361+
['Net Staking Rewards, ETH', ...netStakingRewards.values],
362+
['Gross Staking APR, %', ...grossStakingAPR.values.map(formatRatio)],
363+
['Net Staking APR, %', ...netStakingAPR.values.map(formatRatio)],
364+
['Carry Spread, %', ...carrySpread.values.map(formatRatio)],
365+
['Bottom Line, WEI', ...bottomLine.values],
366+
['Daily Lido Fees, ETH', ...dailyLidoFees.values],
367+
['Timestamp', ...grossStakingRewards.timestamp],
368+
],
369+
params: {
370+
head: [
371+
'Metric',
372+
...grossStakingRewards.timestamp.map((ts) =>
373+
formatTimestamp(ts, 'dd.mm hh:mm', utc ? 'UTC' : 'local'),
374+
),
375+
],
376+
},
377+
csvPath: csv,
378+
});
379+
});
380+
215381
metricsRead
216382
.command('report-data')
217383
.description('get report data for Vault from N last reports')

0 commit comments

Comments
 (0)