From e05ec9bcc4460980ab25e0f801ba21075a5caae9 Mon Sep 17 00:00:00 2001 From: Techno Freak Date: Sat, 9 Dec 2023 19:38:40 +0300 Subject: [PATCH 01/10] feat: add denoms --- pkg/config/config.go | 54 +++++++++++++++++++++++------- pkg/queriers/denom_coefficients.go | 12 ++++--- pkg/queriers/price.go | 39 ++++++++++++--------- 3 files changed, 71 insertions(+), 34 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index b93cd3f..cd255a7 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -2,6 +2,7 @@ package config import ( "fmt" + "github.com/rs/zerolog" "os" "github.com/BurntSushi/toml" @@ -21,18 +22,43 @@ func (v *Validator) Validate() error { return nil } +type DenomInfo struct { + Denom string `toml:"denom"` + DenomCoefficient int64 `default:"1000000"` + DisplayDenom string `toml:"display-denom"` + CoingeckoCurrency string `toml:"coingecko-currency"` + DexScreenerChainID string `toml:"dex-screener-chain-id"` + DexScreenerPair string `toml:"dex-screener-pair"` +} + +func (d *DenomInfo) DisplayWarnings(chain *Chain, logger *zerolog.Logger) { + if d.CoingeckoCurrency == "" { + logger.Warn(). + Str("chain", chain.Name). + Str("denom", d.Denom). + Msg("Coingecko currency not set, denoms won't be displayed correctly.") + } +} + +type DenomInfos []*DenomInfo + +func (d DenomInfos) Find(denom string) *DenomInfo { + for _, info := range d { + if denom == info.Denom { + return info + } + } + + return nil +} + type Chain struct { - Name string `toml:"name"` - LCDEndpoint string `toml:"lcd-endpoint"` - CoingeckoCurrency string `toml:"coingecko-currency"` - DexScreenerChainID string `toml:"dex-screener-chain-id"` - DexScreenerPair string `toml:"dex-screener-pair"` - BaseDenom string `toml:"base-denom"` - Denom string `toml:"denom"` - DenomCoefficient int64 `toml:"denom-coefficient" default:"1000000"` - BechWalletPrefix string `toml:"bech-wallet-prefix"` - Validators []Validator `toml:"validators"` - Queries map[string]bool `toml:"queries"` + Name string `toml:"name"` + LCDEndpoint string `toml:"lcd-endpoint"` + Denoms DenomInfos `toml:"denoms"` + BechWalletPrefix string `toml:"bech-wallet-prefix"` + Validators []Validator `toml:"validators"` + Queries map[string]bool `toml:"queries"` } func (c *Chain) Validate() error { @@ -95,8 +121,10 @@ func (c *Config) GetCoingeckoCurrencies() []string { currencies := []string{} for _, chain := range c.Chains { - if chain.CoingeckoCurrency != "" { - currencies = append(currencies, chain.CoingeckoCurrency) + for _, denom := range chain.Denoms { + if denom.CoingeckoCurrency != "" { + currencies = append(currencies, denom.CoingeckoCurrency) + } } } diff --git a/pkg/queriers/denom_coefficients.go b/pkg/queriers/denom_coefficients.go index 35074cf..2d9c239 100644 --- a/pkg/queriers/denom_coefficients.go +++ b/pkg/queriers/denom_coefficients.go @@ -33,11 +33,13 @@ func (q *DenomCoefficientsQuerier) GetMetrics() ([]prometheus.Collector, []*type ) for _, chain := range q.Config.Chains { - denomCoefficientGauge.With(prometheus.Labels{ - "chain": chain.Name, - "display_denom": chain.Denom, - "denom": chain.BaseDenom, - }).Set(float64(chain.DenomCoefficient)) + for _, denom := range chain.Denoms { + denomCoefficientGauge.With(prometheus.Labels{ + "chain": chain.Name, + "display_denom": denom.DisplayDenom, + "denom": denom.Denom, + }).Set(float64(denom.DenomCoefficient)) + } } return []prometheus.Collector{denomCoefficientGauge}, []*types.QueryInfo{} diff --git a/pkg/queriers/price.go b/pkg/queriers/price.go index 3a21fd5..a42d72d 100644 --- a/pkg/queriers/price.go +++ b/pkg/queriers/price.go @@ -35,19 +35,23 @@ func (q *PriceQuerier) GetMetrics() ([]prometheus.Collector, []*types.QueryInfo) currenciesList := q.Config.GetCoingeckoCurrencies() currenciesRates, query := q.Coingecko.FetchPrices(currenciesList) - currenciesRatesToChains := map[string]float64{} + currenciesRatesToChains := map[string]map[string]float64{} for _, chain := range q.Config.Chains { - // using coingecko response - if rate, ok := currenciesRates[chain.CoingeckoCurrency]; ok { - currenciesRatesToChains[chain.Name] = rate - continue - } + currenciesRatesToChains[chain.Name] = make(map[string]float64) + + for _, denom := range chain.Denoms { + // using coingecko response + if rate, ok := currenciesRates[denom.CoingeckoCurrency]; ok { + currenciesRatesToChains[chain.Name][denom.Denom] = rate + continue + } - // using dexscreener response - if chain.DexScreenerChainID != "" && chain.DexScreenerPair != "" { - rate, err := q.DexScreener.GetCurrency(chain.DexScreenerChainID, chain.DexScreenerPair) - if err == nil { - currenciesRatesToChains[chain.Name] = rate + // using dexscreener response + if denom.DexScreenerChainID != "" && denom.DexScreenerPair != "" { + rate, err := q.DexScreener.GetCurrency(denom.DexScreenerChainID, denom.DexScreenerPair) + if err == nil { + currenciesRatesToChains[chain.Name][denom.Denom] = rate + } } } } @@ -57,13 +61,16 @@ func (q *PriceQuerier) GetMetrics() ([]prometheus.Collector, []*types.QueryInfo) Name: "cosmos_validators_exporter_price", Help: "Price of 1 token in display denom in USD", }, - []string{"chain"}, + []string{"chain", "denom"}, ) - for chain, price := range currenciesRatesToChains { - tokenPriceGauge.With(prometheus.Labels{ - "chain": chain, - }).Set(price) + for chainName, chainPrices := range currenciesRatesToChains { + for denom, price := range chainPrices { + tokenPriceGauge.With(prometheus.Labels{ + "chain": chainName, + "denom": denom, + }).Set(price) + } } return []prometheus.Collector{tokenPriceGauge}, []*types.QueryInfo{&query} From 5a6322569e4398ee00d9ea42d1a11661b76d857e Mon Sep 17 00:00:00 2001 From: Techno Freak Date: Sat, 9 Dec 2023 19:49:17 +0300 Subject: [PATCH 02/10] fix: set default denom-coefficient value --- go.mod | 2 +- go.sum | 4 ++-- pkg/config/config.go | 9 ++++++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 72f736f..6d138de 100644 --- a/go.mod +++ b/go.mod @@ -6,8 +6,8 @@ require ( github.com/BurntSushi/toml v1.1.0 github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce github.com/cosmos/cosmos-sdk v0.46.0 + github.com/creasty/defaults v1.7.0 github.com/google/uuid v1.3.0 - github.com/mcuadros/go-defaults v1.2.0 github.com/prometheus/client_golang v1.12.2 github.com/rs/zerolog v1.27.0 github.com/spf13/cobra v1.5.0 diff --git a/go.sum b/go.sum index 06fd68c..fcbff59 100644 --- a/go.sum +++ b/go.sum @@ -262,6 +262,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creasty/defaults v1.7.0 h1:eNdqZvc5B509z18lD8yc212CAqJNvfT1Jq6L8WowdBA= +github.com/creasty/defaults v1.7.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/daixiang0/gci v0.3.3/go.mod h1:1Xr2bxnQbDxCqqulUOv8qpGqkgRw9RSCGGjEC2LjF8o= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= @@ -750,8 +752,6 @@ github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= -github.com/mcuadros/go-defaults v1.2.0 h1:FODb8WSf0uGaY8elWJAkoLL0Ri6AlZ1bFlenk56oZtc= -github.com/mcuadros/go-defaults v1.2.0/go.mod h1:WEZtHEVIGYVDqkKSWBdWKUVdRyKlMfulPaGDWIVeCWY= github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg= github.com/mgechev/revive v1.2.1/go.mod h1:+Ro3wqY4vakcYNtkBWdZC7dBg1xSB6sp054wWwmeFm0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= diff --git a/pkg/config/config.go b/pkg/config/config.go index cd255a7..e5740f5 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -6,7 +6,7 @@ import ( "os" "github.com/BurntSushi/toml" - "github.com/mcuadros/go-defaults" + "github.com/creasty/defaults" ) type Validator struct { @@ -24,7 +24,7 @@ func (v *Validator) Validate() error { type DenomInfo struct { Denom string `toml:"denom"` - DenomCoefficient int64 `default:"1000000"` + DenomCoefficient int64 `toml:"denom-coefficient "default:"1000000"` DisplayDenom string `toml:"display-denom"` CoingeckoCurrency string `toml:"coingecko-currency"` DexScreenerChainID string `toml:"dex-screener-chain-id"` @@ -144,6 +144,9 @@ func GetConfig(path string) (*Config, error) { return nil, err } - defaults.SetDefaults(&configStruct) + if err = defaults.Set(&configStruct); err != nil { + return nil, err + } + return &configStruct, nil } From 6a0091ceaf6d40704746ebd0c537e51a063d4523 Mon Sep 17 00:00:00 2001 From: Techno Freak Date: Sat, 9 Dec 2023 19:49:47 +0300 Subject: [PATCH 03/10] chore: fixed linting --- .golangci.yml | 1 + pkg/config/config.go | 13 +++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index b713e14..7a06b30 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -51,3 +51,4 @@ linters: - gocyclo - maintidx - deadcode + - depguard diff --git a/pkg/config/config.go b/pkg/config/config.go index e5740f5..58321a5 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -2,9 +2,10 @@ package config import ( "fmt" - "github.com/rs/zerolog" "os" + "github.com/rs/zerolog" + "github.com/BurntSushi/toml" "github.com/creasty/defaults" ) @@ -24,7 +25,7 @@ func (v *Validator) Validate() error { type DenomInfo struct { Denom string `toml:"denom"` - DenomCoefficient int64 `toml:"denom-coefficient "default:"1000000"` + DenomCoefficient int64 `default:"1000000" toml:"denom-coefficient "` DisplayDenom string `toml:"display-denom"` CoingeckoCurrency string `toml:"coingecko-currency"` DexScreenerChainID string `toml:"dex-screener-chain-id"` @@ -93,14 +94,14 @@ func (c *Chain) QueryEnabled(query string) bool { type Config struct { LogConfig LogConfig `toml:"log"` - ListenAddress string `toml:"listen-address" default:":9550"` - Timeout int `toml:"timeout" default:"10"` + ListenAddress string `default:":9550" toml:"listen-address"` + Timeout int `default:"10" toml:"timeout"` Chains []Chain `toml:"chains"` } type LogConfig struct { - LogLevel string `toml:"level" default:"info"` - JSONOutput bool `toml:"json" default:"false"` + LogLevel string `default:"info" toml:"level"` + JSONOutput bool `default:"false" toml:"json"` } func (c *Config) Validate() error { From 571a017fb625c804f956d4980650562b038ee2bb Mon Sep 17 00:00:00 2001 From: Techno Freak Date: Sat, 9 Dec 2023 19:53:09 +0300 Subject: [PATCH 04/10] chore: fixed spacing --- pkg/config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index 58321a5..b1d448a 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -25,7 +25,7 @@ func (v *Validator) Validate() error { type DenomInfo struct { Denom string `toml:"denom"` - DenomCoefficient int64 `default:"1000000" toml:"denom-coefficient "` + DenomCoefficient int64 `default:"1000000" toml:"denom-coefficient"` DisplayDenom string `toml:"display-denom"` CoingeckoCurrency string `toml:"coingecko-currency"` DexScreenerChainID string `toml:"dex-screener-chain-id"` From 3f5891a83c59d0c2000b4f0cb458dac7127c02ec Mon Sep 17 00:00:00 2001 From: Techno Freak Date: Sat, 9 Dec 2023 20:04:25 +0300 Subject: [PATCH 05/10] feat: add base denom gauge --- pkg/config/config.go | 1 + pkg/queriers/denom_coefficients.go | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index b1d448a..b5e02cf 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -56,6 +56,7 @@ func (d DenomInfos) Find(denom string) *DenomInfo { type Chain struct { Name string `toml:"name"` LCDEndpoint string `toml:"lcd-endpoint"` + BaseDenom string `json:"base-denom"` Denoms DenomInfos `toml:"denoms"` BechWalletPrefix string `toml:"bech-wallet-prefix"` Validators []Validator `toml:"validators"` diff --git a/pkg/queriers/denom_coefficients.go b/pkg/queriers/denom_coefficients.go index 2d9c239..fe4216d 100644 --- a/pkg/queriers/denom_coefficients.go +++ b/pkg/queriers/denom_coefficients.go @@ -32,7 +32,22 @@ func (q *DenomCoefficientsQuerier) GetMetrics() ([]prometheus.Collector, []*type []string{"chain", "denom", "display_denom"}, ) + baseDenomGauge := prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "cosmos_validators_exporter_base_denom", + Help: "Base denom info", + }, + []string{"chain", "denom"}, + ) + for _, chain := range q.Config.Chains { + if chain.BaseDenom != "" { + baseDenomGauge.With(prometheus.Labels{ + "chain": chain.Name, + "denom": chain.BaseDenom, + }).Set(float64(1)) + } + for _, denom := range chain.Denoms { denomCoefficientGauge.With(prometheus.Labels{ "chain": chain.Name, @@ -42,5 +57,5 @@ func (q *DenomCoefficientsQuerier) GetMetrics() ([]prometheus.Collector, []*type } } - return []prometheus.Collector{denomCoefficientGauge}, []*types.QueryInfo{} + return []prometheus.Collector{denomCoefficientGauge, baseDenomGauge}, []*types.QueryInfo{} } From a40515f26d4b91aaaa90e9ff4ecec3b8ba5c28fc Mon Sep 17 00:00:00 2001 From: Techno Freak Date: Sat, 9 Dec 2023 20:10:15 +0300 Subject: [PATCH 06/10] chore: fix typo --- pkg/config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index b5e02cf..7a78910 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -56,7 +56,7 @@ func (d DenomInfos) Find(denom string) *DenomInfo { type Chain struct { Name string `toml:"name"` LCDEndpoint string `toml:"lcd-endpoint"` - BaseDenom string `json:"base-denom"` + BaseDenom string `toml:"base-denom"` Denoms DenomInfos `toml:"denoms"` BechWalletPrefix string `toml:"bech-wallet-prefix"` Validators []Validator `toml:"validators"` From 63460f3e5174e248cfd5c02fde9893995caac206 Mon Sep 17 00:00:00 2001 From: Techno Freak Date: Sat, 9 Dec 2023 22:08:18 +0300 Subject: [PATCH 07/10] chore: display warnings if fields are not set and validae denoms --- pkg/app.go | 37 +++++++++++++++++++------------------ pkg/config/config.go | 40 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 20 deletions(-) diff --git a/pkg/app.go b/pkg/app.go index a93ef65..11607d6 100644 --- a/pkg/app.go +++ b/pkg/app.go @@ -9,7 +9,7 @@ import ( "time" "main/pkg/config" - "main/pkg/logger" + loggerPkg "main/pkg/logger" queriersPkg "main/pkg/queriers" "github.com/google/uuid" @@ -27,34 +27,35 @@ type App struct { func NewApp(configPath string) *App { appConfig, err := config.GetConfig(configPath) if err != nil { - logger.GetDefaultLogger().Fatal().Err(err).Msg("Could not load config") + loggerPkg.GetDefaultLogger().Fatal().Err(err).Msg("Could not load config") } if err = appConfig.Validate(); err != nil { - logger.GetDefaultLogger().Fatal().Err(err).Msg("Provided config is invalid!") + loggerPkg.GetDefaultLogger().Fatal().Err(err).Msg("Provided config is invalid!") } - log := logger.GetLogger(appConfig.LogConfig) + logger := loggerPkg.GetLogger(appConfig.LogConfig) + appConfig.DisplayWarnings(logger) - coingecko := coingeckoPkg.NewCoingecko(appConfig, log) - dexScreener := dexScreenerPkg.NewDexScreener(log) + coingecko := coingeckoPkg.NewCoingecko(appConfig, logger) + dexScreener := dexScreenerPkg.NewDexScreener(logger) queriers := []types.Querier{ - queriersPkg.NewCommissionQuerier(log, appConfig), - queriersPkg.NewDelegationsQuerier(log, appConfig), - queriersPkg.NewUnbondsQuerier(log, appConfig), - queriersPkg.NewSelfDelegationsQuerier(log, appConfig), - queriersPkg.NewPriceQuerier(log, appConfig, coingecko, dexScreener), - queriersPkg.NewRewardsQuerier(log, appConfig), - queriersPkg.NewWalletQuerier(log, appConfig), - queriersPkg.NewSlashingParamsQuerier(log, appConfig), - queriersPkg.NewValidatorQuerier(log, appConfig), - queriersPkg.NewDenomCoefficientsQuerier(log, appConfig), - queriersPkg.NewSigningInfoQuerier(log, appConfig), + queriersPkg.NewCommissionQuerier(logger, appConfig), + queriersPkg.NewDelegationsQuerier(logger, appConfig), + queriersPkg.NewUnbondsQuerier(logger, appConfig), + queriersPkg.NewSelfDelegationsQuerier(logger, appConfig), + queriersPkg.NewPriceQuerier(logger, appConfig, coingecko, dexScreener), + queriersPkg.NewRewardsQuerier(logger, appConfig), + queriersPkg.NewWalletQuerier(logger, appConfig), + queriersPkg.NewSlashingParamsQuerier(logger, appConfig), + queriersPkg.NewValidatorQuerier(logger, appConfig), + queriersPkg.NewDenomCoefficientsQuerier(logger, appConfig), + queriersPkg.NewSigningInfoQuerier(logger, appConfig), } return &App{ - Logger: log, + Logger: logger, Config: appConfig, Queriers: queriers, } diff --git a/pkg/config/config.go b/pkg/config/config.go index 7a78910..f43a124 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -32,12 +32,24 @@ type DenomInfo struct { DexScreenerPair string `toml:"dex-screener-pair"` } +func (d *DenomInfo) Validate() error { + if d.Denom == "" { + return fmt.Errorf("empty denom name") + } + + if d.Denom == "" { + return fmt.Errorf("empty display denom name") + } + + return nil +} + func (d *DenomInfo) DisplayWarnings(chain *Chain, logger *zerolog.Logger) { - if d.CoingeckoCurrency == "" { + if d.CoingeckoCurrency == "" && (d.DexScreenerPair == "" || d.DexScreenerChainID == "") { logger.Warn(). Str("chain", chain.Name). Str("denom", d.Denom). - Msg("Coingecko currency not set, denoms won't be displayed correctly.") + Msg("Currency code not set, not fetching exchange rate.") } } @@ -82,9 +94,27 @@ func (c *Chain) Validate() error { } } + for index, denomInfo := range c.Denoms { + if err := denomInfo.Validate(); err != nil { + return fmt.Errorf("error in denom #%d: %s", index, err) + } + } + return nil } +func (c *Chain) DisplayWarnings(logger *zerolog.Logger) { + if c.BaseDenom == "" { + logger.Warn(). + Str("chain", c.Name). + Msg("Base denom is not set") + } + + for _, denom := range c.Denoms { + denom.DisplayWarnings(c, logger) + } +} + func (c *Chain) QueryEnabled(query string) bool { if value, ok := c.Queries[query]; !ok { return true // all queries are enabled by default @@ -119,6 +149,12 @@ func (c *Config) Validate() error { return nil } +func (c *Config) DisplayWarnings(logger *zerolog.Logger) { + for _, chain := range c.Chains { + chain.DisplayWarnings(logger) + } +} + func (c *Config) GetCoingeckoCurrencies() []string { currencies := []string{} From 4b3a304c66087af3e5daec6d47478c0bc0a9e4cb Mon Sep 17 00:00:00 2001 From: Techno Freak Date: Sat, 9 Dec 2023 22:08:40 +0300 Subject: [PATCH 08/10] chore: fixed README --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index 34c1e3d..7c2450b 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ All the metrics provided by cosmos-validators-exporter have the `cosmos_validato When developing, we aimed to only return metrics that are required, and avoid creating metrics that can be computed on Grafana/Prometheus side. This decreases the amount of time series that this exporter will return, but will make writing queries more complex. Here are some examples of queries that we consider useful: - `count(cosmos_validators_exporter_info)` - number of validators monitored -- `sum ((cosmos_validators_exporter_total_delegations) / on (chain) cosmos_validators_exporter_denom_coefficient * on (chain) cosmos_validators_exporter_price)` - total delegated tokens in $ +- `sum((cosmos_validators_exporter_total_delegations) * on (chain) group_left(denom) cosmos_validators_exporter_base_denom / on (chain, denom) cosmos_validators_exporter_denom_coefficient * on (chain, denom) cosmos_validators_exporter_price)` - total delegated tokens in $ - `sum(cosmos_validators_exporter_delegations_count)` - total delegators count - `cosmos_validators_exporter_total_delegations / on (chain) cosmos_validators_exporter_tokens_bonded_total` - voting power percent of your validator - `1 - (cosmos_validators_exporter_missed_blocks / on (chain) cosmos_validators_exporter_missed_blocks_window)` - validator's uptime in % @@ -120,7 +120,3 @@ All configuration is done via the .toml config file, which is passed to the appl ## How can I contribute? Bug reports and feature requests are always welcome! If you want to contribute, feel free to open issues or PRs. - - -## License -[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FQuokkaStake%2Fcosmos-validators-exporter.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2FQuokkaStake%2Fcosmos-validators-exporter?ref=badge_large) \ No newline at end of file From 6d5ca736e9a0f27efe0d99144a657b20a029c7b2 Mon Sep 17 00:00:00 2001 From: Techno Freak Date: Sat, 9 Dec 2023 22:09:33 +0300 Subject: [PATCH 09/10] chore: fixed config example --- config.example.toml | 66 +++++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/config.example.toml b/config.example.toml index 8ce4308..dded5eb 100644 --- a/config.example.toml +++ b/config.example.toml @@ -8,7 +8,7 @@ listen-address = ":9560" # Log level. Change it to "debug" or even trace for more verbosity and debugging. Defaults to "info". level = "debug" # Whether all the logs should be written in JSON instead of a pretty-printed text. Useful if you have -# logging solutions, like ELK. Defaults to false. +# logging solutions, like Elastic stack. Defaults to false. json = false # Per-chain config. @@ -17,29 +17,47 @@ json = false name = "bitsong" # LCD endpoint to query data from. Required. lcd-endpoint = "https://api.bitsong.quokkastake.io" +# Chain's base denom. +# This value is quite useless by itself, but it's exposed in `cosmos_validators_exporter_base_denom` metric, +# which later can be joined with other metrics (such as, total delegated tokens) +# and the price can be calculated based on that. +base-denom = "ubtsg" +# Denoms info. +# Used to 1) be exposed as a standalone metric, and 2) when calculating metric for token price. +# This is an an array of objects with following values: +# 1. coingecko-currency # Coingecko currency, specify it if you want to also get the wallet balance -# in total in USD. -coingecko-currency = "bitsong" +# in total in USD. Optional. +# 2. dex-screener-chain-id and dex-screener-pair. # dexscreener.com's chain ID (usually ""osmosis") and pair (usually pool ID). # Won't be used if coingecko-currency is provided. # Either coingecko-currency or these two params are required for getting token price. -dex-screener-chain-id = "osmosis" -dex-screener-pair = "832" -# The chain's base denom. Only balances with this denom will be used -# to calculate wallet's USD price. -base-denom = "ubtsg" -# The chain's display denom. -denom = "btsg" -# The coefficient you need to multiply base denom to to get 1 token on Coingecko. -# Example: on Cosmos network the base denom is uatom, 1 atom = 1_000_000 uatom -# and 1 atom on Coingecko = $10, and your wallet has 10 atom, or 10_000_000 uatom. -# Then you need to specify the following parameters: -# coingecko-currency = "cosmos-hub" -# base-denom = "uatom" -# denom-coefficient = 1000000 -# and after that, the /metrics endpoint will return your total balance as $100. -# Defaults to 1000000 -denom-coefficient = 1000000 +# 3. denom +# The actual denom value (such as "uatom" for Cosmos Hub or "ibc/xxxxx" for IBC denoms). Required. +# 4. display-denom +# The denom that'll be returned in labels. Required. +# 5. denom-coefficient +# The coefficient you need to multiply base denom to to get 1 token on Coingecko/DexScreener. +# Is exposed by `cosmos_validators_exporter_denom_coefficient` metric. +# Optional, defaults to 1_000_000. +# You can calculate the actual price of something by doing the following: +# 1) taking the actual metric (either with "denom" label, like commission, or joining it with "base-denom" label +# of `cosmos_validators_exporter_base_denom` metric for the chain, which will add the label) +# 2) divide and join it with `cosmos_validators_exporter_denom_coefficient` metric for this chain for this denom +# 3) multiply it with `cosmos_validators_exporter_price` metric for this denom/chain. +# For example, with denom = "uatom", display-denom = "atom", "coingecko-currency" = "cosmos", +# if you have 10 ATOM unclaimed commission, and $ATOM price = 10, here's what'll happen on each step: +# 1) will return a metric with labels/values like this: +# {chain="cosmos",address="cosmosvaloperxxxx",denom="uatom"} 10000000 +# 2) will return a metric like this +# {chain="cosmos",address="cosmosvaloperxxxx",denom="uatom",display-denom="atom"} 10 +# 3) will return a metric like this: +# {chain="cosmos",address="cosmosvaloperxxxx",denom="uatom",display-denom="atom"} 100 +# which you can use to display a worthwhile of your unclaimed commission and use display-denom +# label for legend. +denoms = [ + { denom = "uatom", display-denom = "atom", coingecko-currency = "cosmos", denom-coefficient = 1000000, dex-screener-chain-id = "osmosis", dex-screener-pair-id = "1" }, +] # Bech32 prefix for a wallet address (example: "cosmos" for a Cosmos wallet). If omitted, # the self-delegation metric will not be present. bech-wallet-prefix = "bitsong" @@ -48,6 +66,8 @@ bech-wallet-prefix = "bitsong" # signing-infos metrics (like missed blocks counter). # You can get your consensus-address by running " tendermint show-address" on your validator node, # if you are not using KMS solutions. +# If you are using it to track a consumer chain validator and if you are using the assigned key, +# please make sure to use the consensus address of this chain and not the provider chain one. validators = [ { address = "bitsongvaloper14rvn7anf22e00vj5x3al4w50ns78s7n42rc0ge", consensus-address = "bitsongvalcons16ktzzs4ra4kcw668demahue52zh2xjllwdd6n3" } ] @@ -84,10 +104,10 @@ staking-params = true [[chains]] name = "emoney" lcd-endpoint = "https://api.emoney.quokkastake.io" -coingecko-currency = "e-money" base-denom = "ungm" -denom = "ngm" -bech-wallet-prefix = "emoney" +denoms = [ + { denom = "ungm", display-denom = "ngm", coingecko-currency = "emoney" } +] validators = [ { address = "emoneyvaloper1jk4n79c5gv36972ptnly3rvx5nvn3hl3hgly9g" } ] From 559f7c2b39330c79be8cb38448b071046db543e7 Mon Sep 17 00:00:00 2001 From: Techno Freak Date: Sat, 9 Dec 2023 22:31:26 +0300 Subject: [PATCH 10/10] chore: remove FOSSA --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 7c2450b..268fc4e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ ![Latest release](https://img.shields.io/github/v/release/QuokkaStake/cosmos-validators-exporter) [![Actions Status](https://github.com/QuokkaStake/cosmos-validators-exporter/workflows/test/badge.svg)](https://github.com/QuokkaStake/cosmos-validators-exporter/actions) -[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FQuokkaStake%2Fcosmos-validators-exporter.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2FQuokkaStake%2Fcosmos-validators-exporter?ref=badge_shield) cosmos-validators-exporter is a Prometheus scraper that fetches validators stats from an LCD server exposed by a fullnode.