@marinade.finance/scoring 1.0.0 → 1.0.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.
Files changed (37) hide show
  1. package/computing/cluster.ts +102 -0
  2. package/computing/eligibility.ts +163 -0
  3. package/computing/score.ts +164 -0
  4. package/computing/stake.ts +246 -0
  5. package/computing/validators.ts +133 -0
  6. package/{src/dto → dto}/bonds.dto.ts +0 -2
  7. package/{src/dto → dto}/cluster.dto.ts +0 -1
  8. package/{src/dto → dto}/eligibility.dto.ts +0 -5
  9. package/{src/dto → dto}/jito.dto.ts +1 -2
  10. package/{src/dto → dto}/marinade.dto.ts +1 -1
  11. package/{src/dto → dto}/rewards.dto.ts +1 -3
  12. package/{src/dto → dto}/scoring.dto.ts +1 -7
  13. package/{src/dto → dto}/snapshots.dto.ts +0 -3
  14. package/{src/dto → dto}/stakes.dto.ts +0 -4
  15. package/{src/dto → dto}/validators.dto.ts +1 -37
  16. package/package.json +17 -13
  17. package/{src/providers → providers}/api-data.provider.ts +58 -58
  18. package/{src/providers → providers}/file-data.provider.ts +7 -15
  19. package/{src/utils → utils}/csv.ts +3 -3
  20. package/src/cluster/cluster.module.ts +0 -8
  21. package/src/cluster/cluster.service.ts +0 -108
  22. package/src/config/config.module.ts +0 -8
  23. package/src/config/config.service.ts +0 -136
  24. package/src/eligibility/eligibility.module.ts +0 -11
  25. package/src/eligibility/eligibility.service.ts +0 -183
  26. package/src/scoring/scoring.module.ts +0 -11
  27. package/src/scoring/scoring.service.ts +0 -184
  28. package/src/stake/stake.module.ts +0 -10
  29. package/src/stake/stake.service.ts +0 -242
  30. package/src/validators/validators.module.ts +0 -48
  31. package/src/validators/validators.service.ts +0 -177
  32. /package/{src/constants → constants}/marinade.json +0 -0
  33. /package/{src/errors → errors}/fetching.ts +0 -0
  34. /package/{src/interfaces → interfaces}/data-provider.interface.ts +0 -0
  35. /package/{src/utils → utils}/maths.ts +0 -0
  36. /package/{src/utils → utils}/solana.ts +0 -0
  37. /package/{src/utils → utils}/zip.ts +0 -0
@@ -1,4 +1,3 @@
1
- /* eslint-disable no-console */
2
1
  import { Rewards, RewardsResponseDto } from '../dto/rewards.dto';
3
2
  import { Votes, mSolSnapshotDto, veMNDESnapshotDto } from '../dto/snapshots.dto';
4
3
  import { EpochStatDto, ValidatorDto, ValidatorsResponseDto } from '../dto/validators.dto';
@@ -10,6 +9,7 @@ import { writeFile } from 'fs/promises';
10
9
  import { Bonds, BondsDto } from '../dto/bonds.dto';
11
10
  import { TvlStats } from '../dto/marinade.dto';
12
11
  import axios, { AxiosError } from 'axios';
12
+ import { error } from '../logger';
13
13
 
14
14
  export class URLs {
15
15
  validatorsURL: string;
@@ -23,7 +23,7 @@ export class URLs {
23
23
  }
24
24
 
25
25
  export class ApiDataProvider implements IDataProvider {
26
- constructor (private urls: URLs) { }
26
+ constructor (private urls: URLs, private snapshotsBasePath?: string) { }
27
27
 
28
28
  async fetchValidators (epochsToFetch: number, withSnapshot = false): Promise<ValidatorDto[]> {
29
29
  try {
@@ -43,16 +43,16 @@ export class ApiDataProvider implements IDataProvider {
43
43
  }
44
44
 
45
45
  return rawData.validators;
46
- } catch (error) {
46
+ } catch (err) {
47
47
  if (axios.isAxiosError(error)) {
48
48
  const axiosError = error as AxiosError;
49
49
  if (axiosError.response) {
50
- console.error(FETCHING_ERROR_MESSAGES.validatorsFetchFailed, axiosError.response.status);
50
+ error(FETCHING_ERROR_MESSAGES.validatorsFetchFailed, axiosError.response.status);
51
51
  } else if (axiosError.request) {
52
- console.error(FETCHING_ERROR_MESSAGES.generalValidatorsFetchFailed, axiosError.request);
52
+ error(FETCHING_ERROR_MESSAGES.generalValidatorsFetchFailed, axiosError.request);
53
53
  }
54
54
  }
55
- throw error;
55
+ throw err;
56
56
  }
57
57
  }
58
58
 
@@ -63,20 +63,20 @@ export class ApiDataProvider implements IDataProvider {
63
63
  const data: TvlStats = response.data;
64
64
 
65
65
  if (withSnapshot) {
66
- await writeFile('./snapshot/tvl.json', JSON.stringify(data, null, 2));
66
+ await writeFile(`${this.snapshotsBasePath}/tvl.json`, JSON.stringify(data, null, 2));
67
67
  }
68
68
 
69
69
  return data;
70
- } catch (error) {
70
+ } catch (err) {
71
71
  if (axios.isAxiosError(error)) {
72
72
  const axiosError = error as AxiosError;
73
73
  if (axiosError.response) {
74
- console.error(FETCHING_ERROR_MESSAGES.tvlFetchFailed, axiosError.response.status);
74
+ error(FETCHING_ERROR_MESSAGES.tvlFetchFailed, axiosError.response.status);
75
75
  } else if (axiosError.request) {
76
- console.error(FETCHING_ERROR_MESSAGES.generalTvlFetchFailed, axiosError.request);
76
+ error(FETCHING_ERROR_MESSAGES.generalTvlFetchFailed, axiosError.request);
77
77
  }
78
78
  }
79
- throw error;
79
+ throw err;
80
80
  }
81
81
  }
82
82
 
@@ -91,21 +91,21 @@ export class ApiDataProvider implements IDataProvider {
91
91
  }, {} as Bonds);
92
92
 
93
93
  if (withSnapshot) {
94
- await writeFile('./snapshot/bonds.json', JSON.stringify(data, null, 2));
94
+ await writeFile(`${this.snapshotsBasePath}/bonds.json`, JSON.stringify(data, null, 2));
95
95
  }
96
96
 
97
97
  return bonds;
98
- } catch (error) {
99
- if (axios.isAxiosError(error)) {
100
- const axiosError = error as AxiosError;
98
+ } catch (err) {
99
+ if (axios.isAxiosError(err)) {
100
+ const axiosError = err as AxiosError;
101
101
  if (axiosError.response) {
102
- console.error(FETCHING_ERROR_MESSAGES.bondsFetchFailed, axiosError.response.status);
102
+ error(FETCHING_ERROR_MESSAGES.bondsFetchFailed, axiosError.response.status);
103
103
  } else if (axiosError.request) {
104
- console.error(FETCHING_ERROR_MESSAGES.generalBondsFetchFailed, axiosError.request);
104
+ error(FETCHING_ERROR_MESSAGES.generalBondsFetchFailed, axiosError.request);
105
105
  }
106
106
  }
107
107
 
108
- throw error;
108
+ throw err;
109
109
  }
110
110
  }
111
111
 
@@ -118,7 +118,7 @@ export class ApiDataProvider implements IDataProvider {
118
118
  const csv: string = response.data;
119
119
 
120
120
  if (withSnapshot) {
121
- await writeFile('./snapshot/blacklist.csv', csv);
121
+ await writeFile(`${this.snapshotsBasePath}/blacklist.csv`, csv);
122
122
  }
123
123
 
124
124
  const blacklistSet = new Set(
@@ -129,16 +129,16 @@ export class ApiDataProvider implements IDataProvider {
129
129
  );
130
130
 
131
131
  return blacklistSet;
132
- } catch (error) {
133
- if (axios.isAxiosError(error)) {
134
- if (error.response) {
135
- console.error(FETCHING_ERROR_MESSAGES.blacklistFetchFailed, error.response.status);
136
- } else if (error.request) {
137
- console.error(FETCHING_ERROR_MESSAGES.generalBlacklistFetchFailed, error.request);
132
+ } catch (err) {
133
+ if (axios.isAxiosError(err)) {
134
+ if (err.response) {
135
+ error(FETCHING_ERROR_MESSAGES.blacklistFetchFailed, err.response.status);
136
+ } else if (err.request) {
137
+ error(FETCHING_ERROR_MESSAGES.generalBlacklistFetchFailed, err.request);
138
138
  }
139
139
  }
140
140
 
141
- throw error;
141
+ throw err;
142
142
  }
143
143
  }
144
144
 
@@ -148,7 +148,7 @@ export class ApiDataProvider implements IDataProvider {
148
148
  const data: veMNDESnapshotDto = response.data;
149
149
 
150
150
  if (withSnapshot) {
151
- await writeFile('./snapshot/vemnde-votes.json', JSON.stringify(data, null, 2));
151
+ await writeFile(`${this.snapshotsBasePath}/vemnde-votes.json`, JSON.stringify(data, null, 2));
152
152
  }
153
153
 
154
154
  const result: Votes = {};
@@ -160,16 +160,16 @@ export class ApiDataProvider implements IDataProvider {
160
160
  }
161
161
 
162
162
  return result;
163
- } catch (error) {
164
- if (axios.isAxiosError(error)) {
165
- if (error.response) {
166
- console.error(FETCHING_ERROR_MESSAGES.vemndeFetchFailed, error.response.status);
167
- } else if (error.request) {
168
- console.error(FETCHING_ERROR_MESSAGES.generalVemndeFetchFailed, error.request);
163
+ } catch (err) {
164
+ if (axios.isAxiosError(err)) {
165
+ if (err.response) {
166
+ error(FETCHING_ERROR_MESSAGES.vemndeFetchFailed, err.response.status);
167
+ } else if (err.request) {
168
+ error(FETCHING_ERROR_MESSAGES.generalVemndeFetchFailed, err.request);
169
169
  }
170
170
  }
171
171
 
172
- throw error;
172
+ throw err;
173
173
  }
174
174
  }
175
175
 
@@ -179,7 +179,7 @@ export class ApiDataProvider implements IDataProvider {
179
179
  const data: mSolSnapshotDto = response.data;
180
180
 
181
181
  if (withSnapshot) {
182
- await writeFile('./snapshot/msol-votes.json', JSON.stringify(data, null, 2));
182
+ await writeFile(`${this.snapshotsBasePath}/msol-votes.json`, JSON.stringify(data, null, 2));
183
183
  }
184
184
 
185
185
  const result: Votes = {};
@@ -191,16 +191,16 @@ export class ApiDataProvider implements IDataProvider {
191
191
  }
192
192
 
193
193
  return result;
194
- } catch (error) {
195
- if (axios.isAxiosError(error)) {
196
- if (error.response) {
197
- console.error(FETCHING_ERROR_MESSAGES.msolFetchFailed, error.response.status);
198
- } else if (error.request) {
199
- console.error(FETCHING_ERROR_MESSAGES.generalMsolFetchFailed, error.request);
194
+ } catch (err) {
195
+ if (axios.isAxiosError(err)) {
196
+ if (err.response) {
197
+ error(FETCHING_ERROR_MESSAGES.msolFetchFailed, err.response.status);
198
+ } else if (err.request) {
199
+ error(FETCHING_ERROR_MESSAGES.generalMsolFetchFailed, err.request);
200
200
  }
201
201
  }
202
202
 
203
- throw error;
203
+ throw err;
204
204
  }
205
205
  }
206
206
 
@@ -214,23 +214,23 @@ export class ApiDataProvider implements IDataProvider {
214
214
  const data = new RewardsResponseDto(jsonResponse);
215
215
 
216
216
  if (withSnapshot) {
217
- await writeFile('./snapshot/rewards.json', JSON.stringify(jsonResponse, null, 2));
217
+ await writeFile(`${this.snapshotsBasePath}/rewards.json`, JSON.stringify(jsonResponse, null, 2));
218
218
  }
219
219
 
220
220
  const mev = sum(data.rewards_mev.map(dto => dto.amount));
221
221
  const inflation = sum(data.rewards_inflation_est.map(dto => dto.amount));
222
222
 
223
223
  return { inflation, mev };
224
- } catch (error) {
225
- if (axios.isAxiosError(error)) {
226
- if (error.response) {
227
- console.error(FETCHING_ERROR_MESSAGES.rewardsFetchFailed, error.response.status);
228
- } else if (error.request) {
229
- console.error(FETCHING_ERROR_MESSAGES.generalRewardsFetchFailed, error.request);
224
+ } catch (err) {
225
+ if (axios.isAxiosError(err)) {
226
+ if (err.response) {
227
+ error(FETCHING_ERROR_MESSAGES.rewardsFetchFailed, err.response.status);
228
+ } else if (err.request) {
229
+ error(FETCHING_ERROR_MESSAGES.generalRewardsFetchFailed, err.request);
230
230
  }
231
231
  }
232
232
 
233
- throw error;
233
+ throw err;
234
234
  }
235
235
  }
236
236
 
@@ -240,22 +240,22 @@ export class ApiDataProvider implements IDataProvider {
240
240
  const jitoMevRecords: JitoValidatorsResponseDto = response.data;
241
241
 
242
242
  if (withSnapshot) {
243
- await writeFile('./snapshot/jito-mev-records.json', JSON.stringify(jitoMevRecords, null, 2));
243
+ await writeFile(`${this.snapshotsBasePath}/jito-mev-records.json`, JSON.stringify(jitoMevRecords, null, 2));
244
244
  }
245
245
 
246
246
  return Object.fromEntries(
247
247
  jitoMevRecords.validators.map((validator) => [validator.vote_account, validator])
248
248
  );
249
- } catch (error) {
250
- if (axios.isAxiosError(error)) {
251
- if (error.response) {
252
- console.error(FETCHING_ERROR_MESSAGES.jitoMevFetchFailed, error.response.status);
253
- } else if (error.request) {
254
- console.error(FETCHING_ERROR_MESSAGES.generalJitoMEVFetchFailed, error.request);
249
+ } catch (err) {
250
+ if (axios.isAxiosError(err)) {
251
+ if (err.response) {
252
+ error(FETCHING_ERROR_MESSAGES.jitoMevFetchFailed, err.response.status);
253
+ } else if (err.request) {
254
+ error(FETCHING_ERROR_MESSAGES.generalJitoMEVFetchFailed, err.request);
255
255
  }
256
256
  }
257
257
 
258
- throw error;
258
+ throw err;
259
259
  }
260
260
  }
261
261
  }
@@ -1,4 +1,3 @@
1
- /* eslint-disable no-console */
2
1
  /* eslint-disable @typescript-eslint/no-unused-vars */
3
2
  import { TvlStats } from '../dto/marinade.dto';
4
3
  import { Bonds, BondsDto } from '../dto/bonds.dto';
@@ -10,6 +9,7 @@ import { readFile } from 'fs/promises';
10
9
  import { FETCHING_ERROR_MESSAGES } from '../errors/fetching';
11
10
  import { sum } from '../utils/maths';
12
11
  import { Votes, mSolSnapshotDto } from '../dto/snapshots.dto';
12
+ import { error } from 'logger';
13
13
 
14
14
  class Paths {
15
15
  validatorsPath: string;
@@ -38,25 +38,21 @@ export class FileDataProvider implements IDataProvider {
38
38
  });
39
39
 
40
40
  return validatorsData.validators;
41
- } catch (error) {
42
- console.error(FETCHING_ERROR_MESSAGES.generalValidatorsFetchFailed, error);
43
- throw error;
41
+ } catch (err) {
42
+ error(FETCHING_ERROR_MESSAGES.generalValidatorsFetchFailed, err);
43
+ throw err;
44
44
  }
45
45
  }
46
-
47
46
  async fetchTvl (withSnapshot: boolean): Promise<TvlStats> {
48
47
  const tvlFile = await readFile(this.paths.marinadeTvlPath, 'utf8');
49
48
  const tvlData: TvlStats = JSON.parse(tvlFile);
50
-
51
49
  return tvlData;
52
50
  }
53
-
54
51
  async fetchBlacklist (): Promise<Set<string>> {
55
52
  const blacklistFile = await readFile(this.paths.blacklistPath, 'utf8');
56
53
  const blacklistSet = new Set(blacklistFile.split('\n').map((line) => line.split(',')[0]).filter((value): value is string => !!value));
57
54
  return blacklistSet;
58
55
  }
59
-
60
56
  async fetchBonds (): Promise<Bonds> {
61
57
  const bondsFile = await readFile(this.paths.bondsPath, 'utf8');
62
58
  const bondsData: BondsDto = JSON.parse(bondsFile);
@@ -68,7 +64,6 @@ export class FileDataProvider implements IDataProvider {
68
64
 
69
65
  return bonds;
70
66
  }
71
-
72
67
  async fetchVeMndeVotes (): Promise<Record<string, number>> {
73
68
  const vemndeVotesFile = await readFile(this.paths.vemndeVotesPath, 'utf8');
74
69
  const vemndeVotesData = JSON.parse(vemndeVotesFile) as mSolSnapshotDto;
@@ -82,7 +77,6 @@ export class FileDataProvider implements IDataProvider {
82
77
 
83
78
  return result;
84
79
  }
85
-
86
80
  async fetchMSolVotes (): Promise<Record<string, number>> {
87
81
  const msolVotesFile = await readFile(this.paths.msolVotesPath, 'utf8');
88
82
  const msolVotesData = JSON.parse(msolVotesFile) as mSolSnapshotDto;
@@ -96,7 +90,6 @@ export class FileDataProvider implements IDataProvider {
96
90
 
97
91
  return result;
98
92
  }
99
-
100
93
  async fetchRewards (epochs: number): Promise<Rewards> {
101
94
  const rewardsFile = await readFile(this.paths.rewardsPath, 'utf8');
102
95
  const rewardsData = JSON.parse(rewardsFile) as { rewards_mev: [number, number][], rewards_inflation_est: [number, number][] };
@@ -108,7 +101,6 @@ export class FileDataProvider implements IDataProvider {
108
101
 
109
102
  return { inflation, mev };
110
103
  }
111
-
112
104
  async fetchValidatorsJitoMEV (): Promise<Record<string, JitoValidatorDto>> {
113
105
  try {
114
106
  const jitoMevFile = await readFile(this.paths.jitoMevPath, 'utf8');
@@ -117,9 +109,9 @@ export class FileDataProvider implements IDataProvider {
117
109
  return Object.fromEntries(
118
110
  jitoMevData.validators.map((validator) => [validator.vote_account, validator])
119
111
  );
120
- } catch (error) {
121
- console.error(FETCHING_ERROR_MESSAGES.generalJitoMEVFetchFailed, error);
122
- throw error;
112
+ } catch (err) {
113
+ error(FETCHING_ERROR_MESSAGES.generalJitoMEVFetchFailed, err);
114
+ throw err;
123
115
  }
124
116
  }
125
117
  }
@@ -1,9 +1,9 @@
1
1
  /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
- /* eslint-disable no-console */
3
2
  import * as fs from 'fs';
4
3
  import { Score } from '../dto/scoring.dto';
4
+ import { error } from 'logger';
5
5
 
6
- export function writeScoresToCsv (filePath: string, data: Score[]): void {
6
+ export function writeScoresToCsv(filePath: string, data: Score[]): void {
7
7
  if (data.length === 0) {
8
8
  console.error('Data array is empty, no CSV will be written.');
9
9
  return;
@@ -24,7 +24,7 @@ export function writeScoresToCsv (filePath: string, data: Score[]): void {
24
24
 
25
25
  fs.writeFile(filePath, csvString, (err) => {
26
26
  if (err) {
27
- console.error('Error writing CSV file:', err);
27
+ error('Error writing CSV file:', err);
28
28
  }
29
29
  });
30
30
  }
@@ -1,8 +0,0 @@
1
- import { Module } from '@nestjs/common';
2
- import { ClusterService } from './cluster.service';
3
-
4
- @Module({
5
- providers: [ClusterService],
6
- exports: [ClusterService],
7
- })
8
- export class ClusterModule {}
@@ -1,108 +0,0 @@
1
- import { BlockProductionResult, ClusterInfo } from '../dto/cluster.dto';
2
- import { ValidatorDto } from '../dto/validators.dto';
3
- import { mean, stdDev } from '../utils/maths';
4
- import Decimal from 'decimal.js';
5
-
6
- export class ClusterService {
7
- computeBlockProduction (validators: ValidatorDto[], startEpoch: number, endEpoch: number): BlockProductionResult {
8
- const blockProductions: number[] = [];
9
-
10
- for (const validator of validators) {
11
- let leaderSlots = 0;
12
- let blocksProduced = 0;
13
-
14
- for (let epoch = startEpoch; epoch <= endEpoch; epoch++) {
15
- if (!validator.epochStats) {
16
- continue;
17
- }
18
- const epochStat = validator.epochStats[epoch];
19
- if (epochStat) {
20
- leaderSlots += epochStat.leader_slots;
21
- blocksProduced += epochStat.blocks_produced;
22
- }
23
- }
24
-
25
- if (leaderSlots) {
26
- blockProductions.push(blocksProduced / leaderSlots);
27
- }
28
- }
29
-
30
- return {
31
- mean: mean(blockProductions),
32
- stdDev: stdDev(blockProductions),
33
- };
34
- }
35
-
36
- computeTargetCreditsByEpoch (validators: ValidatorDto[]): Map<number, number> {
37
- const sumOfWeightedCreditsPerEpoch = new Map<number, Decimal>();
38
- const sumOfWeightsPerEpoch = new Map<number, Decimal>();
39
-
40
- validators.forEach(validator => {
41
- validator.epoch_stats.forEach(epochStat => {
42
- if (epochStat.epoch_end_at) {
43
- const activatedStakeDecimal = new Decimal(epochStat.activated_stake);
44
- const stakeInLamports = activatedStakeDecimal.dividedBy(1e9);
45
-
46
- const prevSumOfWeightedCredits = sumOfWeightedCreditsPerEpoch.get(epochStat.epoch) || new Decimal(0);
47
- sumOfWeightedCreditsPerEpoch.set(epochStat.epoch, prevSumOfWeightedCredits.plus(new Decimal(epochStat.credits).times(stakeInLamports)));
48
-
49
- const prevSumOfWeightsPerEpoch = sumOfWeightsPerEpoch.get(epochStat.epoch) || new Decimal(0);
50
- sumOfWeightsPerEpoch.set(epochStat.epoch, prevSumOfWeightsPerEpoch.plus(stakeInLamports));
51
- }
52
- });
53
- });
54
-
55
- const result = new Map<number, number>();
56
- sumOfWeightsPerEpoch.forEach((sumOfWeights, epoch) => {
57
- const weightedCredits = sumOfWeightedCreditsPerEpoch.get(epoch) || new Decimal(0);
58
- result.set(epoch, weightedCredits.dividedBy(sumOfWeights).toDecimalPlaces(0, Decimal.ROUND_HALF_UP).toNumber());
59
- });
60
-
61
- return result;
62
- }
63
-
64
- computeConcentrations (validators: ValidatorDto[], epoch: number): { city: Map<string, number>, country: Map<string, number>, aso: Map<string, number> } {
65
- let total = 0;
66
- const city = new Map<string, number>();
67
- const country = new Map<string, number>();
68
- const aso = new Map<string, number>();
69
-
70
- for (const validator of validators) {
71
- const lastEpochStats = validator.epoch_stats[0];
72
- if (lastEpochStats?.epoch === epoch) {
73
- const cityKey = validator.dc_full_city ?? '???';
74
- const countryKey = validator.dc_country ?? '???';
75
- const asoKey = validator.dc_aso ?? '???';
76
-
77
- const stake = Number(validator.activated_stake) / 1e9;
78
-
79
- city.set(cityKey, (city.get(cityKey) ?? 0) + stake);
80
- country.set(countryKey, (country.get(countryKey) ?? 0) + stake);
81
- aso.set(asoKey, (aso.get(asoKey) ?? 0) + stake);
82
-
83
- total += stake;
84
- }
85
- }
86
-
87
- if (total > 0) {
88
- for (const map of [city, country, aso]) {
89
- for (const [key, value] of map) {
90
- map.set(key, value / total);
91
- }
92
- }
93
- }
94
-
95
- return { city, country, aso };
96
- }
97
-
98
- computeClusterInfo (validators: ValidatorDto[], basicEligibilityEpochs: number, lastEpoch: number): ClusterInfo {
99
- const { mean: meanBlockProduction, stdDev: stdDevBlockProduction } = this.computeBlockProduction(validators, lastEpoch - basicEligibilityEpochs, lastEpoch - 1);
100
-
101
- return {
102
- targetCreditsByEpoch: this.computeTargetCreditsByEpoch(validators),
103
- ...this.computeConcentrations(validators, lastEpoch),
104
- meanBlockProductionOverBasicEligibilityPeriod: meanBlockProduction,
105
- stdDevBlockProductionOverBasicEligibilityPeriod: stdDevBlockProduction,
106
- };
107
- }
108
- }
@@ -1,8 +0,0 @@
1
- import { Module } from '@nestjs/common';
2
- import { ConfigService } from './config.service';
3
-
4
- @Module({
5
- providers: [ConfigService],
6
- exports: [ConfigService],
7
- })
8
- export class ConfigModule {}
@@ -1,136 +0,0 @@
1
- import * as dotenv from 'dotenv';
2
- import { Injectable } from '@nestjs/common';
3
- import { Logger } from '../../../../src/logger';
4
- import { ScoringConfig } from '../dto/scoring.dto';
5
- import { readFileSync } from 'fs';
6
- import * as defaultScoringConfig from '../constants/marinade.json';
7
-
8
- dotenv.config();
9
-
10
- @Injectable()
11
- export class ConfigService {
12
- private readonly logger = new Logger();
13
- readonly scoringConfig: ScoringConfig;
14
- private getEnvVar (key: string): string {
15
- const val = process.env[key];
16
- if (!val) {
17
- this.logger.error(`Missing environment variable: ${key}`);
18
- throw new Error(`Missing environment variable: ${key}`);
19
- }
20
- return val;
21
- }
22
-
23
- getScoringConfig (): ScoringConfig {
24
- const scoringConfigPath = process.env['SCORING_CONFIG_PATH'];
25
-
26
- if (!scoringConfigPath) {
27
- return {
28
- DS_PUBKEY: defaultScoringConfig.DS_PUBKEY,
29
- REWARDS_PAST_EPOCHS: defaultScoringConfig.REWARDS_PAST_EPOCHS,
30
- CAP_FROM_BOND: defaultScoringConfig.CAP_FROM_BOND,
31
- formulaStakeBlockSize: defaultScoringConfig.formulaStakeBlockSize,
32
- formulaStakeBlocksFromScore: defaultScoringConfig.formulaStakeBlocksFromScore,
33
- formulaVoteCredits: defaultScoringConfig.formulaVoteCredits,
34
- formulaBlockProduction: defaultScoringConfig.formulaBlockProduction,
35
- formulaInflationCommission: defaultScoringConfig.formulaInflationCommission,
36
- formulaMEVCommission: defaultScoringConfig.formulaMEVCommission,
37
- formulaStakeConcentrationCountry: defaultScoringConfig.formulaStakeConcentrationCountry,
38
- formulaStakeConcentrationCity: defaultScoringConfig.formulaStakeConcentrationCity,
39
- formulaStakeConcentrationASO: defaultScoringConfig.formulaStakeConcentrationASO,
40
- formulaStakeConcentrationNode: defaultScoringConfig.formulaStakeConcentrationNode,
41
- weightTargetSumOfRewards: defaultScoringConfig.weightTargetSumOfRewards,
42
- weightMevHeuristic: defaultScoringConfig.weightMevHeuristic,
43
- weightVoteCredits: defaultScoringConfig.weightVoteCredits,
44
- weightBlockProduction: defaultScoringConfig.weightBlockProduction,
45
- weightInflationCommission: defaultScoringConfig.weightInflationCommission,
46
- weightMEVCommission: defaultScoringConfig.weightMEVCommission,
47
- weightStakeConcentrationCountry: defaultScoringConfig.weightStakeConcentrationCountry,
48
- weightStakeConcentrationCity: defaultScoringConfig.weightStakeConcentrationCity,
49
- weightStakeConcentrationASO: defaultScoringConfig.weightStakeConcentrationASO,
50
- weightStakeConcentrationNode: defaultScoringConfig.weightStakeConcentrationNode,
51
- basicEligibilityEpochs: defaultScoringConfig.basicEligibilityEpochs,
52
- bonusEligibilityExtraEpochs: defaultScoringConfig.bonusEligibilityExtraEpochs,
53
- maxCommission: defaultScoringConfig.maxCommission,
54
- voteCreditsWarning: defaultScoringConfig.voteCreditsWarning,
55
- voteCreditsLow: defaultScoringConfig.voteCreditsLow,
56
- minExternalStake: defaultScoringConfig.minExternalStake,
57
- minScore: defaultScoringConfig.minScore,
58
- maxStakeShare: defaultScoringConfig.maxStakeShare,
59
- maxWarnings: defaultScoringConfig.maxWarnings,
60
- mSolControl: defaultScoringConfig.mSolControl,
61
- veMndeControl: defaultScoringConfig.veMndeControl,
62
- stakeBlocksFromBonus: defaultScoringConfig.stakeBlocksFromBonus,
63
- concentrationParams: defaultScoringConfig.concentrationParams,
64
- };
65
- } else {
66
- const scoringConfigData = readFileSync(scoringConfigPath, 'utf8');
67
- return JSON.parse(scoringConfigData) as ScoringConfig;
68
- }
69
- }
70
-
71
- getDataProviderMode (): string {
72
- return this.getEnvVar('DATA_PROVIDER_MODE');
73
- }
74
-
75
- getMarinadeTvlURL (): string {
76
- return this.getEnvVar('MARINADE_TVL_URL');
77
- }
78
-
79
- getValidatorsURL (): string {
80
- return this.getEnvVar('VALIDATORS_URL');
81
- }
82
-
83
- getBlacklistURL (): string {
84
- return this.getEnvVar('BLACKLIST_URL');
85
- }
86
-
87
- getBondsURL (): string {
88
- return this.getEnvVar('BONDS_URL');
89
- }
90
-
91
- getVemndeVotesURL (): string {
92
- return this.getEnvVar('VEMNDE_VOTES_URL');
93
- }
94
-
95
- getMsolVotesURL (): string {
96
- return this.getEnvVar('MSOL_VOTES_URL');
97
- }
98
-
99
- getRewardsURL (): string {
100
- return this.getEnvVar('REWARDS_URL');
101
- }
102
- getJitoMevURL (): string {
103
- return this.getEnvVar('JITO_MEV_URL');
104
- }
105
- getValidatorsPath (): string {
106
- return this.getEnvVar('VALIDATORS_PATH');
107
- }
108
-
109
- getBlacklistPath (): string {
110
- return this.getEnvVar('BLACKLIST_PATH');
111
- }
112
-
113
- getVemndeVotesPath (): string {
114
- return this.getEnvVar('VEMNDE_VOTES_PATH');
115
- }
116
-
117
- getMsolVotesPath (): string {
118
- return this.getEnvVar('MSOL_VOTES_PATH');
119
- }
120
-
121
- getRewardsPath (): string {
122
- return this.getEnvVar('REWARDS_PATH');
123
- }
124
-
125
- getJitoMevPath (): string {
126
- return this.getEnvVar('JITO_MEV_PATH');
127
- }
128
-
129
- getBondsPath (): string {
130
- return this.getEnvVar('JITO_MEV_PATH');
131
- }
132
-
133
- getMarinadeTvlPath (): string {
134
- return this.getEnvVar('MARINADE_TVL_PATH');
135
- }
136
- }
@@ -1,11 +0,0 @@
1
- import { Module } from '@nestjs/common';
2
- import { EligibilityService } from './eligibility.service';
3
- import { ValidatorsModule } from '../validators/validators.module';
4
- import { ConfigModule } from '../config/config.module';
5
-
6
- @Module({
7
- imports: [ValidatorsModule, ConfigModule],
8
- providers: [EligibilityService],
9
- exports: [EligibilityService],
10
- })
11
- export class EligibilityModule {}