diff --git a/CHANGELOG.md b/CHANGELOG.md index f9ed2f5b23..84018b94fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +### Features + +- [1888](https://github.com/umee-network/umee/pull/1888) Created `/sdkclient` and `/client` (umee client) packages to easy the E2E tests and external tools. Essentially, you can import that client and broadcast transactions easily. + ## [v4.3.0](https://github.com/umee-network/umee/releases/tag/v4.3.0) - 2023-04-5 ### Features diff --git a/app/app.go b/app/app.go index f1f20c7eb0..0a0077eba7 100644 --- a/app/app.go +++ b/app/app.go @@ -23,6 +23,7 @@ import ( "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" + sdkparams "github.com/cosmos/cosmos-sdk/simapp/params" storetypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" @@ -300,7 +301,7 @@ func New( skipUpgradeHeights map[int64]bool, homePath string, invCheckPeriod uint, - encodingConfig appparams.EncodingConfig, + encodingConfig sdkparams.EncodingConfig, appOpts servertypes.AppOptions, wasmEnabledProposals []wasm.ProposalType, wasmOpts []wasm.Option, diff --git a/app/encoding.go b/app/encoding.go index b59a99a696..de35394796 100644 --- a/app/encoding.go +++ b/app/encoding.go @@ -1,14 +1,14 @@ package app import ( + sdkparams "github.com/cosmos/cosmos-sdk/simapp/params" "github.com/cosmos/cosmos-sdk/std" - "github.com/umee-network/umee/v4/app/params" ) // MakeEncodingConfig returns the application's encoding configuration with all // types and interfaces registered. -func MakeEncodingConfig() params.EncodingConfig { +func MakeEncodingConfig() sdkparams.EncodingConfig { encodingConfig := params.MakeEncodingConfig() std.RegisterLegacyAminoCodec(encodingConfig.Amino) std.RegisterInterfaces(encodingConfig.InterfaceRegistry) diff --git a/app/params/encoding.go b/app/params/encoding.go deleted file mode 100644 index 1b34b952a0..0000000000 --- a/app/params/encoding.go +++ /dev/null @@ -1,16 +0,0 @@ -package params - -import ( - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/codec/types" -) - -// EncodingConfig specifies the concrete encoding types to use for Umee. -// This is provided for compatibility between Protobuf and Amino implementations. -type EncodingConfig struct { - InterfaceRegistry types.InterfaceRegistry - Codec codec.Codec - TxConfig client.TxConfig - Amino *codec.LegacyAmino -} diff --git a/app/params/proto.go b/app/params/proto.go index 02dbf1128d..070b39ef70 100644 --- a/app/params/proto.go +++ b/app/params/proto.go @@ -1,22 +1,10 @@ package params import ( - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/x/auth/tx" + "github.com/cosmos/cosmos-sdk/simapp/params" ) // MakeEncodingConfig creates an EncodingConfig for Amino-based tests. -func MakeEncodingConfig() EncodingConfig { - amino := codec.NewLegacyAmino() - interfaceRegistry := types.NewInterfaceRegistry() - marshaler := codec.NewProtoCodec(interfaceRegistry) - txCfg := tx.NewTxConfig(marshaler, tx.DefaultSignModes) - - return EncodingConfig{ - InterfaceRegistry: interfaceRegistry, - Codec: marshaler, - TxConfig: txCfg, - Amino: amino, - } +func MakeEncodingConfig() params.EncodingConfig { + return params.MakeTestEncodingConfig() } diff --git a/client/client.go b/client/client.go new file mode 100644 index 0000000000..5fa6a3be11 --- /dev/null +++ b/client/client.go @@ -0,0 +1,41 @@ +package client + +import ( + "context" + + sdkparams "github.com/cosmos/cosmos-sdk/simapp/params" + "github.com/umee-network/umee/v4/sdkclient" +) + +// Client sdkclient.Client and provides umee chain specific transactions and queries. +type Client struct { + sdkclient.Client +} + +// NewClient constructs Client object. +func NewClient( + chainID, + tmrpcEndpoint, + grpcEndpoint, + accountName, + accountMnemonic string, + gasAdjustment float64, + encCfg sdkparams.EncodingConfig, +) (Client, error) { + c, err := sdkclient.NewClient(chainID, tmrpcEndpoint, grpcEndpoint, + accountName, accountMnemonic, gasAdjustment, encCfg) + if err != nil { + return Client{}, err + } + return Client{ + Client: c, + }, nil +} + +func (c *Client) NewQCtx() (context.Context, context.CancelFunc) { + return c.Query.NewCtx() +} + +func (c *Client) NewQCtxWithCancel() (context.Context, context.CancelFunc) { + return c.Query.NewCtxWithCancel() +} diff --git a/client/oracle.go b/client/oracle.go new file mode 100644 index 0000000000..2a901036ce --- /dev/null +++ b/client/oracle.go @@ -0,0 +1,43 @@ +package client + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + oracletypes "github.com/umee-network/umee/v4/x/oracle/types" +) + +func (c *Client) OracleQueryClient() oracletypes.QueryClient { + return oracletypes.NewQueryClient(c.Query.GrpcConn) +} + +func (c *Client) QueryOracleParams() (oracletypes.Params, error) { + ctx, cancel := c.NewQCtx() + defer cancel() + + queryResponse, err := c.OracleQueryClient().Params(ctx, &oracletypes.QueryParams{}) + return queryResponse.Params, err +} + +func (c *Client) QueryExchangeRates() ([]sdk.DecCoin, error) { + ctx, cancel := c.NewQCtx() + defer cancel() + + queryResponse, err := c.OracleQueryClient().ExchangeRates(ctx, &oracletypes.QueryExchangeRates{}) + return queryResponse.ExchangeRates, err +} + +func (c *Client) QueryMedians() ([]oracletypes.Price, error) { + ctx, cancel := c.NewQCtx() + defer cancel() + + resp, err := c.OracleQueryClient().Medians(ctx, &oracletypes.QueryMedians{}) + return resp.Medians, err +} + +func (c *Client) QueryMedianDeviations() ([]oracletypes.Price, error) { + ctx, cancel := c.NewQCtx() + defer cancel() + + queryResponse, err := c.OracleQueryClient().MedianDeviations(ctx, &oracletypes.QueryMedianDeviations{}) + return queryResponse.MedianDeviations, err +} diff --git a/cmd/umeed/cmd/app_creator.go b/cmd/umeed/cmd/app_creator.go index 83cd7e5d6b..2b50cf54b7 100644 --- a/cmd/umeed/cmd/app_creator.go +++ b/cmd/umeed/cmd/app_creator.go @@ -13,6 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/server" servertypes "github.com/cosmos/cosmos-sdk/server/types" + sdkparams "github.com/cosmos/cosmos-sdk/simapp/params" "github.com/cosmos/cosmos-sdk/snapshots" snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" "github.com/cosmos/cosmos-sdk/store" @@ -29,7 +30,7 @@ import ( ) type appCreator struct { - encCfg appparams.EncodingConfig + encCfg sdkparams.EncodingConfig moduleManager module.BasicManager } diff --git a/cmd/umeed/cmd/root.go b/cmd/umeed/cmd/root.go index 0f084d7964..be2c25bc60 100644 --- a/cmd/umeed/cmd/root.go +++ b/cmd/umeed/cmd/root.go @@ -12,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/server" serverconfig "github.com/cosmos/cosmos-sdk/server/config" + sdkparams "github.com/cosmos/cosmos-sdk/simapp/params" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -29,7 +30,7 @@ import ( ) // NewRootCmd returns the root command handler for the Umee daemon. -func NewRootCmd() (*cobra.Command, appparams.EncodingConfig) { +func NewRootCmd() (*cobra.Command, sdkparams.EncodingConfig) { encodingConfig := umeeapp.MakeEncodingConfig() moduleManager := umeeapp.ModuleBasics diff --git a/tests/grpc/chain_height.go b/sdkclient/chain_height.go similarity index 73% rename from tests/grpc/chain_height.go rename to sdkclient/chain_height.go index 2cda11b1d7..20ec11b9e5 100644 --- a/tests/grpc/chain_height.go +++ b/sdkclient/chain_height.go @@ -1,4 +1,4 @@ -package grpc +package sdkclient import ( "context" @@ -16,11 +16,11 @@ var ( queryEventNewBlockHeader = tmtypes.QueryForEvent(tmtypes.EventNewBlockHeader) ) -// ChainHeight is used to cache the chain height of the +// ChainHeightListener is used to cache the chain height of the // current node which is being updated each time the // node sends an event of EventNewBlockHeader. // It starts a goroutine to subscribe to blockchain new block event and update the cached height. -type ChainHeight struct { +type ChainHeightListener struct { Logger zerolog.Logger mtx sync.RWMutex @@ -31,11 +31,11 @@ type ChainHeight struct { // NewChainHeight returns a new ChainHeight struct that // starts a new goroutine subscribed to EventNewBlockHeader. -func NewChainHeight( +func NewChainHeightListener( ctx context.Context, rpcClient tmrpcclient.Client, logger zerolog.Logger, -) (*ChainHeight, error) { +) (*ChainHeightListener, error) { if !rpcClient.IsRunning() { if err := rpcClient.Start(); err != nil { return nil, err @@ -47,19 +47,18 @@ func NewChainHeight( if err != nil { return nil, err } - - chainHeight := &ChainHeight{ - Logger: logger.With().Str("oracle_client", "chain_height").Logger(), + chainHeight := &ChainHeightListener{ + Logger: logger.With().Str("app_client", "chain_height").Logger(), + HeightChanged: make(chan int64), } - chainHeight.HeightChanged = make(chan int64) go chainHeight.subscribe(ctx, rpcClient, newBlockHeaderSubscription) return chainHeight, nil } -// updateChainHeight receives the data to be updated thread safe. -func (chainHeight *ChainHeight) updateChainHeight(blockHeight int64, err error) { +// setChainHeight receives the data to be updated thread safe. +func (chainHeight *ChainHeightListener) setChainHeight(blockHeight int64, err error) { chainHeight.mtx.Lock() defer chainHeight.mtx.Unlock() @@ -75,7 +74,7 @@ func (chainHeight *ChainHeight) updateChainHeight(blockHeight int64, err error) // subscribe listens to new blocks being made // and updates the chain height. -func (chainHeight *ChainHeight) subscribe( +func (chainHeight *ChainHeightListener) subscribe( ctx context.Context, eventsClient tmrpcclient.EventsClient, newBlockHeaderSubscription <-chan tmctypes.ResultEvent, @@ -86,7 +85,7 @@ func (chainHeight *ChainHeight) subscribe( err := eventsClient.Unsubscribe(ctx, tmtypes.EventNewBlockHeader, queryEventNewBlockHeader.String()) if err != nil { chainHeight.Logger.Err(err) - chainHeight.updateChainHeight(chainHeight.lastChainHeight, err) + chainHeight.setChainHeight(chainHeight.lastChainHeight, err) } chainHeight.Logger.Info().Msg("closing the ChainHeight subscription") return @@ -95,16 +94,16 @@ func (chainHeight *ChainHeight) subscribe( eventDataNewBlockHeader, ok := resultEvent.Data.(tmtypes.EventDataNewBlockHeader) if !ok { chainHeight.Logger.Err(errParseEventDataNewBlockHeader) - chainHeight.updateChainHeight(chainHeight.lastChainHeight, errParseEventDataNewBlockHeader) + chainHeight.setChainHeight(chainHeight.lastChainHeight, errParseEventDataNewBlockHeader) continue } - chainHeight.updateChainHeight(eventDataNewBlockHeader.Header.Height, nil) + chainHeight.setChainHeight(eventDataNewBlockHeader.Header.Height, nil) } } } -// GetChainHeight returns the last chain height available. -func (chainHeight *ChainHeight) GetChainHeight() (int64, error) { +// GetHeight returns the last chain height available. +func (chainHeight *ChainHeightListener) GetHeight() (int64, error) { chainHeight.mtx.RLock() defer chainHeight.mtx.RUnlock() diff --git a/sdkclient/client.go b/sdkclient/client.go new file mode 100644 index 0000000000..6b105c1b93 --- /dev/null +++ b/sdkclient/client.go @@ -0,0 +1,51 @@ +package sdkclient + +import ( + "context" + "time" + + sdkparams "github.com/cosmos/cosmos-sdk/simapp/params" + "github.com/rs/zerolog" + rpcclient "github.com/tendermint/tendermint/rpc/client" + "github.com/umee-network/umee/v4/sdkclient/query" + "github.com/umee-network/umee/v4/sdkclient/tx" +) + +// Client provides basic capabilities to connect to a Cosmos SDK based chain and execute +// transactions and queries. The object should be extended by another struct to provide +// chain specific transactions and queries. Example: +// https://github.com/umee-network/umee/blob/main/client +type Client struct { + Query *query.Client + Tx *tx.Client +} + +func NewClient( + chainID, + tmrpcEndpoint, + grpcEndpoint, + accountName, + accountMnemonic string, + gasAdjustment float64, + encCfg sdkparams.EncodingConfig, +) (uc Client, err error) { + uc = Client{} + uc.Query, err = query.NewClient(grpcEndpoint, 15*time.Second) + if err != nil { + return Client{}, err + } + uc.Tx, err = tx.NewClient(chainID, tmrpcEndpoint, accountName, accountMnemonic, gasAdjustment, encCfg) + return uc, err +} + +func (c Client) NewChainHeightListener(ctx context.Context, logger zerolog.Logger) (*ChainHeightListener, error) { + return NewChainHeightListener(ctx, c.Tx.ClientContext.Client, logger) +} + +func (c Client) QueryTimeout() time.Duration { + return c.Query.QueryTimeout +} + +func (c Client) TmClient() rpcclient.Client { + return c.Tx.ClientContext.Client +} diff --git a/sdkclient/query/client.go b/sdkclient/query/client.go new file mode 100644 index 0000000000..dc24c1574c --- /dev/null +++ b/sdkclient/query/client.go @@ -0,0 +1,64 @@ +package query + +import ( + "context" + "net" + "strings" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +type Client struct { + GrpcConn *grpc.ClientConn + grpcEndpoint string + QueryTimeout time.Duration +} + +func NewClient(grpcEndpoint string, queryTimeout time.Duration) (*Client, error) { + qc := &Client{grpcEndpoint: grpcEndpoint, QueryTimeout: queryTimeout} + return qc, qc.dialGrpcConn() +} + +func (c *Client) dialGrpcConn() (err error) { + c.GrpcConn, err = grpc.Dial( + c.grpcEndpoint, + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithContextDialer(dialerFunc), + ) + return err +} + +func (c Client) NewCtx() (context.Context, context.CancelFunc) { + return context.WithTimeout(context.Background(), c.QueryTimeout) +} + +func (c Client) NewCtxWithCancel() (context.Context, context.CancelFunc) { + return context.WithCancel(context.Background()) +} + +func dialerFunc(_ context.Context, addr string) (net.Conn, error) { + return Connect(addr) +} + +// Connect dials the given address and returns a net.Conn. +// The protoAddr argument should be prefixed with the protocol, +// eg. "tcp://127.0.0.1:8080" or "unix:///tmp/test.sock". +func Connect(protoAddr string) (net.Conn, error) { + proto, address := protocolAndAddress(protoAddr) + conn, err := net.Dial(proto, address) + return conn, err +} + +// protocolAndAddress splits an address into the protocol and address components. +// For instance, "tcp://127.0.0.1:8080" will be split into "tcp" and "127.0.0.1:8080". +// If the address has no protocol prefix, the default is "tcp". +func protocolAndAddress(listenAddr string) (string, string) { + parts := strings.SplitN(listenAddr, "://", 2) + if len(parts) == 2 { + return parts[0], parts[1] + } + + return "tcp", listenAddr +} diff --git a/sdkclient/query/gov.go b/sdkclient/query/gov.go new file mode 100644 index 0000000000..8880f21a6e --- /dev/null +++ b/sdkclient/query/gov.go @@ -0,0 +1,20 @@ +package query + +import ( + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1" +) + +func (c *Client) GovClient() govtypes.QueryClient { + return govtypes.NewQueryClient(c.GrpcConn) +} + +func (c *Client) GovProposal(proposalID uint64) (*govtypes.Proposal, error) { + ctx, cancel := c.NewCtx() + defer cancel() + + queryResponse, err := c.GovClient().Proposal(ctx, &govtypes.QueryProposalRequest{ProposalId: proposalID}) + if err != nil { + return nil, err + } + return queryResponse.Proposal, nil +} diff --git a/tests/grpc/client/tx/bank.go b/sdkclient/tx/bank.go similarity index 70% rename from tests/grpc/client/tx/bank.go rename to sdkclient/tx/bank.go index 9bff7e054f..8082b71f3b 100644 --- a/tests/grpc/client/tx/bank.go +++ b/sdkclient/tx/bank.go @@ -5,7 +5,7 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" ) -func (c *Client) TxSend(fromAddress string, toAddress string, amount sdk.Coins) (*sdk.TxResponse, error) { +func (c *Client) TxSend(fromAddress, toAddress string, amount sdk.Coins) (*sdk.TxResponse, error) { msg := &banktypes.MsgSend{ FromAddress: fromAddress, ToAddress: toAddress, diff --git a/tests/grpc/client/tx/client.go b/sdkclient/tx/client.go similarity index 78% rename from tests/grpc/client/tx/client.go rename to sdkclient/tx/client.go index 85c40270e7..6d5f939221 100644 --- a/tests/grpc/client/tx/client.go +++ b/sdkclient/tx/client.go @@ -7,16 +7,12 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdkparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/tx/signing" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" rpchttp "github.com/tendermint/tendermint/rpc/client/http" tmjsonclient "github.com/tendermint/tendermint/rpc/jsonrpc/client" - umeeapp "github.com/umee-network/umee/v4/app" -) - -const ( - gasAdjustment = 1 ) type Client struct { @@ -24,48 +20,52 @@ type Client struct { TMRPCEndpoint string ClientContext *client.Context + gasAdjustment float64 keyringKeyring keyring.Keyring keyringRecord *keyring.Record txFactory *tx.Factory + encCfg sdkparams.EncodingConfig } // Initializes a cosmos sdk client context and transaction factory for // signing and broadcasting transactions -func NewTxClient( +func NewClient( chainID string, tmrpcEndpoint string, accountName string, accountMnemonic string, + gasAdjustment float64, + encCfg sdkparams.EncodingConfig, ) (c *Client, err error) { c = &Client{ ChainID: chainID, TMRPCEndpoint: tmrpcEndpoint, + gasAdjustment: gasAdjustment, + encCfg: encCfg, } - c.keyringRecord, c.keyringKeyring, err = CreateAccountFromMnemonic(accountName, accountMnemonic) + c.keyringRecord, c.keyringKeyring, err = CreateAccountFromMnemonic(accountName, accountMnemonic, encCfg.Codec) if err != nil { return nil, err } - err = c.createClientContext() + err = c.initClientCtx() if err != nil { return nil, err } - c.createTxFactory() + c.initTxFactory() return c, err } -func (c *Client) createClientContext() error { - encoding := umeeapp.MakeEncodingConfig() +func (c *Client) initClientCtx() error { fromAddress, _ := c.keyringRecord.GetAddress() tmHTTPClient, err := tmjsonclient.DefaultHTTPClient(c.TMRPCEndpoint) if err != nil { return err } - tmRPCClient, err := rpchttp.NewWithClient(c.TMRPCEndpoint, "/websocket", tmHTTPClient) if err != nil { return err @@ -73,13 +73,13 @@ func (c *Client) createClientContext() error { c.ClientContext = &client.Context{ ChainID: c.ChainID, - InterfaceRegistry: encoding.InterfaceRegistry, + InterfaceRegistry: c.encCfg.InterfaceRegistry, Output: os.Stderr, BroadcastMode: flags.BroadcastBlock, - TxConfig: encoding.TxConfig, + TxConfig: c.encCfg.TxConfig, AccountRetriever: authtypes.AccountRetriever{}, - Codec: encoding.Codec, - LegacyAmino: encoding.Amino, + Codec: c.encCfg.Codec, + LegacyAmino: c.encCfg.Amino, Input: os.Stdin, NodeURI: c.TMRPCEndpoint, Client: tmRPCClient, @@ -97,16 +97,16 @@ func (c *Client) createClientContext() error { return nil } -func (c *Client) createTxFactory() { - factory := tx.Factory{}. +func (c *Client) initTxFactory() { + f := tx.Factory{}. WithAccountRetriever(c.ClientContext.AccountRetriever). WithChainID(c.ChainID). WithTxConfig(c.ClientContext.TxConfig). - WithGasAdjustment(gasAdjustment). + WithGasAdjustment(c.gasAdjustment). WithKeybase(c.ClientContext.Keyring). WithSignMode(signing.SignMode_SIGN_MODE_DIRECT). WithSimulateAndExecute(true) - c.txFactory = &factory + c.txFactory = &f } func (c *Client) BroadcastTx(msgs ...sdk.Msg) (*sdk.TxResponse, error) { diff --git a/tests/grpc/client/tx/gov.go b/sdkclient/tx/gov.go similarity index 61% rename from tests/grpc/client/tx/gov.go rename to sdkclient/tx/gov.go index bb362d4771..fbb3283148 100644 --- a/tests/grpc/client/tx/gov.go +++ b/sdkclient/tx/gov.go @@ -6,7 +6,7 @@ import ( proposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" ) -func (c *Client) TxVoteYes(proposalID uint64) (*sdk.TxResponse, error) { +func (c *Client) GovVoteYes(proposalID uint64) (*sdk.TxResponse, error) { voter, err := c.keyringRecord.GetAddress() if err != nil { return nil, err @@ -25,25 +25,32 @@ func (c *Client) TxVoteYes(proposalID uint64) (*sdk.TxResponse, error) { return c.BroadcastTx(msg) } -func (c *Client) TxSubmitProposal( - changes []proposal.ParamChange, +func (c *Client) GovParamChange(title, description string, changes []proposal.ParamChange, deposit sdk.Coins, ) (*sdk.TxResponse, error) { + content := proposal.NewParameterChangeProposal(title, description, changes) + fromAddr, err := c.keyringRecord.GetAddress() + if err != nil { + return nil, err + } + msg, err := govtypes.NewMsgSubmitProposal(content, deposit, fromAddr) + if err != nil { + return nil, err + } + + return c.BroadcastTx(msg) +} + +func (c *Client) GovSubmitProposal(changes []proposal.ParamChange, deposit sdk.Coins) (*sdk.TxResponse, error) { content := proposal.NewParameterChangeProposal( "update historic stamp period", "auto grpc proposal", changes, ) - deposit, err := sdk.ParseCoinsNormalized("10000000uumee") - if err != nil { - return nil, err - } - fromAddr, err := c.keyringRecord.GetAddress() if err != nil { return nil, err } - msg, err := govtypes.NewMsgSubmitProposal(content, deposit, fromAddr) if err != nil { return nil, err diff --git a/tests/grpc/client/tx/key.go b/sdkclient/tx/key.go similarity index 75% rename from tests/grpc/client/tx/key.go rename to sdkclient/tx/key.go index df72ac9633..ec9ddbac98 100644 --- a/tests/grpc/client/tx/key.go +++ b/sdkclient/tx/key.go @@ -1,11 +1,10 @@ package tx import ( + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" - - umeeapp "github.com/umee-network/umee/v4/app" ) const ( @@ -13,10 +12,7 @@ const ( keyringAppName = "testnet" ) -func CreateAccountFromMnemonic(name, mnemonic string) (*keyring.Record, keyring.Keyring, error) { - encodingConfig := umeeapp.MakeEncodingConfig() - cdc := encodingConfig.Codec - +func CreateAccountFromMnemonic(name, mnemonic string, cdc codec.Codec) (*keyring.Record, keyring.Keyring, error) { kb, err := keyring.New(keyringAppName, keyring.BackendTest, "", nil, cdc) if err != nil { return nil, nil, err diff --git a/tests/grpc/client/tx/sign.go b/sdkclient/tx/sign.go similarity index 88% rename from tests/grpc/client/tx/sign.go rename to sdkclient/tx/sign.go index 7a49289988..343f17be09 100644 --- a/tests/grpc/client/tx/sign.go +++ b/sdkclient/tx/sign.go @@ -27,18 +27,18 @@ func BroadcastTx(clientCtx client.Context, txf tx.Factory, msgs ...sdk.Msg) (*sd // make sure gas in enough to execute the txs txf = txf.WithGas(adjusted * 3 / 2) - unsignedTx, err := txf.BuildUnsignedTx(msgs...) + txBuilder, err := txf.BuildUnsignedTx(msgs...) if err != nil { return nil, err } - unsignedTx.SetFeeGranter(clientCtx.GetFeeGranterAddress()) + txBuilder.SetFeeGranter(clientCtx.GetFeeGranterAddress()) - if err = tx.Sign(txf, clientCtx.GetFromName(), unsignedTx, true); err != nil { + if err = tx.Sign(txf, clientCtx.GetFromName(), txBuilder, true); err != nil { return nil, err } - txBytes, err := clientCtx.TxConfig.TxEncoder()(unsignedTx.GetTx()) + txBytes, err := clientCtx.TxConfig.TxEncoder()(txBuilder.GetTx()) if err != nil { return nil, err } diff --git a/tests/e2e/chain.go b/tests/e2e/chain.go index d84cd7b198..77592231b0 100644 --- a/tests/e2e/chain.go +++ b/tests/e2e/chain.go @@ -8,12 +8,12 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdkparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" tmrand "github.com/tendermint/tendermint/libs/rand" umeeapp "github.com/umee-network/umee/v4/app" - "github.com/umee-network/umee/v4/app/params" ) const ( @@ -22,7 +22,7 @@ const ( ) var ( - encodingConfig params.EncodingConfig + encodingConfig sdkparams.EncodingConfig cdc codec.Codec ) diff --git a/tests/e2e/e2e_setup_test.go b/tests/e2e/e2e_setup_test.go index 43db40fb5f..00d9d34051 100644 --- a/tests/e2e/e2e_setup_test.go +++ b/tests/e2e/e2e_setup_test.go @@ -36,7 +36,7 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" appparams "github.com/umee-network/umee/v4/app/params" - "github.com/umee-network/umee/v4/tests/grpc/client" + "github.com/umee-network/umee/v4/client" "github.com/umee-network/umee/v4/x/leverage/fixtures" leveragetypes "github.com/umee-network/umee/v4/x/leverage/types" oracletypes "github.com/umee-network/umee/v4/x/oracle/types" @@ -81,7 +81,7 @@ type IntegrationTestSuite struct { valResources []*dockertest.Resource orchResources []*dockertest.Resource gravityContractAddr string - umeeClient *client.UmeeClient + umee client.Client } func TestIntegrationTestSuite(t *testing.T) { @@ -1077,12 +1077,15 @@ func (s *IntegrationTestSuite) runPriceFeeder() { func (s *IntegrationTestSuite) initUmeeClient() { var err error - s.umeeClient, err = client.NewUmeeClient( + ecfg := appparams.MakeEncodingConfig() + s.umee, err = client.NewClient( s.chain.id, "tcp://localhost:26657", "tcp://localhost:9090", "val1", s.chain.validators[0].mnemonic, + 1, + ecfg, ) s.Require().NoError(err) } diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index 00bc75530b..5dbd0e0bd3 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -72,13 +72,13 @@ func (s *IntegrationTestSuite) TestUmeeTokenTransfers() { // medians deviations are correct, updates the oracle params with // a gov prop, then checks the medians and median deviations again. func (s *IntegrationTestSuite) TestMedians() { - err := grpc.MedianCheck(s.umeeClient) + err := grpc.MedianCheck(s.umee) s.Require().NoError(err) } func (s *IntegrationTestSuite) TestUpdateOracleParams() { s.T().Skip("paused due to validator power threshold enforcing") - params, err := s.umeeClient.QueryClient.QueryParams() + params, err := s.umee.QueryOracleParams() s.Require().NoError(err) s.Require().Equal(uint64(5), params.HistoricStampPeriod) @@ -86,12 +86,12 @@ func (s *IntegrationTestSuite) TestUpdateOracleParams() { s.Require().Equal(uint64(20), params.MedianStampPeriod) err = grpc.SubmitAndPassProposal( - s.umeeClient, + s.umee, grpc.OracleParamChanges(10, 2, 20), ) s.Require().NoError(err) - params, err = s.umeeClient.QueryClient.QueryParams() + params, err = s.umee.QueryOracleParams() s.Require().NoError(err) s.Require().Equal(uint64(10), params.HistoricStampPeriod) diff --git a/tests/grpc/client/query/bank.go b/tests/grpc/client/query/bank.go deleted file mode 100644 index 1966fcbc88..0000000000 --- a/tests/grpc/client/query/bank.go +++ /dev/null @@ -1,23 +0,0 @@ -package query - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" -) - -func (c *Client) BankQueryClient() banktypes.QueryClient { - return banktypes.NewQueryClient(c.grpcConn) -} - -func (c *Client) QueryAllBalances(address string) (sdk.Coins, error) { - ctx, cancel := context.WithTimeout(context.Background(), queryTimeout) - defer cancel() - - queryResponse, err := c.BankQueryClient().AllBalances(ctx, &banktypes.QueryAllBalancesRequest{Address: address}) - if err != nil { - return nil, err - } - return queryResponse.Balances, nil -} diff --git a/tests/grpc/client/query/client.go b/tests/grpc/client/query/client.go deleted file mode 100644 index 2e4ad6e0ae..0000000000 --- a/tests/grpc/client/query/client.go +++ /dev/null @@ -1,35 +0,0 @@ -package query - -import ( - "time" - - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" -) - -const ( - queryTimeout = 15 * time.Second -) - -type Client struct { - grpcEndpoint string - grpcConn *grpc.ClientConn -} - -func NewQueryClient(grpcEndpoint string) (*Client, error) { - qc := &Client{grpcEndpoint: grpcEndpoint} - err := qc.dialGrpcConn() - if err != nil { - return nil, err - } - return qc, nil -} - -func (c *Client) dialGrpcConn() (err error) { - c.grpcConn, err = grpc.Dial( - c.grpcEndpoint, - grpc.WithTransportCredentials(insecure.NewCredentials()), - grpc.WithContextDialer(dialerFunc), - ) - return err -} diff --git a/tests/grpc/client/query/gov.go b/tests/grpc/client/query/gov.go deleted file mode 100644 index 312d9dccee..0000000000 --- a/tests/grpc/client/query/gov.go +++ /dev/null @@ -1,22 +0,0 @@ -package query - -import ( - "context" - - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1" -) - -func (c *Client) GovQueryClient() govtypes.QueryClient { - return govtypes.NewQueryClient(c.grpcConn) -} - -func (c *Client) QueryProposal(proposalID uint64) (*govtypes.Proposal, error) { - ctx, cancel := context.WithTimeout(context.Background(), queryTimeout) - defer cancel() - - queryResponse, err := c.GovQueryClient().Proposal(ctx, &govtypes.QueryProposalRequest{ProposalId: proposalID}) - if err != nil { - return nil, err - } - return queryResponse.Proposal, nil -} diff --git a/tests/grpc/client/query/grpc.go b/tests/grpc/client/query/grpc.go deleted file mode 100644 index 482c4772d9..0000000000 --- a/tests/grpc/client/query/grpc.go +++ /dev/null @@ -1,34 +0,0 @@ -package query - -import ( - "context" - "net" - "strings" -) - -func dialerFunc(_ context.Context, addr string) (net.Conn, error) { - return Connect(addr) -} - -// Connect dials the given address and returns a net.Conn. The protoAddr -// argument should be prefixed with the protocol, -// eg. "tcp://127.0.0.1:8080" or "unix:///tmp/test.sock". -func Connect(protoAddr string) (net.Conn, error) { - proto, address := ProtocolAndAddress(protoAddr) - conn, err := net.Dial(proto, address) - return conn, err -} - -// ProtocolAndAddress splits an address into the protocol and address components. -// For instance, "tcp://127.0.0.1:8080" will be split into "tcp" and "127.0.0.1:8080". -// If the address has no protocol prefix, the default is "tcp". -func ProtocolAndAddress(listenAddr string) (string, string) { - protocol, address := "tcp", listenAddr - - parts := strings.SplitN(address, "://", 2) - if len(parts) == 2 { - protocol, address = parts[0], parts[1] - } - - return protocol, address -} diff --git a/tests/grpc/client/query/oracle.go b/tests/grpc/client/query/oracle.go deleted file mode 100644 index d445253b5f..0000000000 --- a/tests/grpc/client/query/oracle.go +++ /dev/null @@ -1,56 +0,0 @@ -package query - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - oracletypes "github.com/umee-network/umee/v4/x/oracle/types" -) - -func (c *Client) OracleQueryClient() oracletypes.QueryClient { - return oracletypes.NewQueryClient(c.grpcConn) -} - -func (c *Client) QueryParams() (oracletypes.Params, error) { - ctx, cancel := context.WithTimeout(context.Background(), queryTimeout) - defer cancel() - - queryResponse, err := c.OracleQueryClient().Params(ctx, &oracletypes.QueryParams{}) - if err != nil { - return oracletypes.Params{}, err - } - return queryResponse.Params, nil -} - -func (c *Client) QueryExchangeRates() ([]sdk.DecCoin, error) { - ctx, cancel := context.WithTimeout(context.Background(), queryTimeout) - defer cancel() - - queryResponse, err := c.OracleQueryClient().ExchangeRates(ctx, &oracletypes.QueryExchangeRates{}) - if err != nil { - return nil, err - } - return queryResponse.ExchangeRates, nil -} - -func (c *Client) QueryMedians() (oracletypes.Prices, error) { - ctx, cancel := context.WithTimeout(context.Background(), queryTimeout) - defer cancel() - - queryResponse, err := c.OracleQueryClient().Medians(ctx, &oracletypes.QueryMedians{}) - if err != nil { - return nil, err - } - return queryResponse.Medians, nil -} - -func (c *Client) QueryMedianDeviations() (oracletypes.Prices, error) { - ctx, cancel := context.WithTimeout(context.Background(), queryTimeout) - defer cancel() - - queryResponse, err := c.OracleQueryClient().MedianDeviations(ctx, &oracletypes.QueryMedianDeviations{}) - if err != nil { - return nil, err - } - return queryResponse.MedianDeviations, nil -} diff --git a/tests/grpc/client/umee_client.go b/tests/grpc/client/umee_client.go deleted file mode 100644 index e8df845569..0000000000 --- a/tests/grpc/client/umee_client.go +++ /dev/null @@ -1,29 +0,0 @@ -package client - -import ( - "github.com/umee-network/umee/v4/tests/grpc/client/query" - "github.com/umee-network/umee/v4/tests/grpc/client/tx" -) - -// UmeeClient is a helper for initializing a keychain, a cosmos-sdk client context, -// and sending transactions/queries to a specific Umee node -type UmeeClient struct { - QueryClient *query.Client - TxClient *tx.Client -} - -func NewUmeeClient( - chainID string, - tmrpcEndpoint string, - grpcEndpoint string, - accountName string, - accountMnemonic string, -) (uc *UmeeClient, err error) { - uc = &UmeeClient{} - uc.QueryClient, err = query.NewQueryClient(grpcEndpoint) - if err != nil { - return nil, err - } - uc.TxClient, err = tx.NewTxClient(chainID, tmrpcEndpoint, accountName, accountMnemonic) - return uc, err -} diff --git a/tests/grpc/gov.go b/tests/grpc/gov.go index d0f631f808..9e499c0195 100644 --- a/tests/grpc/gov.go +++ b/tests/grpc/gov.go @@ -5,12 +5,23 @@ import ( "strconv" "time" + sdk "github.com/cosmos/cosmos-sdk/types" proposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" - "github.com/umee-network/umee/v4/tests/grpc/client" + "github.com/umee-network/umee/v4/client" ) -func SubmitAndPassProposal(umeeClient *client.UmeeClient, changes []proposal.ParamChange) error { - resp, err := umeeClient.TxClient.TxSubmitProposal(changes) +var govDeposit sdk.Coins + +func init() { + var err error + govDeposit, err = sdk.ParseCoinsNormalized("10000000uumee") + if err != nil { + panic(err) + } +} + +func SubmitAndPassProposal(umee client.Client, changes []proposal.ParamChange) error { + resp, err := umee.Tx.GovSubmitProposal(changes, govDeposit) if err != nil { return err } @@ -35,12 +46,12 @@ func SubmitAndPassProposal(umeeClient *client.UmeeClient, changes []proposal.Par return err } - _, err = umeeClient.TxClient.TxVoteYes(proposalIDInt) + _, err = umee.Tx.GovVoteYes(proposalIDInt) if err != nil { return err } - prop, err := umeeClient.QueryClient.QueryProposal(proposalIDInt) + prop, err := umee.Query.GovProposal(proposalIDInt) if err != nil { return err } @@ -50,7 +61,7 @@ func SubmitAndPassProposal(umeeClient *client.UmeeClient, changes []proposal.Par fmt.Printf("sleeping %s until end of voting period + 1 block\n", sleepDuration) time.Sleep(sleepDuration) - prop, err = umeeClient.QueryClient.QueryProposal(proposalIDInt) + prop, err = umee.Query.GovProposal(proposalIDInt) if err != nil { return err } diff --git a/tests/grpc/historical.go b/tests/grpc/historical.go index 033c4be62c..89d2eafea3 100644 --- a/tests/grpc/historical.go +++ b/tests/grpc/historical.go @@ -1,24 +1,23 @@ package grpc import ( - "context" "errors" "strings" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/rs/zerolog" - "github.com/umee-network/umee/v4/tests/grpc/client" + "github.com/umee-network/umee/v4/client" ) // MedianCheck waits for availability of all exchange rates from the denom accept list, // records historical stamp data based on the oracle params, computes the // median/median deviation and then compares that to the data in the // median/median deviation gRPC query -func MedianCheck(val1Client *client.UmeeClient) error { - ctx, cancel := context.WithCancel(context.Background()) +func MedianCheck(umee client.Client) error { + ctx, cancel := umee.NewQCtxWithCancel() defer cancel() - params, err := val1Client.QueryClient.QueryParams() + params, err := umee.QueryOracleParams() if err != nil { return err } @@ -28,14 +27,14 @@ func MedianCheck(val1Client *client.UmeeClient) error { denomAcceptList = append(denomAcceptList, strings.ToUpper(acceptItem.SymbolDenom)) } - chainHeight, err := NewChainHeight(ctx, val1Client.TxClient.ClientContext.Client, zerolog.Nop()) + chainHeight, err := umee.NewChainHeightListener(ctx, zerolog.Nop()) if err != nil { return err } var exchangeRates sdk.DecCoins for i := 0; i < 20; i++ { - exchangeRates, err = val1Client.QueryClient.QueryExchangeRates() + exchangeRates, err = umee.QueryExchangeRates() if err == nil && len(exchangeRates) == len(denomAcceptList) { break } @@ -49,7 +48,7 @@ func MedianCheck(val1Client *client.UmeeClient) error { return errors.New("couldn't fetch exchange rates matching denom accept list") } - priceStore, err := listenForPrices(val1Client, params, chainHeight) + priceStore, err := listenForPrices(umee, params, chainHeight) if err != nil { return err } diff --git a/tests/grpc/price_listener.go b/tests/grpc/price_listener.go index 137066c494..25706edd01 100644 --- a/tests/grpc/price_listener.go +++ b/tests/grpc/price_listener.go @@ -3,14 +3,15 @@ package grpc import ( "fmt" - "github.com/umee-network/umee/v4/tests/grpc/client" + "github.com/umee-network/umee/v4/client" + sdkclient "github.com/umee-network/umee/v4/sdkclient" oracletypes "github.com/umee-network/umee/v4/x/oracle/types" ) func listenForPrices( - umeeClient *client.UmeeClient, + umee client.Client, params oracletypes.Params, - chainHeight *ChainHeight, + chainHeight *sdkclient.ChainHeightListener, ) (*PriceStore, error) { priceStore := NewPriceStore() // Wait until the beginning of a median period @@ -26,7 +27,7 @@ func listenForPrices( for i := 0; i < int(params.MedianStampPeriod); i++ { height := <-chainHeight.HeightChanged if isPeriodFirstBlock(height, params.HistoricStampPeriod) { - exchangeRates, err := umeeClient.QueryClient.QueryExchangeRates() + exchangeRates, err := umee.QueryExchangeRates() fmt.Printf("block %d stamp: %+v\n", height, exchangeRates) if err != nil { return nil, err @@ -37,7 +38,7 @@ func listenForPrices( } } - medians, err := umeeClient.QueryClient.QueryMedians() + medians, err := umee.QueryMedians() if err != nil { return nil, err } @@ -52,7 +53,7 @@ func listenForPrices( priceStore.medians[median.ExchangeRateTuple.Denom] = median.ExchangeRateTuple.ExchangeRate } - medianDeviations, err := umeeClient.QueryClient.QueryMedianDeviations() + medianDeviations, err := umee.QueryMedianDeviations() if err != nil { return nil, err }