Skip to content

Commit

Permalink
Add TWAP CLI (#3214)
Browse files Browse the repository at this point in the history
## What is the purpose of the change

Add CLI query support for TWAP. I've eye ball-tested the values for correctness against imperator API. Ideally we add this logic to our querygen, or use proto-reflect from SDK to automate CLI boilerplate going for.

## Testing and Verifying

Manually tested

## Documentation and Release Note

  - Does this pull request introduce a new feature or user-facing behavior changes? yes
  - Is a relevant changelog entry added to the `Unreleased` section in `CHANGELOG.md`? yes
  - How is the feature or change documented? CLI help
  • Loading branch information
ValarDragon authored Nov 2, 2022
1 parent d80e025 commit e3e8e27
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

* [#2804](https://github.com/osmosis-labs/osmosis/pull/2804) Improve error handling and messages when parsing pool assets.
* [#3035](https://github.com/osmosis-labs/osmosis/pull/3035) Remove `PokePool` from `PoolI` interface. Define on a new WeightedPoolExtension` instead.
* [#3214](https://github.com/osmosis-labs/osmosis/pull/3214) Add basic CLI query support for TWAP.


## v12.0.0

Expand Down
139 changes: 139 additions & 0 deletions x/twap/client/cli/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package twapcli

import (
"fmt"
"strconv"
"strings"
"time"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/version"
"github.com/spf13/cobra"

gammtypes "github.com/osmosis-labs/osmosis/v12/x/gamm/types"
"github.com/osmosis-labs/osmosis/v12/x/twap/client/queryproto"
"github.com/osmosis-labs/osmosis/v12/x/twap/types"
)

// GetQueryCmd returns the cli query commands for this module.
func GetQueryCmd() *cobra.Command {
// Group superfluid queries under a subcommand
cmd := &cobra.Command{
Use: types.ModuleName,
Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName),
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}

cmd.AddCommand(GetQueryTwapCommand())

return cmd
}

// GetCmdAssetMultiplier returns multiplier of an asset by denom.
func GetQueryTwapCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "twap [poolid] [base denom] [start time] [end time]",
Short: "Query twap",
Long: strings.TrimSpace(
fmt.Sprintf(`Query twap for pull. Start time must be unix time. End time can be unix time or duration.
Example:
$ %s q twap 1 uosmo 1667088000 24h
$ %s q twap 1 uosmo 1667088000 1667174400
`,
version.AppName, version.AppName,
),
),
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
// boilerplate parse fields
// <UINT PARSE>
poolId, err := parseUint(args[0], "poolId")
if err != nil {
return err
}

// <DENOM PARSE>
baseDenom := strings.TrimSpace(args[1])

// <UNIX TIME PARSE>
startTime, err := parseUnixTime(args[2], "start time")
if err != nil {
return err
}

// END TIME PARSE: ONEOF {<UNIX TIME PARSE>, <DURATION>}
// try parsing in unix time, if failed try parsing in duration
endTime, err := parseUnixTime(args[3], "end time")
if err != nil {
// TODO if we don't use protoreflect:
// make better error combiner, rather than just returning last error
duration, err := time.ParseDuration(args[3])
if err != nil {
return err
}
endTime = startTime.Add(duration)
}

clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := queryproto.NewQueryClient(clientCtx)
gammClient := gammtypes.NewQueryClient(clientCtx)
liquidity, err := gammClient.TotalPoolLiquidity(cmd.Context(), &gammtypes.QueryTotalPoolLiquidityRequest{PoolId: poolId})
if err != nil {
return err
}
if len(liquidity.Liquidity) != 2 {
return fmt.Errorf("pool %d has %d assets of liquidity, CLI support only exists for 2 assets right now.", poolId, len(liquidity.Liquidity))
}
quoteDenom := ""
if liquidity.Liquidity[0].Denom == baseDenom {
quoteDenom = liquidity.Liquidity[1].Denom
} else if liquidity.Liquidity[1].Denom == baseDenom {
quoteDenom = liquidity.Liquidity[0].Denom
} else {
return fmt.Errorf("pool %d doesn't have provided baseDenom %s, has %s and %s",
poolId, baseDenom, liquidity.Liquidity[0], liquidity.Liquidity[1])
}

res, err := queryClient.ArithmeticTwap(cmd.Context(), &queryproto.ArithmeticTwapRequest{
PoolId: poolId,
BaseAsset: baseDenom,
QuoteAsset: quoteDenom,
StartTime: startTime,
EndTime: &endTime,
})
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}

func parseUint(arg string, fieldName string) (uint64, error) {
v, err := strconv.ParseUint(arg, 10, 64)
if err != nil {
return 0, fmt.Errorf("could not parse %s as uint for field %s: %w", arg, fieldName, err)
}
return v, nil
}

func parseUnixTime(arg string, fieldName string) (time.Time, error) {
timeUnix, err := strconv.ParseInt(arg, 10, 64)
if err != nil {
return time.Time{}, fmt.Errorf("could not parse %s as unix time for field %s: %w", arg, fieldName, err)
}
startTime := time.Unix(timeUnix, 0)
return startTime, nil
}
4 changes: 2 additions & 2 deletions x/twap/twapmodule/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (

"github.com/osmosis-labs/osmosis/v12/x/twap"
twapclient "github.com/osmosis-labs/osmosis/v12/x/twap/client"
twapcli "github.com/osmosis-labs/osmosis/v12/x/twap/client/cli"
"github.com/osmosis-labs/osmosis/v12/x/twap/client/grpc"
"github.com/osmosis-labs/osmosis/v12/x/twap/client/queryproto"
"github.com/osmosis-labs/osmosis/v12/x/twap/types"
Expand Down Expand Up @@ -63,8 +64,7 @@ func (b AppModuleBasic) GetTxCmd() *cobra.Command {
}

func (b AppModuleBasic) GetQueryCmd() *cobra.Command {
return nil
// return cli.GetQueryCmd()
return twapcli.GetQueryCmd()
}

// RegisterInterfaces registers interfaces and implementations of the gamm module.
Expand Down

0 comments on commit e3e8e27

Please sign in to comment.