Skip to content

feat: rate limit module #8268

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

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
218 changes: 218 additions & 0 deletions modules/apps/rate-limiting/client/cli/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
package cli

import (
"context"
"fmt"
"strings"

"github.com/cosmos/ibc-go/v10/modules/apps/rate-limiting/types"

Check failure on line 8 in modules/apps/rate-limiting/client/cli/query.go

View workflow job for this annotation

GitHub Actions / lint

File is not properly formatted (gci)
"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/version"
)

const (
FlagDenom = "denom"
)

// GetQueryCmd returns the cli query commands for this module.
func GetQueryCmd() *cobra.Command {
// Group ratelimit 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(
GetCmdQueryRateLimit(),
GetCmdQueryAllRateLimits(),
GetCmdQueryRateLimitsByChainId(),
GetCmdQueryAllBlacklistedDenoms(), // Add Blacklisted Denoms query
GetCmdQueryAllWhitelistedAddresses(), // Add Whitelisted Addresses query
// TODO: Add GetCmdQueryParams if needed
)
return cmd
}

// GetCmdQueryRateLimit implements a command to query rate limits by channel-id or client-id and denom
func GetCmdQueryRateLimit() *cobra.Command {
cmd := &cobra.Command{
Use: "rate-limit [channel-or-client-id]",
Short: "Query rate limits by channel-id/client-id and denom",
Long: strings.TrimSpace(
fmt.Sprintf(`Query rate limits by channel-id/client-id and denom.
If the denom flag is omitted, all rate limits for the given channel-id/client-id are returned.

Example:
$ %s query %s rate-limit [channel-or-client-id]
$ %s query %s rate-limit [channel-or-client-id] --denom=[denom]
`,
version.AppName, types.ModuleName, version.AppName, types.ModuleName,
),
),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
channelOrClientId := args[0]
denom, err := cmd.Flags().GetString(FlagDenom)
if err != nil {
return err
}

clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)

if denom == "" {
// Query all rate limits for the channel/client ID if denom is not specified
req := &types.QueryRateLimitsByChannelOrClientIdRequest{
ChannelOrClientId: channelOrClientId,
}
res, err := queryClient.RateLimitsByChannelOrClientId(context.Background(), req)
if err != nil {
return err
}
// Use PrintProto for slice types as PrintObjectLegacy might not work well
return clientCtx.PrintProto(res)
}

// Query specific rate limit if denom is provided
req := &types.QueryRateLimitRequest{
Denom: denom,
ChannelOrClientId: channelOrClientId,
}
res, err := queryClient.RateLimit(context.Background(), req)
if err != nil {
return err
}

return clientCtx.PrintProto(res.RateLimit)
},
}

cmd.Flags().String(FlagDenom, "", "The denom identifying a specific rate limit")
flags.AddQueryFlagsToCmd(cmd)

return cmd
}

// GetCmdQueryAllRateLimits return all available rate limits.
func GetCmdQueryAllRateLimits() *cobra.Command {
cmd := &cobra.Command{
Use: "list-rate-limits",
Short: "Query all rate limits",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)

req := &types.QueryAllRateLimitsRequest{}
res, err := queryClient.AllRateLimits(context.Background(), req)
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}

// GetCmdQueryRateLimitsByChainId return all rate limits that exist between this chain
// and the specified ChainId
func GetCmdQueryRateLimitsByChainId() *cobra.Command {
cmd := &cobra.Command{
Use: "rate-limits-by-chain [chain-id]",
Short: "Query all rate limits associated with the channels/clients connecting to the given ChainID",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
chainId := args[0]

clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)

req := &types.QueryRateLimitsByChainIdRequest{
ChainId: chainId,
}
res, err := queryClient.RateLimitsByChainId(context.Background(), req)
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}

// GetCmdQueryAllBlacklistedDenoms returns the command to query all blacklisted denoms
func GetCmdQueryAllBlacklistedDenoms() *cobra.Command {
cmd := &cobra.Command{
Use: "list-blacklisted-denoms",
Short: "Query all blacklisted denoms",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)

req := &types.QueryAllBlacklistedDenomsRequest{}
res, err := queryClient.AllBlacklistedDenoms(context.Background(), req)
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)
return cmd
}

// GetCmdQueryAllWhitelistedAddresses returns the command to query all whitelisted address pairs
func GetCmdQueryAllWhitelistedAddresses() *cobra.Command {
cmd := &cobra.Command{
Use: "list-whitelisted-addresses",
Short: "Query all whitelisted address pairs",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)

req := &types.QueryAllWhitelistedAddressesRequest{}
res, err := queryClient.AllWhitelistedAddresses(context.Background(), req)
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)
return cmd
}
71 changes: 71 additions & 0 deletions modules/apps/rate-limiting/client/cli/tx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package cli

import (
"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client"

"github.com/cosmos/ibc-go/v10/modules/apps/rate-limiting/types"
)

// NewTxCmd returns the CLI transaction commands for the rate-limiting module
func NewTxCmd() *cobra.Command {
txCmd := &cobra.Command{
Use: types.ModuleName,
Short: "Rate-limiting transaction subcommands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}

// Add transaction commands here when defined
// Example:
// txCmd.AddCommand(
// NewSetRateLimitCmd(),
// )

return txCmd
}

// Example command structure to be implemented
/*
// NewSetRateLimitCmd creates a CLI command for setting a rate limit
func NewSetRateLimitCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "set-rate-limit [channel-id] [denom] [max-outflow] [max-inflow] [period]",
Short: "Set a rate limit for a specific channel and denomination",
Args: cobra.ExactArgs(5),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

// Parse arguments
channelID := args[0]
denom := args[1]
maxOutflow := args[2]
maxInflow := args[3]
period, err := strconv.ParseUint(args[4], 10, 64)
if err != nil {
return err
}

// Create and return message
msg := types.NewMsgSetRateLimit(
clientCtx.GetFromAddress(),
channelID,
denom,
maxOutflow,
maxInflow,
period,
)

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

flags.AddTxFlagsToCmd(cmd)
return cmd
}
*/
8 changes: 8 additions & 0 deletions modules/apps/rate-limiting/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
Package rate-limiting implements a middleware to rate limit IBC transfers
between different chains to prevent excessive token flow in either direction.
This module monitors and enforces configurable rate limits on token transfers
across IBC channels to protect chains from economic attacks or unintended
token drainage.
*/
package ratelimiting
Loading
Loading