From d9a2671e63e1da1e03edb90283567e1afe9c627a Mon Sep 17 00:00:00 2001 From: Techno Freak Date: Sun, 11 Dec 2022 22:14:14 +0300 Subject: [PATCH 1/2] feat: add explorer wallet links --- config.example.toml | 14 ++++--- config.go | 68 +++++++++++++++++++------------ config_test.go | 6 +-- pagerduty.go | 2 +- report_generator_test.go | 10 ++--- state_generator.go | 10 ++--- templates/telegram/not_voted.html | 4 +- templates/telegram/proposals.html | 7 ++-- templates/telegram/revoted.html | 2 +- templates/telegram/voted.html | 2 +- types.go | 13 +++++- 11 files changed, 84 insertions(+), 54 deletions(-) diff --git a/config.example.toml b/config.example.toml index 07c641d..81f07ec 100644 --- a/config.example.toml +++ b/config.example.toml @@ -21,12 +21,8 @@ name = "bitsong" pretty-name = "Bitsong" # Chain name in Keplr wallet, to generate links to a proposal. Optional. keplr-name = "bitsong" -# Mintscan prefix, to generate links to a proposal. Optional. +# Mintscan prefix, to generate links to a proposal/wallet. Optional. mintscan-prefix = "bitsong" -# A pattern for proposal link for explorer, if there's no Mintscan support -# for the chain, but there is a custom explorer. %s is replaced by the proposal ID. -# Also optional. -explorer-link-pattern = "https://explorebitsong.com/bitsong/proposals/%s" # List of LCD endpoints to get data from. At least 1 is required. You can use # multiple LCD endpoints, in case a single one fails. lcd-endpoints = ["https://lcd-bitsong-app.cosmostation.io"] @@ -34,6 +30,14 @@ lcd-endpoints = ["https://lcd-bitsong-app.cosmostation.io"] wallets = [ "bitsong14rvn7anf22e00vj5x3al4w50ns78s7n4t8yxcy" ] +# Custom explorer links patterns. They are overridden if mintscan-prefix is specified. +[chains.explorer] +# A pattern for proposal link for explorer, if there's no Mintscan support +# for the chain, but there is a custom explorer. %s is replaced by the proposal ID. +# Also optional. +proposal-link-pattern = "https://mintscan.io/bitsong/proposals/%s" +# A pattern for wallet links for the explorer. Also optional. +wallet-link-pattern = "https://mintscan.io/bitsong/account/%s" [[chains]] name = "sentinel" diff --git a/config.go b/config.go index 0444c77..84398b3 100644 --- a/config.go +++ b/config.go @@ -2,20 +2,26 @@ package main import ( "fmt" + "html/template" "os" "github.com/BurntSushi/toml" "github.com/mcuadros/go-defaults" ) +type Explorer struct { + ProposalLinkPattern string `toml:"proposal-link-pattern"` + WalletLinkPattern string `toml:"wallet-link-pattern"` +} + type Chain struct { - Name string `toml:"name"` - PrettyName string `toml:"pretty-name"` - KeplrName string `toml:"keplr-name"` - LCDEndpoints []string `toml:"lcd-endpoints"` - Wallets []string `toml:"wallets"` - MintscanPrefix string `toml:"mintscan-prefix"` - ExplorerLinkPattern string `toml:"explorer-link-pattern"` + Name string `toml:"name"` + PrettyName string `toml:"pretty-name"` + KeplrName string `toml:"keplr-name"` + LCDEndpoints []string `toml:"lcd-endpoints"` + Wallets []string `toml:"wallets"` + MintscanPrefix string `toml:"mintscan-prefix"` + Explorer *Explorer `toml:"explorer"` } func (c *Chain) Validate() error { @@ -46,34 +52,34 @@ func (c Chain) GetKeplrLink(proposalID string) string { return fmt.Sprintf("https://wallet.keplr.app/#/%s/governance?detailId=%s", c.KeplrName, proposalID) } -func (c Chain) GetExplorerProposalsLinks(proposalID string) []ExplorerLink { - if c.MintscanPrefix == "" { - return []ExplorerLink{} +func (c Chain) GetExplorerProposalsLinks(proposalID string) []Link { + if c.Explorer == nil || c.Explorer.ProposalLinkPattern == "" { + return []Link{} } - links := []ExplorerLink{ + return []Link{ { - Name: "Mintscan", - Link: fmt.Sprintf("https://mintscan.io/%s/proposals/%s", c.MintscanPrefix, proposalID), + Name: "Explorer", + Href: fmt.Sprintf(c.Explorer.ProposalLinkPattern, proposalID), }, } +} - if c.ExplorerLinkPattern != "" { - links = append(links, ExplorerLink{ - Name: "Explorer", - Link: fmt.Sprintf(c.ExplorerLinkPattern, proposalID), - }) +func (c Chain) GetWalletLink(wallet string) template.HTML { + if c.Explorer == nil || c.Explorer.WalletLinkPattern == "" { + return template.HTML(wallet) } - return links + link := fmt.Sprintf(c.Explorer.WalletLinkPattern, wallet) + return template.HTML(fmt.Sprintf("%s", link, wallet)) } -type Chains []Chain +type Chains []*Chain func (c Chains) FindByName(name string) *Chain { for _, chain := range c { if chain.Name == name { - return &chain + return chain } } @@ -86,7 +92,7 @@ type Config struct { LogConfig LogConfig `toml:"log"` StatePath string `toml:"state-path"` MutesPath string `toml:"mutes-path"` - Chains []Chain `toml:"chains"` + Chains Chains `toml:"chains"` Interval int64 `toml:"interval" default:"3600"` } @@ -127,11 +133,21 @@ func GetConfig(path string) (*Config, error) { configString := string(configBytes) - configStruct := Config{} - if _, err = toml.Decode(configString, &configStruct); err != nil { + configStruct := &Config{} + if _, err = toml.Decode(configString, configStruct); err != nil { return nil, err } - defaults.SetDefaults(&configStruct) - return &configStruct, nil + defaults.SetDefaults(configStruct) + + for _, chain := range configStruct.Chains { + if chain.MintscanPrefix != "" { + chain.Explorer = &Explorer{ + ProposalLinkPattern: fmt.Sprintf("https://mintscan.io/%s/proposals/%%s", chain.MintscanPrefix), + WalletLinkPattern: fmt.Sprintf("https://mintscan.io/%s/account/%%s", chain.MintscanPrefix), + } + } + } + + return configStruct, nil } diff --git a/config_test.go b/config_test.go index 617ef4e..3054ed7 100644 --- a/config_test.go +++ b/config_test.go @@ -83,7 +83,7 @@ func TestValidateConfigNoChains(t *testing.T) { t.Parallel() config := Config{ - Chains: []Chain{}, + Chains: []*Chain{}, } err := config.Validate() assert.NotEqual(t, err, nil, "Error should be presented!") @@ -93,7 +93,7 @@ func TestValidateConfigInvalidChain(t *testing.T) { t.Parallel() config := Config{ - Chains: []Chain{ + Chains: []*Chain{ { Name: "", }, @@ -107,7 +107,7 @@ func TestValidateConfigValidChain(t *testing.T) { t.Parallel() config := Config{ - Chains: []Chain{ + Chains: []*Chain{ { Name: "chain", LCDEndpoints: []string{"endpoint"}, diff --git a/pagerduty.go b/pagerduty.go index 8f88bf7..00aa20d 100644 --- a/pagerduty.go +++ b/pagerduty.go @@ -74,7 +74,7 @@ func (r *PagerDutyReporter) NewPagerDutyAlertFromReportEntry(e ReportEntry) Page explorerLinks := e.Chain.GetExplorerProposalsLinks(e.ProposalID) for _, link := range explorerLinks { links = append(links, PagerDutyLink{ - Href: link.Link, + Href: link.Href, Text: link.Name, }) } diff --git a/report_generator_test.go b/report_generator_test.go index bdd5adb..352993a 100644 --- a/report_generator_test.go +++ b/report_generator_test.go @@ -21,7 +21,7 @@ func TestReportGeneratorWithProposalError(t *testing.T) { } generator := NewReportGenerator(stateManager, GetDefaultLogger(), Chains{ - Chain{Name: "chain"}, + &Chain{Name: "chain"}, }) report := generator.GenerateReport(oldState, newState) @@ -56,7 +56,7 @@ func TestReportGeneratorWithVoteError(t *testing.T) { } generator := NewReportGenerator(stateManager, GetDefaultLogger(), Chains{ - Chain{Name: "chain"}, + &Chain{Name: "chain"}, }) report := generator.GenerateReport(oldState, newState) @@ -89,7 +89,7 @@ func TestReportGeneratorWithNotVoted(t *testing.T) { } generator := NewReportGenerator(stateManager, GetDefaultLogger(), Chains{ - Chain{Name: "chain"}, + &Chain{Name: "chain"}, }) report := generator.GenerateReport(oldState, newState) @@ -141,7 +141,7 @@ func TestReportGeneratorWithVoted(t *testing.T) { } generator := NewReportGenerator(stateManager, GetDefaultLogger(), Chains{ - Chain{Name: "chain"}, + &Chain{Name: "chain"}, }) report := generator.GenerateReport(oldState, newState) @@ -197,7 +197,7 @@ func TestReportGeneratorWithRevoted(t *testing.T) { } generator := NewReportGenerator(stateManager, GetDefaultLogger(), Chains{ - Chain{Name: "chain"}, + &Chain{Name: "chain"}, }) report := generator.GenerateReport(oldState, newState) diff --git a/state_generator.go b/state_generator.go index ec31968..e4256fa 100644 --- a/state_generator.go +++ b/state_generator.go @@ -6,10 +6,10 @@ import ( type StateGenerator struct { Logger zerolog.Logger - Chains []Chain + Chains Chains } -func NewStateGenerator(logger *zerolog.Logger, chains []Chain) *StateGenerator { +func NewStateGenerator(logger *zerolog.Logger, chains Chains) *StateGenerator { return &StateGenerator{ Logger: logger.With().Str("component", "state_generator").Logger(), Chains: chains, @@ -27,7 +27,7 @@ func (g *StateGenerator) GetState(oldState State) State { proposals, err := rpc.GetAllProposals() if err != nil { g.Logger.Warn().Err(err).Msg("Error processing proposals") - state.SetChainProposalsError(chain, err) + state.SetChainProposalsError(*chain, err) continue } @@ -57,7 +57,7 @@ func (g *StateGenerator) GetState(oldState State) State { Msg("Wallet has voted and there's no vote in the new state - using old vote") state.SetVote( - chain, + *chain, proposal, wallet, oldVote, @@ -75,7 +75,7 @@ func (g *StateGenerator) GetState(oldState State) State { } state.SetVote( - chain, + *chain, proposal, wallet, proposalVote, diff --git a/templates/telegram/not_voted.html b/templates/telegram/not_voted.html index 4402633..a26feb5 100644 --- a/templates/telegram/not_voted.html +++ b/templates/telegram/not_voted.html @@ -1,9 +1,9 @@ -🔴 Wallet {{ .Wallet }} hasn't voted on proposal {{ .ProposalID }} on {{ .Chain.GetName }} +🔴 Wallet {{ .Chain.GetWalletLink .Wallet }} hasn't voted on proposal {{ .ProposalID }} on {{ .Chain.GetName }} {{ .ProposalTitle }} Voting ends at: {{ .GetProposalTime }} (in {{ .GetProposalTimeLeft }}) {{ if .Chain.KeplrName }}Keplr{{ end }} -{{ range .Chain.GetExplorerProposalsLinks .ProposalID }}{{ .Name }} +{{ range .Chain.GetExplorerProposalsLinks .ProposalID }}{{ .Name }} {{ end }} Sent by cosmos-proposals-checker. \ No newline at end of file diff --git a/templates/telegram/proposals.html b/templates/telegram/proposals.html index 451b6ec..364b978 100644 --- a/templates/telegram/proposals.html +++ b/templates/telegram/proposals.html @@ -1,4 +1,5 @@ {{ range .ChainInfos }} +{{ $chain := .Chain }} {{ .Chain.GetName }} {{- if .HasProposalsError }} ❌ Error quering for proposals: {{ .ProposalsError }} @@ -7,11 +8,11 @@ Proposal #{{ .Proposal.ProposalID }}: {{ .Proposal.Content.Title }} {{- range $wallet, $vote := .Votes }} {{- if $vote.IsError }} -❌ Wallet {{ $wallet }} - error querying: {{ $vote.Error }} +❌ Wallet {{ $chain.GetWalletLink $wallet }} - error querying: {{ $vote.Error }} {{- else if $vote.HasVoted }} -✅ Wallet {{ $wallet }} - voted: {{ $vote.Vote.ResolveVote }} +✅ Wallet {{ $chain.GetWalletLink $wallet }} - voted: {{ $vote.Vote.ResolveVote }} {{- else }} -🔴 Wallet {{ $wallet }} - not voted +🔴 Wallet {{ $chain.GetWalletLink $wallet }} - not voted {{- end }} {{- end }} {{ end }} diff --git a/templates/telegram/revoted.html b/templates/telegram/revoted.html index 8c9abcb..32d3493 100644 --- a/templates/telegram/revoted.html +++ b/templates/telegram/revoted.html @@ -1,4 +1,4 @@ -↔️ Wallet {{ .Wallet }} has changed its vote on proposal {{ .ProposalID }} on {{ .Chain.GetName }} +↔️ Wallet {{ .Chain.GetWalletLink .Wallet }} has changed its vote on proposal {{ .ProposalID }} on {{ .Chain.GetName }} {{ .ProposalTitle }} Vote: {{ .GetVote }} diff --git a/templates/telegram/voted.html b/templates/telegram/voted.html index a5b2e67..0d742f0 100644 --- a/templates/telegram/voted.html +++ b/templates/telegram/voted.html @@ -1,4 +1,4 @@ -✅ Wallet {{ .Wallet }} has voted on proposal {{ .ProposalID }} on {{ .Chain.GetName }} +✅ Wallet {{ .Chain.GetWalletLink .Wallet }} has voted on proposal {{ .ProposalID }} on {{ .Chain.GetName }} {{ .ProposalTitle }} Vote: {{ .GetVote }} diff --git a/types.go b/types.go index 88b550e..c84451a 100644 --- a/types.go +++ b/types.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "time" ) @@ -121,9 +122,17 @@ type Reporter interface { Name() string } -type ExplorerLink struct { +type Link struct { Name string - Link string + Href string +} + +func (l Link) Serialize() string { + if l.Href == "" { + return l.Name + } + + return fmt.Sprintf("%s", l.Href, l.Name) } type Mute struct { From c08e37a5da687fc211572a2353d41c1ea2f18745 Mon Sep 17 00:00:00 2001 From: Techno Freak Date: Sun, 11 Dec 2022 22:16:12 +0300 Subject: [PATCH 2/2] chore: removed gosec --- .golangci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.golangci.yml b/.golangci.yml index 716d4d1..6b61042 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -36,3 +36,4 @@ linters: - errorlint - gofumpt - noctx + - gosec