Skip to content

Commit

Permalink
feat(client): unify and refactore client package (#2256)
Browse files Browse the repository at this point in the history
* add metoken client

* refactore tx client

* metoken queries

* add proto.Message validator

* use umee client in e2e tests

* nil check

* add QueryMetokenIndexPrices

* lint

* rollback change to 20s

* fix metoken e2e

---------

Co-authored-by: Egor Kostetskiy <[email protected]>
  • Loading branch information
robert-zaremba and kosegor authored Sep 21, 2023
1 parent 855f07e commit da24d25
Show file tree
Hide file tree
Showing 16 changed files with 158 additions and 109 deletions.
58 changes: 58 additions & 0 deletions client/metoken.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package client

import (
"github.com/umee-network/umee/v6/util/sdkutil"
"github.com/umee-network/umee/v6/x/metoken"
)

func (c Client) MetokenQClient() metoken.QueryClient {
return metoken.NewQueryClient(c.Query.GrpcConn)
}

func (c Client) QueryMetokenParams() (metoken.Params, error) {
ctx, cancel := c.NewQCtx()
defer cancel()

resp, err := c.MetokenQClient().Params(ctx, &metoken.QueryParams{})
if err != nil {
return metoken.Params{}, err
}
return resp.Params, err
}

func (c Client) QueryMetokenIndexBalances(denom string) (*metoken.QueryIndexBalancesResponse, error) {
ctx, cancel := c.NewQCtx()
defer cancel()

msg := &metoken.QueryIndexBalances{MetokenDenom: denom}
if err := sdkutil.ValidateProtoMsg(msg); err != nil {
return nil, err
}
return c.MetokenQClient().IndexBalances(ctx, msg)
}

func (c Client) QueryMetokenIndexes(denom string) (*metoken.QueryIndexesResponse, error) {
ctx, cancel := c.NewQCtx()
defer cancel()

msg := &metoken.QueryIndexes{MetokenDenom: denom}
if err := sdkutil.ValidateProtoMsg(msg); err != nil {
return nil, err
}
return c.MetokenQClient().Indexes(ctx, msg)
}

func (c Client) QueryMetokenIndexPrices(denom string) (*metoken.QueryIndexPricesResponse, error) {
ctx, cancel := c.NewQCtx()
defer cancel()

msg := &metoken.QueryIndexPrices{MetokenDenom: denom}
if err := sdkutil.ValidateProtoMsg(msg); err != nil {
return nil, err
}
return c.MetokenQClient().IndexPrices(ctx, msg)
}

//
// Tx
//
7 changes: 5 additions & 2 deletions sdkclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package sdkclient

import (
"context"
"log"
"os"
"time"

sdkparams "github.com/cosmos/cosmos-sdk/simapp/params"
Expand Down Expand Up @@ -32,11 +34,12 @@ func NewClient(
encCfg sdkparams.EncodingConfig,
) (uc Client, err error) {
uc = Client{}
uc.Query, err = query.NewClient(grpcEndpoint, 15*time.Second)
logger := log.New(os.Stderr, "chain-client", log.LstdFlags)
uc.Query, err = query.NewClient(logger, grpcEndpoint, 15*time.Second)
if err != nil {
return Client{}, err
}
uc.Tx, err = tx.NewClient(chainDataDir, chainID, tmrpcEndpoint, mnemonics, gasAdjustment, encCfg)
uc.Tx, err = tx.NewClient(logger, chainDataDir, chainID, tmrpcEndpoint, mnemonics, gasAdjustment, encCfg)
return uc, err
}

Expand Down
7 changes: 5 additions & 2 deletions sdkclient/query/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package query

import (
"context"
"log"
"net"
"strings"
"time"
Expand All @@ -14,10 +15,12 @@ type Client struct {
GrpcConn *grpc.ClientConn
grpcEndpoint string
QueryTimeout time.Duration

logger *log.Logger
}

func NewClient(grpcEndpoint string, queryTimeout time.Duration) (*Client, error) {
qc := &Client{grpcEndpoint: grpcEndpoint, QueryTimeout: queryTimeout}
func NewClient(logger *log.Logger, grpcEndpoint string, queryTimeout time.Duration) (*Client, error) {
qc := &Client{logger: logger, grpcEndpoint: grpcEndpoint, QueryTimeout: queryTimeout}
return qc, qc.dialGrpcConn()
}

Expand Down
8 changes: 5 additions & 3 deletions sdkclient/tx/bank.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import (
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)

func (c *Client) TxSend(fromAddress, toAddress string, amount sdk.Coins) (*sdk.TxResponse, error) {
// BankSend creates and broadcasts bank send tx. `fromIdx` is an account index in the client
// keyring.
func (c *Client) BankSend(fromIdx int, toAddress string, amount sdk.Coins) (*sdk.TxResponse, error) {
msg := &banktypes.MsgSend{
FromAddress: fromAddress,
FromAddress: c.KeyringAddress(fromIdx).String(),
ToAddress: toAddress,
Amount: amount,
}
return c.BroadcastTx(msg)
return c.BroadcastTx(fromIdx, msg)
}
18 changes: 14 additions & 4 deletions sdkclient/tx/client.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package tx

import (
"log"
"os"

"github.com/cosmos/cosmos-sdk/client"
Expand All @@ -26,12 +27,15 @@ type Client struct {
keyringRecord []*keyring.Record
txFactory *tx.Factory
encCfg sdkparams.EncodingConfig

logger *log.Logger
}

// Initializes a cosmos sdk client context and transaction factory for
// signing and broadcasting transactions by passing chainDataDir and remaining func arguments
// Note: For signing the transactions accounts are created by names like this val0, val1....
func NewClient(
logger *log.Logger,
chainDataDir,
chainID,
tmrpcEndpoint string,
Expand All @@ -44,6 +48,7 @@ func NewClient(
TMRPCEndpoint: tmrpcEndpoint,
gasAdjustment: gasAdjustment,
encCfg: encCfg,
logger: logger,
}

c.keyringKeyring, err = keyring.New(keyringAppName, keyring.BackendTest, chainDataDir, nil, encCfg.Codec)
Expand Down Expand Up @@ -120,10 +125,15 @@ func (c *Client) initTxFactory() {
c.txFactory = &f
}

func (c *Client) BroadcastTx(msgs ...sdk.Msg) (*sdk.TxResponse, error) {
c.ClientContext.From = c.keyringRecord[0].Name
c.ClientContext.FromName = c.keyringRecord[0].Name
c.ClientContext.FromAddress, _ = c.keyringRecord[0].GetAddress()
func (c *Client) BroadcastTx(idx int, msgs ...sdk.Msg) (*sdk.TxResponse, error) {
var err error
r := c.keyringRecord[idx]
c.ClientContext.From = r.Name
c.ClientContext.FromName = r.Name
c.ClientContext.FromAddress, err = r.GetAddress()
if err != nil {
c.logger.Fatalln("can't get keyring record, idx=", idx, err)
}
return BroadcastTx(*c.ClientContext, *c.txFactory, msgs...)
}

Expand Down
24 changes: 10 additions & 14 deletions sdkclient/tx/gov.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ func (c *Client) GovParamChange(title, description string, changes []proposal.Pa
return nil, err
}

return c.BroadcastTx(msg)
return c.BroadcastTx(0, msg)
}

func (c *Client) GovSubmitProposal(changes []proposal.ParamChange, deposit sdk.Coins) (*sdk.TxResponse, error) {
func (c *Client) GovSubmitParamProposal(changes []proposal.ParamChange, deposit sdk.Coins) (*sdk.TxResponse, error) {
content := proposal.NewParameterChangeProposal(
"update historic stamp period",
"auto grpc proposal",
Expand All @@ -40,10 +40,10 @@ func (c *Client) GovSubmitProposal(changes []proposal.ParamChange, deposit sdk.C
return nil, err
}

return c.BroadcastTx(msg)
return c.BroadcastTx(0, msg)
}

func (c *Client) TxSubmitProposalWithMsg(msgs []sdk.Msg) (*sdk.TxResponse, error) {
func (c *Client) GovSubmitProposal(msgs []sdk.Msg) (*sdk.TxResponse, error) {
deposit, err := sdk.ParseCoinsNormalized("1000uumee")
if err != nil {
return nil, err
Expand All @@ -59,11 +59,11 @@ func (c *Client) TxSubmitProposalWithMsg(msgs []sdk.Msg) (*sdk.TxResponse, error
return nil, err
}

return c.BroadcastTx(submitProposal)
return c.BroadcastTx(0, submitProposal)
}

// TxGovVoteYesAll creates transactions (one for each registered account) to approve a given proposal.
func (c *Client) TxGovVoteYesAll(proposalID uint64) error {
// GovVoteAllYes creates transactions (one for each account in the keyring) to approve a given proposal.
func (c *Client) GovVoteAllYes(proposalID uint64) error {
for index := range c.keyringRecord {
voter, err := c.keyringRecord[index].GetAddress()
if err != nil {
Expand All @@ -80,16 +80,12 @@ func (c *Client) TxGovVoteYesAll(proposalID uint64) error {
proposalID,
voteType,
)

c.ClientContext.From = c.keyringRecord[index].Name
c.ClientContext.FromName = c.keyringRecord[index].Name
c.ClientContext.FromAddress, _ = c.keyringRecord[index].GetAddress()

for retry := 0; retry < 5; retry++ {
for retry := 0; retry < 3; retry++ {
// retry if txs fails, because sometimes account sequence mismatch occurs due to txs pending
if _, err = BroadcastTx(*c.ClientContext, *c.txFactory, []sdk.Msg{msg}...); err == nil {
if _, err = c.BroadcastTx(index, msg); err == nil {
break
}
c.logger.Println("Tx broadcast failed. RETRYING. Err: ", err)
time.Sleep(time.Millisecond * 300)
}

Expand Down
9 changes: 9 additions & 0 deletions sdkclient/tx/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,12 @@ func CreateAccountFromMnemonic(kb keyring.Keyring, name, mnemonic string) (*keyr

return account, nil
}

// Returns account address stored at give index
func (c *Client) KeyringAddress(idx int) sdk.AccAddress {
addr, err := c.keyringRecord[idx].GetAddress()
if err != nil {
c.logger.Fatalln("can't get keyring record, idx=", idx, err)
}
return addr
}
1 change: 0 additions & 1 deletion sdkclient/tx/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ func BroadcastTx(clientCtx client.Context, txf tx.Factory, msgs ...sdk.Msg) (*sd
// the updated fields will be returned.
func prepareFactory(clientCtx client.Context, txf tx.Factory) (tx.Factory, error) {
from := clientCtx.GetFromAddress()

if err := txf.AccountRetriever().EnsureExists(clientCtx, from); err != nil {
return txf, err
}
Expand Down
51 changes: 19 additions & 32 deletions sdkclient/tx/wasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,60 +12,49 @@ import (
"github.com/umee-network/umee/v6/util/coin"
)

func (c *Client) TxSubmitWasmContract(contractPath string) (*sdk.TxResponse, error) {
fromAddr, err := c.keyringRecord[0].GetAddress()
func (c *Client) WasmDeployContract(contractPath string) (*sdk.TxResponse, error) {
fromIdx := 0
msg, err := readWasmCode(contractPath, c.KeyringAddress(fromIdx))
if err != nil {
return nil, err
}

msg, err := readWasmCode(contractPath, fromAddr)
if err != nil {
return nil, err
}

return c.BroadcastTx(&msg)
return c.BroadcastTx(fromIdx, &msg)
}

func (c *Client) TxWasmInstantiateContract(storeCode uint64, initMsg []byte) (*sdk.TxResponse, error) {
fromAddr, err := c.keyringRecord[0].GetAddress()
if err != nil {
return nil, err
}
func (c *Client) WasmInitContract(storeCode uint64, initMsg []byte) (*sdk.TxResponse, error) {
fromIdx := 0
amount := sdk.NewCoins(sdk.NewCoin(appparams.BondDenom, sdk.NewInt(1)))
msg := types.MsgInstantiateContract{
Sender: fromAddr.String(),
Sender: c.KeyringAddress(fromIdx).String(),
CodeID: storeCode,
Label: "label",
Funds: amount,
Msg: initMsg,
Admin: "",
}

return c.BroadcastTx(&msg)
return c.BroadcastTx(fromIdx, &msg)
}

func (c *Client) TxWasmExecuteContractByAccSeq(contractAddr string, execMsg []byte,
accSeq uint64,
func (c *Client) WasmExecContractWithAccSeq(contractAddr string, execMsg []byte, accSeq uint64,
) (*sdk.TxResponse, error) {
fromAddr, err := c.keyringRecord[0].GetAddress()
if err != nil {
return nil, err
}
fromIdx := 0
amount := sdk.NewCoins(coin.Umee1)
msg := types.MsgExecuteContract{
Sender: fromAddr.String(),
Sender: c.KeyringAddress(fromIdx).String(),
Contract: contractAddr,
Funds: amount,
Msg: execMsg,
}
if accSeq != 0 {
return c.WithAccSeq(accSeq).WithAsyncBlock().BroadcastTx(&msg)
return c.WithAccSeq(accSeq).WithAsyncBlock().BroadcastTx(fromIdx, &msg)
}
return c.WithAsyncBlock().BroadcastTx(&msg)
return c.WithAsyncBlock().BroadcastTx(fromIdx, &msg)
}

func (c *Client) TxWasmExecuteContract(contractAddr string, execMsg []byte) (*sdk.TxResponse, error) {
return c.TxWasmExecuteContractByAccSeq(contractAddr, execMsg, 0)
func (c *Client) WasmExecuteContract(contractAddr string, execMsg []byte) (*sdk.TxResponse, error) {
return c.WasmExecContractWithAccSeq(contractAddr, execMsg, 0)
}

// Prepares MsgStoreCode object from flags with gzipped wasm byte code field
Expand All @@ -75,21 +64,19 @@ func readWasmCode(file string, sender sdk.AccAddress) (types.MsgStoreCode, error
return types.MsgStoreCode{}, err
}

// gzip the wasm file
if ioutils.IsWasm(wasm) {
wasm, err = ioutils.GzipIt(wasm)

if err != nil {
return types.MsgStoreCode{}, err
}
} else if !ioutils.IsGzip(wasm) {
return types.MsgStoreCode{}, fmt.Errorf("invalid input file. Use wasm binary or gzip")
return types.MsgStoreCode{},
fmt.Errorf("invalid input file. Wasm file must be a binary or gzip of a binary")
}

msg := types.MsgStoreCode{
return types.MsgStoreCode{
Sender: sender.String(),
WASMByteCode: wasm,
InstantiatePermission: &types.AllowEverybody,
}
return msg, nil
}, nil
}
Loading

0 comments on commit da24d25

Please sign in to comment.