github.com/KiraCore/sekai@v0.3.43/x/basket/client/cli/tx.go (about)

     1  package cli
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"strings"
     7  
     8  	"github.com/KiraCore/sekai/x/basket/types"
     9  	govcli "github.com/KiraCore/sekai/x/gov/client/cli"
    10  	govtypes "github.com/KiraCore/sekai/x/gov/types"
    11  	"github.com/cosmos/cosmos-sdk/client"
    12  	"github.com/cosmos/cosmos-sdk/client/flags"
    13  	"github.com/cosmos/cosmos-sdk/client/tx"
    14  	sdk "github.com/cosmos/cosmos-sdk/types"
    15  	"github.com/spf13/cobra"
    16  )
    17  
    18  // flags for basket module txs
    19  const (
    20  	FlagBasketId          = "basket-id"
    21  	FlagBasketSuffix      = "basket-suffix"
    22  	FlagBasketDescription = "basket-description"
    23  	FlagSwapFee           = "swap-fee"
    24  	FlagSlippageFeeMin    = "slippage-fee-min"
    25  	FlagTokensCap         = "tokens-cap"
    26  	FlagLimitsPeriod      = "limits-period"
    27  	FlagMintsMin          = "mints-min"
    28  	FlagMintsMax          = "mints-max"
    29  	FlagMintsDisabled     = "mints-disabled"
    30  	FlagBurnsMin          = "burns-min"
    31  	FlagBurnsMax          = "burns-max"
    32  	FlagBurnsDisabled     = "burns-disabled"
    33  	FlagSwapsMin          = "swaps-min"
    34  	FlagSwapsMax          = "swaps-max"
    35  	FlagSwapsDisabled     = "swaps-disabled"
    36  	FlagBasketTokens      = "basket-tokens"
    37  )
    38  
    39  // NewTxCmd returns a root CLI command handler for all x/bank transaction commands.
    40  func NewTxCmd() *cobra.Command {
    41  	txCmd := &cobra.Command{
    42  		Use:                        types.ModuleName,
    43  		Short:                      "Tokens sub commands",
    44  		DisableFlagParsing:         true,
    45  		SuggestionsMinimumDistance: 2,
    46  		RunE:                       client.ValidateCmd,
    47  	}
    48  
    49  	txCmd.AddCommand(
    50  		GetTxDisableBasketDepositsCmd(),
    51  		GetTxDisableBasketWithdrawsCmd(),
    52  		GetTxDisableBasketSwapsCmd(),
    53  		GetTxBasketTokenMintCmd(),
    54  		GetTxBasketTokenBurnCmd(),
    55  		GetTxBasketTokenSwapCmd(),
    56  		GetTxBasketClaimRewardsCmd(),
    57  		GetTxProposalCreateBasketCmd(),
    58  		GetTxProposalEditBasketCmd(),
    59  		GetTxProposalBasketWithdrawSurplusCmd(),
    60  	)
    61  
    62  	return txCmd
    63  }
    64  
    65  // GetTxDisableBasketDepositsCmd implement cli command for MsgDisableBasketDeposits
    66  func GetTxDisableBasketDepositsCmd() *cobra.Command {
    67  	cmd := &cobra.Command{
    68  		Use:   "disable-basket-deposits [basket_id] [disabled]",
    69  		Short: "Emergency function & permission to disable one or all deposits of one or all token in the basket",
    70  		Args:  cobra.MinimumNArgs(2),
    71  		RunE: func(cmd *cobra.Command, args []string) error {
    72  			clientCtx, err := client.GetClientTxContext(cmd)
    73  			if err != nil {
    74  				return err
    75  			}
    76  
    77  			basketId, err := strconv.Atoi(args[0])
    78  			if err != nil {
    79  				return err
    80  			}
    81  
    82  			disabled, err := strconv.ParseBool(args[1])
    83  			if err != nil {
    84  				return err
    85  			}
    86  
    87  			msg := types.NewMsgDisableBasketDeposits(
    88  				clientCtx.FromAddress,
    89  				uint64(basketId),
    90  				disabled,
    91  			)
    92  
    93  			err = msg.ValidateBasic()
    94  			if err != nil {
    95  				return err
    96  			}
    97  
    98  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
    99  		},
   100  	}
   101  
   102  	flags.AddTxFlagsToCmd(cmd)
   103  	_ = cmd.MarkFlagRequired(flags.FlagFrom)
   104  
   105  	return cmd
   106  }
   107  
   108  // GetTxDisableBasketWithdrawsCmd implement cli command for MsgDisableBasketWithdraws
   109  func GetTxDisableBasketWithdrawsCmd() *cobra.Command {
   110  	cmd := &cobra.Command{
   111  		Use:   "disable-basket-withdraws [basket_id] [disabled]",
   112  		Short: "Emergency function & permission to disable one or all withdraws of one or all token in the basket",
   113  		Args:  cobra.MinimumNArgs(2),
   114  		RunE: func(cmd *cobra.Command, args []string) error {
   115  			clientCtx, err := client.GetClientTxContext(cmd)
   116  			if err != nil {
   117  				return err
   118  			}
   119  
   120  			basketId, err := strconv.Atoi(args[0])
   121  			if err != nil {
   122  				return err
   123  			}
   124  
   125  			disabled, err := strconv.ParseBool(args[1])
   126  			if err != nil {
   127  				return err
   128  			}
   129  
   130  			msg := types.NewMsgDisableBasketWithdraws(
   131  				clientCtx.FromAddress,
   132  				uint64(basketId),
   133  				disabled,
   134  			)
   135  
   136  			err = msg.ValidateBasic()
   137  			if err != nil {
   138  				return err
   139  			}
   140  
   141  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
   142  		},
   143  	}
   144  
   145  	flags.AddTxFlagsToCmd(cmd)
   146  	_ = cmd.MarkFlagRequired(flags.FlagFrom)
   147  
   148  	return cmd
   149  }
   150  
   151  // GetTxDisableBasketSwapsCmd implement cli command for MsgDisableBasketSwaps
   152  func GetTxDisableBasketSwapsCmd() *cobra.Command {
   153  	cmd := &cobra.Command{
   154  		Use:   "disable-basket-swaps [basket_id] [disabled]",
   155  		Short: "Emergency function & permission to disable one or all swaps of one or all token in the basket",
   156  		Args:  cobra.MinimumNArgs(2),
   157  		RunE: func(cmd *cobra.Command, args []string) error {
   158  			clientCtx, err := client.GetClientTxContext(cmd)
   159  			if err != nil {
   160  				return err
   161  			}
   162  
   163  			basketId, err := strconv.Atoi(args[0])
   164  			if err != nil {
   165  				return err
   166  			}
   167  
   168  			disabled, err := strconv.ParseBool(args[1])
   169  			if err != nil {
   170  				return err
   171  			}
   172  
   173  			msg := types.NewMsgDisableBasketSwaps(
   174  				clientCtx.FromAddress,
   175  				uint64(basketId),
   176  				disabled,
   177  			)
   178  
   179  			err = msg.ValidateBasic()
   180  			if err != nil {
   181  				return err
   182  			}
   183  
   184  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
   185  		},
   186  	}
   187  
   188  	flags.AddTxFlagsToCmd(cmd)
   189  	_ = cmd.MarkFlagRequired(flags.FlagFrom)
   190  
   191  	return cmd
   192  }
   193  
   194  // GetTxBasketTokenMintCmd implement cli command for MsgBasketTokenMint
   195  func GetTxBasketTokenMintCmd() *cobra.Command {
   196  	cmd := &cobra.Command{
   197  		Use:   "mint-basket-tokens [basket_id] [deposit_coins]",
   198  		Short: "mint basket tokens",
   199  		Args:  cobra.MinimumNArgs(2),
   200  		RunE: func(cmd *cobra.Command, args []string) error {
   201  			clientCtx, err := client.GetClientTxContext(cmd)
   202  			if err != nil {
   203  				return err
   204  			}
   205  
   206  			basketId, err := strconv.Atoi(args[0])
   207  			if err != nil {
   208  				return err
   209  			}
   210  
   211  			coins, err := sdk.ParseCoinsNormalized(args[1])
   212  			if err != nil {
   213  				return err
   214  			}
   215  
   216  			msg := types.NewMsgBasketTokenMint(
   217  				clientCtx.FromAddress,
   218  				uint64(basketId),
   219  				coins,
   220  			)
   221  
   222  			err = msg.ValidateBasic()
   223  			if err != nil {
   224  				return err
   225  			}
   226  
   227  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
   228  		},
   229  	}
   230  
   231  	flags.AddTxFlagsToCmd(cmd)
   232  	_ = cmd.MarkFlagRequired(flags.FlagFrom)
   233  
   234  	return cmd
   235  }
   236  
   237  // GetTxBasketTokenBurnCmd implement cli command for MsgBasketTokenBurn
   238  func GetTxBasketTokenBurnCmd() *cobra.Command {
   239  	cmd := &cobra.Command{
   240  		Use:   "burn-basket-tokens [basket_id] [burn_coin]",
   241  		Short: "burn basket tokens",
   242  		Args:  cobra.MinimumNArgs(2),
   243  		RunE: func(cmd *cobra.Command, args []string) error {
   244  			clientCtx, err := client.GetClientTxContext(cmd)
   245  			if err != nil {
   246  				return err
   247  			}
   248  
   249  			basketId, err := strconv.Atoi(args[0])
   250  			if err != nil {
   251  				return err
   252  			}
   253  
   254  			coin, err := sdk.ParseCoinNormalized(args[1])
   255  			if err != nil {
   256  				return err
   257  			}
   258  
   259  			msg := types.NewMsgBasketTokenBurn(
   260  				clientCtx.FromAddress,
   261  				uint64(basketId),
   262  				coin,
   263  			)
   264  
   265  			err = msg.ValidateBasic()
   266  			if err != nil {
   267  				return err
   268  			}
   269  
   270  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
   271  		},
   272  	}
   273  
   274  	flags.AddTxFlagsToCmd(cmd)
   275  	_ = cmd.MarkFlagRequired(flags.FlagFrom)
   276  
   277  	return cmd
   278  }
   279  
   280  // GetTxBasketTokenSwapCmd implement cli command for MsgBasketTokenSwap
   281  func GetTxBasketTokenSwapCmd() *cobra.Command {
   282  	cmd := &cobra.Command{
   283  		Use:   "swap-basket-tokens [basket_id] [in_amount1] [out_token1] [in_amount2] [out_token2] ...",
   284  		Short: "swap one or many of the basket tokens for one or many others",
   285  		Args:  cobra.MinimumNArgs(3),
   286  		RunE: func(cmd *cobra.Command, args []string) error {
   287  			clientCtx, err := client.GetClientTxContext(cmd)
   288  
   289  			basketId, err := strconv.Atoi(args[0])
   290  			if err != nil {
   291  				return err
   292  			}
   293  
   294  			pairs := []types.SwapPair{}
   295  			for i := 1; i < len(args); i += 2 {
   296  				coin, err := sdk.ParseCoinNormalized(args[i])
   297  				if err != nil {
   298  					return err
   299  				}
   300  				if i+1 == len(args) {
   301  					return fmt.Errorf("out token not set for %s", args[i])
   302  				}
   303  				pairs = append(pairs, types.SwapPair{
   304  					InAmount: coin,
   305  					OutToken: args[i+1],
   306  				})
   307  			}
   308  
   309  			msg := types.NewMsgBasketTokenSwap(
   310  				clientCtx.FromAddress,
   311  				uint64(basketId),
   312  				pairs,
   313  			)
   314  			err = msg.ValidateBasic()
   315  			if err != nil {
   316  				return err
   317  			}
   318  
   319  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
   320  		},
   321  	}
   322  
   323  	flags.AddTxFlagsToCmd(cmd)
   324  	_ = cmd.MarkFlagRequired(flags.FlagFrom)
   325  
   326  	return cmd
   327  }
   328  
   329  // GetTxBasketClaimRewardsCmd implement cli command for MsgBasketClaimRewards
   330  func GetTxBasketClaimRewardsCmd() *cobra.Command {
   331  	cmd := &cobra.Command{
   332  		Use:   "basket-claim-rewards [basket_tokens]",
   333  		Short: "force staking derivative `SDB` basket to claim outstanding rewards of one all or many aggregate `V<ID>` tokens",
   334  		RunE: func(cmd *cobra.Command, args []string) error {
   335  			clientCtx, err := client.GetClientTxContext(cmd)
   336  			if err != nil {
   337  				return err
   338  			}
   339  
   340  			basketTokens, err := sdk.ParseCoinsNormalized(args[0])
   341  			if err != nil {
   342  				return err
   343  			}
   344  
   345  			msg := types.NewMsgBasketClaimRewards(
   346  				clientCtx.FromAddress,
   347  				basketTokens,
   348  			)
   349  
   350  			err = msg.ValidateBasic()
   351  			if err != nil {
   352  				return err
   353  			}
   354  
   355  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
   356  		},
   357  	}
   358  
   359  	flags.AddTxFlagsToCmd(cmd)
   360  	_ = cmd.MarkFlagRequired(flags.FlagFrom)
   361  
   362  	return cmd
   363  }
   364  
   365  // GetTxProposalCreateBasketCmd implement cli command for ProposalCreateBasket
   366  func GetTxProposalCreateBasketCmd() *cobra.Command {
   367  	cmd := &cobra.Command{
   368  		Use:   "proposal-create-basket",
   369  		Short: "Create a proposal to create a basket",
   370  		Args:  cobra.ExactArgs(0),
   371  		RunE: func(cmd *cobra.Command, args []string) error {
   372  			clientCtx, err := client.GetClientTxContext(cmd)
   373  			if err != nil {
   374  				return err
   375  			}
   376  			title, err := cmd.Flags().GetString(govcli.FlagTitle)
   377  			if err != nil {
   378  				return fmt.Errorf("invalid title: %w", err)
   379  			}
   380  			description, err := cmd.Flags().GetString(govcli.FlagDescription)
   381  			if err != nil {
   382  				return fmt.Errorf("invalid description: %w", err)
   383  			}
   384  
   385  			suffix, err := cmd.Flags().GetString(FlagBasketSuffix)
   386  			if err != nil {
   387  				return fmt.Errorf("invalid basket suffix: %w", err)
   388  			}
   389  
   390  			basketDescription, err := cmd.Flags().GetString(FlagBasketDescription)
   391  			if err != nil {
   392  				return fmt.Errorf("invalid basket description: %w", err)
   393  			}
   394  
   395  			swapFeeStr, err := cmd.Flags().GetString(FlagSwapFee)
   396  			if err != nil {
   397  				return fmt.Errorf("invalid basket swap fee: %w", err)
   398  			}
   399  
   400  			swapFee, err := sdk.NewDecFromStr(swapFeeStr)
   401  			if err != nil {
   402  				return fmt.Errorf("invalid basket swap fee: %w", err)
   403  			}
   404  
   405  			slippageFeeMinStr, err := cmd.Flags().GetString(FlagSlippageFeeMin)
   406  			if err != nil {
   407  				return fmt.Errorf("invalid basket slippage fee min: %w", err)
   408  			}
   409  
   410  			slipppageFeeMin, err := sdk.NewDecFromStr(slippageFeeMinStr)
   411  			if err != nil {
   412  				return fmt.Errorf("invalid basket slippage fee min: %w", err)
   413  			}
   414  
   415  			tokensCapStr, err := cmd.Flags().GetString(FlagTokensCap)
   416  			if err != nil {
   417  				return fmt.Errorf("invalid basket tokens cap: %w", err)
   418  			}
   419  
   420  			tokensCap, err := sdk.NewDecFromStr(tokensCapStr)
   421  			if err != nil {
   422  				return fmt.Errorf("invalid basket tokens cap: %w", err)
   423  			}
   424  
   425  			limitsPeriod, err := cmd.Flags().GetUint64(FlagLimitsPeriod)
   426  			if err != nil {
   427  				return fmt.Errorf("invalid basket limits cap: %w", err)
   428  			}
   429  
   430  			mintsMinStr, err := cmd.Flags().GetString(FlagMintsMin)
   431  			if err != nil {
   432  				return fmt.Errorf("invalid basket minimum mints: %w", err)
   433  			}
   434  
   435  			mintsMin, ok := sdk.NewIntFromString(mintsMinStr)
   436  			if !ok {
   437  				return fmt.Errorf("invalid basket minimum mints: %s", mintsMinStr)
   438  			}
   439  
   440  			mintsMaxStr, err := cmd.Flags().GetString(FlagMintsMax)
   441  			if err != nil {
   442  				return fmt.Errorf("invalid basket maximum mints: %w", err)
   443  			}
   444  
   445  			mintsMax, ok := sdk.NewIntFromString(mintsMaxStr)
   446  			if !ok {
   447  				return fmt.Errorf("invalid basket maximum mints: %s", mintsMaxStr)
   448  			}
   449  
   450  			mintsDisabled, err := cmd.Flags().GetBool(FlagMintsDisabled)
   451  			if err != nil {
   452  				return fmt.Errorf("invalid basket mints disabled flag: %w", err)
   453  			}
   454  
   455  			burnsMinStr, err := cmd.Flags().GetString(FlagBurnsMin)
   456  			if err != nil {
   457  				return fmt.Errorf("invalid basket minimum burns: %w", err)
   458  			}
   459  
   460  			burnsMin, ok := sdk.NewIntFromString(burnsMinStr)
   461  			if !ok {
   462  				return fmt.Errorf("invalid basket minimum burns: %s", burnsMinStr)
   463  			}
   464  
   465  			burnsMaxStr, err := cmd.Flags().GetString(FlagBurnsMax)
   466  			if err != nil {
   467  				return fmt.Errorf("invalid basket maximum burns: %w", err)
   468  			}
   469  
   470  			burnsMax, ok := sdk.NewIntFromString(burnsMaxStr)
   471  			if !ok {
   472  				return fmt.Errorf("invalid basket maximum burns: %s", burnsMaxStr)
   473  			}
   474  
   475  			burnsDisabled, err := cmd.Flags().GetBool(FlagBurnsDisabled)
   476  			if err != nil {
   477  				return fmt.Errorf("invalid basket burns disabled flag: %w", err)
   478  			}
   479  
   480  			swapsMinStr, err := cmd.Flags().GetString(FlagSwapsMin)
   481  			if err != nil {
   482  				return fmt.Errorf("invalid basket minimum swaps: %w", err)
   483  			}
   484  
   485  			swapsMin, ok := sdk.NewIntFromString(swapsMinStr)
   486  			if !ok {
   487  				return fmt.Errorf("invalid basket minimum mints: %s", swapsMinStr)
   488  			}
   489  
   490  			swapsMaxStr, err := cmd.Flags().GetString(FlagSwapsMax)
   491  			if err != nil {
   492  				return fmt.Errorf("invalid basket maximum swaps: %w", err)
   493  			}
   494  
   495  			swapsMax, ok := sdk.NewIntFromString(swapsMaxStr)
   496  			if !ok {
   497  				return fmt.Errorf("invalid basket maximum swaps: %s", swapsMaxStr)
   498  			}
   499  
   500  			swapsDisabled, err := cmd.Flags().GetBool(FlagSwapsDisabled)
   501  			if err != nil {
   502  				return fmt.Errorf("invalid basket swaps disabled flag: %w", err)
   503  			}
   504  
   505  			basketTokensStr, err := cmd.Flags().GetString(FlagBasketTokens)
   506  			if err != nil {
   507  				return fmt.Errorf("invalid basket tokens: %w", err)
   508  			}
   509  
   510  			basketTokens, err := parseBasketTokens(basketTokensStr)
   511  			if err != nil {
   512  				return err
   513  			}
   514  
   515  			msg, err := govtypes.NewMsgSubmitProposal(
   516  				clientCtx.FromAddress,
   517  				title,
   518  				description,
   519  				types.NewProposalCreateBasket(types.Basket{
   520  					Suffix:          suffix,
   521  					Description:     basketDescription,
   522  					SwapFee:         swapFee,
   523  					SlipppageFeeMin: slipppageFeeMin,
   524  					TokensCap:       tokensCap,
   525  					LimitsPeriod:    limitsPeriod,
   526  					MintsMin:        mintsMin,
   527  					MintsMax:        mintsMax,
   528  					MintsDisabled:   mintsDisabled,
   529  					BurnsMin:        burnsMin,
   530  					BurnsMax:        burnsMax,
   531  					BurnsDisabled:   burnsDisabled,
   532  					SwapsMin:        swapsMin,
   533  					SwapsMax:        swapsMax,
   534  					SwapsDisabled:   swapsDisabled,
   535  					Tokens:          basketTokens,
   536  				}),
   537  			)
   538  			if err != nil {
   539  				return err
   540  			}
   541  
   542  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
   543  		},
   544  	}
   545  
   546  	cmd.Flags().String(govcli.FlagTitle, "", "The title of the proposal.")
   547  	cmd.MarkFlagRequired(govcli.FlagTitle)
   548  	cmd.Flags().String(govcli.FlagDescription, "", "The description of the proposal, it can be a url, some text, etc.")
   549  	cmd.MarkFlagRequired(govcli.FlagDescription)
   550  	cmd.Flags().String(FlagBasketSuffix, "", "The suffix of the basket.")
   551  	cmd.Flags().String(FlagBasketDescription, "", "The description of the basket.")
   552  	cmd.Flags().String(FlagSwapFee, "", "Swap fee on the basket.")
   553  	cmd.Flags().String(FlagSlippageFeeMin, "", "Minimum slippage fee on the basket.")
   554  	cmd.Flags().String(FlagTokensCap, "", "Tokens cap on the basket.")
   555  	cmd.Flags().Uint64(FlagLimitsPeriod, 0, "Limits period on the basket.")
   556  	cmd.Flags().String(FlagMintsMin, "", "Min mint amount on the basket.")
   557  	cmd.Flags().String(FlagMintsMax, "", "Max mint amount on a day on the basket.")
   558  	cmd.Flags().Bool(FlagMintsDisabled, false, "Mints enabled flag on the basket.")
   559  	cmd.Flags().String(FlagBurnsMin, "", "Min burn amount on the basket.")
   560  	cmd.Flags().String(FlagBurnsMax, "", "Max burn amount on a day on the basket.")
   561  	cmd.Flags().Bool(FlagBurnsDisabled, false, "Burns enabled flag on the basket.")
   562  	cmd.Flags().String(FlagSwapsMin, "", "Min swap amount on the basket.")
   563  	cmd.Flags().String(FlagSwapsMax, "", "Max swap amount on a day on the basket.")
   564  	cmd.Flags().Bool(FlagSwapsDisabled, false, "Swap disabled flag on the basket.")
   565  	cmd.Flags().String(FlagBasketTokens, "", "Underlying tokens with rates on the basket.")
   566  
   567  	flags.AddTxFlagsToCmd(cmd)
   568  	_ = cmd.MarkFlagRequired(flags.FlagFrom)
   569  
   570  	return cmd
   571  }
   572  
   573  // GetTxProposalEditBasketCmd implement cli command for ProposalEditBasket
   574  func GetTxProposalEditBasketCmd() *cobra.Command {
   575  	cmd := &cobra.Command{
   576  		Use:   "proposal-edit-basket",
   577  		Short: "Create a proposal to edit a basket",
   578  		Args:  cobra.ExactArgs(0),
   579  		RunE: func(cmd *cobra.Command, args []string) error {
   580  			clientCtx, err := client.GetClientTxContext(cmd)
   581  			if err != nil {
   582  				return err
   583  			}
   584  			title, err := cmd.Flags().GetString(govcli.FlagTitle)
   585  			if err != nil {
   586  				return fmt.Errorf("invalid title: %w", err)
   587  			}
   588  			description, err := cmd.Flags().GetString(govcli.FlagDescription)
   589  			if err != nil {
   590  				return fmt.Errorf("invalid description: %w", err)
   591  			}
   592  
   593  			basketId, err := cmd.Flags().GetUint64(FlagBasketId)
   594  			if err != nil {
   595  				return fmt.Errorf("invalid basket id: %w", err)
   596  			}
   597  
   598  			suffix, err := cmd.Flags().GetString(FlagBasketSuffix)
   599  			if err != nil {
   600  				return fmt.Errorf("invalid basket suffix: %w", err)
   601  			}
   602  
   603  			basketDescription, err := cmd.Flags().GetString(FlagBasketDescription)
   604  			if err != nil {
   605  				return fmt.Errorf("invalid basket description: %w", err)
   606  			}
   607  
   608  			swapFeeStr, err := cmd.Flags().GetString(FlagSwapFee)
   609  			if err != nil {
   610  				return fmt.Errorf("invalid basket swap fee: %w", err)
   611  			}
   612  
   613  			swapFee, err := sdk.NewDecFromStr(swapFeeStr)
   614  			if err != nil {
   615  				return fmt.Errorf("invalid basket swap fee: %w", err)
   616  			}
   617  
   618  			slippageFeeMinStr, err := cmd.Flags().GetString(FlagSlippageFeeMin)
   619  			if err != nil {
   620  				return fmt.Errorf("invalid basket slippage fee min: %w", err)
   621  			}
   622  
   623  			slipppageFeeMin, err := sdk.NewDecFromStr(slippageFeeMinStr)
   624  			if err != nil {
   625  				return fmt.Errorf("invalid basket slippage fee min: %w", err)
   626  			}
   627  
   628  			tokensCapStr, err := cmd.Flags().GetString(FlagTokensCap)
   629  			if err != nil {
   630  				return fmt.Errorf("invalid basket tokens cap: %w", err)
   631  			}
   632  
   633  			tokensCap, err := sdk.NewDecFromStr(tokensCapStr)
   634  			if err != nil {
   635  				return fmt.Errorf("invalid basket tokens cap: %w", err)
   636  			}
   637  
   638  			limitsPeriod, err := cmd.Flags().GetUint64(FlagLimitsPeriod)
   639  			if err != nil {
   640  				return fmt.Errorf("invalid basket limits cap: %w", err)
   641  			}
   642  
   643  			mintsMinStr, err := cmd.Flags().GetString(FlagMintsMin)
   644  			if err != nil {
   645  				return fmt.Errorf("invalid basket minimum mints: %w", err)
   646  			}
   647  
   648  			mintsMin, ok := sdk.NewIntFromString(mintsMinStr)
   649  			if !ok {
   650  				return fmt.Errorf("invalid basket minimum mints: %s", mintsMinStr)
   651  			}
   652  
   653  			mintsMaxStr, err := cmd.Flags().GetString(FlagMintsMax)
   654  			if err != nil {
   655  				return fmt.Errorf("invalid basket maximum mints: %w", err)
   656  			}
   657  
   658  			mintsMax, ok := sdk.NewIntFromString(mintsMaxStr)
   659  			if !ok {
   660  				return fmt.Errorf("invalid basket maximum mints: %s", mintsMaxStr)
   661  			}
   662  
   663  			mintsDisabled, err := cmd.Flags().GetBool(FlagMintsDisabled)
   664  			if err != nil {
   665  				return fmt.Errorf("invalid basket mints disabled flag: %w", err)
   666  			}
   667  
   668  			burnsMinStr, err := cmd.Flags().GetString(FlagBurnsMin)
   669  			if err != nil {
   670  				return fmt.Errorf("invalid basket minimum burns: %w", err)
   671  			}
   672  
   673  			burnsMin, ok := sdk.NewIntFromString(burnsMinStr)
   674  			if !ok {
   675  				return fmt.Errorf("invalid basket minimum burns: %s", burnsMinStr)
   676  			}
   677  
   678  			burnsMaxStr, err := cmd.Flags().GetString(FlagBurnsMax)
   679  			if err != nil {
   680  				return fmt.Errorf("invalid basket maximum burns: %w", err)
   681  			}
   682  
   683  			burnsMax, ok := sdk.NewIntFromString(burnsMaxStr)
   684  			if !ok {
   685  				return fmt.Errorf("invalid basket maximum burns: %s", burnsMaxStr)
   686  			}
   687  
   688  			burnsDisabled, err := cmd.Flags().GetBool(FlagBurnsDisabled)
   689  			if err != nil {
   690  				return fmt.Errorf("invalid basket burns disabled flag: %w", err)
   691  			}
   692  
   693  			swapsMinStr, err := cmd.Flags().GetString(FlagSwapsMin)
   694  			if err != nil {
   695  				return fmt.Errorf("invalid basket minimum swaps: %w", err)
   696  			}
   697  
   698  			swapsMin, ok := sdk.NewIntFromString(swapsMinStr)
   699  			if !ok {
   700  				return fmt.Errorf("invalid basket minimum mints: %s", swapsMinStr)
   701  			}
   702  
   703  			swapsMaxStr, err := cmd.Flags().GetString(FlagSwapsMax)
   704  			if err != nil {
   705  				return fmt.Errorf("invalid basket maximum swaps: %w", err)
   706  			}
   707  
   708  			swapsMax, ok := sdk.NewIntFromString(swapsMaxStr)
   709  			if !ok {
   710  				return fmt.Errorf("invalid basket maximum swaps: %s", swapsMaxStr)
   711  			}
   712  
   713  			swapsDisabled, err := cmd.Flags().GetBool(FlagSwapsDisabled)
   714  			if err != nil {
   715  				return fmt.Errorf("invalid basket swaps disabled flag: %w", err)
   716  			}
   717  
   718  			basketTokensStr, err := cmd.Flags().GetString(FlagBasketTokens)
   719  			if err != nil {
   720  				return fmt.Errorf("invalid basket tokens: %w", err)
   721  			}
   722  
   723  			basketTokens, err := parseBasketTokens(basketTokensStr)
   724  			if err != nil {
   725  				return err
   726  			}
   727  
   728  			msg, err := govtypes.NewMsgSubmitProposal(
   729  				clientCtx.FromAddress,
   730  				title,
   731  				description,
   732  				types.NewProposalEditBasket(types.Basket{
   733  					Id:              basketId,
   734  					Suffix:          suffix,
   735  					Description:     basketDescription,
   736  					SwapFee:         swapFee,
   737  					SlipppageFeeMin: slipppageFeeMin,
   738  					TokensCap:       tokensCap,
   739  					LimitsPeriod:    limitsPeriod,
   740  					MintsMin:        mintsMin,
   741  					MintsMax:        mintsMax,
   742  					MintsDisabled:   mintsDisabled,
   743  					BurnsMin:        burnsMin,
   744  					BurnsMax:        burnsMax,
   745  					BurnsDisabled:   burnsDisabled,
   746  					SwapsMin:        swapsMin,
   747  					SwapsMax:        swapsMax,
   748  					SwapsDisabled:   swapsDisabled,
   749  					Tokens:          basketTokens,
   750  				}),
   751  			)
   752  			if err != nil {
   753  				return err
   754  			}
   755  
   756  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
   757  		},
   758  	}
   759  
   760  	cmd.Flags().String(govcli.FlagTitle, "", "The title of the proposal.")
   761  	cmd.MarkFlagRequired(govcli.FlagTitle)
   762  	cmd.Flags().String(govcli.FlagDescription, "", "The description of the proposal, it can be a url, some text, etc.")
   763  	cmd.MarkFlagRequired(govcli.FlagDescription)
   764  	cmd.Flags().Uint64(FlagBasketId, 0, "The id of the basket.")
   765  	cmd.Flags().String(FlagBasketSuffix, "", "The suffix of the basket.")
   766  	cmd.Flags().String(FlagBasketDescription, "", "The description of the basket.")
   767  	cmd.Flags().String(FlagSwapFee, "", "Swap fee on the basket.")
   768  	cmd.Flags().String(FlagSlippageFeeMin, "", "Minimum slippage fee on the basket.")
   769  	cmd.Flags().String(FlagTokensCap, "", "Tokens cap on the basket.")
   770  	cmd.Flags().Uint64(FlagLimitsPeriod, 0, "Limits period on the basket.")
   771  	cmd.Flags().String(FlagMintsMin, "", "Min mint amount on the basket.")
   772  	cmd.Flags().String(FlagMintsMax, "", "Max mint amount on a day on the basket.")
   773  	cmd.Flags().Bool(FlagMintsDisabled, false, "Mints enabled flag on the basket.")
   774  	cmd.Flags().String(FlagBurnsMin, "", "Min burn amount on the basket.")
   775  	cmd.Flags().String(FlagBurnsMax, "", "Max burn amount on a day on the basket.")
   776  	cmd.Flags().Bool(FlagBurnsDisabled, false, "Burns enabled flag on the basket.")
   777  	cmd.Flags().String(FlagSwapsMin, "", "Min swap amount on the basket.")
   778  	cmd.Flags().String(FlagSwapsMax, "", "Max swap amount on a day on the basket.")
   779  	cmd.Flags().Bool(FlagSwapsDisabled, false, "Swap disabled flag on the basket.")
   780  	cmd.Flags().String(FlagBasketTokens, "", "Underlying tokens with rates on the basket.")
   781  
   782  	flags.AddTxFlagsToCmd(cmd)
   783  	_ = cmd.MarkFlagRequired(flags.FlagFrom)
   784  
   785  	return cmd
   786  }
   787  
   788  // GetTxProposalBasketWithdrawSurplusCmd implement cli command for ProposalBasketWithdrawSurplus
   789  func GetTxProposalBasketWithdrawSurplusCmd() *cobra.Command {
   790  	cmd := &cobra.Command{
   791  		Use:   "proposal-basket-withdraw-surplus [basket_ids] [withdraw_target]",
   792  		Short: "Create a proposal to withdraw surplus from the basket",
   793  		Args:  cobra.ExactArgs(2),
   794  		RunE: func(cmd *cobra.Command, args []string) error {
   795  			clientCtx, err := client.GetClientTxContext(cmd)
   796  			if err != nil {
   797  				return err
   798  			}
   799  			title, err := cmd.Flags().GetString(govcli.FlagTitle)
   800  			if err != nil {
   801  				return fmt.Errorf("invalid title: %w", err)
   802  			}
   803  			description, err := cmd.Flags().GetString(govcli.FlagDescription)
   804  			if err != nil {
   805  				return fmt.Errorf("invalid description: %w", err)
   806  			}
   807  
   808  			basketIdsArr := strings.Split(args[0], ",")
   809  			basketIds := []uint64{}
   810  			for _, basketIdStr := range basketIdsArr {
   811  				basketId, err := strconv.Atoi(basketIdStr)
   812  				if err != nil {
   813  					return err
   814  				}
   815  				basketIds = append(basketIds, uint64(basketId))
   816  			}
   817  
   818  			msg, err := govtypes.NewMsgSubmitProposal(
   819  				clientCtx.FromAddress,
   820  				title,
   821  				description,
   822  				types.NewProposalBasketWithdrawSurplus(basketIds, args[1]),
   823  			)
   824  			if err != nil {
   825  				return err
   826  			}
   827  
   828  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
   829  		},
   830  	}
   831  
   832  	cmd.Flags().String(govcli.FlagTitle, "", "The title of the proposal.")
   833  	cmd.MarkFlagRequired(govcli.FlagTitle)
   834  	cmd.Flags().String(govcli.FlagDescription, "", "The description of the proposal, it can be a url, some text, etc.")
   835  	cmd.MarkFlagRequired(govcli.FlagDescription)
   836  
   837  	flags.AddTxFlagsToCmd(cmd)
   838  	_ = cmd.MarkFlagRequired(flags.FlagFrom)
   839  
   840  	return cmd
   841  }
   842  
   843  func parseBasketTokens(basketTokensStr string) ([]types.BasketToken, error) {
   844  	basketTokens := []types.BasketToken{}
   845  	basketTokensArr := strings.Split(basketTokensStr, ",")
   846  	for _, basketTokenStr := range basketTokensArr {
   847  		split := strings.Split(basketTokenStr, "#")
   848  		if len(split) != 5 {
   849  			return basketTokens, fmt.Errorf("invalid basket token info: %s", basketTokenStr)
   850  		}
   851  		weight, err := sdk.NewDecFromStr(split[1])
   852  		if err != nil {
   853  			return basketTokens, fmt.Errorf("invalid basket token weight: %w", err)
   854  		}
   855  		deposits, err := strconv.ParseBool(split[2])
   856  		if err != nil {
   857  			return basketTokens, fmt.Errorf("invalid basket token deposits: %w", err)
   858  		}
   859  		withdraws, _ := strconv.ParseBool(split[3])
   860  		if err != nil {
   861  			return basketTokens, fmt.Errorf("invalid basket token withdraws: %w", err)
   862  		}
   863  		swaps, _ := strconv.ParseBool(split[4])
   864  		if err != nil {
   865  			return basketTokens, fmt.Errorf("invalid basket token swaps: %w", err)
   866  		}
   867  		basketTokens = append(basketTokens, types.BasketToken{
   868  			Denom:     split[0],
   869  			Weight:    weight,
   870  			Deposits:  deposits,
   871  			Withdraws: withdraws,
   872  			Swaps:     swaps,
   873  		})
   874  	}
   875  	return basketTokens, nil
   876  }