Skip to content

Commit

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

* chore: add config example
  • Loading branch information
freak12techno authored Dec 23, 2023
1 parent 38bc617 commit 770e864
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 38 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ Go to your PagerDuty page, then go to Services. Create a service if you haven't

## Which networks this is guaranteed to work?

In theory, it should work on a Cosmos-based blockchains that expose a REST server.
In theory, it should work on a Cosmos-based blockchains that expose a REST server, and also on Neutron.

## How can I contribute?

Expand Down
6 changes: 6 additions & 0 deletions config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ wallets = [
{ address = "bitsong14rvn7anf22e00vj5x3al4w50ns78s7n4t8yxcy", alias = "Validator wallet" },
{ address = "bitsong125hdkukw4pu2urhj4nv366q0avdqv24t0vprxs" },
]
# Type. Currently can be either "cosmos" or "neutron". Optional, defaults to "cosmos.
type = "cosmos"
# Neutron smart contract address. Defaults to "neutron1436kxs0w2es6xlqpp9rd35e3d0cjnw4sv8j3a7483sgks29jqwgshlt6zh"
# (mainnet contract address).
neutron-smart-contract = "neutron1436kxs0w2es6xlqpp9rd35e3d0cjnw4sv8j3a7483sgks29jqwgshlt6zh"

# Some chains have a new proposals structure (v1) compared to an older one (v1beta1),
# when there are 2 or more actual proposals inside a single one (namely, Quicksilver).
# On such chains, querying proposals with an older endpoint when there are proposals
Expand Down
21 changes: 21 additions & 0 deletions pkg/fetchers/neutron/fetcher.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package neutron

import (
"encoding/base64"
"fmt"
"main/pkg/http"
"main/pkg/types"

Expand All @@ -20,3 +22,22 @@ func NewFetcher(chainConfig *types.Chain, logger zerolog.Logger) *Fetcher {
Client: http.NewClient(chainConfig.Name, chainConfig.LCDEndpoints, logger),
}
}

func (fetcher *Fetcher) GetSmartContractState(queryString string, output interface{}) *types.QueryError {
query := base64.StdEncoding.EncodeToString([]byte(queryString))

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

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

return nil
}
17 changes: 3 additions & 14 deletions pkg/fetchers/neutron/proposals.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,16 @@
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,
)
query := "{\"list_proposals\": {}}"

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

proposalsParsed, err := proposals.ToProposals()
Expand Down
44 changes: 44 additions & 0 deletions pkg/fetchers/neutron/responses/vote.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package responses

import (
"main/pkg/types"
)

type Vote struct {
Voter string `json:"voter"`
Vote string `json:"vote"`
}

func (v Vote) GetOption() string {
options := map[string]string{
"yes": "Yes",
"no": "No",
"abstain": "Abstain",
}

if option, ok := options[v.Vote]; ok {
return option
}

return v.Vote
}

type VoteResponse struct {
Data struct {
Vote *Vote `json:"vote"`
} `json:"data"`
}

func (v VoteResponse) ToVote(proposalID string) *types.Vote {
if v.Data.Vote == nil {
return nil
}

return &types.Vote{
ProposalID: proposalID,
Voter: v.Data.Vote.Voter,
Options: []types.VoteOption{
{Option: v.Data.Vote.GetOption(), Weight: 1},
},
}
}
17 changes: 3 additions & 14 deletions pkg/fetchers/neutron/tally.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,16 @@
package neutron

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

func (fetcher *Fetcher) GetTallies() (types.ChainTallyInfos, error) {
query := base64.StdEncoding.EncodeToString([]byte("{\"list_proposals\": {}}"))

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

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

tallyInfos, err := proposals.ToTally()
Expand Down
21 changes: 18 additions & 3 deletions pkg/fetchers/neutron/vote.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
package neutron

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

func (fetcher *Fetcher) GetVote(proposal, voter string) (*types.Vote, *types.QueryError) {
// TODO: fix
return nil, nil
query := fmt.Sprintf(
"{\"get_vote\":{\"proposal_id\":%s,\"voter\":\"%s\"}}",
proposal,
voter,
)

var vote responses.VoteResponse
if err := fetcher.GetSmartContractState(query, &vote); err != nil {
return nil, err
}

voteParsed := vote.ToVote(proposal)
return voteParsed, nil
}
8 changes: 2 additions & 6 deletions pkg/types/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,18 +108,14 @@ func (c Chain) GetProposalLink(proposal Proposal) Link {

func (c Chain) GetWalletLink(wallet *Wallet) Link {
if c.Explorer == nil || c.Explorer.WalletLinkPattern == "" {
return Link{Name: wallet.Address}
return Link{Name: wallet.AddressOrAlias()}
}

link := Link{
Name: wallet.Address,
Name: wallet.AddressOrAlias(),
Href: fmt.Sprintf(c.Explorer.WalletLinkPattern, wallet.Address),
}

if wallet.Alias != "" {
link.Name = wallet.Alias
}

return link
}

Expand Down

0 comments on commit 770e864

Please sign in to comment.