Skip to content

Commit

Permalink
feat(x/twap): modify cli to add geometric option (#3812)
Browse files Browse the repository at this point in the history
* feat(x/twap): geometric twap code gen query boilerplate

* revert cli change

* query gen

* wire up API

* test

* fix

* fixes

* cli

* lint

* refactor via flag

* refactor

* refactor

* fixes

* lint

* add arithmetic twap alias
  • Loading branch information
p0mvn authored and czarcas7ic committed Jan 4, 2023
1 parent ad0c311 commit bb27842
Showing 1 changed file with 88 additions and 22 deletions.
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) {
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

0 comments on commit bb27842

Please sign in to comment.