@marinade.finance/scoring 1.0.0

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/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@marinade.finance/scoring",
3
+ "version": "1.0.0",
4
+ "description": "Delegation Strategy Scoring",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git@github.com:marinade-finance/ds-scoring.git"
8
+ },
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+
13
+ "files": [
14
+ "src",
15
+ "generated",
16
+ "README.md"
17
+ ],
18
+ "main": "index.js",
19
+ "scripts": {
20
+ "build": "nest build",
21
+ "test": "echo \"Error: no test specified\" && exit 1"
22
+ },
23
+ "keywords": [
24
+ "solana",
25
+ "marinade.finance",
26
+ "liquid staking",
27
+ "DeFi"
28
+ ],
29
+ "author": "Marinade Finance",
30
+ "license": "ISC",
31
+ "dependencies": {
32
+ "@nestjs/cli": "^10.3.2",
33
+ "@nestjs/common": "^10.3.3",
34
+ "axios": "^1.6.7",
35
+ "class-transformer": "^0.5.1",
36
+ "class-validator": "^0.14.1",
37
+ "decimal.js": "^10.4.3",
38
+ "expr-eval": "^2.0.2",
39
+ "nestjs": "^0.0.1"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^20.11.19"
43
+ }
44
+ }
@@ -0,0 +1,8 @@
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 {}
@@ -0,0 +1,108 @@
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
+ }
@@ -0,0 +1,8 @@
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 {}
@@ -0,0 +1,136 @@
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
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "DS_PUBKEY": "MarinadeA1gorithmicDe1egationStrategy111111",
3
+ "REWARDS_PAST_EPOCHS": 14,
4
+ "CAP_FROM_BOND": 1000000000,
5
+ "formulaStakeBlockSize": "tvl / ((6000000 / 30000) * 1.5 ^ (log(tvl / 6000000) / log(2)))",
6
+ "formulaStakeBlocksFromScore": "1 + ((max(0.94, score) - 0.94) / (1 - 0.94)) ^ 10",
7
+ "formulaVoteCredits": "min(credits_pct_mean ^ 10, 1)",
8
+ "formulaBlockProduction": "piecewise((bp_mean - bp_cluster_mean) / bp_cluster_std_dev < -1, bp_mean / (bp_cluster_mean - bp_cluster_std_dev), 1)",
9
+ "formulaInflationCommission": "piecewise(commission_inflation_max <= 10, (100 - commission_inflation_max) / 100, 0)",
10
+ "formulaMEVCommission": "(100 - commission_mev) / 100",
11
+ "formulaStakeConcentrationCountry": "piecewise(country_stake_concentration_last < 1/3, (1 - (3 * country_stake_concentration_last)) ^ (1/3), 0)",
12
+ "formulaStakeConcentrationCity": "piecewise(city_stake_concentration_last < 1/3, (1 - (3 * city_stake_concentration_last)) ^ (1/3), 0)",
13
+ "formulaStakeConcentrationASO": "piecewise(aso_stake_concentration_last < 1/3, (1 - (3 * aso_stake_concentration_last)) ^ (1/3), 0)",
14
+ "formulaStakeConcentrationNode": "piecewise(node_stake_last < 100000, 1, node_stake_last < 4000000, 1 - (node_stake_last - 100000) / (4000000 - 100000), 0)",
15
+ "weightTargetSumOfRewards": 5,
16
+ "weightMevHeuristic": 0.1,
17
+ "weightVoteCredits": 10,
18
+ "weightBlockProduction": 5,
19
+ "weightInflationCommission": 4.9,
20
+ "weightMEVCommission": 0.1,
21
+ "weightStakeConcentrationCountry": 2,
22
+ "weightStakeConcentrationCity": 3,
23
+ "weightStakeConcentrationASO": 4,
24
+ "weightStakeConcentrationNode": 2,
25
+ "basicEligibilityEpochs": 14,
26
+ "bonusEligibilityExtraEpochs": 0,
27
+ "maxCommission": 7,
28
+ "voteCreditsWarning": 0,
29
+ "voteCreditsLow": 80,
30
+ "minExternalStake": 0,
31
+ "minScore": 0.8,
32
+ "maxStakeShare": 0.8,
33
+ "maxWarnings": 1,
34
+ "mSolControl": 0.2,
35
+ "veMndeControl": 0.2,
36
+ "stakeBlocksFromBonus": 0,
37
+ "concentrationParams": [4, 5, 6, 7]
38
+ }
@@ -0,0 +1,14 @@
1
+ export type BondDto = {
2
+ pubkey: string;
3
+ vote_account: string;
4
+ authority: string;
5
+ cpmpe: number;
6
+ updated_at: string;
7
+ epoch: number;
8
+ }
9
+
10
+ export type BondsDto = {
11
+ bonds: BondDto[];
12
+ }
13
+
14
+ export type Bonds = Record<string, number>;
@@ -0,0 +1,13 @@
1
+ export type ClusterInfo = {
2
+ city: Map<string, number>,
3
+ country: Map<string, number>,
4
+ aso: Map<string, number>,
5
+ targetCreditsByEpoch: Map<number, number>,
6
+ meanBlockProductionOverBasicEligibilityPeriod: number,
7
+ stdDevBlockProductionOverBasicEligibilityPeriod: number,
8
+ }
9
+
10
+ export type BlockProductionResult = {
11
+ mean: number;
12
+ stdDev: number;
13
+ }
@@ -0,0 +1,43 @@
1
+ export type EligibilityConfig = {
2
+ maxCommission: number;
3
+ voteCreditsWarning: number;
4
+ voteCreditsLow: number;
5
+ minExternalStake: number;
6
+ basicEligibilityEpochs: number;
7
+ bonusEligibilityExtraEpochs: number;
8
+ minScore: number;
9
+ maxStakeShare: number;
10
+ maxWarnings: number;
11
+ }
12
+
13
+ export type ValidatorEligibility = {
14
+ basicEligibility: boolean;
15
+ bonusEligibility: boolean;
16
+ issuesCollection: Issue[][];
17
+ capFromBond: number;
18
+ capFromExternalStake: number;
19
+ }
20
+
21
+ export type EvaluationResult = {
22
+ criticals: number;
23
+ warnings: number;
24
+ }
25
+
26
+ export type Issue = {
27
+ type: IssueType;
28
+ message: string;
29
+ }
30
+
31
+ export const enum IssueType {
32
+ NO_DATA = 'NO_DATA',
33
+ NO_BOND = 'NO_BOND',
34
+ SCORE = 'SCORE',
35
+ BLACKLIST = 'BLACKLIST',
36
+ COMMISSION = 'COMMISSION',
37
+ EXTERNAL_STAKE = 'EXTERNAL_STAKE',
38
+ CENTRALIZATION = 'CENTRALIZATION',
39
+ VOTE_CREDITS_LOW = 'VOTE_CREDITS_LOW',
40
+ VOTE_CREDITS_WARNING = 'VOTE_CREDITS_WARNING',
41
+ }
42
+
43
+ export type ValidatorsEligibilities = Record<string, ValidatorEligibility>
@@ -0,0 +1,10 @@
1
+ export class JitoValidatorDto {
2
+ vote_account: string;
3
+ mev_commission_bps: number;
4
+ running_jito: boolean;
5
+ active_stake: number;
6
+ }
7
+
8
+ export class JitoValidatorsResponseDto {
9
+ validators: JitoValidatorDto[];
10
+ }
@@ -0,0 +1,18 @@
1
+ export type TvlStats = {
2
+ staked_sol: number;
3
+ staked_usd: number;
4
+ msol_directed_stake_sol: number;
5
+ msol_directed_stake_msol: number;
6
+ liquidity_sol: number;
7
+ liquidity_usd: number;
8
+ total_sol: number;
9
+ total_usd: number;
10
+ self_staked_sol: number;
11
+ self_staked_usd: number;
12
+ standard_staked_sol: number;
13
+ standard_staked_usd: number;
14
+ total_virtual_staked_sol: number;
15
+ total_virtual_staked_usd: number;
16
+ marinade_native_stake_sol: number;
17
+ marinade_native_stake_usd: number;
18
+ }
@@ -0,0 +1,21 @@
1
+ export class RewardPairDto {
2
+ epoch: number;
3
+ amount: number;
4
+
5
+ constructor (pair: [number, number]) {
6
+ this.epoch = pair[0];
7
+ this.amount = pair[1];
8
+ }
9
+ }
10
+
11
+ export class RewardsResponseDto {
12
+ rewards_mev: RewardPairDto[];
13
+ rewards_inflation_est: RewardPairDto[];
14
+
15
+ constructor (data: { rewards_mev: [number, number][], rewards_inflation_est: [number, number][] }) {
16
+ this.rewards_mev = data.rewards_mev.map(pair => new RewardPairDto(pair));
17
+ this.rewards_inflation_est = data.rewards_inflation_est.map(pair => new RewardPairDto(pair));
18
+ }
19
+ }
20
+
21
+ export type Rewards = { inflation: number, mev: number }
@@ -0,0 +1,109 @@
1
+ import { ClusterInfo } from './cluster.dto';
2
+ import { AggregatedValidator } from './validators.dto';
3
+
4
+ export type ScoreDto = {
5
+ score: number,
6
+ concentrationScore: number,
7
+ scores: number[]
8
+ values: number[]
9
+ scoreErrors: boolean[]
10
+ tooltips: string[]
11
+ }
12
+
13
+ export type Score = {
14
+ vote_account: string,
15
+ score: string,
16
+ score_credits: string,
17
+ score_block_production: string,
18
+ score_inflation_commission: string,
19
+ score_mev_commission: string,
20
+ score_country_concentration: string,
21
+ score_city_concentration: string,
22
+ score_aso_concentration: string,
23
+ score_node_concentration: string,
24
+ ui_hints: string,
25
+ eligible_stake_algo: number;
26
+ eligible_bonus: number;
27
+ in_algo_stake_set: number;
28
+ msol_votes: string;
29
+ vemnde_votes: string;
30
+ blacklisted: number,
31
+ rank: number,
32
+ version: string,
33
+ max_commission: number,
34
+ marinade_stake: string,
35
+ target_stake_vemnde: string,
36
+ target_stake_msol: string,
37
+ target_stake_algo: string,
38
+ target_stake: string,
39
+ }
40
+
41
+ export type ScoreConfig = {
42
+ epochs: number,
43
+ concentrationParams: number[]
44
+ }
45
+
46
+ export type ScoringConfig = {
47
+ DS_PUBKEY: string;
48
+ REWARDS_PAST_EPOCHS: number;
49
+ CAP_FROM_BOND: number;
50
+ formulaStakeBlockSize: string;
51
+ formulaStakeBlocksFromScore: string;
52
+ formulaVoteCredits: string;
53
+ formulaBlockProduction: string;
54
+ formulaInflationCommission: string;
55
+ formulaMEVCommission: string;
56
+ formulaStakeConcentrationCountry: string;
57
+ formulaStakeConcentrationCity: string;
58
+ formulaStakeConcentrationASO: string;
59
+ formulaStakeConcentrationNode: string;
60
+ weightTargetSumOfRewards: number;
61
+ weightMevHeuristic: number;
62
+ weightVoteCredits: number;
63
+ weightBlockProduction: number;
64
+ weightInflationCommission: number;
65
+ weightMEVCommission: number;
66
+ weightStakeConcentrationCountry: number;
67
+ weightStakeConcentrationCity: number;
68
+ weightStakeConcentrationASO: number;
69
+ weightStakeConcentrationNode: number;
70
+ basicEligibilityEpochs: number;
71
+ bonusEligibilityExtraEpochs: number;
72
+ maxCommission: number;
73
+ voteCreditsWarning: number;
74
+ voteCreditsLow: number;
75
+ minExternalStake: number;
76
+ minScore: number;
77
+ maxStakeShare: number;
78
+ maxWarnings: number;
79
+ mSolControl: number;
80
+ veMndeControl: number;
81
+ stakeBlocksFromBonus: number;
82
+ concentrationParams: number[];
83
+ };
84
+
85
+ export type Variables = {
86
+ bp_cluster_mean: number;
87
+ bp_cluster_std_dev: number;
88
+ credits_pct_mean: number;
89
+ bp_mean: number;
90
+ commission_inflation_max: number;
91
+ commission_mev: number;
92
+ country_stake_concentration_last: number;
93
+ city_stake_concentration_last: number;
94
+ aso_stake_concentration_last: number;
95
+ node_stake_last: number;
96
+ };
97
+
98
+ export type Scores = Record<string, ScoreDto>
99
+ export type ScoreTooltipBuilder = (validator: AggregatedValidator, clusterInfo: ClusterInfo) => string
100
+
101
+ export type UnstakeHint = {
102
+ vote_account: string;
103
+ marinade_stake: string;
104
+ hints: string[];
105
+ };
106
+
107
+ export type UnstakeHints = {
108
+ unstake_hints: UnstakeHint[];
109
+ };
@@ -0,0 +1,19 @@
1
+ export class RecordDto {
2
+ amount: string | null;
3
+ tokenOwner: string;
4
+ validatorVoteAccount: string;
5
+ }
6
+
7
+ export class veMNDESnapshotDto {
8
+ voteRecordsCreatedAt: string;
9
+ records: RecordDto[];
10
+ }
11
+
12
+ export class mSolSnapshotDto {
13
+ mSolSnapshotCreatedAt: string;
14
+ voteRecordsCreatedAt: string;
15
+ records: RecordDto[];
16
+ }
17
+
18
+ export type Votes = Record<string, number>
19
+
@@ -0,0 +1,35 @@
1
+ import { Votes } from './snapshots.dto';
2
+
3
+ export type StakesConfig = {
4
+ tvl: number
5
+ mSolControl: number
6
+ veMndeControl: number
7
+ stakeBlocksFromBonus: number
8
+ formulaStakeBlockSize: string
9
+ formulaStakeBlocksFromScore: string
10
+ }
11
+
12
+ export type Stake = {
13
+ algoStake: number
14
+ mSolStake: number
15
+ veMndeStake: number
16
+ totalStake: number
17
+ algoStakeFromOverflow: number
18
+ mSolStakeFromOverflow: number
19
+ veMndeStakeFromOverflow: number
20
+ totalStakeFromOverlfow: number
21
+ }
22
+
23
+ export type ProcessedVotesAndTVLs = {
24
+ updatedMSolVotes: Votes;
25
+ updatedVeMndeVotes: Votes;
26
+ mSolTvl: number;
27
+ veMndeTvl: number;
28
+ totalTvl: number;
29
+ };
30
+
31
+ export type StakingVariables = {
32
+ tvl: number;
33
+ }
34
+
35
+ export type Stakes = Record<string, Stake>