Skip to content

Commit 46ee7cc

Browse files
committed
feat: update metrcis calc to take it into account settledGrowth for NOrewards
1 parent b7c20c6 commit 46ee7cc

File tree

14 files changed

+320
-76
lines changed

14 files changed

+320
-76
lines changed

features/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ export * from './deposits/index.js';
1111
export * from './lazy-oracle.js';
1212
export * from './defi-wrapper/index.js';
1313
export * from './dev-tools/index.js';
14+
export * from './metrics.js';

features/metrics.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { callReadMethodSilent, cache } from 'utils';
2+
import { DashboardContract } from 'contracts';
3+
4+
export const getNodeOperatorFeeRatesByBlockNumbers = async (
5+
vaultAddress: string,
6+
blockNumbers: number[],
7+
dashboardContract: DashboardContract,
8+
) => {
9+
// Get nodeOperatorFeeBP for each report block with caching
10+
const nodeOperatorFeeBPs: bigint[] = [];
11+
for (const blockNumber of blockNumbers) {
12+
let fee = await cache.getNodeOperatorFeeRate(vaultAddress, blockNumber);
13+
if (fee === null) {
14+
const feeRate = await callReadMethodSilent(dashboardContract, 'feeRate', {
15+
blockNumber: BigInt(blockNumber),
16+
});
17+
fee = BigInt(feeRate);
18+
await cache.setNodeOperatorFeeRate(vaultAddress, blockNumber, fee);
19+
}
20+
21+
nodeOperatorFeeBPs.push(fee);
22+
}
23+
24+
return nodeOperatorFeeBPs;
25+
};
26+
27+
export const getSettledGrowthsByBlockNumbers = async (
28+
vaultAddress: string,
29+
blockNumbers: number[],
30+
dashboardContract: DashboardContract,
31+
) => {
32+
// Get settled growth for each report block with caching
33+
const settledGrowths: bigint[] = [];
34+
for (const blockNumber of blockNumbers) {
35+
let settledGrowth = await cache.getSettledGrowth(vaultAddress, blockNumber);
36+
if (settledGrowth === null) {
37+
settledGrowth = await callReadMethodSilent(
38+
dashboardContract,
39+
'settledGrowth',
40+
{
41+
blockNumber: BigInt(blockNumber),
42+
},
43+
);
44+
await cache.setSettledGrowth(vaultAddress, blockNumber, settledGrowth);
45+
}
46+
47+
settledGrowths.push(settledGrowth);
48+
}
49+
50+
return settledGrowths;
51+
};

programs/use-cases/metrics/read.ts

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,19 @@ import {
2222
prepareGrossStakingRewards,
2323
prepareNodeOperatorRewards,
2424
prepareNetStakingRewards,
25-
callReadMethodSilent,
26-
cache,
2725
prepareGrossStakingAPR,
2826
prepareNetStakingAPR,
2927
prepareCarrySpread,
3028
prepareBottomLine,
3129
prepareDailyLidoFees,
3230
formatTimestamp,
3331
} from 'utils';
34-
import { checkQuarantine, chooseVaultAndGetDashboard } from 'features';
32+
import {
33+
checkQuarantine,
34+
chooseVaultAndGetDashboard,
35+
getNodeOperatorFeeRatesByBlockNumbers,
36+
getSettledGrowthsByBlockNumbers,
37+
} from 'features';
3538

3639
import { metrics } from './main.js';
3740

@@ -150,23 +153,16 @@ metricsRead
150153
cacheUse,
151154
);
152155

153-
// Get nodeOperatorFeeBP for each report block with caching
154-
const nodeOperatorFeeBPs: bigint[] = [];
155-
for (const r of history) {
156-
let fee = await cache.getNodeOperatorFeeRate(vault, r.blockNumber);
157-
if (fee === null) {
158-
const feeRate = await callReadMethodSilent(
159-
dashboardContract,
160-
'feeRate',
161-
{
162-
blockNumber: BigInt(r.blockNumber),
163-
},
164-
);
165-
fee = BigInt(feeRate);
166-
await cache.setNodeOperatorFeeRate(vault, r.blockNumber, fee);
167-
}
168-
nodeOperatorFeeBPs.push(fee);
169-
}
156+
const blockNumbers = history.map((r) => r.blockNumber);
157+
const [nodeOperatorFeeBPs, settledGrowths] = await Promise.all([
158+
getNodeOperatorFeeRatesByBlockNumbers(
159+
vault,
160+
blockNumbers,
161+
dashboardContract,
162+
),
163+
getSettledGrowthsByBlockNumbers(vault, blockNumbers, dashboardContract),
164+
]);
165+
170166
const [
171167
grossStakingRewards,
172168
nodeOperatorRewards,
@@ -178,12 +174,22 @@ metricsRead
178174
dailyLidoFees,
179175
] = await Promise.all([
180176
prepareGrossStakingRewards(history),
181-
prepareNodeOperatorRewards(history, nodeOperatorFeeBPs),
182-
prepareNetStakingRewards(history, nodeOperatorFeeBPs),
177+
prepareNodeOperatorRewards(history, nodeOperatorFeeBPs, settledGrowths),
178+
prepareNetStakingRewards(history, nodeOperatorFeeBPs, settledGrowths),
183179
prepareGrossStakingAPR(history),
184-
prepareNetStakingAPR(history, nodeOperatorFeeBPs),
185-
prepareCarrySpread(history, nodeOperatorFeeBPs, vaultAddress),
186-
prepareBottomLine(history, nodeOperatorFeeBPs, vaultAddress),
180+
prepareNetStakingAPR(history, nodeOperatorFeeBPs, settledGrowths),
181+
prepareCarrySpread(
182+
history,
183+
nodeOperatorFeeBPs,
184+
vaultAddress,
185+
settledGrowths,
186+
),
187+
prepareBottomLine(
188+
history,
189+
nodeOperatorFeeBPs,
190+
vaultAddress,
191+
settledGrowths,
192+
),
187193
prepareDailyLidoFees(history),
188194
]);
189195

tests/utils/bigInt.test.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { describe, expect, test } from '@jest/globals';
2+
3+
import { bigIntMax, bigIntMin } from '../../utils/bigInt.js';
4+
5+
describe('bigIntMax', () => {
6+
test('returns maximum value from multiple positive bigints', () => {
7+
expect(bigIntMax(1n, 5n, 3n, 9n, 2n)).toBe(9n);
8+
});
9+
10+
test('returns maximum value from multiple negative bigints', () => {
11+
expect(bigIntMax(-10n, -5n, -20n, -1n)).toBe(-1n);
12+
});
13+
14+
test('returns maximum value from mixed positive and negative bigints', () => {
15+
expect(bigIntMax(-5n, 10n, -20n, 3n, -1n)).toBe(10n);
16+
});
17+
18+
test('returns the single value when only one argument is provided', () => {
19+
expect(bigIntMax(42n)).toBe(42n);
20+
});
21+
22+
test('returns correct value when all values are equal', () => {
23+
expect(bigIntMax(5n, 5n, 5n)).toBe(5n);
24+
});
25+
26+
test('handles very large bigint values', () => {
27+
const largeValue = 999999999999999999999999999999n;
28+
const smallerValue = 999999999999999999999999999998n;
29+
expect(bigIntMax(smallerValue, largeValue)).toBe(largeValue);
30+
});
31+
32+
test('returns zero when comparing zero with negative values', () => {
33+
expect(bigIntMax(0n, -5n, -10n)).toBe(0n);
34+
});
35+
36+
test('handles two values correctly', () => {
37+
expect(bigIntMax(100n, 200n)).toBe(200n);
38+
expect(bigIntMax(200n, 100n)).toBe(200n);
39+
});
40+
});
41+
42+
describe('bigIntMin', () => {
43+
test('returns minimum value from multiple positive bigints', () => {
44+
expect(bigIntMin(1n, 5n, 3n, 9n, 2n)).toBe(1n);
45+
});
46+
47+
test('returns minimum value from multiple negative bigints', () => {
48+
expect(bigIntMin(-10n, -5n, -20n, -1n)).toBe(-20n);
49+
});
50+
51+
test('returns minimum value from mixed positive and negative bigints', () => {
52+
expect(bigIntMin(-5n, 10n, -20n, 3n, -1n)).toBe(-20n);
53+
});
54+
55+
test('returns the single value when only one argument is provided', () => {
56+
expect(bigIntMin(42n)).toBe(42n);
57+
});
58+
59+
test('returns correct value when all values are equal', () => {
60+
expect(bigIntMin(5n, 5n, 5n)).toBe(5n);
61+
});
62+
63+
test('handles very large bigint values', () => {
64+
const largeValue = 999999999999999999999999999999n;
65+
const smallerValue = 999999999999999999999999999998n;
66+
expect(bigIntMin(smallerValue, largeValue)).toBe(smallerValue);
67+
});
68+
69+
test('returns negative value when comparing zero with negative values', () => {
70+
expect(bigIntMin(0n, -5n, -10n)).toBe(-10n);
71+
});
72+
73+
test('handles two values correctly', () => {
74+
expect(bigIntMin(100n, 200n)).toBe(100n);
75+
expect(bigIntMin(200n, 100n)).toBe(100n);
76+
});
77+
});

utils/bigInt.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export const bigIntMax = (...args: bigint[]) =>
2+
args.reduce((a, b) => (a > b ? a : b));
3+
export const bigIntMin = (...args: bigint[]) =>
4+
args.reduce((a, b) => (a < b ? a : b));

utils/cache.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ const getRebaseRewardCacheFile = (vaultAddress: string) =>
3030
path.resolve('cache', `rebase-rewards-cache-${vaultAddress}.json`);
3131
const getNodeOperatorFeeRateCacheFile = (vaultAddress: string) =>
3232
path.resolve('cache', `node-operator-fee-rate-cache-${vaultAddress}.json`);
33+
const getSettledGrowthCacheFile = (vaultAddress: string) =>
34+
path.resolve('cache', `settled-growth-cache-${vaultAddress}.json`);
3335
const getIndexedEventsCacheFile = (poolAddress: string) =>
3436
path.resolve('cache', `indexed-events-cache-${poolAddress}.json`);
3537

@@ -45,6 +47,7 @@ export const cache = {
4547
}
4648
return null;
4749
},
50+
4851
async setShareRate(blockNumber: number, value: bigint) {
4952
let data: Record<string, string> = {};
5053
try {
@@ -58,6 +61,7 @@ export const cache = {
5861
});
5962
await fs.writeFile(getShareRateCacheFile(), JSON.stringify(data), 'utf-8');
6063
},
64+
6165
async getRebaseReward(
6266
vaultAddress: string,
6367
cacheKey: string,
@@ -72,6 +76,7 @@ export const cache = {
7276
}
7377
return null;
7478
},
79+
7580
async setRebaseReward(vaultAddress: string, cacheKey: string, value: bigint) {
7681
let data: Record<string, string> = {};
7782
try {
@@ -91,6 +96,7 @@ export const cache = {
9196
'utf-8',
9297
);
9398
},
99+
94100
async getNodeOperatorFeeRate(
95101
vaultAddress: string,
96102
blockNumber: number,
@@ -108,6 +114,7 @@ export const cache = {
108114
}
109115
return null;
110116
},
117+
111118
async setNodeOperatorFeeRate(
112119
vaultAddress: string,
113120
blockNumber: number,
@@ -137,6 +144,46 @@ export const cache = {
137144
'utf-8',
138145
);
139146
},
147+
148+
async getSettledGrowth(
149+
vaultAddress: string,
150+
blockNumber: number,
151+
): Promise<bigint | null> {
152+
try {
153+
const data = JSON.parse(
154+
await fs.readFile(getSettledGrowthCacheFile(vaultAddress), 'utf-8'),
155+
);
156+
if (data[blockNumber] !== undefined) return BigInt(data[blockNumber]);
157+
} catch {
158+
/* ignore */
159+
}
160+
return null;
161+
},
162+
163+
async setSettledGrowth(
164+
vaultAddress: string,
165+
blockNumber: number,
166+
value: bigint,
167+
) {
168+
let data: Record<string, string> = {};
169+
try {
170+
data = JSON.parse(
171+
await fs.readFile(getSettledGrowthCacheFile(vaultAddress), 'utf-8'),
172+
);
173+
} catch {
174+
/* ignore */
175+
}
176+
data[blockNumber] = value.toString();
177+
await fs.mkdir(path.dirname(getSettledGrowthCacheFile(vaultAddress)), {
178+
recursive: true,
179+
});
180+
await fs.writeFile(
181+
getSettledGrowthCacheFile(vaultAddress),
182+
JSON.stringify(data),
183+
'utf-8',
184+
);
185+
},
186+
140187
async getIndexedEventsByBlock(
141188
poolAddress: string,
142189
blockNumber: bigint,
@@ -152,6 +199,7 @@ export const cache = {
152199
}
153200
return null;
154201
},
202+
155203
async getAllIndexedEvents(
156204
poolAddress: string,
157205
): Promise<Record<string, CachedEvents>> {
@@ -165,6 +213,7 @@ export const cache = {
165213
}
166214
return {};
167215
},
216+
168217
async setIndexedEventsForBlocks(
169218
poolAddress: string,
170219
eventsMap: Map<bigint, CachedEvents>,

utils/calculate-overview-v2.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { calculateHealth } from './health/calculate-health.js';
2+
import { bigIntMax, bigIntMin } from './bigInt.js';
23

34
type OverviewArgs = {
45
totalValue: bigint;
@@ -17,9 +18,6 @@ type OverviewArgs = {
1718

1819
const BASIS_POINTS = 10_000n;
1920

20-
const bigIntMax = (...args: bigint[]) => args.reduce((a, b) => (a > b ? a : b));
21-
const bigIntMin = (...args: bigint[]) => args.reduce((a, b) => (a < b ? a : b));
22-
2321
/**
2422
* Performs division with rounding up (ceiling division) for bigint values
2523
* @param numerator - The dividend

utils/calculate-overview.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { parseEther } from 'viem';
22

33
import { calculateHealth } from './health/calculate-health.js';
4+
import { bigIntMax, bigIntMin } from './bigInt.js';
45
import { BASIS_POINTS_DENOMINATOR, SCALING_FACTOR } from './consts.js';
56

67
type OverviewArgs = {
@@ -15,8 +16,6 @@ type OverviewArgs = {
1516
totalMintingCapacityStethWei: bigint;
1617
};
1718

18-
const bigIntMax = (...args: bigint[]) => args.reduce((a, b) => (a > b ? a : b));
19-
const bigIntMin = (...args: bigint[]) => args.reduce((a, b) => (a < b ? a : b));
2019
// Percent helper (basis points → percentage)
2120
export const formatBP = (bp: number | bigint) =>
2221
`${((Number(bp) / Number(BASIS_POINTS_DENOMINATOR)) * 100).toFixed(2)}%`;

0 commit comments

Comments
 (0)