@lidofinance/lsv-cli 1.8.0 → 1.10.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/dist/abi/defi-wrapper/MellowStrategy.d.ts +429 -0
- package/dist/abi/defi-wrapper/MellowStrategy.js +892 -0
- package/dist/abi/defi-wrapper/MellowStrategy.js.map +1 -0
- package/dist/abi/defi-wrapper/index.d.ts +1 -0
- package/dist/abi/defi-wrapper/index.js +1 -0
- package/dist/abi/defi-wrapper/index.js.map +1 -1
- package/dist/configs/constants.d.ts +7 -1
- package/dist/features/consolidation.d.ts +2 -3
- package/dist/features/consolidation.js +60 -32
- package/dist/features/consolidation.js.map +1 -1
- package/dist/features/defi-wrapper/timelock.d.ts +8928 -2
- package/dist/features/defi-wrapper/timelock.js +82 -8
- package/dist/features/defi-wrapper/timelock.js.map +1 -1
- package/dist/programs/defi-wrapper/use-cases/timelock-governance/common/read.js +22 -4
- package/dist/programs/defi-wrapper/use-cases/timelock-governance/common/read.js.map +1 -1
- package/dist/programs/defi-wrapper/use-cases/timelock-governance/common/write.js +194 -16
- package/dist/programs/defi-wrapper/use-cases/timelock-governance/common/write.js.map +1 -1
- package/dist/programs/use-cases/consolidation/write.js +4 -4
- package/dist/programs/use-cases/consolidation/write.js.map +1 -1
- package/dist/programs/use-cases/metrics/read.js +4 -4
- package/dist/programs/use-cases/metrics/read.js.map +1 -1
- package/dist/programs/use-cases/report/read.js +4 -4
- package/dist/programs/use-cases/report/read.js.map +1 -1
- package/dist/providers/wallet.d.ts +2905 -8441
- package/dist/tests/fixtures/consolidation-fixtures.js +1 -0
- package/dist/tests/fixtures/consolidation-fixtures.js.map +1 -1
- package/dist/tests/integration/helpers/test-client.d.ts +2071 -5761
- package/dist/tests/utils/consolidation-fee-exemption-calc.test.d.ts +1 -0
- package/dist/tests/utils/consolidation-fee-exemption-calc.test.js +145 -0
- package/dist/tests/utils/consolidation-fee-exemption-calc.test.js.map +1 -0
- package/dist/tests/utils/consolidation-fee-exemption-confirm.test.d.ts +1 -0
- package/dist/tests/utils/consolidation-fee-exemption-confirm.test.js +118 -0
- package/dist/tests/utils/consolidation-fee-exemption-confirm.test.js.map +1 -0
- package/dist/tests/utils/consolidation-fee-exemption.test.d.ts +1 -0
- package/dist/tests/utils/consolidation-fee-exemption.test.js +168 -0
- package/dist/tests/utils/consolidation-fee-exemption.test.js.map +1 -0
- package/dist/tests/utils/first-validator-gindex.test.d.ts +1 -0
- package/dist/tests/utils/first-validator-gindex.test.js +48 -0
- package/dist/tests/utils/first-validator-gindex.test.js.map +1 -0
- package/dist/tests/utils/ipfs-security.test.js +130 -3
- package/dist/tests/utils/ipfs-security.test.js.map +1 -1
- package/dist/tests/utils/ipfs.test.js +40 -12
- package/dist/tests/utils/ipfs.test.js.map +1 -1
- package/dist/tests/utils/parse-abi-arguments.test.d.ts +1 -0
- package/dist/tests/utils/parse-abi-arguments.test.js +399 -0
- package/dist/tests/utils/parse-abi-arguments.test.js.map +1 -0
- package/dist/tests/utils/stream-helpers.d.ts +1 -0
- package/dist/tests/utils/stream-helpers.js +11 -0
- package/dist/tests/utils/stream-helpers.js.map +1 -0
- package/dist/utils/consolidation/confirms.js +19 -8
- package/dist/utils/consolidation/confirms.js.map +1 -1
- package/dist/utils/consolidation/fee-exemption.d.ts +19 -0
- package/dist/utils/consolidation/fee-exemption.js +70 -0
- package/dist/utils/consolidation/fee-exemption.js.map +1 -0
- package/dist/utils/consolidation/index.d.ts +1 -0
- package/dist/utils/consolidation/index.js +1 -0
- package/dist/utils/consolidation/index.js.map +1 -1
- package/dist/utils/consolidation/pubkeys.js +2 -0
- package/dist/utils/consolidation/pubkeys.js.map +1 -1
- package/dist/utils/consolidation/types.d.ts +1 -0
- package/dist/utils/consolidation/validator-info.d.ts +2 -1
- package/dist/utils/consolidation/validator-info.js +6 -0
- package/dist/utils/consolidation/validator-info.js.map +1 -1
- package/dist/utils/env.d.ts +1 -0
- package/dist/utils/env.js +8 -0
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/ipfs.d.ts +10 -3
- package/dist/utils/ipfs.js +109 -27
- package/dist/utils/ipfs.js.map +1 -1
- package/dist/utils/parse-abi-arguments.d.ts +24 -0
- package/dist/utils/parse-abi-arguments.js +159 -0
- package/dist/utils/parse-abi-arguments.js.map +1 -0
- package/dist/utils/proof/constants.d.ts +1 -0
- package/dist/utils/proof/constants.js +1 -0
- package/dist/utils/proof/constants.js.map +1 -1
- package/dist/utils/proof/first-validator-gindex.js +27 -13
- package/dist/utils/proof/first-validator-gindex.js.map +1 -1
- package/dist/utils/proof/proofs.d.ts +1 -1
- package/dist/utils/proof/proofs.js +1 -1
- package/dist/utils/proof/proofs.js.map +1 -1
- package/dist/utils/rate-limit.d.ts +9 -0
- package/dist/utils/rate-limit.js +1 -6
- package/dist/utils/rate-limit.js.map +1 -1
- package/dist/version/index.js +1 -1
- package/package.json +20 -16
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { consolidatedBalance } from '../../utils/consolidation/validator-info.js';
|
|
3
|
+
import { VALID_PUBKEY_1, VALID_PUBKEY_2, VALID_PUBKEY_3, createValidatorInfo, createTargetAndSourceMap, } from '../fixtures/consolidation-fixtures.js';
|
|
4
|
+
const mockConfirmOperation = vi.fn();
|
|
5
|
+
vi.mock('utils', async () => {
|
|
6
|
+
const logging = await vi.importActual('../../utils/logging/console.js');
|
|
7
|
+
return {
|
|
8
|
+
...logging,
|
|
9
|
+
confirmOperation: mockConfirmOperation,
|
|
10
|
+
};
|
|
11
|
+
});
|
|
12
|
+
const importSubject = async () => {
|
|
13
|
+
const { calculateAndConfirmFeeExemption } = await import('../../utils/consolidation/confirms.js');
|
|
14
|
+
return calculateAndConfirmFeeExemption;
|
|
15
|
+
};
|
|
16
|
+
const ETH = 1000000000000000000n;
|
|
17
|
+
describe('consolidatedBalance', () => {
|
|
18
|
+
it('returns the effective balance when it is below the actual balance', () => {
|
|
19
|
+
const info = createValidatorInfo({
|
|
20
|
+
balance: 32n * ETH + ETH / 2n,
|
|
21
|
+
effectiveBalance: 32n * ETH,
|
|
22
|
+
});
|
|
23
|
+
expect(consolidatedBalance(info)).toBe(32n * ETH);
|
|
24
|
+
});
|
|
25
|
+
it('returns the actual balance when it dropped below the effective balance', () => {
|
|
26
|
+
const info = createValidatorInfo({
|
|
27
|
+
balance: 31n * ETH,
|
|
28
|
+
effectiveBalance: 32n * ETH,
|
|
29
|
+
});
|
|
30
|
+
expect(consolidatedBalance(info)).toBe(31n * ETH);
|
|
31
|
+
});
|
|
32
|
+
it('returns zero for a slashed validator', () => {
|
|
33
|
+
const info = createValidatorInfo({
|
|
34
|
+
balance: 32n * ETH,
|
|
35
|
+
effectiveBalance: 32n * ETH,
|
|
36
|
+
slashed: true,
|
|
37
|
+
});
|
|
38
|
+
expect(consolidatedBalance(info)).toBe(0n);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
describe('calculateAndConfirmFeeExemption', () => {
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
vi.clearAllMocks();
|
|
44
|
+
mockConfirmOperation.mockResolvedValue(true);
|
|
45
|
+
});
|
|
46
|
+
it('sums active sources without asking about them', async () => {
|
|
47
|
+
const calculateAndConfirmFeeExemption = await importSubject();
|
|
48
|
+
const map = createTargetAndSourceMap([
|
|
49
|
+
{
|
|
50
|
+
target: VALID_PUBKEY_1,
|
|
51
|
+
sources: [
|
|
52
|
+
{
|
|
53
|
+
pubkey: VALID_PUBKEY_2,
|
|
54
|
+
info: { balance: 33n * ETH, effectiveBalance: 32n * ETH },
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
pubkey: VALID_PUBKEY_3,
|
|
58
|
+
info: { balance: 33n * ETH, effectiveBalance: 32n * ETH },
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
]);
|
|
63
|
+
const feeExemption = await calculateAndConfirmFeeExemption(map);
|
|
64
|
+
// effective balance (32) is what moves, not the 33 ETH actual balance
|
|
65
|
+
expect(feeExemption).toBe(64n * ETH);
|
|
66
|
+
// only the final "Fee Exemption: … Continue?" confirmation
|
|
67
|
+
expect(mockConfirmOperation).toHaveBeenCalledTimes(1);
|
|
68
|
+
});
|
|
69
|
+
it('excludes a slashed source without asking', async () => {
|
|
70
|
+
const calculateAndConfirmFeeExemption = await importSubject();
|
|
71
|
+
const map = createTargetAndSourceMap([
|
|
72
|
+
{
|
|
73
|
+
target: VALID_PUBKEY_1,
|
|
74
|
+
sources: [
|
|
75
|
+
{
|
|
76
|
+
pubkey: VALID_PUBKEY_2,
|
|
77
|
+
info: {
|
|
78
|
+
status: 'active_slashed',
|
|
79
|
+
slashed: true,
|
|
80
|
+
balance: 32n * ETH,
|
|
81
|
+
effectiveBalance: 32n * ETH,
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
]);
|
|
87
|
+
const feeExemption = await calculateAndConfirmFeeExemption(map);
|
|
88
|
+
expect(feeExemption).toBe(0n);
|
|
89
|
+
expect(mockConfirmOperation).toHaveBeenCalledTimes(1);
|
|
90
|
+
});
|
|
91
|
+
it('asks about a non-active source and counts it when confirmed', async () => {
|
|
92
|
+
const calculateAndConfirmFeeExemption = await importSubject();
|
|
93
|
+
const map = createTargetAndSourceMap([
|
|
94
|
+
{
|
|
95
|
+
target: VALID_PUBKEY_1,
|
|
96
|
+
sources: [
|
|
97
|
+
{
|
|
98
|
+
pubkey: VALID_PUBKEY_2,
|
|
99
|
+
info: {
|
|
100
|
+
status: 'active_exiting',
|
|
101
|
+
balance: 32n * ETH,
|
|
102
|
+
effectiveBalance: 32n * ETH,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
]);
|
|
108
|
+
const feeExemption = await calculateAndConfirmFeeExemption(map);
|
|
109
|
+
expect(feeExemption).toBe(32n * ETH);
|
|
110
|
+
expect(mockConfirmOperation).toHaveBeenCalledTimes(2);
|
|
111
|
+
expect(mockConfirmOperation.mock.calls[0]?.[0]).toContain('active_exiting');
|
|
112
|
+
});
|
|
113
|
+
it('skips a non-active source when the operator declines', async () => {
|
|
114
|
+
const calculateAndConfirmFeeExemption = await importSubject();
|
|
115
|
+
mockConfirmOperation
|
|
116
|
+
.mockResolvedValueOnce(false)
|
|
117
|
+
.mockResolvedValueOnce(true);
|
|
118
|
+
const map = createTargetAndSourceMap([
|
|
119
|
+
{
|
|
120
|
+
target: VALID_PUBKEY_1,
|
|
121
|
+
sources: [
|
|
122
|
+
{
|
|
123
|
+
pubkey: VALID_PUBKEY_2,
|
|
124
|
+
info: {
|
|
125
|
+
status: 'active_exiting',
|
|
126
|
+
balance: 32n * ETH,
|
|
127
|
+
effectiveBalance: 32n * ETH,
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
},
|
|
132
|
+
]);
|
|
133
|
+
const feeExemption = await calculateAndConfirmFeeExemption(map);
|
|
134
|
+
expect(feeExemption).toBe(0n);
|
|
135
|
+
});
|
|
136
|
+
it('throws when the operator rejects the calculated amount', async () => {
|
|
137
|
+
const calculateAndConfirmFeeExemption = await importSubject();
|
|
138
|
+
mockConfirmOperation.mockResolvedValue(false);
|
|
139
|
+
const map = createTargetAndSourceMap([
|
|
140
|
+
{ target: VALID_PUBKEY_1, sources: [{ pubkey: VALID_PUBKEY_2 }] },
|
|
141
|
+
]);
|
|
142
|
+
await expect(calculateAndConfirmFeeExemption(map)).rejects.toThrow('User cancelled consolidation');
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
//# sourceMappingURL=consolidation-fee-exemption-calc.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consolidation-fee-exemption-calc.test.js","sourceRoot":"","sources":["../../../tests/utils/consolidation-fee-exemption-calc.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
const mockConfirmOperation = vi.fn();
|
|
3
|
+
const mockCallReadMethodSilent = vi.fn();
|
|
4
|
+
const mockFindRecentFeeExemptions = vi.fn();
|
|
5
|
+
const mockLogCancel = vi.fn();
|
|
6
|
+
const DAY_SEC = 24n * 60n * 60n;
|
|
7
|
+
const HOUR_SEC = 60n * 60n;
|
|
8
|
+
const NOW_SEC = BigInt(Math.floor(Date.now() / 1000));
|
|
9
|
+
// real loggers: a stubbed printError would hide that it rethrows
|
|
10
|
+
vi.mock('utils', async () => {
|
|
11
|
+
const logging = await vi.importActual('../../utils/logging/console.js');
|
|
12
|
+
const errorHandler = await vi.importActual('../../utils/error-handler.js');
|
|
13
|
+
return {
|
|
14
|
+
...logging,
|
|
15
|
+
...errorHandler,
|
|
16
|
+
callReadMethodSilent: mockCallReadMethodSilent,
|
|
17
|
+
confirmOperation: mockConfirmOperation,
|
|
18
|
+
findRecentFeeExemptions: mockFindRecentFeeExemptions,
|
|
19
|
+
formatFeeExemptionMatch: () => 'formatted-match',
|
|
20
|
+
FEE_EXEMPTION_DUPLICATE_LOOKBACK_SEC: DAY_SEC,
|
|
21
|
+
logCancel: mockLogCancel,
|
|
22
|
+
showSpinner: () => () => { },
|
|
23
|
+
callWriteMethodWithReceipt: vi.fn(),
|
|
24
|
+
callWriteMethodWithReceiptBatchCalls: vi.fn(),
|
|
25
|
+
flattenSourcePubkeys: vi.fn(),
|
|
26
|
+
getSourceAndTargetPubkeysFromEncodedCall: vi.fn(),
|
|
27
|
+
addDummyTargetAndSourceValidator: vi.fn(),
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
vi.mock('providers', () => ({ getPublicClient: vi.fn() }));
|
|
31
|
+
vi.mock('contracts', () => ({
|
|
32
|
+
getDashboardContract: vi.fn(),
|
|
33
|
+
getValidatorConsolidationRequestsContract: vi.fn(),
|
|
34
|
+
}));
|
|
35
|
+
vi.mock('abi', () => ({ DashboardAbi: [] }));
|
|
36
|
+
const DASHBOARD_CONTRACT = {
|
|
37
|
+
address: '0x1234567890abcdef1234567890abcdef12345678',
|
|
38
|
+
};
|
|
39
|
+
const FEE_EXEMPTION = 32000000000000000000n;
|
|
40
|
+
const importSubject = async () => {
|
|
41
|
+
const { confirmFeeExemptionIncrease } = await import('../../features/consolidation.js');
|
|
42
|
+
return confirmFeeExemptionIncrease;
|
|
43
|
+
};
|
|
44
|
+
const aMatch = {
|
|
45
|
+
txHash: `0x${'ab'.repeat(32)}`,
|
|
46
|
+
blockNumber: 1n,
|
|
47
|
+
delta: FEE_EXEMPTION,
|
|
48
|
+
timestamp: NOW_SEC,
|
|
49
|
+
};
|
|
50
|
+
describe('confirmFeeExemptionIncrease', () => {
|
|
51
|
+
beforeEach(() => {
|
|
52
|
+
vi.clearAllMocks();
|
|
53
|
+
});
|
|
54
|
+
it('does nothing when there is no exemption to add', async () => {
|
|
55
|
+
const confirmFeeExemptionIncrease = await importSubject();
|
|
56
|
+
const result = await confirmFeeExemptionIncrease(DASHBOARD_CONTRACT, 0n);
|
|
57
|
+
expect(result).toEqual({ shouldAddFeeExemption: false });
|
|
58
|
+
expect(mockCallReadMethodSilent).not.toHaveBeenCalled();
|
|
59
|
+
expect(mockConfirmOperation).not.toHaveBeenCalled();
|
|
60
|
+
});
|
|
61
|
+
it('adds the exemption without prompting when there are no recent corrections', async () => {
|
|
62
|
+
mockCallReadMethodSilent.mockResolvedValue(0n);
|
|
63
|
+
const confirmFeeExemptionIncrease = await importSubject();
|
|
64
|
+
const result = await confirmFeeExemptionIncrease(DASHBOARD_CONTRACT, FEE_EXEMPTION);
|
|
65
|
+
expect(result).toEqual({ shouldAddFeeExemption: true });
|
|
66
|
+
expect(mockFindRecentFeeExemptions).not.toHaveBeenCalled();
|
|
67
|
+
expect(mockConfirmOperation).not.toHaveBeenCalled();
|
|
68
|
+
});
|
|
69
|
+
it('adds the exemption without prompting when no matching exemption is found', async () => {
|
|
70
|
+
mockCallReadMethodSilent.mockResolvedValue(NOW_SEC - HOUR_SEC);
|
|
71
|
+
mockFindRecentFeeExemptions.mockResolvedValue([]);
|
|
72
|
+
const confirmFeeExemptionIncrease = await importSubject();
|
|
73
|
+
const result = await confirmFeeExemptionIncrease(DASHBOARD_CONTRACT, FEE_EXEMPTION);
|
|
74
|
+
expect(result).toEqual({ shouldAddFeeExemption: true });
|
|
75
|
+
expect(mockFindRecentFeeExemptions).toHaveBeenCalledWith(DASHBOARD_CONTRACT.address, FEE_EXEMPTION);
|
|
76
|
+
expect(mockConfirmOperation).not.toHaveBeenCalled();
|
|
77
|
+
});
|
|
78
|
+
// --yes / NODE_ENV=test auto-confirm every prompt, so the first one must mean "add"
|
|
79
|
+
it('adds the exemption when prompts are auto-confirmed', async () => {
|
|
80
|
+
mockCallReadMethodSilent.mockResolvedValue(NOW_SEC - HOUR_SEC);
|
|
81
|
+
mockFindRecentFeeExemptions.mockResolvedValue([aMatch]);
|
|
82
|
+
mockConfirmOperation.mockResolvedValue(true);
|
|
83
|
+
const confirmFeeExemptionIncrease = await importSubject();
|
|
84
|
+
const result = await confirmFeeExemptionIncrease(DASHBOARD_CONTRACT, FEE_EXEMPTION);
|
|
85
|
+
expect(result).toEqual({ shouldAddFeeExemption: true });
|
|
86
|
+
expect(mockConfirmOperation).toHaveBeenCalledTimes(1);
|
|
87
|
+
});
|
|
88
|
+
it('skips only after an explicit decline and an explicit skip confirmation', async () => {
|
|
89
|
+
mockCallReadMethodSilent.mockResolvedValue(NOW_SEC - HOUR_SEC);
|
|
90
|
+
mockFindRecentFeeExemptions.mockResolvedValue([aMatch]);
|
|
91
|
+
mockConfirmOperation
|
|
92
|
+
.mockResolvedValueOnce(false)
|
|
93
|
+
.mockResolvedValueOnce(true);
|
|
94
|
+
const confirmFeeExemptionIncrease = await importSubject();
|
|
95
|
+
const result = await confirmFeeExemptionIncrease(DASHBOARD_CONTRACT, FEE_EXEMPTION);
|
|
96
|
+
expect(result).toEqual({ shouldAddFeeExemption: false });
|
|
97
|
+
expect(mockConfirmOperation).toHaveBeenCalledTimes(2);
|
|
98
|
+
});
|
|
99
|
+
it('cancels consolidation when the operator declines both prompts', async () => {
|
|
100
|
+
mockCallReadMethodSilent.mockResolvedValue(NOW_SEC - HOUR_SEC);
|
|
101
|
+
mockFindRecentFeeExemptions.mockResolvedValue([aMatch]);
|
|
102
|
+
mockConfirmOperation.mockResolvedValue(false);
|
|
103
|
+
const confirmFeeExemptionIncrease = await importSubject();
|
|
104
|
+
await expect(confirmFeeExemptionIncrease(DASHBOARD_CONTRACT, FEE_EXEMPTION)).rejects.toThrow('User cancelled consolidation');
|
|
105
|
+
expect(mockLogCancel).toHaveBeenCalled();
|
|
106
|
+
});
|
|
107
|
+
// fails if fail-soft regresses into a hard abort
|
|
108
|
+
it('falls back to an operator decision when the log scan fails', async () => {
|
|
109
|
+
mockCallReadMethodSilent.mockResolvedValue(NOW_SEC - HOUR_SEC);
|
|
110
|
+
mockFindRecentFeeExemptions.mockRejectedValue(new Error('range too wide'));
|
|
111
|
+
mockConfirmOperation.mockResolvedValue(true);
|
|
112
|
+
const confirmFeeExemptionIncrease = await importSubject();
|
|
113
|
+
const result = await confirmFeeExemptionIncrease(DASHBOARD_CONTRACT, FEE_EXEMPTION);
|
|
114
|
+
expect(result).toEqual({ shouldAddFeeExemption: true });
|
|
115
|
+
expect(mockConfirmOperation).toHaveBeenCalledTimes(1);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
//# sourceMappingURL=consolidation-fee-exemption-confirm.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consolidation-fee-exemption-confirm.test.js","sourceRoot":"","sources":["../../../tests/utils/consolidation-fee-exemption-confirm.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { matchFeeExemptionLogs, findRecentFeeExemptions, formatFeeExemptionMatch, } from '../../utils/consolidation/fee-exemption.js';
|
|
3
|
+
const mockGetBlockNumber = vi.fn();
|
|
4
|
+
const mockGetContractEvents = vi.fn();
|
|
5
|
+
const mockGetBlock = vi.fn();
|
|
6
|
+
vi.mock('providers', () => ({
|
|
7
|
+
getPublicClient: async () => ({
|
|
8
|
+
getBlockNumber: mockGetBlockNumber,
|
|
9
|
+
getContractEvents: mockGetContractEvents,
|
|
10
|
+
getBlock: mockGetBlock,
|
|
11
|
+
}),
|
|
12
|
+
}));
|
|
13
|
+
const TX_EXEMPTION = '0xaaa1';
|
|
14
|
+
const TX_DISBURSE = '0xbbb2';
|
|
15
|
+
const TX_OTHER = '0xccc3';
|
|
16
|
+
const DASHBOARD = '0x1234567890abcdef1234567890abcdef12345678';
|
|
17
|
+
const settledGrowthLog = (transactionHash, oldSettledGrowth, newSettledGrowth, blockNumber = 100n) => ({
|
|
18
|
+
transactionHash,
|
|
19
|
+
blockNumber,
|
|
20
|
+
args: { oldSettledGrowth, newSettledGrowth },
|
|
21
|
+
});
|
|
22
|
+
describe('matchFeeExemptionLogs', () => {
|
|
23
|
+
it('matches a correction tx with delta equal to the amount', () => {
|
|
24
|
+
const logs = [settledGrowthLog(TX_EXEMPTION, 100n, 132n)];
|
|
25
|
+
const matches = matchFeeExemptionLogs(logs, new Set([TX_EXEMPTION]), 32n);
|
|
26
|
+
expect(matches).toHaveLength(1);
|
|
27
|
+
expect(matches[0]).toMatchObject({ txHash: TX_EXEMPTION, delta: 32n });
|
|
28
|
+
});
|
|
29
|
+
it('ignores SettledGrowthSet from disburseFee (no correction event in tx)', () => {
|
|
30
|
+
const logs = [settledGrowthLog(TX_DISBURSE, 100n, 132n)];
|
|
31
|
+
const matches = matchFeeExemptionLogs(logs, new Set(), 32n);
|
|
32
|
+
expect(matches).toHaveLength(0);
|
|
33
|
+
});
|
|
34
|
+
it('ignores corrections with a different delta', () => {
|
|
35
|
+
const logs = [
|
|
36
|
+
settledGrowthLog(TX_EXEMPTION, 100n, 132n),
|
|
37
|
+
settledGrowthLog(TX_OTHER, 132n, 196n),
|
|
38
|
+
];
|
|
39
|
+
const matches = matchFeeExemptionLogs(logs, new Set([TX_EXEMPTION, TX_OTHER]), 64n);
|
|
40
|
+
expect(matches).toHaveLength(1);
|
|
41
|
+
expect(matches[0]?.txHash).toBe(TX_OTHER);
|
|
42
|
+
});
|
|
43
|
+
it('ignores downward corrections (negative delta)', () => {
|
|
44
|
+
const logs = [settledGrowthLog(TX_OTHER, 132n, 100n)];
|
|
45
|
+
const matches = matchFeeExemptionLogs(logs, new Set([TX_OTHER]), 32n);
|
|
46
|
+
expect(matches).toHaveLength(0);
|
|
47
|
+
});
|
|
48
|
+
it('returns all matching corrections', () => {
|
|
49
|
+
const logs = [
|
|
50
|
+
settledGrowthLog(TX_EXEMPTION, 100n, 132n, 100n),
|
|
51
|
+
settledGrowthLog(TX_OTHER, 132n, 164n, 200n),
|
|
52
|
+
];
|
|
53
|
+
const matches = matchFeeExemptionLogs(logs, new Set([TX_EXEMPTION, TX_OTHER]), 32n);
|
|
54
|
+
expect(matches).toHaveLength(2);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
describe('formatFeeExemptionMatch', () => {
|
|
58
|
+
const VALID_HASH = `0x${'ab'.repeat(32)}`;
|
|
59
|
+
it('renders a valid hash and timestamp', () => {
|
|
60
|
+
const line = formatFeeExemptionMatch({
|
|
61
|
+
txHash: VALID_HASH,
|
|
62
|
+
blockNumber: 100n,
|
|
63
|
+
delta: 32000000000000000000n,
|
|
64
|
+
timestamp: 1700000000n,
|
|
65
|
+
});
|
|
66
|
+
expect(line).toBe(`32 ETH in tx ${VALID_HASH} at 2023-11-14T22:13:20.000Z`);
|
|
67
|
+
});
|
|
68
|
+
it('replaces a tx hash carrying terminal escape sequences', () => {
|
|
69
|
+
const line = formatFeeExemptionMatch({
|
|
70
|
+
txHash: '[2K[1ASkip the exemption',
|
|
71
|
+
blockNumber: 100n,
|
|
72
|
+
delta: 32000000000000000000n,
|
|
73
|
+
timestamp: 1700000000n,
|
|
74
|
+
});
|
|
75
|
+
expect(line).toContain('<invalid tx hash from RPC>');
|
|
76
|
+
expect(line).not.toContain('');
|
|
77
|
+
});
|
|
78
|
+
it('replaces a non-hex tx hash of the right length', () => {
|
|
79
|
+
const line = formatFeeExemptionMatch({
|
|
80
|
+
txHash: `0x${'zz'.repeat(32)}`,
|
|
81
|
+
blockNumber: 100n,
|
|
82
|
+
delta: 1n,
|
|
83
|
+
timestamp: 1700000000n,
|
|
84
|
+
});
|
|
85
|
+
expect(line).toContain('<invalid tx hash from RPC>');
|
|
86
|
+
});
|
|
87
|
+
it('replaces an out-of-range timestamp instead of throwing', () => {
|
|
88
|
+
const line = formatFeeExemptionMatch({
|
|
89
|
+
txHash: VALID_HASH,
|
|
90
|
+
blockNumber: 100n,
|
|
91
|
+
delta: 1n,
|
|
92
|
+
timestamp: 2n ** 64n,
|
|
93
|
+
});
|
|
94
|
+
expect(line).toContain('<invalid timestamp from RPC>');
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
describe('findRecentFeeExemptions', () => {
|
|
98
|
+
beforeEach(() => {
|
|
99
|
+
vi.clearAllMocks();
|
|
100
|
+
});
|
|
101
|
+
// mimics an RPC honouring fromBlock/toBlock, so chunked scans see each log once
|
|
102
|
+
const mockChainLogs = (settledGrowthLogs, correctionTxHashes) => {
|
|
103
|
+
mockGetContractEvents.mockImplementation(async ({ eventName, fromBlock, toBlock }) => {
|
|
104
|
+
const inRange = settledGrowthLogs.filter((log) => log.blockNumber >= fromBlock && log.blockNumber <= toBlock);
|
|
105
|
+
if (eventName === 'SettledGrowthSet')
|
|
106
|
+
return inRange;
|
|
107
|
+
return inRange
|
|
108
|
+
.filter((log) => correctionTxHashes.includes(log.transactionHash))
|
|
109
|
+
.map((log) => ({ transactionHash: log.transactionHash }));
|
|
110
|
+
});
|
|
111
|
+
};
|
|
112
|
+
it('returns matching exemptions with block timestamps', async () => {
|
|
113
|
+
mockGetBlockNumber.mockResolvedValue(1000000n);
|
|
114
|
+
mockChainLogs([
|
|
115
|
+
settledGrowthLog(TX_EXEMPTION, 100n, 132n, 999000n),
|
|
116
|
+
settledGrowthLog(TX_DISBURSE, 132n, 150n, 999500n),
|
|
117
|
+
], [TX_EXEMPTION]);
|
|
118
|
+
mockGetBlock.mockResolvedValue({ timestamp: 1700000000n });
|
|
119
|
+
const matches = await findRecentFeeExemptions(DASHBOARD, 32n);
|
|
120
|
+
expect(matches).toHaveLength(1);
|
|
121
|
+
expect(matches[0]).toMatchObject({
|
|
122
|
+
txHash: TX_EXEMPTION,
|
|
123
|
+
delta: 32n,
|
|
124
|
+
timestamp: 1700000000n,
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
it('queries both events over the same block range', async () => {
|
|
128
|
+
mockGetBlockNumber.mockResolvedValue(1000000n);
|
|
129
|
+
mockGetContractEvents.mockResolvedValue([]);
|
|
130
|
+
// 1200 sec / 12 sec per block = 100 blocks back, fits in a single chunk
|
|
131
|
+
await findRecentFeeExemptions(DASHBOARD, 32n, 1200n);
|
|
132
|
+
const ranges = mockGetContractEvents.mock.calls.map(([{ fromBlock, toBlock }]) => [fromBlock, toBlock]);
|
|
133
|
+
expect(ranges).toEqual([
|
|
134
|
+
[999900n, 1000000n],
|
|
135
|
+
[999900n, 1000000n],
|
|
136
|
+
]);
|
|
137
|
+
});
|
|
138
|
+
it('splits a wide lookback into chunks without rescanning blocks', async () => {
|
|
139
|
+
mockGetBlockNumber.mockResolvedValue(100000n);
|
|
140
|
+
mockGetContractEvents.mockResolvedValue([]);
|
|
141
|
+
// 25 000 blocks back over a 10 000-block chunk size = 3 chunks per event
|
|
142
|
+
await findRecentFeeExemptions(DASHBOARD, 32n, 25000n * 12n);
|
|
143
|
+
const settledGrowthRanges = mockGetContractEvents.mock.calls
|
|
144
|
+
.filter(([{ eventName }]) => eventName === 'SettledGrowthSet')
|
|
145
|
+
.map(([{ fromBlock, toBlock }]) => [fromBlock, toBlock]);
|
|
146
|
+
expect(settledGrowthRanges).toEqual([
|
|
147
|
+
[75000n, 84999n],
|
|
148
|
+
[85000n, 94999n],
|
|
149
|
+
[95000n, 100000n],
|
|
150
|
+
]);
|
|
151
|
+
});
|
|
152
|
+
it('clamps fromBlock to 0 when the chain is shorter than the lookback', async () => {
|
|
153
|
+
mockGetBlockNumber.mockResolvedValue(10n);
|
|
154
|
+
mockGetContractEvents.mockResolvedValue([]);
|
|
155
|
+
await findRecentFeeExemptions(DASHBOARD, 32n);
|
|
156
|
+
const firstCall = mockGetContractEvents.mock.calls[0];
|
|
157
|
+
expect(firstCall?.[0]?.fromBlock).toBe(0n);
|
|
158
|
+
expect(firstCall?.[0]?.toBlock).toBe(10n);
|
|
159
|
+
});
|
|
160
|
+
it('returns empty when only disburse events exist', async () => {
|
|
161
|
+
mockGetBlockNumber.mockResolvedValue(1000000n);
|
|
162
|
+
mockChainLogs([settledGrowthLog(TX_DISBURSE, 100n, 132n, 999000n)], []);
|
|
163
|
+
const matches = await findRecentFeeExemptions(DASHBOARD, 32n);
|
|
164
|
+
expect(matches).toHaveLength(0);
|
|
165
|
+
expect(mockGetBlock).not.toHaveBeenCalled();
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
//# sourceMappingURL=consolidation-fee-exemption.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consolidation-fee-exemption.test.js","sourceRoot":"","sources":["../../../tests/utils/consolidation-fee-exemption.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAG9D,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,uBAAuB,GAExB,MAAM,4CAA4C,CAAC;AAEpD,MAAM,kBAAkB,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;AACnC,MAAM,qBAAqB,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;AACtC,MAAM,YAAY,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;AAE7B,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;IAC1B,eAAe,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;QAC5B,cAAc,EAAE,kBAAkB;QAClC,iBAAiB,EAAE,qBAAqB;QACxC,QAAQ,EAAE,YAAY;KACvB,CAAC;CACH,CAAC,CAAC,CAAC;AAEJ,MAAM,YAAY,GAAG,QAAe,CAAC;AACrC,MAAM,WAAW,GAAG,QAAe,CAAC;AACpC,MAAM,QAAQ,GAAG,QAAe,CAAC;AACjC,MAAM,SAAS,GAAG,4CAA4C,CAAC;AAE/D,MAAM,gBAAgB,GAAG,CACvB,eAAoB,EACpB,gBAAwB,EACxB,gBAAwB,EACxB,WAAW,GAAG,IAAI,EACG,EAAE,CAAC,CAAC;IACzB,eAAe;IACf,WAAW;IACX,IAAI,EAAE,EAAE,gBAAgB,EAAE,gBAAgB,EAAE;CAC7C,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,IAAI,GAAG,CAAC,gBAAgB,CAAC,YAAY,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAC1D,MAAM,OAAO,GAAG,qBAAqB,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAE1E,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,GAAG,EAAE;QAC/E,MAAM,IAAI,GAAG,CAAC,gBAAgB,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QACzD,MAAM,OAAO,GAAG,qBAAqB,CAAC,IAAI,EAAE,IAAI,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC;QAE5D,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,IAAI,GAAG;YACX,gBAAgB,CAAC,YAAY,EAAE,IAAI,EAAE,IAAI,CAAC;YAC1C,gBAAgB,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC;SACvC,CAAC;QACF,MAAM,OAAO,GAAG,qBAAqB,CACnC,IAAI,EACJ,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,EACjC,GAAG,CACJ,CAAC;QAEF,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,IAAI,GAAG,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QACtD,MAAM,OAAO,GAAG,qBAAqB,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAEtE,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,IAAI,GAAG;YACX,gBAAgB,CAAC,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;YAChD,gBAAgB,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;SAC7C,CAAC;QACF,MAAM,OAAO,GAAG,qBAAqB,CACnC,IAAI,EACJ,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,EACjC,GAAG,CACJ,CAAC;QAEF,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,MAAM,UAAU,GAAG,KAAK,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAS,CAAC;IAEjD,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,IAAI,GAAG,uBAAuB,CAAC;YACnC,MAAM,EAAE,UAAU;YAClB,WAAW,EAAE,IAAI;YACjB,KAAK,EAAE,qBAA2B;YAClC,SAAS,EAAE,WAAc;SAC1B,CAAC,CAAC;QAEH,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,gBAAgB,UAAU,8BAA8B,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,IAAI,GAAG,uBAAuB,CAAC;YACnC,MAAM,EAAE,4BAAmC;YAC3C,WAAW,EAAE,IAAI;YACjB,KAAK,EAAE,qBAA2B;YAClC,SAAS,EAAE,WAAc;SAC1B,CAAC,CAAC;QAEH,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC;QACrD,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,IAAI,GAAG,uBAAuB,CAAC;YACnC,MAAM,EAAE,KAAK,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAS;YACrC,WAAW,EAAE,IAAI;YACjB,KAAK,EAAE,EAAE;YACT,SAAS,EAAE,WAAc;SAC1B,CAAC,CAAC;QAEH,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,IAAI,GAAG,uBAAuB,CAAC;YACnC,MAAM,EAAE,UAAU;YAClB,WAAW,EAAE,IAAI;YACjB,KAAK,EAAE,EAAE;YACT,SAAS,EAAE,EAAE,IAAI,GAAG;SACrB,CAAC,CAAC;QAEH,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,8BAA8B,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,gFAAgF;IAChF,MAAM,aAAa,GAAG,CACpB,iBAAwC,EACxC,kBAAyB,EACzB,EAAE;QACF,qBAAqB,CAAC,kBAAkB,CACtC,KAAK,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE;YAC1C,MAAM,OAAO,GAAG,iBAAiB,CAAC,MAAM,CACtC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,IAAI,SAAS,IAAI,GAAG,CAAC,WAAW,IAAI,OAAO,CACpE,CAAC;YACF,IAAI,SAAS,KAAK,kBAAkB;gBAAE,OAAO,OAAO,CAAC;YAErD,OAAO,OAAO;iBACX,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,kBAAkB,CAAC,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;iBACjE,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,eAAe,EAAE,GAAG,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;QAC9D,CAAC,CACF,CAAC;IACJ,CAAC,CAAC;IAEF,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,kBAAkB,CAAC,iBAAiB,CAAC,QAAU,CAAC,CAAC;QACjD,aAAa,CACX;YACE,gBAAgB,CAAC,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,OAAQ,CAAC;YACpD,gBAAgB,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,OAAQ,CAAC;SACpD,EACD,CAAC,YAAY,CAAC,CACf,CAAC;QACF,YAAY,CAAC,iBAAiB,CAAC,EAAE,SAAS,EAAE,WAAc,EAAE,CAAC,CAAC;QAE9D,MAAM,OAAO,GAAG,MAAM,uBAAuB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAE9D,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;YAC/B,MAAM,EAAE,YAAY;YACpB,KAAK,EAAE,GAAG;YACV,SAAS,EAAE,WAAc;SAC1B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,kBAAkB,CAAC,iBAAiB,CAAC,QAAU,CAAC,CAAC;QACjD,qBAAqB,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;QAE5C,wEAAwE;QACxE,MAAM,uBAAuB,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QAErD,MAAM,MAAM,GAAG,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CACjD,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,OAAO,CAAC,CACnD,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB,CAAC,OAAQ,EAAE,QAAU,CAAC;YACtB,CAAC,OAAQ,EAAE,QAAU,CAAC;SACvB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,kBAAkB,CAAC,iBAAiB,CAAC,OAAQ,CAAC,CAAC;QAC/C,qBAAqB,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;QAE5C,yEAAyE;QACzE,MAAM,uBAAuB,CAAC,SAAS,EAAE,GAAG,EAAE,MAAO,GAAG,GAAG,CAAC,CAAC;QAE7D,MAAM,mBAAmB,GAAG,qBAAqB,CAAC,IAAI,CAAC,KAAK;aACzD,MAAM,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,SAAS,KAAK,kBAAkB,CAAC;aAC7D,GAAG,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;QAC3D,MAAM,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC;YAClC,CAAC,MAAO,EAAE,MAAO,CAAC;YAClB,CAAC,MAAO,EAAE,MAAO,CAAC;YAClB,CAAC,MAAO,EAAE,OAAQ,CAAC;SACpB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,kBAAkB,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;QAC1C,qBAAqB,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;QAE5C,MAAM,uBAAuB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAE9C,MAAM,SAAS,GAAG,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACtD,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC3C,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,kBAAkB,CAAC,iBAAiB,CAAC,QAAU,CAAC,CAAC;QACjD,aAAa,CAAC,CAAC,gBAAgB,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,OAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAEzE,MAAM,OAAO,GAAG,MAAM,uBAAuB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAE9D,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { describe, expect, test, vi, beforeEach } from 'vitest';
|
|
2
|
+
const mockLogResult = vi.fn();
|
|
3
|
+
vi.mock('utils', () => ({
|
|
4
|
+
logResult: mockLogResult,
|
|
5
|
+
}));
|
|
6
|
+
const importSubject = async () => {
|
|
7
|
+
const { getFirstValidatorGIndex } = await import('../../utils/proof/first-validator-gindex.js');
|
|
8
|
+
return getFirstValidatorGIndex;
|
|
9
|
+
};
|
|
10
|
+
const rowsFor = async (forks) => {
|
|
11
|
+
const getFirstValidatorGIndex = await importSubject();
|
|
12
|
+
getFirstValidatorGIndex(forks);
|
|
13
|
+
return mockLogResult.mock.calls[0]?.[0]?.data;
|
|
14
|
+
};
|
|
15
|
+
// Values the verifiers are deployed with, see deploy params in lidofinance/core
|
|
16
|
+
const CAPELLA_GINDEX = '0x0000000000000000000000000000000000000000000000000056000000000028';
|
|
17
|
+
const ELECTRA_GINDEX = '0x0000000000000000000000000000000000000000000000000096000000000028';
|
|
18
|
+
const GLOAS_GINDEX = '0x0000000000000000000000000000000000000000000000000000000000016600';
|
|
19
|
+
describe('getFirstValidatorGIndex', () => {
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
mockLogResult.mockClear();
|
|
22
|
+
});
|
|
23
|
+
test('packs first validator gindex with list depth before gloas', async () => {
|
|
24
|
+
const rows = await rowsFor(['capella', 'deneb', 'electra', 'fulu']);
|
|
25
|
+
expect(rows.map((row) => row[1])).toEqual([
|
|
26
|
+
CAPELLA_GINDEX,
|
|
27
|
+
CAPELLA_GINDEX,
|
|
28
|
+
ELECTRA_GINDEX,
|
|
29
|
+
ELECTRA_GINDEX,
|
|
30
|
+
]);
|
|
31
|
+
expect(rows.map((row) => row[2])).toEqual([
|
|
32
|
+
'gIFirstValidatorPreGloas',
|
|
33
|
+
'gIFirstValidatorPreGloas',
|
|
34
|
+
'gIFirstValidatorPreGloas',
|
|
35
|
+
'gIFirstValidatorPreGloas',
|
|
36
|
+
]);
|
|
37
|
+
});
|
|
38
|
+
test('returns the validators field gindex with zero width for gloas', async () => {
|
|
39
|
+
const rows = await rowsFor(['gloas']);
|
|
40
|
+
expect(rows[0]).toEqual(['gloas', GLOAS_GINDEX, 'gIValidators']);
|
|
41
|
+
});
|
|
42
|
+
test('rejects an unknown fork instead of emitting a gindex', async () => {
|
|
43
|
+
const getFirstValidatorGIndex = await importSubject();
|
|
44
|
+
expect(() => getFirstValidatorGIndex(['notafork'])).toThrow('Fork name [notafork] is not supported');
|
|
45
|
+
expect(mockLogResult).not.toHaveBeenCalled();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
//# sourceMappingURL=first-validator-gindex.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"first-validator-gindex.test.js","sourceRoot":"","sources":["../../../tests/utils/first-validator-gindex.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEhE,MAAM,aAAa,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;AAE9B,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;IACtB,SAAS,EAAE,aAAa;CACzB,CAAC,CAAC,CAAC;AAEJ,MAAM,aAAa,GAAG,KAAK,IAAI,EAAE;IAC/B,MAAM,EAAE,uBAAuB,EAAE,GAC/B,MAAM,MAAM,CAAC,6CAA6C,CAAC,CAAC;IAC9D,OAAO,uBAAuB,CAAC;AACjC,CAAC,CAAC;AAEF,MAAM,OAAO,GAAG,KAAK,EAAE,KAAe,EAAE,EAAE;IACxC,MAAM,uBAAuB,GAAG,MAAM,aAAa,EAAE,CAAC;IACtD,uBAAuB,CAAC,KAAK,CAAC,CAAC;IAC/B,OAAO,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAkB,CAAC;AAC9D,CAAC,CAAC;AAEF,gFAAgF;AAChF,MAAM,cAAc,GAClB,oEAAoE,CAAC;AACvE,MAAM,cAAc,GAClB,oEAAoE,CAAC;AACvE,MAAM,YAAY,GAChB,oEAAoE,CAAC;AAEvE,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,UAAU,CAAC,GAAG,EAAE;QACd,aAAa,CAAC,SAAS,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QAC3E,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;QAEpE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YACxC,cAAc;YACd,cAAc;YACd,cAAc;YACd,cAAc;SACf,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YACxC,0BAA0B;YAC1B,0BAA0B;YAC1B,0BAA0B;YAC1B,0BAA0B;SAC3B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QAEtC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACtE,MAAM,uBAAuB,GAAG,MAAM,aAAa,EAAE,CAAC;QAEtD,MAAM,CAAC,GAAG,EAAE,CAAC,uBAAuB,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CACzD,uCAAuC,CACxC,CAAC;QACF,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|