0g-chain/x/bep3/client/cli/query.go
Kevin Davis 790753f156
BEP3: support multiple assets (#616)
* wip: refactor to allow multiple bep3 assets

* update tests

* sims: validate asset before claiming

* move asset supply to params

* update tests

* fix sims

* fix tests

* wip: add migration from v0.9 -> v0.10 bep3

* fix build and migration tests

* nit: rename file

* move asset supply out of params

* update committee tests

* fix sims

* address review comments

* address review comments

* address review comments
2020-08-17 11:06:59 -04:00

338 lines
11 KiB
Go

package cli
import (
"encoding/hex"
"fmt"
"strconv"
"strings"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/spf13/cobra"
"github.com/spf13/viper"
tmtime "github.com/tendermint/tendermint/types/time"
"github.com/kava-labs/kava/x/bep3/types"
)
// Query atomic swaps flags
const (
flagInvolve = "involve"
flagExpiration = "expiration"
flagStatus = "status"
flagDirection = "direction"
)
// GetQueryCmd returns the cli query commands for this module
func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
// Group bep3 queries under a subcommand
bep3QueryCmd := &cobra.Command{
Use: "bep3",
Short: "Querying commands for the bep3 module",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
bep3QueryCmd.AddCommand(flags.GetCommands(
QueryCalcSwapIDCmd(queryRoute, cdc),
QueryCalcRandomNumberHashCmd(queryRoute, cdc),
QueryGetAssetSupplyCmd(queryRoute, cdc),
QueryGetAssetSuppliesCmd(queryRoute, cdc),
QueryGetAtomicSwapCmd(queryRoute, cdc),
QueryGetAtomicSwapsCmd(queryRoute, cdc),
QueryParamsCmd(queryRoute, cdc),
)...)
return bep3QueryCmd
}
// QueryCalcRandomNumberHashCmd calculates the random number hash for a number and timestamp
func QueryCalcRandomNumberHashCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "calc-rnh [unix-timestamp]",
Short: "calculates an example random number hash from an optional timestamp",
Example: "bep3 calc-rnh now",
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
userTimestamp := "now"
if len(args) > 0 {
userTimestamp = args[0]
}
// Timestamp defaults to time.Now() unless it's explicitly set
var timestamp int64
if strings.Compare(userTimestamp, "now") == 0 {
timestamp = tmtime.Now().Unix()
} else {
userTimestamp, err := strconv.ParseInt(userTimestamp, 10, 64)
if err != nil {
return err
}
timestamp = userTimestamp
}
// Load hex-encoded cryptographically strong pseudo-random number
randomNumber, err := types.GenerateSecureRandomNumber()
if err != nil {
return err
}
randomNumberHash := types.CalculateRandomHash(randomNumber, timestamp)
// Prepare random number, timestamp, and hash for output
randomNumberStr := fmt.Sprintf("Random number: %s\n", hex.EncodeToString(randomNumber))
timestampStr := fmt.Sprintf("Timestamp: %d\n", timestamp)
randomNumberHashStr := fmt.Sprintf("Random number hash: %s", hex.EncodeToString(randomNumberHash))
output := []string{randomNumberStr, timestampStr, randomNumberHashStr}
return cliCtx.PrintOutput(strings.Join(output, ""))
},
}
}
// QueryCalcSwapIDCmd calculates the swapID for a random number hash, sender, and sender other chain
func QueryCalcSwapIDCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "calc-swapid [random-number-hash] [sender] [sender-other-chain]",
Short: "calculate swap ID for the given random number hash, sender, and sender other chain",
Example: "bep3 calc-swapid 0677bd8a303dd981810f34d8e5cc6507f13b391899b84d3c1be6c6045a17d747 kava1l0xsq2z7gqd7yly0g40y5836g0appumark77ny bnb1ud3q90r98l3mhd87kswv3h8cgrymzeljct8qn7",
Args: cobra.MinimumNArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
// Parse query params
randomNumberHash, err := hex.DecodeString(args[0])
if err != nil {
return err
}
sender, err := sdk.AccAddressFromBech32(args[1])
if err != nil {
return err
}
senderOtherChain := args[2]
// Calculate swap ID and convert to human-readable string
swapID := types.CalculateSwapID(randomNumberHash, sender, senderOtherChain)
return cliCtx.PrintOutput(hex.EncodeToString(swapID))
},
}
}
// QueryGetAssetSupplyCmd queries as asset's current in swap supply, active, supply, and supply limit
func QueryGetAssetSupplyCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "supply [denom]",
Short: "get information about an asset's supply",
Example: "bep3 supply bnb",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
// Prepare query params
bz, err := cdc.MarshalJSON(types.NewQueryAssetSupply(args[0]))
if err != nil {
return err
}
// Execute query
res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetAssetSupply), bz)
if err != nil {
return err
}
// Decode and print results
var assetSupply types.AssetSupply
cdc.MustUnmarshalJSON(res, &assetSupply)
return cliCtx.PrintOutput(assetSupply)
},
}
}
// QueryGetAssetSuppliesCmd queries AssetSupplies in the store
func QueryGetAssetSuppliesCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "supplies",
Short: "get a list of all asset supplies",
Example: "bep3 supplies",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetAssetSupplies), nil)
if err != nil {
return err
}
var assetSupplies types.AssetSupplies
cdc.MustUnmarshalJSON(res, &assetSupplies)
if len(assetSupplies) == 0 {
return fmt.Errorf("There are currently no asset supplies")
}
cliCtx = cliCtx.WithHeight(height)
return cliCtx.PrintOutput(assetSupplies)
},
}
}
// QueryGetAtomicSwapCmd queries an AtomicSwap by swapID
func QueryGetAtomicSwapCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "swap [swap-id]",
Short: "get atomic swap information",
Example: "bep3 swap 6682c03cc3856879c8fb98c9733c6b0c30758299138166b6523fe94628b1d3af",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
// Decode swapID's hex encoded string to []byte
swapID, err := hex.DecodeString(args[0])
if err != nil {
return err
}
// Prepare query params
bz, err := cdc.MarshalJSON(types.NewQueryAtomicSwapByID(swapID))
if err != nil {
return err
}
// Execute query
res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetAtomicSwap), bz)
if err != nil {
return err
}
var atomicSwap types.AugmentedAtomicSwap
cdc.MustUnmarshalJSON(res, &atomicSwap)
cliCtx = cliCtx.WithHeight(height)
return cliCtx.PrintOutput(atomicSwap)
},
}
}
// QueryGetAtomicSwapsCmd queries AtomicSwaps in the store
func QueryGetAtomicSwapsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "swaps",
Short: "query atomic swaps with optional filters",
Long: strings.TrimSpace(`Query for all paginated atomic swaps that match optional filters:
Example:
$ kvcli q bep3 swaps --involve=kava1l0xsq2z7gqd7yly0g40y5836g0appumark77ny
$ kvcli q bep3 swaps --expiration=280
$ kvcli q bep3 swaps --status=(Open|Completed|Expired)
$ kvcli q bep3 swaps --direction=(Incoming|Outgoing)
$ kvcli q bep3 swaps --page=2 --limit=100
`,
),
RunE: func(cmd *cobra.Command, args []string) error {
bechInvolveAddr := viper.GetString(flagInvolve)
strExpiration := viper.GetString(flagExpiration)
strSwapStatus := viper.GetString(flagStatus)
strSwapDirection := viper.GetString(flagDirection)
page := viper.GetInt(flags.FlagPage)
limit := viper.GetInt(flags.FlagLimit)
var involveAddr sdk.AccAddress
var expiration uint64
var swapStatus types.SwapStatus
var swapDirection types.SwapDirection
params := types.NewQueryAtomicSwaps(page, limit, involveAddr, expiration, swapStatus, swapDirection)
if len(bechInvolveAddr) != 0 {
involveAddr, err := sdk.AccAddressFromBech32(bechInvolveAddr)
if err != nil {
return err
}
params.Involve = involveAddr
}
if len(strExpiration) != 0 {
expiration, err := strconv.ParseUint(strExpiration, 10, 64)
if err != nil {
return err
}
params.Expiration = expiration
}
if len(strSwapStatus) != 0 {
swapStatus := types.NewSwapStatusFromString(strSwapStatus)
if !swapStatus.IsValid() {
return fmt.Errorf("invalid swap status %s", strSwapStatus)
}
params.Status = swapStatus
}
if len(strSwapDirection) != 0 {
swapDirection := types.NewSwapDirectionFromString(strSwapDirection)
if !swapDirection.IsValid() {
return fmt.Errorf("invalid swap direction %s", strSwapDirection)
}
params.Direction = swapDirection
}
bz, err := cdc.MarshalJSON(params)
if err != nil {
return err
}
cliCtx := context.NewCLIContext().WithCodec(cdc)
res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetAtomicSwaps), bz)
if err != nil {
return err
}
var matchingAtomicSwaps types.AugmentedAtomicSwaps
cdc.UnmarshalJSON(res, &matchingAtomicSwaps)
if len(matchingAtomicSwaps) == 0 {
return fmt.Errorf("No matching atomic swaps found")
}
cliCtx = cliCtx.WithHeight(height)
return cliCtx.PrintOutput(matchingAtomicSwaps) // nolint:errcheck
},
}
cmd.Flags().Int(flags.FlagPage, 1, "pagination page of atomic swaps to to query for")
cmd.Flags().Int(flags.FlagLimit, 100, "pagination limit of atomic swaps to query for")
cmd.Flags().String(flagInvolve, "", "(optional) filter by atomic swaps that involve an address")
cmd.Flags().String(flagExpiration, "", "(optional) filter by atomic swaps that expire before a block height")
cmd.Flags().String(flagStatus, "", "(optional) filter by atomic swap status, status: open/completed/expired")
cmd.Flags().String(flagDirection, "", "(optional) filter by atomic swap direction, direction: incoming/outgoing")
return cmd
}
// QueryParamsCmd queries the bep3 module parameters
func QueryParamsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "params",
Short: "get the bep3 module parameters",
Example: "bep3 params",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
// Query
route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetParams)
res, _, err := cliCtx.QueryWithData(route, nil)
if err != nil {
return err
}
// Decode and print results
var out types.Params
cdc.MustUnmarshalJSON(res, &out)
return cliCtx.PrintOutput(out)
},
}
}