Skip to content

Commit

Permalink
feat: add Neutron proposals fetching (#64)
Browse files Browse the repository at this point in the history
* feat: add Neutron proposals fetching

* chore: fix linting
  • Loading branch information
freak12techno committed Dec 22, 2023
1 parent e6f583a commit abb5232
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 0 deletions.
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,4 @@ linters:
- depguard
- ifshort
- ireturn
- godox
5 changes: 5 additions & 0 deletions pkg/fetchers/fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package fetchers

import (
"main/pkg/fetchers/cosmos"
"main/pkg/fetchers/neutron"
"main/pkg/types"

"github.com/rs/zerolog"
Expand All @@ -16,5 +17,9 @@ type Fetcher interface {
}

func GetFetcher(chainConfig *types.Chain, logger zerolog.Logger) Fetcher {
if chainConfig.Type == "neutron" {
return neutron.NewFetcher(chainConfig, logger)
}

return cosmos.NewRPC(chainConfig, logger)
}
22 changes: 22 additions & 0 deletions pkg/fetchers/neutron/fetcher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package neutron

import (
"main/pkg/http"
"main/pkg/types"

"github.com/rs/zerolog"
)

type Fetcher struct {
ChainConfig *types.Chain
Logger zerolog.Logger
Client *http.Client
}

func NewFetcher(chainConfig *types.Chain, logger zerolog.Logger) *Fetcher {
return &Fetcher{
ChainConfig: chainConfig,
Logger: logger.With().Str("component", "neutron_fetcher").Logger(),
Client: http.NewClient(chainConfig.Name, chainConfig.LCDEndpoints, logger),
}
}
11 changes: 11 additions & 0 deletions pkg/fetchers/neutron/params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package neutron

import "main/pkg/types"

func (fetcher *Fetcher) GetChainParams() (*types.ChainWithVotingParams, []error) {
// TODO: fix
return &types.ChainWithVotingParams{
Chain: fetcher.ChainConfig,
Params: []types.ChainParam{},
}, nil
}
36 changes: 36 additions & 0 deletions pkg/fetchers/neutron/proposals.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package neutron

import (
"encoding/base64"
"fmt"
"main/pkg/fetchers/neutron/responses"
"main/pkg/types"
)

func (fetcher *Fetcher) GetAllProposals() ([]types.Proposal, *types.QueryError) {
query := base64.StdEncoding.EncodeToString([]byte("{\"list_proposals\": {}}"))

url := fmt.Sprintf(
"/cosmwasm/wasm/v1/contract/%s/smart/%s",
fetcher.ChainConfig.NeutronSmartContract,
query,
)

var proposals responses.ProposalsResponse
if errs := fetcher.Client.Get(url, &proposals); len(errs) > 0 {
return nil, &types.QueryError{
QueryError: nil,
NodeErrors: errs,
}
}

proposalsParsed, err := proposals.ToProposals()
if err != nil {
return nil, &types.QueryError{
QueryError: err,
NodeErrors: nil,
}
}

return proposalsParsed, nil
}
52 changes: 52 additions & 0 deletions pkg/fetchers/neutron/responses/proposals.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package responses

import (
"main/pkg/types"
"main/pkg/utils"
"strconv"
"time"
)

type ProposalWithID struct {
ID int `json:"id"`
Proposal Proposal `json:"proposal"`
}
type Proposal struct {
Title string `json:"title"`
Description string `json:"description"`
Expiration struct {
AtTime string `json:"at_time"`
} `json:"expiration"`
Status string `json:"status"`
TotalPower string `json:"total_power"`
}

type ProposalsResponse struct {
Data struct {
Proposals []ProposalWithID `json:"proposals"`
} `json:"data"`
}

func (p ProposalsResponse) ToProposals() ([]types.Proposal, error) {
allProposals := utils.Filter(p.Data.Proposals, func(p ProposalWithID) bool {
return p.Proposal.Status == "open"
})

proposals := make([]types.Proposal, len(allProposals))

for index, proposal := range allProposals {
expiresAt, err := strconv.ParseInt(proposal.Proposal.Expiration.AtTime, 10, 64)
if err != nil {
return nil, err
}

proposals[index] = types.Proposal{
ID: strconv.Itoa(proposal.ID),
Title: proposal.Proposal.Title,
Description: proposal.Proposal.Description,
EndTime: time.Unix(0, expiresAt),
}
}

return proposals, nil
}
8 changes: 8 additions & 0 deletions pkg/fetchers/neutron/tally.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package neutron

import "main/pkg/types"

func (fetcher *Fetcher) GetTallies() (types.ChainTallyInfos, error) {
// TODO: fix
return types.ChainTallyInfos{}, nil
}
8 changes: 8 additions & 0 deletions pkg/fetchers/neutron/vote.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package neutron

import "main/pkg/types"

func (fetcher *Fetcher) GetVote(proposal, voter string) (*types.Vote, *types.QueryError) {
// TODO: fix
return nil, nil
}
7 changes: 7 additions & 0 deletions pkg/types/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,20 @@ type Chain struct {
Wallets []*Wallet `toml:"wallets"`
MintscanPrefix string `toml:"mintscan-prefix"`
Explorer *Explorer `toml:"explorer"`

Type string `default:"cosmos" toml:"type"`
NeutronSmartContract string `default:"neutron1436kxs0w2es6xlqpp9rd35e3d0cjnw4sv8j3a7483sgks29jqwgshlt6zh" toml:"neutron-smart-contract"`
}

func (c Chain) Validate() error {
if c.Name == "" {
return fmt.Errorf("empty chain name")
}

if !utils.Contains([]string{"cosmos", "neutron"}, c.Type) {
return fmt.Errorf("expected type to be one of 'cosmos', 'neutron', but got '%s'", c.Type)
}

if len(c.LCDEndpoints) == 0 {
return fmt.Errorf("no LCD endpoints provided")
}
Expand Down
21 changes: 21 additions & 0 deletions pkg/types/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ func TestValidateChainWithValidConfig(t *testing.T) {
LCDEndpoints: []string{"endpoint"},
Wallets: []*Wallet{{Address: "wallet"}},
ProposalsType: "v1",
Type: "cosmos",
}

err := chain.Validate()
Expand Down Expand Up @@ -159,6 +160,25 @@ func TestValidateConfigInvalidWallet(t *testing.T) {
require.Error(t, err, nil, "Error should be presented!")
}

func TestValidateConfigInvalidType(t *testing.T) {
t.Parallel()

config := Config{
Timezone: "Europe/Moscow",
Chains: []*Chain{
{
Name: "chain",
LCDEndpoints: []string{"endpoint"},
Wallets: []*Wallet{{Address: "wallet"}},
ProposalsType: "v1",
Type: "invalid",
},
},
}
err := config.Validate()
require.Error(t, err, nil, "Error should be presented!")
}

func TestValidateConfigValidChain(t *testing.T) {
t.Parallel()

Expand All @@ -170,6 +190,7 @@ func TestValidateConfigValidChain(t *testing.T) {
LCDEndpoints: []string{"endpoint"},
Wallets: []*Wallet{{Address: "wallet"}},
ProposalsType: "v1",
Type: "cosmos",
},
},
}
Expand Down

0 comments on commit abb5232

Please sign in to comment.