Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add explorer wallet links #20

Merged
merged 2 commits into from
Dec 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ linters:
- errorlint
- gofumpt
- noctx
- gosec
14 changes: 9 additions & 5 deletions config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,23 @@ 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"]
# List of wallets to monitor. At least 1 is required.
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"
Expand Down
68 changes: 42 additions & 26 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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("<a href='%s'>%s</a>", 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
}
}

Expand All @@ -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"`
}

Expand Down Expand Up @@ -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
}
6 changes: 3 additions & 3 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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!")
Expand All @@ -93,7 +93,7 @@ func TestValidateConfigInvalidChain(t *testing.T) {
t.Parallel()

config := Config{
Chains: []Chain{
Chains: []*Chain{
{
Name: "",
},
Expand All @@ -107,7 +107,7 @@ func TestValidateConfigValidChain(t *testing.T) {
t.Parallel()

config := Config{
Chains: []Chain{
Chains: []*Chain{
{
Name: "chain",
LCDEndpoints: []string{"endpoint"},
Expand Down
2 changes: 1 addition & 1 deletion pagerduty.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
})
}
Expand Down
10 changes: 5 additions & 5 deletions report_generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
10 changes: 5 additions & 5 deletions state_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
}

Expand Down Expand Up @@ -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,
Expand All @@ -75,7 +75,7 @@ func (g *StateGenerator) GetState(oldState State) State {
}

state.SetVote(
chain,
*chain,
proposal,
wallet,
proposalVote,
Expand Down
4 changes: 2 additions & 2 deletions templates/telegram/not_voted.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
🔴 <strong>Wallet {{ .Wallet }} hasn't voted on proposal {{ .ProposalID }} on {{ .Chain.GetName }}</strong>
🔴 <strong> Wallet {{ .Chain.GetWalletLink .Wallet }} hasn't voted on proposal {{ .ProposalID }} on {{ .Chain.GetName }} </strong>
{{ .ProposalTitle }}

Voting ends at: {{ .GetProposalTime }} (in {{ .GetProposalTimeLeft }})

{{ if .Chain.KeplrName }}<a href='{{ .Chain.GetKeplrLink .ProposalID }}'>Keplr</a>{{ end }}
{{ range .Chain.GetExplorerProposalsLinks .ProposalID }}<a href='{{ .Link }} '>{{ .Name }}</a>
{{ range .Chain.GetExplorerProposalsLinks .ProposalID }}<a href='{{ .Href }} '>{{ .Name }}</a>
{{ end }}
Sent by <a href='https://github.com/freak12techno/cosmos-proposals-checker'>cosmos-proposals-checker.</a>
7 changes: 4 additions & 3 deletions templates/telegram/proposals.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{{ range .ChainInfos }}
{{ $chain := .Chain }}
<strong>{{ .Chain.GetName }}</strong>
{{- if .HasProposalsError }}
❌ Error quering for proposals: {{ .ProposalsError }}
Expand All @@ -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 }}
Expand Down
2 changes: 1 addition & 1 deletion templates/telegram/revoted.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
↔️ <strong>Wallet {{ .Wallet }} has changed its vote on proposal {{ .ProposalID }} on {{ .Chain.GetName }}</strong>
↔️ <strong>Wallet {{ .Chain.GetWalletLink .Wallet }} has changed its vote on proposal {{ .ProposalID }} on {{ .Chain.GetName }}</strong>
{{ .ProposalTitle }}

Vote: {{ .GetVote }}
Expand Down
2 changes: 1 addition & 1 deletion templates/telegram/voted.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
✅ <strong>Wallet {{ .Wallet }} has voted on proposal {{ .ProposalID }} on {{ .Chain.GetName }}</strong>
✅ <strong>Wallet {{ .Chain.GetWalletLink .Wallet }} has voted on proposal {{ .ProposalID }} on {{ .Chain.GetName }}</strong>
{{ .ProposalTitle }}

Vote: {{ .GetVote }}
Expand Down
13 changes: 11 additions & 2 deletions types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"fmt"
"time"
)

Expand Down Expand Up @@ -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("<a href='%s'>%s</a>", l.Href, l.Name)
}

type Mute struct {
Expand Down