diff --git a/modules/core/04-channel/v2/client/cli/cli.go b/modules/core/04-channel/v2/client/cli/cli.go index 5c5a897b0f9..c725fe8ee12 100644 --- a/modules/core/04-channel/v2/client/cli/cli.go +++ b/modules/core/04-channel/v2/client/cli/cli.go @@ -36,7 +36,8 @@ func NewTxCmd() *cobra.Command { } txCmd.AddCommand( - newProvideCounterpartyCmd(), + newCreateChannelTxCmd(), + newProvideCounterpartyTxCmd(), ) return txCmd diff --git a/modules/core/04-channel/v2/client/cli/tx.go b/modules/core/04-channel/v2/client/cli/tx.go index 9ff268d4843..418f01815e7 100644 --- a/modules/core/04-channel/v2/client/cli/tx.go +++ b/modules/core/04-channel/v2/client/cli/tx.go @@ -1,7 +1,9 @@ package cli import ( + "encoding/hex" "fmt" + "strings" "github.com/spf13/cobra" @@ -11,11 +13,42 @@ import ( "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/ibc-go/v9/modules/core/04-channel/v2/types" + commitmenttypesv2 "github.com/cosmos/ibc-go/v9/modules/core/23-commitment/types/v2" "github.com/cosmos/ibc-go/v9/modules/core/exported" ) +// newCreateChannelTxCmd defines the command to create an IBC channel/v2. +func newCreateChannelTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "create-channel [client-identifier] [merkle-path-prefix]", + Args: cobra.ExactArgs(2), + Short: "create an IBC channel/v2", + Long: `Creates an IBC channel/v2 using the client identifier representing the counterparty chain and the hex-encoded merkle path prefix under which the counterparty stores packet flow information.`, + Example: fmt.Sprintf("%s tx %s %s create-channel 07-tendermint-0 696263,657572656b61", version.AppName, exported.ModuleName, types.SubModuleName), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + clientID := args[0] + merklePathPrefix, err := parseMerklePathPrefix(args[2]) + if err != nil { + return err + } + + msg := types.NewMsgCreateChannel(clientID, merklePathPrefix, clientCtx.GetFromAddress().String()) + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + // newProvideCounterpartyCmd defines the command to provide the counterparty channel identifier to an IBC channel. -func newProvideCounterpartyCmd() *cobra.Command { +func newProvideCounterpartyTxCmd() *cobra.Command { cmd := &cobra.Command{ Use: "provide-counterparty [channel-identifier] [counterparty-channel-identifier]", Args: cobra.ExactArgs(2), @@ -43,3 +76,18 @@ func newProvideCounterpartyCmd() *cobra.Command { flags.AddTxFlagsToCmd(cmd) return cmd } + +// parseMerklePathPrefix parses a comma-separated list of hex-encoded strings into a MerklePath. +func parseMerklePathPrefix(merklePathPrefixString string) (commitmenttypesv2.MerklePath, error) { + var keyPath [][]byte + hexPrefixes := strings.Split(merklePathPrefixString, ",") + for _, hexPrefix := range hexPrefixes { + prefix, err := hex.DecodeString(hexPrefix) + if err != nil { + return commitmenttypesv2.MerklePath{}, fmt.Errorf("invalid hex merkle path prefix: %w", err) + } + keyPath = append(keyPath, prefix) + } + + return commitmenttypesv2.MerklePath{KeyPath: keyPath}, nil +}