diff --git a/pkg/data/manager.go b/pkg/data/manager.go index c74d667..a99149b 100644 --- a/pkg/data/manager.go +++ b/pkg/data/manager.go @@ -4,9 +4,7 @@ import ( "fmt" "main/pkg/fetchers/cosmos" "main/pkg/types" - "strconv" "sync" - "time" "github.com/rs/zerolog" ) @@ -61,104 +59,6 @@ func (m *Manager) GetTallies() (map[string]types.ChainTallyInfos, error) { return tallies, nil } -func (m *Manager) GetChainParams(chain *types.Chain) (*types.ChainWithVotingParams, []error) { - var wg sync.WaitGroup - var mutex sync.Mutex - - errors := make([]error, 0) - params := &types.ParamsResponse{} - - rpc := cosmos.NewRPC(chain, m.Logger) - - wg.Add(3) - - go func() { - defer wg.Done() - - votingParams, err := rpc.GetGovParams("voting") - mutex.Lock() - defer mutex.Unlock() - - if err != nil { - errors = append(errors, err) - return - } - - params.VotingParams = votingParams.VotingParams - }() - - go func() { - defer wg.Done() - - depositParams, err := rpc.GetGovParams("deposit") - mutex.Lock() - defer mutex.Unlock() - - if err != nil { - errors = append(errors, err) - return - } - - params.DepositParams = depositParams.DepositParams - }() - - go func() { - defer wg.Done() - - tallyingParams, err := rpc.GetGovParams("tallying") - mutex.Lock() - defer mutex.Unlock() - - if err != nil { - errors = append(errors, err) - return - } - - params.TallyParams = tallyingParams.TallyParams - }() - - wg.Wait() - - if len(errors) > 0 { - return nil, errors - } - - quorum, err := strconv.ParseFloat(params.TallyParams.Quorum, 64) - if err != nil { - return nil, []error{err} - } - - threshold, err := strconv.ParseFloat(params.TallyParams.Threshold, 64) - if err != nil { - return nil, []error{err} - } - - vetoThreshold, err := strconv.ParseFloat(params.TallyParams.VetoThreshold, 64) - if err != nil { - return nil, []error{err} - } - - votingPeriod, err := time.ParseDuration(params.VotingParams.VotingPeriod) - if err != nil { - return nil, []error{err} - } - - maxDepositPeriod, err := time.ParseDuration(params.DepositParams.MaxDepositPeriod) - if err != nil { - return nil, []error{err} - } - - return &types.ChainWithVotingParams{ - Chain: chain, - VotingPeriod: votingPeriod, - MaxDepositPeriod: maxDepositPeriod, - MinDepositAmount: params.DepositParams.MinDepositAmount, - Quorum: quorum, - Threshold: threshold, - VetoThreshold: vetoThreshold, - }, nil -} - func (m *Manager) GetParams() (map[string]types.ChainWithVotingParams, error) { var wg sync.WaitGroup var mutex sync.Mutex @@ -172,7 +72,9 @@ func (m *Manager) GetParams() (map[string]types.ChainWithVotingParams, error) { go func(chain *types.Chain) { defer wg.Done() - chainParams, errs := m.GetChainParams(chain) + rpc := cosmos.NewRPC(chain, m.Logger) + + chainParams, errs := rpc.GetChainParams() mutex.Lock() defer mutex.Unlock() diff --git a/pkg/fetchers/cosmos/fetcher.go b/pkg/fetchers/cosmos/fetcher.go index 1dba776..f66377d 100644 --- a/pkg/fetchers/cosmos/fetcher.go +++ b/pkg/fetchers/cosmos/fetcher.go @@ -2,7 +2,6 @@ package cosmos import ( "encoding/json" - "fmt" "main/pkg/fetchers/cosmos/responses" "net/http" "time" @@ -38,23 +37,6 @@ func (rpc *RPC) GetAllProposals() ([]types.Proposal, *types.QueryError) { return rpc.GetAllV1beta1Proposals() } -func (rpc *RPC) GetTally(proposal string) (*types.Tally, *types.QueryError) { - url := fmt.Sprintf( - "/cosmos/gov/v1beta1/proposals/%s/tally", - proposal, - ) - - var tally responses.TallyRPCResponse - if errs := rpc.Get(url, &tally); len(errs) > 0 { - return nil, &types.QueryError{ - QueryError: nil, - NodeErrors: errs, - } - } - - return tally.Tally.ToTally(), nil -} - func (rpc *RPC) GetStakingPool() (*responses.PoolRPCResponse, *types.QueryError) { url := "/cosmos/staking/v1beta1/pool" @@ -69,20 +51,6 @@ func (rpc *RPC) GetStakingPool() (*responses.PoolRPCResponse, *types.QueryError) return &pool, nil } -func (rpc *RPC) GetGovParams(paramsType string) (*types.ParamsResponse, *types.QueryError) { - url := fmt.Sprintf("/cosmos/gov/v1beta1/params/%s", paramsType) - - var pool types.ParamsResponse - if errs := rpc.Get(url, &pool); len(errs) > 0 { - return nil, &types.QueryError{ - QueryError: nil, - NodeErrors: errs, - } - } - - return &pool, nil -} - func (rpc *RPC) Get(url string, target interface{}) []types.NodeError { nodeErrors := make([]types.NodeError, len(rpc.URLs)) diff --git a/pkg/fetchers/cosmos/params.go b/pkg/fetchers/cosmos/params.go new file mode 100644 index 0000000..21d2674 --- /dev/null +++ b/pkg/fetchers/cosmos/params.go @@ -0,0 +1,85 @@ +package cosmos + +import ( + "fmt" + "main/pkg/fetchers/cosmos/responses" + "main/pkg/types" + "sync" +) + +func (rpc *RPC) GetGovParams(paramsType string) (*responses.ParamsResponse, *types.QueryError) { + url := fmt.Sprintf("/cosmos/gov/v1beta1/params/%s", paramsType) + + var params responses.ParamsResponse + if errs := rpc.Get(url, ¶ms); len(errs) > 0 { + return nil, &types.QueryError{ + QueryError: nil, + NodeErrors: errs, + } + } + + return ¶ms, nil +} + +func (rpc *RPC) GetChainParams() (*types.ChainWithVotingParams, []error) { + var wg sync.WaitGroup + var mutex sync.Mutex + + errors := make([]error, 0) + params := &responses.ParamsResponse{} + + wg.Add(3) + + go func() { + defer wg.Done() + + votingParams, err := rpc.GetGovParams("voting") + mutex.Lock() + defer mutex.Unlock() + + if err != nil { + errors = append(errors, err) + return + } + + params.VotingParams = votingParams.VotingParams + }() + + go func() { + defer wg.Done() + + depositParams, err := rpc.GetGovParams("deposit") + mutex.Lock() + defer mutex.Unlock() + + if err != nil { + errors = append(errors, err) + return + } + + params.DepositParams = depositParams.DepositParams + }() + + go func() { + defer wg.Done() + + tallyingParams, err := rpc.GetGovParams("tallying") + mutex.Lock() + defer mutex.Unlock() + + if err != nil { + errors = append(errors, err) + return + } + + params.TallyParams = tallyingParams.TallyParams + }() + + wg.Wait() + + if len(errors) > 0 { + return nil, errors + } + + return params.ToParams(rpc.ChainConfig) +} diff --git a/pkg/fetchers/cosmos/responses/params.go b/pkg/fetchers/cosmos/responses/params.go new file mode 100644 index 0000000..e9c9bd0 --- /dev/null +++ b/pkg/fetchers/cosmos/responses/params.go @@ -0,0 +1,76 @@ +package responses + +import ( + "main/pkg/types" + "main/pkg/utils" + "strconv" + "time" +) + +type ParamsResponse struct { + VotingParams VotingParams `json:"voting_params"` + DepositParams DepositParams `json:"deposit_params"` + TallyParams TallyParams `json:"tally_params"` +} + +type VotingParams struct { + VotingPeriod string `json:"voting_period"` +} + +type DepositParams struct { + MinDepositAmount []Amount `json:"min_deposit"` + MaxDepositPeriod string `json:"max_deposit_period"` +} + +type Amount struct { + Denom string `json:"denom"` + Amount string `json:"amount"` +} + +type TallyParams struct { + Quorum string `json:"quorum"` + Threshold string `json:"threshold"` + VetoThreshold string `json:"veto_threshold"` +} + +func (params ParamsResponse) ToParams(chain *types.Chain) (*types.ChainWithVotingParams, []error) { + quorum, err := strconv.ParseFloat(params.TallyParams.Quorum, 64) + if err != nil { + return nil, []error{err} + } + + threshold, err := strconv.ParseFloat(params.TallyParams.Threshold, 64) + if err != nil { + return nil, []error{err} + } + + vetoThreshold, err := strconv.ParseFloat(params.TallyParams.VetoThreshold, 64) + if err != nil { + return nil, []error{err} + } + + votingPeriod, err := time.ParseDuration(params.VotingParams.VotingPeriod) + if err != nil { + return nil, []error{err} + } + + maxDepositPeriod, err := time.ParseDuration(params.DepositParams.MaxDepositPeriod) + if err != nil { + return nil, []error{err} + } + + return &types.ChainWithVotingParams{ + Chain: chain, + VotingPeriod: votingPeriod, + MaxDepositPeriod: maxDepositPeriod, + MinDepositAmount: utils.Map(params.DepositParams.MinDepositAmount, func(amount Amount) types.Amount { + return types.Amount{ + Denom: amount.Denom, + Amount: amount.Amount, + } + }), + Quorum: quorum, + Threshold: threshold, + VetoThreshold: vetoThreshold, + }, nil +} diff --git a/pkg/fetchers/cosmos/responses/vote.go b/pkg/fetchers/cosmos/responses/vote.go index eb7a12e..998142c 100644 --- a/pkg/fetchers/cosmos/responses/vote.go +++ b/pkg/fetchers/cosmos/responses/vote.go @@ -30,6 +30,13 @@ func (v VoteRPCResponse) IsError() bool { } func (v VoteRPCResponse) ToVote() (*types.Vote, error) { + votesMap := map[string]string{ + "VOTE_OPTION_YES": "Yes", + "VOTE_OPTION_ABSTAIN": "Abstain", + "VOTE_OPTION_NO": "No", + "VOTE_OPTION_NO_WITH_VETO": "No with veto", + } + var options []types.VoteOption if len(v.Vote.Options) > 0 { @@ -41,15 +48,26 @@ func (v VoteRPCResponse) ToVote() (*types.Vote, error) { return nil, err } + voteOption, found := votesMap[option.Option] + if !found { + voteOption = option.Option + } + options[index] = types.VoteOption{ - Option: types.VoteType(option.Option), + Option: voteOption, Weight: weight, } } } else { options = make([]types.VoteOption, 1) + + voteOption, found := votesMap[v.Vote.Option] + if !found { + voteOption = v.Vote.Option + } + options[0] = types.VoteOption{ - Option: types.VoteType(v.Vote.Option), + Option: voteOption, Weight: 1, } } diff --git a/pkg/fetchers/cosmos/tally.go b/pkg/fetchers/cosmos/tally.go index bcd485f..83c95e5 100644 --- a/pkg/fetchers/cosmos/tally.go +++ b/pkg/fetchers/cosmos/tally.go @@ -2,12 +2,30 @@ package cosmos import ( "fmt" + "main/pkg/fetchers/cosmos/responses" "main/pkg/types" "sync" "cosmossdk.io/math" ) +func (rpc *RPC) GetTally(proposal string) (*types.Tally, *types.QueryError) { + url := fmt.Sprintf( + "/cosmos/gov/v1beta1/proposals/%s/tally", + proposal, + ) + + var tally responses.TallyRPCResponse + if errs := rpc.Get(url, &tally); len(errs) > 0 { + return nil, &types.QueryError{ + QueryError: nil, + NodeErrors: errs, + } + } + + return tally.Tally.ToTally(), nil +} + func (rpc *RPC) GetTallies() (types.ChainTallyInfos, error) { var wg sync.WaitGroup var mutex sync.Mutex diff --git a/pkg/mutes/manager.go b/pkg/mutes/manager.go index b1ad2f1..9b726a5 100644 --- a/pkg/mutes/manager.go +++ b/pkg/mutes/manager.go @@ -72,8 +72,3 @@ func (m *Manager) AddMute(mute *Mute) { m.Mutes.AddMute(mute) m.Save() } - -func (m *Manager) DeleteMute(chain string, proposalID string) { - m.Mutes.DeleteMute(chain, proposalID) - m.Save() -} diff --git a/pkg/mutes/mutes.go b/pkg/mutes/mutes.go index ba6c170..956eba7 100644 --- a/pkg/mutes/mutes.go +++ b/pkg/mutes/mutes.go @@ -55,21 +55,3 @@ func (m *Mutes) AddMute(mute *Mute) { return !m.IsExpired() }) } - -func (m *Mutes) DeleteMute(chain string, proposalID string) bool { - for index, mute := range m.Mutes { - if mute.Chain == chain && mute.ProposalID == proposalID { - m.Mutes = append(m.Mutes[:index], m.Mutes[index+1:]...) - m.Mutes = utils.Filter(m.Mutes, func(m *Mute) bool { - return !m.IsExpired() - }) - return true - } - } - - m.Mutes = utils.Filter(m.Mutes, func(m *Mute) bool { - return !m.IsExpired() - }) - - return false -} diff --git a/pkg/mutes/mutes_test.go b/pkg/mutes/mutes_test.go index 71ab1fc..bc84c61 100644 --- a/pkg/mutes/mutes_test.go +++ b/pkg/mutes/mutes_test.go @@ -84,17 +84,3 @@ func TestMutesAddsMute(t *testing.T) { assert.Len(t, mutes.Mutes, 1, "There should be 1 mute!") assert.Equal(t, "chain2", mutes.Mutes[0].Chain, "Chain name should match!") } - -func TestMutesDeletesMute(t *testing.T) { - t.Parallel() - - mutes := Mutes{ - Mutes: []*Mute{ - {Chain: "chain1", Expires: time.Now().Add(-time.Hour)}, - }, - } - - mutes.AddMute(&Mute{Chain: "chain2", Expires: time.Now().Add(time.Hour)}) - assert.Len(t, mutes.Mutes, 1, "There should be 1 mute!") - assert.Equal(t, "chain2", mutes.Mutes[0].Chain, "Chain name should match!") -} diff --git a/pkg/types/chain_test.go b/pkg/types/chain_test.go new file mode 100644 index 0000000..66e6e87 --- /dev/null +++ b/pkg/types/chain_test.go @@ -0,0 +1,127 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestWalletAddressOrAliasWithoutAlias(t *testing.T) { + t.Parallel() + + wallet := Wallet{Address: "test"} + assert.Equal(t, "test", wallet.AddressOrAlias(), "Wrong value!") +} + +func TestWalletAddressOrAliasWithAlias(t *testing.T) { + t.Parallel() + + wallet := Wallet{Address: "test", Alias: "alias"} + assert.Equal(t, "alias", wallet.AddressOrAlias(), "Wrong value!") +} + +func TestFindChainByNameIfPresent(t *testing.T) { + t.Parallel() + + chains := Chains{ + {Name: "chain1"}, + {Name: "chain2"}, + } + + chain := chains.FindByName("chain2") + assert.NotNil(t, chain, "Chain should be presented!") +} + +func TestFindChainByNameIfNotPresent(t *testing.T) { + t.Parallel() + + chains := Chains{ + {Name: "chain1"}, + {Name: "chain2"}, + } + + chain := chains.FindByName("chain3") + assert.Nil(t, chain, "Chain should not be presented!") +} + +func TestGetLinksEmpty(t *testing.T) { + t.Parallel() + + chain := Chain{} + links := chain.GetExplorerProposalsLinks("test") + + assert.Empty(t, links, "Expected 0 links") +} + +func TestGetLinksPresent(t *testing.T) { + t.Parallel() + + chain := Chain{ + KeplrName: "chain", + Explorer: &Explorer{ + ProposalLinkPattern: "example.com/proposal/%s", + }, + } + links := chain.GetExplorerProposalsLinks("test") + + assert.Len(t, links, 2, "Expected 2 links") + assert.Equal(t, "Keplr", links[0].Name, "Expected Keplr link") + assert.Equal(t, "https://wallet.keplr.app/#/chain/governance?detailId=test", links[0].Href, "Wrong Keplr link") + assert.Equal(t, "Explorer", links[1].Name, "Expected Explorer link") + assert.Equal(t, "example.com/proposal/test", links[1].Href, "Wrong explorer link") +} + +func TestGetExplorerProposalLinkWithoutExplorer(t *testing.T) { + t.Parallel() + + chain := Chain{} + proposal := Proposal{ID: "ID", Title: "Title"} + link := chain.GetProposalLink(proposal) + + assert.Equal(t, "Title", link.Name, "Wrong value!") + assert.Equal(t, "", link.Href, "Wrong value!") +} + +func TestGetExplorerProposalLinkWithExplorer(t *testing.T) { + t.Parallel() + + chain := Chain{Explorer: &Explorer{ProposalLinkPattern: "example.com/%s"}} + proposal := Proposal{ID: "ID", Title: "Title"} + link := chain.GetProposalLink(proposal) + + assert.Equal(t, "Title", link.Name, "Wrong value!") + assert.Equal(t, "example.com/ID", link.Href, "Wrong value!") +} + +func TestGetWalletLinkWithoutExplorer(t *testing.T) { + t.Parallel() + + chain := Chain{} + wallet := &Wallet{Address: "wallet"} + link := chain.GetWalletLink(wallet) + + assert.Equal(t, "wallet", link.Name, "Wrong value!") + assert.Equal(t, "", link.Href, "Wrong value!") +} + +func TestGetWalletLinkWithoutAlias(t *testing.T) { + t.Parallel() + + chain := Chain{Explorer: &Explorer{WalletLinkPattern: "example.com/%s"}} + wallet := &Wallet{Address: "wallet"} + link := chain.GetWalletLink(wallet) + + assert.Equal(t, "wallet", link.Name, "Wrong value!") + assert.Equal(t, "example.com/wallet", link.Href, "Wrong value!") +} + +func TestGetWalletLinkWithAlias(t *testing.T) { + t.Parallel() + + chain := Chain{Explorer: &Explorer{WalletLinkPattern: "example.com/%s"}} + wallet := &Wallet{Address: "wallet", Alias: "alias"} + link := chain.GetWalletLink(wallet) + + assert.Equal(t, "alias", link.Name, "Wrong value!") + assert.Equal(t, "example.com/wallet", link.Href, "Wrong value!") +} diff --git a/pkg/types/config_test.go b/pkg/types/config_test.go index 00abf6f..e574824 100644 --- a/pkg/types/config_test.go +++ b/pkg/types/config_test.go @@ -141,7 +141,7 @@ func TestValidateConfigInvalidTimezone(t *testing.T) { require.Error(t, err, nil, "Error should be presented!") } -func TestValidateConfigValidChain(t *testing.T) { +func TestValidateConfigInvalidWallet(t *testing.T) { t.Parallel() config := Config{ @@ -150,62 +150,29 @@ func TestValidateConfigValidChain(t *testing.T) { { Name: "chain", LCDEndpoints: []string{"endpoint"}, - Wallets: []*Wallet{{Address: "wallet"}}, + Wallets: []*Wallet{{Address: ""}}, ProposalsType: "v1", }, }, } err := config.Validate() - require.NoError(t, err, "Error should not be presented!") -} - -func TestFindChainByNameIfPresent(t *testing.T) { - t.Parallel() - - chains := Chains{ - {Name: "chain1"}, - {Name: "chain2"}, - } - - chain := chains.FindByName("chain2") - assert.NotNil(t, chain, "Chain should be presented!") -} - -func TestFindChainByNameIfNotPresent(t *testing.T) { - t.Parallel() - - chains := Chains{ - {Name: "chain1"}, - {Name: "chain2"}, - } - - chain := chains.FindByName("chain3") - assert.Nil(t, chain, "Chain should not be presented!") -} - -func TestGetLinksEmpty(t *testing.T) { - t.Parallel() - - chain := Chain{} - links := chain.GetExplorerProposalsLinks("test") - - assert.Empty(t, links, "Expected 0 links") + require.Error(t, err, nil, "Error should be presented!") } -func TestGetLinksPresent(t *testing.T) { +func TestValidateConfigValidChain(t *testing.T) { t.Parallel() - chain := Chain{ - KeplrName: "chain", - Explorer: &Explorer{ - ProposalLinkPattern: "example.com/proposal/%s", + config := Config{ + Timezone: "Europe/Moscow", + Chains: []*Chain{ + { + Name: "chain", + LCDEndpoints: []string{"endpoint"}, + Wallets: []*Wallet{{Address: "wallet"}}, + ProposalsType: "v1", + }, }, } - links := chain.GetExplorerProposalsLinks("test") - - assert.Len(t, links, 2, "Expected 2 links") - assert.Equal(t, "Keplr", links[0].Name, "Expected Keplr link") - assert.Equal(t, "https://wallet.keplr.app/#/chain/governance?detailId=test", links[0].Href, "Wrong Keplr link") - assert.Equal(t, "Explorer", links[1].Name, "Expected Explorer link") - assert.Equal(t, "example.com/proposal/test", links[1].Href, "Wrong explorer link") + err := config.Validate() + require.NoError(t, err, "Error should not be presented!") } diff --git a/pkg/types/params.go b/pkg/types/params.go new file mode 100644 index 0000000..e022b8e --- /dev/null +++ b/pkg/types/params.go @@ -0,0 +1,43 @@ +package types + +import ( + "fmt" + "strings" + "time" + + "main/pkg/utils" +) + +type Amount struct { + Denom string + Amount string +} + +type ChainWithVotingParams struct { + Chain *Chain + VotingPeriod time.Duration + MinDepositAmount []Amount + MaxDepositPeriod time.Duration + Quorum float64 + Threshold float64 + VetoThreshold float64 +} + +func (c ChainWithVotingParams) FormatQuorum() string { + return fmt.Sprintf("%.2f%%", c.Quorum*100) +} + +func (c ChainWithVotingParams) FormatThreshold() string { + return fmt.Sprintf("%.2f%%", c.Threshold*100) +} + +func (c ChainWithVotingParams) FormatVetoThreshold() string { + return fmt.Sprintf("%.2f%%", c.VetoThreshold*100) +} + +func (c ChainWithVotingParams) FormatMinDepositAmount() string { + amountsAsStrings := utils.Map(c.MinDepositAmount, func(a Amount) string { + return a.Amount + " " + a.Denom + }) + return strings.Join(amountsAsStrings, ",") +} diff --git a/pkg/types/params_test.go b/pkg/types/params_test.go new file mode 100644 index 0000000..8e9f985 --- /dev/null +++ b/pkg/types/params_test.go @@ -0,0 +1,50 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestParamsFormatQuorum(t *testing.T) { + t.Parallel() + + params := ChainWithVotingParams{ + Quorum: 0.4, + } + + assert.Equal(t, "40.00%", params.FormatQuorum(), "Wrong value!") +} + +func TestParamsFormatThreshold(t *testing.T) { + t.Parallel() + + params := ChainWithVotingParams{ + Threshold: 0.4, + } + + assert.Equal(t, "40.00%", params.FormatThreshold(), "Wrong value!") +} + +func TestParamsFormatVetoThreshold(t *testing.T) { + t.Parallel() + + params := ChainWithVotingParams{ + VetoThreshold: 0.4, + } + + assert.Equal(t, "40.00%", params.FormatVetoThreshold(), "Wrong value!") +} + +func TestParamsFormatFormatMinDepositAmount(t *testing.T) { + t.Parallel() + + params := ChainWithVotingParams{ + MinDepositAmount: []Amount{ + {Denom: "stake", Amount: "100"}, + {Denom: "test", Amount: "100"}, + }, + } + + assert.Equal(t, "100 stake,100 test", params.FormatMinDepositAmount(), "Wrong value!") +} diff --git a/pkg/types/proposal_test.go b/pkg/types/proposal_test.go new file mode 100644 index 0000000..a48eab8 --- /dev/null +++ b/pkg/types/proposal_test.go @@ -0,0 +1,18 @@ +package types + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestProposalGetVotingTime(t *testing.T) { + t.Parallel() + + proposal := Proposal{ + EndTime: time.Now().Add(time.Hour).Add(time.Minute), + } + + assert.Equal(t, "1 hour 1 minute", proposal.GetTimeLeft(), "Wrong value!") +} diff --git a/pkg/types/responses.go b/pkg/types/responses.go deleted file mode 100644 index d6ba5f5..0000000 --- a/pkg/types/responses.go +++ /dev/null @@ -1,64 +0,0 @@ -package types - -import ( - "fmt" - "strings" - "time" - - "main/pkg/utils" -) - -type ParamsResponse struct { - VotingParams VotingParams `json:"voting_params"` - DepositParams DepositParams `json:"deposit_params"` - TallyParams TallyParams `json:"tally_params"` -} - -type VotingParams struct { - VotingPeriod string `json:"voting_period"` -} - -type DepositParams struct { - MinDepositAmount []Amount `json:"min_deposit"` - MaxDepositPeriod string `json:"max_deposit_period"` -} - -type Amount struct { - Denom string `json:"denom"` - Amount string `json:"amount"` -} - -type TallyParams struct { - Quorum string `json:"quorum"` - Threshold string `json:"threshold"` - VetoThreshold string `json:"veto_threshold"` -} - -type ChainWithVotingParams struct { - Chain *Chain - VotingPeriod time.Duration `json:"voting_period"` - MinDepositAmount []Amount `json:"amount"` - MaxDepositPeriod time.Duration `json:"max_deposit_period"` - Quorum float64 `json:"quorum"` - Threshold float64 `json:"threshold"` - VetoThreshold float64 `json:"veto_threshold"` -} - -func (c ChainWithVotingParams) FormatQuorum() string { - return fmt.Sprintf("%.2f%%", c.Quorum*100) -} - -func (c ChainWithVotingParams) FormatThreshold() string { - return fmt.Sprintf("%.2f%%", c.Threshold*100) -} - -func (c ChainWithVotingParams) FormatVetoThreshold() string { - return fmt.Sprintf("%.2f%%", c.VetoThreshold*100) -} - -func (c ChainWithVotingParams) FormatMinDepositAmount() string { - amountsAsStrings := utils.Map(c.MinDepositAmount, func(a Amount) string { - return a.Amount + " " + a.Denom - }) - return strings.Join(amountsAsStrings, ",") -} diff --git a/pkg/types/types_test.go b/pkg/types/types_test.go new file mode 100644 index 0000000..dc4a52b --- /dev/null +++ b/pkg/types/types_test.go @@ -0,0 +1,28 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSerializeLinkWithoutHref(t *testing.T) { + t.Parallel() + + link := Link{ + Name: "link", + } + + assert.Equal(t, "link", link.Serialize(), "Wrong value!") +} + +func TestSerializeLinkWithHref(t *testing.T) { + t.Parallel() + + link := Link{ + Name: "link", + Href: "example.com", + } + + assert.Equal(t, "link", link.Serialize(), "Wrong value!") +} diff --git a/pkg/types/vote.go b/pkg/types/vote.go index 92ae623..b98d1c5 100644 --- a/pkg/types/vote.go +++ b/pkg/types/vote.go @@ -7,25 +7,8 @@ import ( // cosmos/gov/v1beta1/proposals/:id/votes/:wallet -type VoteType string - -func (v VoteType) Resolve() string { - votes := map[string]string{ - "VOTE_OPTION_YES": "Yes", - "VOTE_OPTION_ABSTAIN": "Abstain", - "VOTE_OPTION_NO": "No", - "VOTE_OPTION_NO_WITH_VETO": "No with veto", - } - - if vote, ok := votes[string(v)]; ok && v != "" { - return vote - } - - return string(v) -} - type VoteOption struct { - Option VoteType + Option string Weight float64 } type VoteOptions []VoteOption @@ -38,7 +21,7 @@ type Vote struct { func (v Vote) ResolveVote() string { optionsStrings := utils.Map(v.Options, func(v VoteOption) string { - return v.Option.Resolve() + return v.Option }) return strings.Join(optionsStrings, ", ") diff --git a/pkg/types/vote_test.go b/pkg/types/vote_test.go new file mode 100644 index 0000000..cc9e94c --- /dev/null +++ b/pkg/types/vote_test.go @@ -0,0 +1,99 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestVoteResolveVote(t *testing.T) { + t.Parallel() + + vote := Vote{ + Options: []VoteOption{ + {Option: "Yes", Weight: 1}, + {Option: "No", Weight: 2}, + }, + } + + assert.Equal(t, "Yes, No", vote.ResolveVote(), "Wrong value!") +} + +func TestVoteEqualsDifferentLength(t *testing.T) { + t.Parallel() + + vote1 := &Vote{ + Options: []VoteOption{ + {Option: "Yes", Weight: 1}, + {Option: "No", Weight: 2}, + }, + } + + vote2 := &Vote{ + Options: []VoteOption{ + {Option: "Yes", Weight: 1}, + }, + } + + assert.False(t, vote1.VotesEquals(vote2), "Wrong value!") +} + +func TestVoteEqualsDifferentVotesOptions(t *testing.T) { + t.Parallel() + + vote1 := &Vote{ + Options: []VoteOption{ + {Option: "Yes", Weight: 1}, + {Option: "No", Weight: 2}, + }, + } + + vote2 := &Vote{ + Options: []VoteOption{ + {Option: "Yes", Weight: 1}, + {Option: "Abstain", Weight: 2}, + }, + } + + assert.False(t, vote1.VotesEquals(vote2), "Wrong value!") +} + +func TestVoteEqualsDifferentVotesWeight(t *testing.T) { + t.Parallel() + + vote1 := &Vote{ + Options: []VoteOption{ + {Option: "Yes", Weight: 1}, + {Option: "No", Weight: 2}, + }, + } + + vote2 := &Vote{ + Options: []VoteOption{ + {Option: "Yes", Weight: 1}, + {Option: "No", Weight: 3}, + }, + } + + assert.False(t, vote1.VotesEquals(vote2), "Wrong value!") +} + +func TestVoteEqualsSame(t *testing.T) { + t.Parallel() + + vote1 := &Vote{ + Options: []VoteOption{ + {Option: "Yes", Weight: 1}, + {Option: "No", Weight: 2}, + }, + } + + vote2 := &Vote{ + Options: []VoteOption{ + {Option: "Yes", Weight: 1}, + {Option: "No", Weight: 2}, + }, + } + + assert.True(t, vote1.VotesEquals(vote2), "Wrong value!") +}