From 65df2559224ee4e815237ea00e4aac58edee6f56 Mon Sep 17 00:00:00 2001 From: Adam Tucker Date: Mon, 22 May 2023 11:23:05 -0500 Subject: [PATCH 1/3] multiple fee tokens gov prop --- proto/osmosis/txfees/v1beta1/gov.proto | 14 ++-- x/txfees/client/cli/query_test.go | 8 +- x/txfees/client/cli/tx.go | 103 ++++++++++++++++++------- x/txfees/keeper/gov.go | 7 +- x/txfees/keeper/keeper_test.go | 8 +- x/txfees/types/gov.go | 18 ++++- x/txfees/types/gov.pb.go | 82 ++++++++++++-------- 7 files changed, 160 insertions(+), 80 deletions(-) diff --git a/proto/osmosis/txfees/v1beta1/gov.proto b/proto/osmosis/txfees/v1beta1/gov.proto index ab251d9825c..f2b9891de23 100644 --- a/proto/osmosis/txfees/v1beta1/gov.proto +++ b/proto/osmosis/txfees/v1beta1/gov.proto @@ -8,11 +8,11 @@ import "osmosis/txfees/v1beta1/feetoken.proto"; option go_package = "github.com/osmosis-labs/osmosis/v15/x/txfees/types"; -// UpdateFeeTokenProposal is a gov Content type for adding a new whitelisted fee -// token. It must specify a denom along with gamm pool ID to use as a spot price -// calculator. It can be used to add a new denom to the whitelist It can also be -// used to update the Pool to associate with the denom. If Pool ID is set to 0, -// it will remove the denom from the whitelisted set. +// UpdateFeeTokenProposal is a gov Content type for adding new whitelisted fee +// token(s). It must specify a denom along with gamm pool ID to use as a spot +// price calculator. It can be used to add new denoms to the whitelist. It can +// also be used to update the Pool to associate with the denom. If Pool ID is +// set to 0, it will remove the denom from the whitelisted set. message UpdateFeeTokenProposal { option (gogoproto.equal) = true; option (gogoproto.goproto_getters) = false; @@ -22,8 +22,8 @@ message UpdateFeeTokenProposal { string title = 1 [ (gogoproto.moretags) = "yaml:\"title\"" ]; string description = 2 [ (gogoproto.moretags) = "yaml:\"description\"" ]; - FeeToken feetoken = 3 [ - (gogoproto.moretags) = "yaml:\"fee_token\"", + repeated FeeToken feetokens = 3 [ + (gogoproto.moretags) = "yaml:\"fee_tokens\"", (gogoproto.nullable) = false ]; } \ No newline at end of file diff --git a/x/txfees/client/cli/query_test.go b/x/txfees/client/cli/query_test.go index 4f29cccb782..f9cfa0362d3 100644 --- a/x/txfees/client/cli/query_test.go +++ b/x/txfees/client/cli/query_test.go @@ -32,9 +32,11 @@ func (s *QueryTestSuite) SetupSuite() { upgradeProp := types.NewUpdateFeeTokenProposal( "Test Proposal", "test", - types.FeeToken{ - Denom: "uosmo", - PoolID: 1, + []types.FeeToken{ + { + Denom: "uosmo", + PoolID: 1, + }, }, ) err := s.App.TxFeesKeeper.HandleUpdateFeeTokenProposal(s.Ctx, &upgradeProp) diff --git a/x/txfees/client/cli/tx.go b/x/txfees/client/cli/tx.go index 8c0c196b001..cc66b28bba5 100644 --- a/x/txfees/client/cli/tx.go +++ b/x/txfees/client/cli/tx.go @@ -1,14 +1,15 @@ package cli import ( + "errors" "strconv" + "strings" "github.com/cosmos/cosmos-sdk/client/tx" "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov/client/cli" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" @@ -17,6 +18,8 @@ import ( "github.com/osmosis-labs/osmosis/v15/x/txfees/types" ) +const FlagFeeTokens = "fee-tokens" + func NewTxCmd() *cobra.Command { txCmd := osmocli.TxIndexCmd(types.ModuleName) txCmd.AddCommand( @@ -27,32 +30,21 @@ func NewTxCmd() *cobra.Command { func NewCmdSubmitUpdateFeeTokenProposal() *cobra.Command { cmd := &cobra.Command{ - Use: "update-fee-token [denom] [poolId]", - Args: cobra.ExactArgs(2), - Short: "Submit an update to a fee token to be usable for tx fees", - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } + Use: "update-fee-token [flags]", + Args: cobra.ExactArgs(0), + Short: "Submit a update fee token record proposal", + Long: strings.TrimSpace(`Submit a update fee token record proposal. - denom := args[0] - pool_id, err := strconv.ParseUint(args[1], 10, 64) - if err != nil { - return err - } +Passing in denom,poolID pairs separated by commas would be parsed automatically to pairs of fee token records. +Ex) uosmo,1,uion,2,ufoo,0 -> [Adds uosmo<>pool1, uion<>pool2, Removes ufoo as a fee token] - feeToken := types.FeeToken{ - Denom: denom, - PoolID: pool_id, - } - - title, err := cmd.Flags().GetString(cli.FlagTitle) + `), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err } - - description, err := cmd.Flags().GetString(cli.FlagDescription) + content, err := parseFeeTokenRecordsArgsToContent(cmd) if err != nil { return err } @@ -68,9 +60,7 @@ func NewCmdSubmitUpdateFeeTokenProposal() *cobra.Command { return err } - content := types.NewUpdateFeeTokenProposal(title, description, feeToken) - - msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, from) + msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from) if err != nil { return err } @@ -86,9 +76,66 @@ func NewCmdSubmitUpdateFeeTokenProposal() *cobra.Command { cmd.Flags().String(cli.FlagTitle, "", "title of proposal") cmd.Flags().String(cli.FlagDescription, "", "description of proposal") cmd.Flags().String(cli.FlagDeposit, "", "deposit of proposal") - flags.AddTxFlagsToCmd(cmd) - _ = cmd.MarkFlagRequired(cli.FlagTitle) - _ = cmd.MarkFlagRequired(cli.FlagDescription) + cmd.Flags().Bool(cli.FlagIsExpedited, false, "If true, makes the proposal an expedited one") + cmd.Flags().String(cli.FlagProposal, "", "Proposal file path (if this path is given, other proposal flags are ignored)") + cmd.Flags().String(FlagFeeTokens, "", "The fee token records array") return cmd } + +func parseFeeTokenRecords(cmd *cobra.Command) ([]types.FeeToken, error) { + feeTokensStr, err := cmd.Flags().GetString(FlagFeeTokens) + if err != nil { + return nil, err + } + + feeTokens := strings.Split(feeTokensStr, ",") + + if len(feeTokens)%2 != 0 { + return nil, errors.New("fee denom records should be a comma separated list of denom and poolId pairs") + } + + feeTokenRecords := []types.FeeToken{} + i := 0 + for i < len(feeTokens) { + denom := feeTokens[i] + poolId, err := strconv.Atoi(feeTokens[i+1]) + if err != nil { + return nil, err + } + + feeTokenRecords = append(feeTokenRecords, types.FeeToken{ + Denom: denom, + PoolID: uint64(poolId), + }) + + // increase counter by the next 2 + i = i + 2 + } + + return feeTokenRecords, nil +} + +func parseFeeTokenRecordsArgsToContent(cmd *cobra.Command) (govtypes.Content, error) { + title, err := cmd.Flags().GetString(cli.FlagTitle) + if err != nil { + return nil, err + } + + description, err := cmd.Flags().GetString(cli.FlagDescription) + if err != nil { + return nil, err + } + + feeTokenRecords, err := parseFeeTokenRecords(cmd) + if err != nil { + return nil, err + } + + content := &types.UpdateFeeTokenProposal{ + Title: title, + Description: description, + Feetokens: feeTokenRecords, + } + return content, nil +} diff --git a/x/txfees/keeper/gov.go b/x/txfees/keeper/gov.go index 17b90f7594a..2d37ef13d33 100644 --- a/x/txfees/keeper/gov.go +++ b/x/txfees/keeper/gov.go @@ -8,5 +8,10 @@ import ( func (k Keeper) HandleUpdateFeeTokenProposal(ctx sdk.Context, p *types.UpdateFeeTokenProposal) error { // setFeeToken internally calls ValidateFeeToken - return k.setFeeToken(ctx, p.Feetoken) + for _, feeToken := range p.Feetokens { + if err := k.setFeeToken(ctx, feeToken); err != nil { + return err + } + } + return nil } diff --git a/x/txfees/keeper/keeper_test.go b/x/txfees/keeper/keeper_test.go index 3e9d3568442..136e53f165c 100644 --- a/x/txfees/keeper/keeper_test.go +++ b/x/txfees/keeper/keeper_test.go @@ -55,9 +55,11 @@ func (s *KeeperTestSuite) ExecuteUpgradeFeeTokenProposal(feeToken string, poolId upgradeProp := types.NewUpdateFeeTokenProposal( "Test Proposal", "test", - types.FeeToken{ - Denom: feeToken, - PoolID: poolId, + []types.FeeToken{ + { + Denom: feeToken, + PoolID: poolId, + }, }, ) return s.App.TxFeesKeeper.HandleUpdateFeeTokenProposal(s.Ctx, &upgradeProp) diff --git a/x/txfees/types/gov.go b/x/txfees/types/gov.go index 7670d454f41..375307db5f8 100644 --- a/x/txfees/types/gov.go +++ b/x/txfees/types/gov.go @@ -19,11 +19,11 @@ func init() { var _ govtypes.Content = &UpdateFeeTokenProposal{} -func NewUpdateFeeTokenProposal(title, description string, feeToken FeeToken) UpdateFeeTokenProposal { +func NewUpdateFeeTokenProposal(title, description string, feeTokens []FeeToken) UpdateFeeTokenProposal { return UpdateFeeTokenProposal{ Title: title, Description: description, - Feetoken: feeToken, + Feetokens: feeTokens, } } @@ -43,15 +43,25 @@ func (p *UpdateFeeTokenProposal) ValidateBasic() error { return err } - return sdk.ValidateDenom(p.Feetoken.Denom) + for _, feeToken := range p.Feetokens { + if err := sdk.ValidateDenom(feeToken.Denom); err != nil { + return err + } + } + return nil } func (p UpdateFeeTokenProposal) String() string { + recordsStr := "" + for _, feeToken := range p.Feetokens { + recordsStr = recordsStr + fmt.Sprintf("(Denom: %s, PoolID: %d) ", feeToken.Denom, feeToken.PoolID) + } + var b strings.Builder b.WriteString(fmt.Sprintf(`Update Fee Token Proposal: Title: %s Description: %s Records: %s -`, p.Title, p.Description, p.Feetoken.String())) +`, p.Title, p.Description, recordsStr)) return b.String() } diff --git a/x/txfees/types/gov.pb.go b/x/txfees/types/gov.pb.go index 8ea089cf909..4ba518cbf55 100644 --- a/x/txfees/types/gov.pb.go +++ b/x/txfees/types/gov.pb.go @@ -25,15 +25,15 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// UpdateFeeTokenProposal is a gov Content type for adding a new whitelisted fee -// token. It must specify a denom along with gamm pool ID to use as a spot price -// calculator. It can be used to add a new denom to the whitelist It can also be -// used to update the Pool to associate with the denom. If Pool ID is set to 0, -// it will remove the denom from the whitelisted set. +// UpdateFeeTokenProposal is a gov Content type for adding new whitelisted fee +// token(s). It must specify a denom along with gamm pool ID to use as a spot +// price calculator. It can be used to add new denoms to the whitelist. It can +// also be used to update the Pool to associate with the denom. If Pool ID is +// set to 0, it will remove the denom from the whitelisted set. type UpdateFeeTokenProposal struct { - Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty" yaml:"title"` - Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` - Feetoken FeeToken `protobuf:"bytes,3,opt,name=feetoken,proto3" json:"feetoken" yaml:"fee_token"` + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty" yaml:"title"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` + Feetokens []FeeToken `protobuf:"bytes,3,rep,name=feetokens,proto3" json:"feetokens" yaml:"fee_tokens"` } func (m *UpdateFeeTokenProposal) Reset() { *m = UpdateFeeTokenProposal{} } @@ -75,30 +75,30 @@ func init() { func init() { proto.RegisterFile("osmosis/txfees/v1beta1/gov.proto", fileDescriptor_2c4a51bafc82863d) } var fileDescriptor_2c4a51bafc82863d = []byte{ - // 362 bytes of a gzipped FileDescriptorProto + // 363 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xc8, 0x2f, 0xce, 0xcd, 0x2f, 0xce, 0x2c, 0xd6, 0x2f, 0xa9, 0x48, 0x4b, 0x4d, 0x2d, 0xd6, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x4f, 0xcf, 0x2f, 0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x83, 0xaa, 0xd0, 0x83, 0xa8, 0xd0, 0x83, 0xaa, 0x90, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0x2b, 0xd1, 0x07, 0xb1, 0x20, 0xaa, 0xa5, 0x24, 0x93, 0xc1, 0xca, 0xe3, 0x21, 0x12, 0x10, 0x0e, 0x54, 0x4a, 0x30, 0x31, 0x37, 0x33, 0x2f, 0x5f, 0x1f, 0x4c, 0x42, 0x85, 0x54, 0x71, 0xd8, 0x9e, 0x96, 0x9a, 0x5a, - 0x92, 0x9f, 0x9d, 0x9a, 0x07, 0x51, 0xa6, 0xb4, 0x90, 0x89, 0x4b, 0x2c, 0xb4, 0x20, 0x25, 0xb1, + 0x92, 0x9f, 0x9d, 0x9a, 0x07, 0x51, 0xa6, 0xb4, 0x84, 0x89, 0x4b, 0x2c, 0xb4, 0x20, 0x25, 0xb1, 0x24, 0xd5, 0x2d, 0x35, 0x35, 0x04, 0x24, 0x11, 0x50, 0x94, 0x5f, 0x90, 0x5f, 0x9c, 0x98, 0x23, 0xa4, 0xc6, 0xc5, 0x5a, 0x92, 0x59, 0x92, 0x93, 0x2a, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0xe9, 0x24, 0xf0, 0xe9, 0x9e, 0x3c, 0x4f, 0x65, 0x62, 0x6e, 0x8e, 0x95, 0x12, 0x58, 0x58, 0x29, 0x08, 0x22, 0x2d, 0x64, 0xc1, 0xc5, 0x9d, 0x92, 0x5a, 0x9c, 0x5c, 0x94, 0x59, 0x50, 0x92, 0x99, 0x9f, 0x27, 0xc1, 0x04, 0x56, 0x2d, 0xf6, 0xe9, 0x9e, 0xbc, 0x10, 0x44, 0x35, 0x92, 0xa4, 0x52, 0x10, 0xb2, - 0x52, 0xa1, 0x30, 0x2e, 0x0e, 0x98, 0x73, 0x24, 0x98, 0x15, 0x18, 0x35, 0xb8, 0x8d, 0x14, 0xf4, - 0xb0, 0x07, 0x89, 0x1e, 0xcc, 0x75, 0x4e, 0x12, 0x27, 0xee, 0xc9, 0x33, 0x7c, 0xba, 0x27, 0x2f, - 0x00, 0x31, 0x3c, 0x2d, 0x35, 0x35, 0x1e, 0x6c, 0x80, 0x52, 0x10, 0xdc, 0x2c, 0x2b, 0xdf, 0x8e, - 0x05, 0xf2, 0x0c, 0x33, 0x16, 0xc8, 0x33, 0xbc, 0x58, 0x20, 0xcf, 0x78, 0x6a, 0x8b, 0xae, 0x14, - 0x34, 0xb0, 0x40, 0x21, 0x0f, 0x33, 0xd0, 0x39, 0x3f, 0xaf, 0x24, 0x35, 0xaf, 0xa4, 0xeb, 0xf9, - 0x06, 0x2d, 0x39, 0x58, 0x50, 0x61, 0x0f, 0x08, 0x27, 0x9f, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, - 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, - 0x3c, 0x96, 0x63, 0x88, 0x32, 0x4a, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, - 0x87, 0x1a, 0xa2, 0x9b, 0x93, 0x98, 0x54, 0x0c, 0xe3, 0xe8, 0x97, 0x19, 0x9a, 0xea, 0x57, 0xc0, - 0xa2, 0xa0, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, 0x0d, 0x1c, 0xf0, 0xc6, 0x80, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xe2, 0xf0, 0xb4, 0x1a, 0x1f, 0x02, 0x00, 0x00, + 0x52, 0xa1, 0x48, 0x2e, 0x4e, 0x98, 0x73, 0x8a, 0x25, 0x98, 0x15, 0x98, 0x35, 0xb8, 0x8d, 0x14, + 0xf4, 0xb0, 0x87, 0x89, 0x1e, 0xcc, 0x79, 0x4e, 0x92, 0x27, 0xee, 0xc9, 0x33, 0x7c, 0xba, 0x27, + 0x2f, 0x08, 0x31, 0x3d, 0x2d, 0x35, 0x35, 0x1e, 0x62, 0x82, 0x52, 0x10, 0xc2, 0x34, 0x2b, 0xdf, + 0x8e, 0x05, 0xf2, 0x0c, 0x33, 0x16, 0xc8, 0x33, 0xbc, 0x58, 0x20, 0xcf, 0x78, 0x6a, 0x8b, 0xae, + 0x14, 0x34, 0xbc, 0x40, 0x81, 0x0f, 0x33, 0xd2, 0x39, 0x3f, 0xaf, 0x24, 0x35, 0xaf, 0xa4, 0xeb, + 0xf9, 0x06, 0x2d, 0x39, 0x58, 0x68, 0x61, 0x0f, 0x0b, 0x27, 0x9f, 0x13, 0x8f, 0xe4, 0x18, 0x2f, + 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, + 0x6e, 0x3c, 0x96, 0x63, 0x88, 0x32, 0x4a, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, + 0xd5, 0x87, 0x1a, 0xa2, 0x9b, 0x93, 0x98, 0x54, 0x0c, 0xe3, 0xe8, 0x97, 0x19, 0x9a, 0xea, 0x57, + 0xc0, 0x62, 0xa1, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, 0x0d, 0x1c, 0xf6, 0xc6, 0x80, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xf3, 0xd9, 0x7e, 0x03, 0x22, 0x02, 0x00, 0x00, } func (this *UpdateFeeTokenProposal) Equal(that interface{}) bool { @@ -126,9 +126,14 @@ func (this *UpdateFeeTokenProposal) Equal(that interface{}) bool { if this.Description != that1.Description { return false } - if !this.Feetoken.Equal(&that1.Feetoken) { + if len(this.Feetokens) != len(that1.Feetokens) { return false } + for i := range this.Feetokens { + if !this.Feetokens[i].Equal(&that1.Feetokens[i]) { + return false + } + } return true } func (m *UpdateFeeTokenProposal) Marshal() (dAtA []byte, err error) { @@ -151,16 +156,20 @@ func (m *UpdateFeeTokenProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l - { - size, err := m.Feetoken.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + if len(m.Feetokens) > 0 { + for iNdEx := len(m.Feetokens) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Feetokens[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGov(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a } - i -= size - i = encodeVarintGov(dAtA, i, uint64(size)) } - i-- - dAtA[i] = 0x1a if len(m.Description) > 0 { i -= len(m.Description) copy(dAtA[i:], m.Description) @@ -203,8 +212,12 @@ func (m *UpdateFeeTokenProposal) Size() (n int) { if l > 0 { n += 1 + l + sovGov(uint64(l)) } - l = m.Feetoken.Size() - n += 1 + l + sovGov(uint64(l)) + if len(m.Feetokens) > 0 { + for _, e := range m.Feetokens { + l = e.Size() + n += 1 + l + sovGov(uint64(l)) + } + } return n } @@ -309,7 +322,7 @@ func (m *UpdateFeeTokenProposal) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Feetoken", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Feetokens", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -336,7 +349,8 @@ func (m *UpdateFeeTokenProposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Feetoken.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Feetokens = append(m.Feetokens, FeeToken{}) + if err := m.Feetokens[len(m.Feetokens)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex From 1bbb0525c5db346a25371aeba14adf989ecbef8f Mon Sep 17 00:00:00 2001 From: Adam Tucker Date: Mon, 22 May 2023 12:09:05 -0500 Subject: [PATCH 2/3] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e605d96a7e..a7e6f518147 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,6 +70,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * [#5165](https://github.com/osmosis-labs/osmosis/pull/5165) Improve error message when fully exiting from a pool. * [#5187](https://github.com/osmosis-labs/osmosis/pull/5187) Expand `IncentivizedPools` query to include internally incentivized CL pools. * [#5239](https://github.com/osmosis-labs/osmosis/pull/5239) Implement `GetTotalPoolShares` public keeper function for GAMM. + * [#5261](https://github.com/osmosis-labs/osmosis/pull/5261) Allows `UpdateFeeTokenProposal` to take in multiple fee tokens instead of just one. ### API breaks From 6b23864b2ad0e32977f95771a770b520ab1ce44e Mon Sep 17 00:00:00 2001 From: Adam Tucker Date: Mon, 22 May 2023 12:11:22 -0500 Subject: [PATCH 3/3] add cli example line --- x/txfees/client/cli/tx.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/x/txfees/client/cli/tx.go b/x/txfees/client/cli/tx.go index cc66b28bba5..27d6917059d 100644 --- a/x/txfees/client/cli/tx.go +++ b/x/txfees/client/cli/tx.go @@ -30,9 +30,10 @@ func NewTxCmd() *cobra.Command { func NewCmdSubmitUpdateFeeTokenProposal() *cobra.Command { cmd := &cobra.Command{ - Use: "update-fee-token [flags]", - Args: cobra.ExactArgs(0), - Short: "Submit a update fee token record proposal", + Use: "update-fee-token [flags]", + Args: cobra.ExactArgs(0), + Example: "update-fee-token --fee-tokens uosmo,1,uion,2,ufoo,0 --from val --chain-id osmosis-1", + Short: "Submit a update fee token record proposal", Long: strings.TrimSpace(`Submit a update fee token record proposal. Passing in denom,poolID pairs separated by commas would be parsed automatically to pairs of fee token records.