Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(x/twap): modify cli to add geometric option #3812

Merged
merged 18 commits into from
Dec 22, 2022
110 changes: 88 additions & 22 deletions x/twap/client/cli/query.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package twapcli

import (
"context"
"fmt"
"strings"
"time"
Expand All @@ -18,21 +19,23 @@ import (
// GetQueryCmd returns the cli query commands for this module.
func GetQueryCmd() *cobra.Command {
cmd := osmocli.QueryIndexCmd(types.ModuleName)
cmd.AddCommand(GetQueryTwapCommand())
cmd.AddCommand(GetQueryArithmeticCommand())
cmd.AddCommand(GetQueryGeometricCommand())

return cmd
}

// GetQueryTwapCommand returns multiplier of an asset by denom.
func GetQueryTwapCommand() *cobra.Command {
// GetQueryArithmeticCommand returns an arithmetic twap query command.
func GetQueryArithmeticCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "twap [poolid] [base denom] [start time] [end time]",
Short: "Query twap",
Long: osmocli.FormatLongDescDirect(`Query twap for pool. Start time must be unix time. End time can be unix time or duration.
Use: "arithmetic [poolid] [base denom] [start time] [end time]",
Short: "Query arithmetic twap",
Aliases: []string{"twap"},
Long: osmocli.FormatLongDescDirect(`Query arithmetic twap for pool. Start time must be unix time. End time can be unix time or duration.

Example:
{{.CommandPrefix}} twap 1 uosmo 1667088000 24h
{{.CommandPrefix}} twap 1 uosmo 1667088000 1667174400
{{.CommandPrefix}} arithmetic 1 uosmo 1667088000 24h
{{.CommandPrefix}} arithmetic 1 uosmo 1667088000 1667174400
`, types.ModuleName),
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
Expand All @@ -41,37 +44,76 @@ Example:
if err != nil {
return err
}

clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
quoteDenom, err := getQuoteDenomFromLiquidity(cmd.Context(), clientCtx, poolId, baseDenom)
if err != nil {
return err
}

queryClient := queryproto.NewQueryClient(clientCtx)
gammClient := gammtypes.NewQueryClient(clientCtx)
liquidity, err := gammClient.TotalPoolLiquidity(cmd.Context(), &gammtypes.QueryTotalPoolLiquidityRequest{PoolId: poolId})
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
}

// GetQueryGeometricCommand returns a geometric twap query command.
func GetQueryGeometricCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "geometric [poolid] [base denom] [start time] [end time]",
Short: "Query geometric twap",
Long: osmocli.FormatLongDescDirect(`Query geometric twap for pool. Start time must be unix time. End time can be unix time or duration.

Example:
{{.CommandPrefix}} geometric 1 uosmo 1667088000 24h
{{.CommandPrefix}} geometric 1 uosmo 1667088000 1667174400
`, types.ModuleName),
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
// boilerplate parse fields
poolId, baseDenom, startTime, endTime, err := twapQueryParseArgs(args)
if err != nil {
return err
}
clientCtx, err := client.GetClientQueryContext(cmd)
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, err := getQuoteDenomFromLiquidity(cmd.Context(), clientCtx, poolId, baseDenom)
if err != nil {
return err
}
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])
queryClient := queryproto.NewQueryClient(clientCtx)
if err != nil {
return err
}

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

if err != nil {
return err
}
Expand All @@ -85,6 +127,30 @@ Example:
return cmd
}

// getQuoteDenomFromLiquidity gets the quote liquidity denom from the pool. In addition, validates that base denom
// exists in the pool. Fails if not.
func getQuoteDenomFromLiquidity(ctx context.Context, clientCtx client.Context, poolId uint64, baseDenom string) (string, error) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: this was extracted from pre-existing code. No additional changes were made

gammClient := gammtypes.NewQueryClient(clientCtx)
liquidity, err := gammClient.TotalPoolLiquidity(ctx, &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])
}
return quoteDenom, nil
}

func twapQueryParseArgs(args []string) (poolId uint64, baseDenom string, startTime time.Time, endTime time.Time, err error) {
// boilerplate parse fields
// <UINT PARSE>
Expand Down